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