iPXE
parseopt.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <stddef.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <getopt.h>
34 #include <ipxe/netdevice.h>
35 #include <ipxe/menu.h>
36 #include <ipxe/settings.h>
37 #include <ipxe/params.h>
38 #include <ipxe/timer.h>
39 #include <ipxe/keys.h>
40 #include <ipxe/parseopt.h>
41 #include <config/branding.h>
42 
43 /** @file
44  *
45  * Command line option parsing
46  *
47  */
48 
49 /** Return status code for "--help" option */
50 #define ECANCELED_NO_OP __einfo_error ( EINFO_ECANCELED_NO_OP )
51 #define EINFO_ECANCELED_NO_OP \
52  __einfo_uniqify ( EINFO_ECANCELED, 0x01, "Nothing to do" )
53 
54 /* Disambiguate the various error codes */
55 #define EINVAL_INTEGER __einfo_error ( EINFO_EINVAL_INTEGER )
56 #define EINFO_EINVAL_INTEGER \
57  __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid integer value" )
58 #define EINVAL_UNKNOWN_OPTION __einfo_error ( EINFO_EINVAL_UNKNOWN_OPTION )
59 #define EINFO_EINVAL_UNKNOWN_OPTION \
60  __einfo_uniqify ( EINFO_EINVAL, 0x02, "Unrecognised option" )
61 #define EINVAL_MISSING_ARGUMENT __einfo_error ( EINFO_EINVAL_MISSING_ARGUMENT )
62 #define EINFO_EINVAL_MISSING_ARGUMENT \
63  __einfo_uniqify ( EINFO_EINVAL, 0x03, "Missing argument" )
64 
65 /**
66 * Parse string value
67  *
68  * @v text Text
69  * @ret value String value
70  * @ret rc Return status code
71  */
72 int parse_string ( char *text, char **value ) {
73 
74  /* Sanity check */
75  assert ( text != NULL );
76 
77  /* Parse string */
78  *value = text;
79 
80  return 0;
81 }
82 
83 /**
84  * Parse integer value
85  *
86  * @v text Text
87  * @ret value Integer value
88  * @ret rc Return status code
89  */
90 int parse_integer ( char *text, unsigned int *value ) {
91  char *endp;
92 
93  /* Sanity check */
94  assert ( text != NULL );
95 
96  /* Parse integer */
97  *value = strtoul ( text, &endp, 0 );
98  if ( *endp || ( ! *text ) ) {
99  printf ( "\"%s\": invalid integer value\n", text );
100  return -EINVAL_INTEGER;
101  }
102 
103  return 0;
104 }
105 
106 /**
107  * Parse timeout value (in ms)
108  *
109  * @v text Text
110  * @ret value Integer value
111  * @ret rc Return status code
112  */
113 int parse_timeout ( char *text, unsigned long *value ) {
114  unsigned int value_ms;
115  int rc;
116 
117  /* Parse raw integer value */
118  if ( ( rc = parse_integer ( text, &value_ms ) ) != 0 )
119  return rc;
120 
121  /* Convert to a number of timer ticks */
122  *value = ( value_ms * TICKS_PER_MS );
123 
124  return 0;
125 }
126 
127 /**
128  * Parse network device name
129  *
130  * @v text Text
131  * @ret netdev Network device
132  * @ret rc Return status code
133  */
134 int parse_netdev ( char *text, struct net_device **netdev ) {
135 
136  /* Sanity check */
137  assert ( text != NULL );
138 
139  /* Find network device */
140  *netdev = find_netdev ( text );
141  if ( ! *netdev ) {
142  printf ( "\"%s\": no such network device\n", text );
143  return -ENODEV;
144  }
145 
146  return 0;
147 }
148 
149 /**
150  * Parse network device configurator name
151  *
152  * @v text Text
153  * @ret configurator Network device configurator
154  * @ret rc Return status code
155  */
156 int parse_netdev_configurator ( char *text,
157  struct net_device_configurator **configurator ){
158 
159  /* Sanity check */
160  assert ( text != NULL );
161 
162  /* Find network device configurator */
163  *configurator = find_netdev_configurator ( text );
164  if ( ! *configurator ) {
165  printf ( "\"%s\": no such configurator\n", text );
166  return -ENOTSUP;
167  }
168 
169  return 0;
170 }
171 
172 /**
173  * Parse menu name
174  *
175  * @v text Text
176  * @ret menu Menu
177  * @ret rc Return status code
178  */
179 int parse_menu ( char *text, struct menu **menu ) {
180 
181  /* Find menu */
182  *menu = find_menu ( text );
183  if ( ! *menu ) {
184  if ( text ) {
185  printf ( "\"%s\": no such menu\n", text );
186  } else {
187  printf ( "No default menu\n" );
188  }
189  return -ENOENT;
190  }
191 
192  return 0;
193 }
194 
195 /**
196  * Parse flag
197  *
198  * @v text Text (ignored)
199  * @ret flag Flag to set
200  * @ret rc Return status code
201  */
202 int parse_flag ( char *text __unused, int *flag ) {
203 
204  /* Set flag */
205  *flag = 1;
206 
207  return 0;
208 }
209 
210 /**
211  * Parse key
212  *
213  * @v text Text
214  * @ret key Key
215  * @ret rc Return status code
216  */
217 int parse_key ( char *text, unsigned int *key ) {
218  int rc;
219 
220  /* Interpret single characters as being a literal key character */
221  if ( text[0] && ! text[1] ) {
222  *key = text[0];
223  return 0;
224  }
225 
226  /* Otherwise, interpret as an integer */
227  if ( ( rc = parse_integer ( text, key ) ) < 0 )
228  return rc;
229 
230  /* For backwards compatibility with existing scripts, treat
231  * integers between the ASCII range and special key range as
232  * being relative special key values.
233  */
234  if ( ( ! isascii ( *key ) ) && ( *key < KEY_MIN ) )
235  *key += KEY_MIN;
236 
237  return 0;
238 }
239 
240 /**
241  * Parse settings block name
242  *
243  * @v text Text
244  * @ret value Integer value
245  * @ret rc Return status code
246  */
247 int parse_settings ( char *text, struct settings **value ) {
248 
249  /* Sanity check */
250  assert ( text != NULL );
251 
252  /* Parse scope name */
253  *value = find_settings ( text );
254  if ( ! *value ) {
255  printf ( "\"%s\": no such scope\n", text );
256  return -EINVAL;
257  }
258 
259  return 0;
260 }
261 
262 /**
263  * Parse setting name
264  *
265  * @v text Text
266  * @v setting Named setting to fill in
267  * @v get_child Function to find or create child settings block
268  * @ret rc Return status code
269  *
270  * Note that this function modifies the original @c text.
271  */
272 int parse_setting ( char *text, struct named_setting *setting,
273  get_child_settings_t get_child ) {
274  int rc;
275 
276  /* Sanity check */
277  assert ( text != NULL );
278 
279  /* Parse setting name */
280  if ( ( rc = parse_setting_name ( text, get_child, &setting->settings,
281  &setting->setting ) ) != 0 ) {
282  printf ( "\"%s\": invalid setting\n", text );
283  return rc;
284  }
285 
286  return 0;
287 }
288 
289 /**
290  * Parse existing setting name
291  *
292  * @v text Text
293  * @v setting Named setting to fill in
294  * @ret rc Return status code
295  *
296  * Note that this function modifies the original @c text.
297  */
298 int parse_existing_setting ( char *text, struct named_setting *setting ) {
299 
300  return parse_setting ( text, setting, find_child_settings );
301 }
302 
303 /**
304  * Parse and autovivify setting name
305  *
306  * @v text Text
307  * @v setting Named setting to fill in
308  * @ret rc Return status code
309  *
310  * Note that this function modifies the original @c text.
311  */
312 int parse_autovivified_setting ( char *text, struct named_setting *setting ) {
313 
315 }
316 
317 /**
318  * Parse request parameter list name
319  *
320  * @v text Text
321  * @ret params Parameter list
322  * @ret rc Return status code
323  */
324 int parse_parameters ( char *text, struct parameters **params ) {
325 
326  /* Find parameter list */
327  *params = find_parameters ( text );
328  if ( ! *params ) {
329  if ( text ) {
330  printf ( "\"%s\": no such parameter list\n", text );
331  } else {
332  printf ( "No default parameter list\n" );
333  }
334  return -ENOENT;
335  }
336 
337  return 0;
338 }
339 
340 /**
341  * Print command usage message
342  *
343  * @v cmd Command descriptor
344  * @v argv Argument list
345  */
346 void print_usage ( struct command_descriptor *cmd, char **argv ) {
347  struct option_descriptor *option;
348  unsigned int i;
349  int is_optional;
350 
351  printf ( "Usage:\n\n %s", argv[0] );
352  for ( i = 0 ; i < cmd->num_options ; i++ ) {
353  option = &cmd->options[i];
354  printf ( " [-%c|--%s", option->shortopt, option->longopt );
355  if ( option->has_arg ) {
356  is_optional = ( option->has_arg == optional_argument );
357  printf ( " %s<%s>%s", ( is_optional ? "[" : "" ),
358  option->longopt, ( is_optional ? "]" : "" ) );
359  }
360  printf ( "]" );
361  }
362  if ( cmd->usage )
363  printf ( " %s", cmd->usage );
364  printf ( "\n\nSee " PRODUCT_COMMAND_URI " for further information\n",
365  argv[0] );
366 }
367 
368 /**
369  * Reparse command-line options
370  *
371  * @v argc Argument count
372  * @v argv Argument list
373  * @v cmd Command descriptor
374  * @v opts Options (already initialised with default values)
375  * @ret rc Return status code
376  */
377 int reparse_options ( int argc, char **argv, struct command_descriptor *cmd,
378  void *opts ) {
379  struct option longopts[ cmd->num_options + 1 /* help */ + 1 /* end */ ];
380  char shortopts[ cmd->num_options * 3 /* possible "::" */ + 1 /* "h" */
381  + 1 /* NUL */ ];
382  unsigned int shortopt_idx = 0;
383  int ( * parse ) ( char *text, void *value );
384  void *value;
385  unsigned int i;
386  unsigned int j;
387  unsigned int num_args;
388  int c;
389  int rc;
390 
391  /* Construct long and short option lists for getopt_long() */
392  memset ( longopts, 0, sizeof ( longopts ) );
393  for ( i = 0 ; i < cmd->num_options ; i++ ) {
394  longopts[i].name = cmd->options[i].longopt;
395  longopts[i].has_arg = cmd->options[i].has_arg;
396  longopts[i].val = cmd->options[i].shortopt;
397  shortopts[shortopt_idx++] = cmd->options[i].shortopt;
398  assert ( cmd->options[i].has_arg <= optional_argument );
399  for ( j = cmd->options[i].has_arg ; j > 0 ; j-- )
400  shortopts[shortopt_idx++] = ':';
401  }
402  longopts[i].name = "help";
403  longopts[i].val = 'h';
404  shortopts[shortopt_idx++] = 'h';
405  shortopts[shortopt_idx++] = '\0';
406  assert ( shortopt_idx <= sizeof ( shortopts ) );
407  DBGC ( cmd, "Command \"%s\" has options \"%s\", %d-%d args, len %d\n",
408  argv[0], shortopts, cmd->min_args, cmd->max_args, cmd->len );
409 
410  /* Parse options */
411  while ( ( c = getopt_long ( argc, argv, shortopts, longopts,
412  NULL ) ) >= 0 ) {
413  switch ( c ) {
414  case 'h' :
415  /* Print help */
416  print_usage ( cmd, argv );
417  return -ECANCELED_NO_OP;
418  case '?' :
419  /* Print usage message */
420  print_usage ( cmd, argv );
421  return -EINVAL_UNKNOWN_OPTION;
422  case ':' :
423  /* Print usage message */
424  print_usage ( cmd, argv );
425  return -EINVAL_MISSING_ARGUMENT;
426  default:
427  /* Search for an option to parse */
428  for ( i = 0 ; i < cmd->num_options ; i++ ) {
429  if ( c != cmd->options[i].shortopt )
430  continue;
431  parse = cmd->options[i].parse;
432  value = ( opts + cmd->options[i].offset );
433  if ( ( rc = parse ( optarg, value ) ) != 0 )
434  return rc;
435  break;
436  }
437  assert ( i < cmd->num_options );
438  }
439  }
440 
441  /* Check remaining arguments */
442  num_args = ( argc - optind );
443  if ( ( num_args < cmd->min_args ) || ( num_args > cmd->max_args ) ) {
444  print_usage ( cmd, argv );
445  return -ERANGE;
446  }
447 
448  return 0;
449 }
450 
451 /**
452  * Parse command-line options
453  *
454  * @v argc Argument count
455  * @v argv Argument list
456  * @v cmd Command descriptor
457  * @v opts Options (may be uninitialised)
458  * @ret rc Return status code
459  */
460 int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
461  void *opts ) {
462 
463  /* Clear options */
464  memset ( opts, 0, cmd->len );
465 
466  return reparse_options ( argc, argv, cmd, opts );
467 }
#define EINVAL_UNKNOWN_OPTION
Definition: parseopt.c:58
int parse_integer(char *text, unsigned int *value)
Parse integer value.
Definition: parseopt.c:90
uint32_t c
Definition: md4.c:30
#define EINVAL
Invalid argument.
Definition: errno.h:428
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition: vsprintf.c:464
A parsed named setting.
Definition: parseopt.h:121
int parse_key(char *text, unsigned int *key)
Parse key.
Definition: parseopt.c:217
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition: string.c:471
int optind
Current option index.
Definition: getopt.c:51
int val
Value to return.
Definition: getopt.h:49
int parse_netdev_configurator(char *text, struct net_device_configurator **configurator)
Parse network device configurator name.
Definition: parseopt.c:156
Error codes.
int parse_timeout(char *text, unsigned long *value)
Parse timeout value (in ms)
Definition: parseopt.c:113
A request parameter list.
Definition: params.h:16
int parse_autovivified_setting(char *text, struct named_setting *setting)
Parse and autovivify setting name.
Definition: parseopt.c:312
#define DBGC(...)
Definition: compiler.h:505
#define ENOENT
No such file or directory.
Definition: errno.h:514
int parse_setting(char *text, struct named_setting *setting, get_child_settings_t get_child)
Parse setting name.
Definition: parseopt.c:272
int parse_options(int argc, char **argv, struct command_descriptor *cmd, void *opts)
Parse command-line options.
Definition: parseopt.c:460
Branding configuration.
static int isascii(int character)
Check if character is ASCII.
Definition: ctype.h:18
iPXE timers
Character types.
A command descriptor.
Definition: parseopt.h:76
struct parameters * find_parameters(const char *name)
Find request parameter list by name.
Definition: params.c:68
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
#define KEY_MIN
Minimum value for special keypresses.
Definition: keys.h:68
struct net_device_configurator * find_netdev_configurator(const char *name)
Find network device configurator.
Definition: netdevice.c:1278
Parse command-line options.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
Request parameters.
int parse_string(char *text, char **value)
Parse string value.
Definition: parseopt.c:72
A long option, as used for getopt_long()
Definition: getopt.h:24
struct settings *(* get_child_settings_t)(struct settings *settings, const char *name)
A child settings block locator function.
Definition: settings.h:306
static struct net_device * netdev
Definition: gdbudp.c:52
struct settings * autovivify_child_settings(struct settings *parent, const char *name)
Find or create child settings block.
Definition: settings.c:306
int reparse_options(int argc, char **argv, struct command_descriptor *cmd, void *opts)
Reparse command-line options.
Definition: parseopt.c:377
int parse_existing_setting(char *text, struct named_setting *setting)
Parse existing setting name.
Definition: parseopt.c:298
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
Configuration settings.
int parse_flag(char *text __unused, int *flag)
Parse flag.
Definition: parseopt.c:202
#define PRODUCT_COMMAND_URI
Definition: branding.h:127
#define ERANGE
Result too large.
Definition: errno.h:639
const char * name
Long name of this option.
Definition: getopt.h:26
int parse_parameters(char *text, struct parameters **params)
Parse request parameter list name.
Definition: parseopt.c:324
Command line option parsing.
A network device.
Definition: netdevice.h:352
#define ENODEV
No such device.
Definition: errno.h:509
A settings block.
Definition: settings.h:132
static union @437 opts
"cert<xxx>" option list
A setting.
Definition: settings.h:23
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Parse command-line options.
Definition: getopt.c:229
void print_usage(struct command_descriptor *cmd, char **argv)
Print command usage message.
Definition: parseopt.c:346
Network device management.
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
struct net_device * find_netdev(const char *name)
Get network device by name.
Definition: netdevice.c:988
Key definitions.
A network device configurator.
Definition: netdevice.h:313
A command-line option descriptor.
Definition: parseopt.h:22
#define EINVAL_MISSING_ARGUMENT
Definition: parseopt.c:61
struct settings * find_settings(const char *name)
Find settings block.
Definition: settings.c:406
int parse_menu(char *text, struct menu **menu)
Parse menu name.
Definition: parseopt.c:179
#define EINVAL_INTEGER
Definition: parseopt.c:55
char * optarg
Option argument.
Definition: getopt.c:43
#define ECANCELED_NO_OP
Return status code for "--help" option.
Definition: parseopt.c:50
Option may have an argument.
Definition: getopt.h:20
int parse_settings(char *text, struct settings **value)
Parse settings block name.
Definition: parseopt.c:247
struct settings * find_child_settings(struct settings *parent, const char *name)
Find child settings block.
Definition: settings.c:279
int has_arg
Option takes an argument.
Definition: getopt.h:32
A menu.
Definition: menu.h:15
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
struct golan_eqe_cmd cmd
Definition: CIB_PRM.h:29
String functions.
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define TICKS_PER_MS
Number of ticks per millisecond.
Definition: timer.h:25
union @382 key
Sense key.
Definition: crypto.h:284
int parse_setting_name(char *name, get_child_settings_t get_child, struct settings **settings, struct setting *setting)
Parse setting name.
Definition: settings.c:1528
uint16_t flag
Flag number.
Definition: hyperv.h:14
void * memset(void *dest, int character, size_t len) __nonnull
int parse_netdev(char *text, struct net_device **netdev)
Parse network device name.
Definition: parseopt.c:134