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