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/uuid.h>
35 #include <ipxe/netdevice.h>
36 #include <ipxe/menu.h>
37 #include <ipxe/settings.h>
38 #include <ipxe/params.h>
39 #include <ipxe/timer.h>
40 #include <ipxe/keys.h>
41 #include <ipxe/parseopt.h>
42 #include <config/branding.h>
43 
44 /** @file
45  *
46  * Command line option parsing
47  *
48  */
49 
50 /** Return status code for "--help" option */
51 #define ECANCELED_NO_OP __einfo_error ( EINFO_ECANCELED_NO_OP )
52 #define EINFO_ECANCELED_NO_OP \
53  __einfo_uniqify ( EINFO_ECANCELED, 0x01, "Nothing to do" )
54 
55 /* Disambiguate the various error codes */
56 #define EINVAL_INTEGER __einfo_error ( EINFO_EINVAL_INTEGER )
57 #define EINFO_EINVAL_INTEGER \
58  __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid integer value" )
59 #define EINVAL_UNKNOWN_OPTION __einfo_error ( EINFO_EINVAL_UNKNOWN_OPTION )
60 #define EINFO_EINVAL_UNKNOWN_OPTION \
61  __einfo_uniqify ( EINFO_EINVAL, 0x02, "Unrecognised option" )
62 #define EINVAL_MISSING_ARGUMENT __einfo_error ( EINFO_EINVAL_MISSING_ARGUMENT )
63 #define EINFO_EINVAL_MISSING_ARGUMENT \
64  __einfo_uniqify ( EINFO_EINVAL, 0x03, "Missing argument" )
65 
66 /**
67 * Parse string value
68  *
69  * @v text Text
70  * @ret value String value
71  * @ret rc Return status code
72  */
73 int parse_string ( char *text, char **value ) {
74 
75  /* Sanity check */
76  assert ( text != NULL );
77 
78  /* Parse string */
79  *value = text;
80 
81  return 0;
82 }
83 
84 /**
85  * Parse integer value
86  *
87  * @v text Text
88  * @ret value Integer value
89  * @ret rc Return status code
90  */
91 int parse_integer ( char *text, unsigned int *value ) {
92  char *endp;
93 
94  /* Sanity check */
95  assert ( text != NULL );
96 
97  /* Parse integer */
98  *value = strtoul ( text, &endp, 0 );
99  if ( *endp || ( ! *text ) ) {
100  printf ( "\"%s\": invalid integer value\n", text );
101  return -EINVAL_INTEGER;
102  }
103 
104  return 0;
105 }
106 
107 /**
108  * Parse timeout value (in ms)
109  *
110  * @v text Text
111  * @ret value Integer value
112  * @ret rc Return status code
113  */
114 int parse_timeout ( char *text, unsigned long *value ) {
115  unsigned int value_ms;
116  int rc;
117 
118  /* Parse raw integer value */
119  if ( ( rc = parse_integer ( text, &value_ms ) ) != 0 )
120  return rc;
121 
122  /* Convert to a number of timer ticks */
123  *value = ( value_ms * TICKS_PER_MS );
124 
125  return 0;
126 }
127 
128 /**
129  * Parse UUID
130  *
131  * @v text Text
132  * @ret uuid UUID value
133  * @ret rc Return status code
134  */
135 int parse_uuid ( char *text, struct uuid_option *uuid ) {
136  int rc;
137 
138  /* Sanity check */
139  assert ( text != NULL );
140 
141  /* Parse UUID */
142  if ( ( rc = uuid_aton ( text, &uuid->buf ) ) != 0 ) {
143  printf ( "\"%s\": invalid UUID\n", text );
144  return rc;
145  }
146  uuid->value = &uuid->buf;
147 
148  return 0;
149 }
150 
151 /**
152  * Parse network device name
153  *
154  * @v text Text
155  * @ret netdev Network device
156  * @ret rc Return status code
157  */
158 int parse_netdev ( char *text, struct net_device **netdev ) {
159 
160  /* Sanity check */
161  assert ( text != NULL );
162 
163  /* Find network device */
164  *netdev = find_netdev ( text );
165  if ( ! *netdev ) {
166  printf ( "\"%s\": no such network device\n", text );
167  return -ENODEV;
168  }
169 
170  return 0;
171 }
172 
173 /**
174  * Parse network device configurator name
175  *
176  * @v text Text
177  * @ret configurator Network device configurator
178  * @ret rc Return status code
179  */
180 int parse_netdev_configurator ( char *text,
181  struct net_device_configurator **configurator ){
182 
183  /* Sanity check */
184  assert ( text != NULL );
185 
186  /* Find network device configurator */
187  *configurator = find_netdev_configurator ( text );
188  if ( ! *configurator ) {
189  printf ( "\"%s\": no such configurator\n", text );
190  return -ENOTSUP;
191  }
192 
193  return 0;
194 }
195 
196 /**
197  * Parse menu name
198  *
199  * @v text Text
200  * @ret menu Menu
201  * @ret rc Return status code
202  */
203 int parse_menu ( char *text, struct menu **menu ) {
204 
205  /* Find menu */
206  *menu = find_menu ( text );
207  if ( ! *menu ) {
208  if ( text ) {
209  printf ( "\"%s\": no such menu\n", text );
210  } else {
211  printf ( "No default menu\n" );
212  }
213  return -ENOENT;
214  }
215 
216  return 0;
217 }
218 
219 /**
220  * Parse flag
221  *
222  * @v text Text (ignored)
223  * @ret flag Flag to set
224  * @ret rc Return status code
225  */
226 int parse_flag ( char *text __unused, int *flag ) {
227 
228  /* Set flag */
229  *flag = 1;
230 
231  return 0;
232 }
233 
234 /**
235  * Parse key
236  *
237  * @v text Text
238  * @ret key Key
239  * @ret rc Return status code
240  */
241 int parse_key ( char *text, unsigned int *key ) {
242  int rc;
243 
244  /* Interpret single characters as being a literal key character */
245  if ( text[0] && ! text[1] ) {
246  *key = text[0];
247  return 0;
248  }
249 
250  /* Otherwise, interpret as an integer */
251  if ( ( rc = parse_integer ( text, key ) ) < 0 )
252  return rc;
253 
254  /* For backwards compatibility with existing scripts, treat
255  * integers between the ASCII range and special key range as
256  * being relative special key values.
257  */
258  if ( ( ! isascii ( *key ) ) && ( *key < KEY_MIN ) )
259  *key += KEY_MIN;
260 
261  return 0;
262 }
263 
264 /**
265  * Parse settings block name
266  *
267  * @v text Text
268  * @ret value Integer value
269  * @ret rc Return status code
270  */
271 int parse_settings ( char *text, struct settings **value ) {
272 
273  /* Sanity check */
274  assert ( text != NULL );
275 
276  /* Parse scope name */
277  *value = find_settings ( text );
278  if ( ! *value ) {
279  printf ( "\"%s\": no such scope\n", text );
280  return -EINVAL;
281  }
282 
283  return 0;
284 }
285 
286 /**
287  * Parse setting name
288  *
289  * @v text Text
290  * @v setting Named setting to fill in
291  * @v get_child Function to find or create child settings block
292  * @ret rc Return status code
293  *
294  * Note that this function modifies the original @c text.
295  */
296 int parse_setting ( char *text, struct named_setting *setting,
297  get_child_settings_t get_child ) {
298  int rc;
299 
300  /* Sanity check */
301  assert ( text != NULL );
302 
303  /* Parse setting name */
304  if ( ( rc = parse_setting_name ( text, get_child, &setting->settings,
305  &setting->setting ) ) != 0 ) {
306  printf ( "\"%s\": invalid setting\n", text );
307  return rc;
308  }
309 
310  return 0;
311 }
312 
313 /**
314  * Parse existing setting name
315  *
316  * @v text Text
317  * @v setting Named setting to fill in
318  * @ret rc Return status code
319  *
320  * Note that this function modifies the original @c text.
321  */
322 int parse_existing_setting ( char *text, struct named_setting *setting ) {
323 
324  return parse_setting ( text, setting, find_child_settings );
325 }
326 
327 /**
328  * Parse and autovivify setting name
329  *
330  * @v text Text
331  * @v setting Named setting to fill in
332  * @ret rc Return status code
333  *
334  * Note that this function modifies the original @c text.
335  */
336 int parse_autovivified_setting ( char *text, struct named_setting *setting ) {
337 
339 }
340 
341 /**
342  * Parse request parameter list name
343  *
344  * @v text Text
345  * @ret params Parameter list
346  * @ret rc Return status code
347  */
348 int parse_parameters ( char *text, struct parameters **params ) {
349 
350  /* Find parameter list */
351  *params = find_parameters ( text );
352  if ( ! *params ) {
353  if ( text ) {
354  printf ( "\"%s\": no such parameter list\n", text );
355  } else {
356  printf ( "No default parameter list\n" );
357  }
358  return -ENOENT;
359  }
360 
361  return 0;
362 }
363 
364 /**
365  * Print command usage message
366  *
367  * @v cmd Command descriptor
368  * @v argv Argument list
369  */
370 void print_usage ( struct command_descriptor *cmd, char **argv ) {
371  struct option_descriptor *option;
372  unsigned int i;
373  int is_optional;
374 
375  printf ( "Usage:\n\n %s", argv[0] );
376  for ( i = 0 ; i < cmd->num_options ; i++ ) {
377  option = &cmd->options[i];
378  printf ( " [-%c|--%s", option->shortopt, option->longopt );
379  if ( option->has_arg ) {
380  is_optional = ( option->has_arg == optional_argument );
381  printf ( " %s<%s>%s", ( is_optional ? "[" : "" ),
382  option->longopt, ( is_optional ? "]" : "" ) );
383  }
384  printf ( "]" );
385  }
386  if ( cmd->usage )
387  printf ( " %s", cmd->usage );
388  printf ( "\n\nSee " PRODUCT_COMMAND_URI " for further information\n",
389  argv[0] );
390 }
391 
392 /**
393  * Reparse command-line options
394  *
395  * @v argc Argument count
396  * @v argv Argument list
397  * @v cmd Command descriptor
398  * @v opts Options (already initialised with default values)
399  * @ret rc Return status code
400  */
401 int reparse_options ( int argc, char **argv, struct command_descriptor *cmd,
402  void *opts ) {
403  struct option longopts[ cmd->num_options + 1 /* help */ + 1 /* end */ ];
404  char shortopts[ cmd->num_options * 3 /* possible "::" */ + 1 /* "h" */
405  + 1 /* NUL */ ];
406  unsigned int shortopt_idx = 0;
407  int ( * parse ) ( char *text, void *value );
408  void *value;
409  unsigned int i;
410  unsigned int j;
411  unsigned int num_args;
412  int c;
413  int rc;
414 
415  /* Construct long and short option lists for getopt_long() */
416  memset ( longopts, 0, sizeof ( longopts ) );
417  for ( i = 0 ; i < cmd->num_options ; i++ ) {
418  longopts[i].name = cmd->options[i].longopt;
419  longopts[i].has_arg = cmd->options[i].has_arg;
420  longopts[i].val = cmd->options[i].shortopt;
421  shortopts[shortopt_idx++] = cmd->options[i].shortopt;
422  assert ( cmd->options[i].has_arg <= optional_argument );
423  for ( j = cmd->options[i].has_arg ; j > 0 ; j-- )
424  shortopts[shortopt_idx++] = ':';
425  }
426  longopts[i].name = "help";
427  longopts[i].val = 'h';
428  shortopts[shortopt_idx++] = 'h';
429  shortopts[shortopt_idx++] = '\0';
430  assert ( shortopt_idx <= sizeof ( shortopts ) );
431  DBGC ( cmd, "Command \"%s\" has options \"%s\", %d-%d args, len %d\n",
432  argv[0], shortopts, cmd->min_args, cmd->max_args, cmd->len );
433 
434  /* Parse options */
435  while ( ( c = getopt_long ( argc, argv, shortopts, longopts,
436  NULL ) ) >= 0 ) {
437  switch ( c ) {
438  case 'h' :
439  /* Print help */
440  print_usage ( cmd, argv );
441  return -ECANCELED_NO_OP;
442  case '?' :
443  /* Print usage message */
444  print_usage ( cmd, argv );
445  return -EINVAL_UNKNOWN_OPTION;
446  case ':' :
447  /* Print usage message */
448  print_usage ( cmd, argv );
449  return -EINVAL_MISSING_ARGUMENT;
450  default:
451  /* Search for an option to parse */
452  for ( i = 0 ; i < cmd->num_options ; i++ ) {
453  if ( c != cmd->options[i].shortopt )
454  continue;
455  parse = cmd->options[i].parse;
456  value = ( opts + cmd->options[i].offset );
457  if ( ( rc = parse ( optarg, value ) ) != 0 )
458  return rc;
459  break;
460  }
461  assert ( i < cmd->num_options );
462  }
463  }
464 
465  /* Check remaining arguments */
466  num_args = ( argc - optind );
467  if ( ( num_args < cmd->min_args ) || ( num_args > cmd->max_args ) ) {
468  print_usage ( cmd, argv );
469  return -ERANGE;
470  }
471 
472  return 0;
473 }
474 
475 /**
476  * Parse command-line options
477  *
478  * @v argc Argument count
479  * @v argv Argument list
480  * @v cmd Command descriptor
481  * @v opts Options (may be uninitialised)
482  * @ret rc Return status code
483  */
484 int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
485  void *opts ) {
486 
487  /* Clear options */
488  memset ( opts, 0, cmd->len );
489 
490  return reparse_options ( argc, argv, cmd, opts );
491 }
#define EINVAL_UNKNOWN_OPTION
Definition: parseopt.c:59
int parse_integer(char *text, unsigned int *value)
Parse integer value.
Definition: parseopt.c:91
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:122
int parse_key(char *text, unsigned int *key)
Parse key.
Definition: parseopt.c:241
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:180
int parse_uuid(char *text, struct uuid_option *uuid)
Parse UUID.
Definition: parseopt.c:135
A UUID command-line option.
Definition: parseopt.h:130
Error codes.
A universally unique ID.
Definition: uuid.h:15
int parse_timeout(char *text, unsigned long *value)
Parse timeout value (in ms)
Definition: parseopt.c:114
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:336
#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:296
Universally unique IDs.
int parse_options(int argc, char **argv, struct command_descriptor *cmd, void *opts)
Parse command-line options.
Definition: parseopt.c:484
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:77
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
int uuid_aton(const char *string, union uuid *uuid)
Parse UUID.
Definition: uuid.c:66
#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:73
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:401
int parse_existing_setting(char *text, struct named_setting *setting)
Parse existing setting name.
Definition: parseopt.c:322
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
Configuration settings.
int parse_flag(char *text __unused, int *flag)
Parse flag.
Definition: parseopt.c:226
#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:348
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:370
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:23
#define EINVAL_MISSING_ARGUMENT
Definition: parseopt.c:62
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:203
#define EINVAL_INTEGER
Definition: parseopt.c:56
char * optarg
Option argument.
Definition: getopt.c:43
#define ECANCELED_NO_OP
Return status code for "--help" option.
Definition: parseopt.c:51
Option may have an argument.
Definition: getopt.h:20
int parse_settings(char *text, struct settings **value)
Parse settings block name.
Definition: parseopt.c:271
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:158