iPXE
exec.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006 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 <stdint.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <unistd.h>
32 #include <getopt.h>
33 #include <errno.h>
34 #include <assert.h>
35 #include <ipxe/tables.h>
36 #include <ipxe/command.h>
37 #include <ipxe/parseopt.h>
38 #include <ipxe/settings.h>
39 #include <ipxe/shell.h>
40 
41 /** @file
42  *
43  * Command execution
44  *
45  */
46 
47 /** Shell stop state */
48 static int stop_state;
49 
50 /**
51  * Execute command
52  *
53  * @v command Command name
54  * @v argv Argument list
55  * @ret rc Return status code
56  *
57  * Execute the named command. Unlike a traditional POSIX execv(),
58  * this function returns the exit status of the command.
59  */
60 int execv ( const char *command, char * const argv[] ) {
61  struct command *cmd;
62  int argc;
63  int rc;
64 
65  /* Count number of arguments */
66  for ( argc = 0 ; argv[argc] ; argc++ ) {}
67 
68  /* An empty command is deemed to do nothing, successfully */
69  if ( command == NULL ) {
70  rc = 0;
71  goto done;
72  }
73 
74  /* Sanity checks */
75  if ( argc == 0 ) {
76  DBG ( "%s: empty argument list\n", command );
77  rc = -EINVAL;
78  goto done;
79  }
80 
81  /* Reset getopt() library ready for use by the command. This
82  * is an artefact of the POSIX getopt() API within the context
83  * of Etherboot; see the documentation for reset_getopt() for
84  * details.
85  */
86  reset_getopt();
87 
88  /* Hand off to command implementation */
90  if ( strcmp ( command, cmd->name ) == 0 ) {
91  rc = cmd->exec ( argc, ( char ** ) argv );
92  goto done;
93  }
94  }
95 
96  printf ( "%s: command not found\n", command );
97  rc = -ENOEXEC;
98 
99  done:
100  /* Store error number, if an error occurred */
101  if ( rc ) {
102  errno = rc;
103  if ( errno < 0 )
104  errno = -errno;
105  }
106 
107  return rc;
108 }
109 
110 /**
111  * Split command line into tokens
112  *
113  * @v command Command line
114  * @v tokens Token list to populate, or NULL
115  * @ret count Number of tokens
116  *
117  * Splits the command line into whitespace-delimited tokens. If @c
118  * tokens is non-NULL, any whitespace in the command line will be
119  * replaced with NULs.
120  */
121 static int split_command ( char *command, char **tokens ) {
122  int count = 0;
123 
124  while ( 1 ) {
125  /* Skip over any whitespace / convert to NUL */
126  while ( isspace ( *command ) ) {
127  if ( tokens )
128  *command = '\0';
129  command++;
130  }
131  /* Check for end of line */
132  if ( ! *command )
133  break;
134  /* We have found the start of the next argument */
135  if ( tokens )
136  tokens[count] = command;
137  count++;
138  /* Skip to start of next whitespace, if any */
139  while ( *command && ! isspace ( *command ) ) {
140  command++;
141  }
142  }
143  return count;
144 }
145 
146 /**
147  * Process next command only if previous command succeeded
148  *
149  * @v rc Status of previous command
150  * @ret process Process next command
151  */
152 static int process_on_success ( int rc ) {
153  return ( rc == 0 );
154 }
155 
156 /**
157  * Process next command only if previous command failed
158  *
159  * @v rc Status of previous command
160  * @ret process Process next command
161  */
162 static int process_on_failure ( int rc ) {
163  return ( rc != 0 );
164 }
165 
166 /**
167  * Process next command regardless of status from previous command
168  *
169  * @v rc Status of previous command
170  * @ret process Process next command
171  */
172 static int process_always ( int rc __unused ) {
173  return 1;
174 }
175 
176 /**
177  * Find command terminator
178  *
179  * @v tokens Token list
180  * @ret process_next "Should next command be processed?" function
181  * @ret argc Argument count
182  */
183 static int command_terminator ( char **tokens,
184  int ( **process_next ) ( int rc ) ) {
185  unsigned int i;
186 
187  /* Find first terminating token */
188  for ( i = 0 ; tokens[i] ; i++ ) {
189  if ( tokens[i][0] == '#' ) {
190  /* Start of a comment */
191  break;
192  } else if ( strcmp ( tokens[i], "||" ) == 0 ) {
193  /* Short-circuit logical OR */
194  *process_next = process_on_failure;
195  return i;
196  } else if ( strcmp ( tokens[i], "&&" ) == 0 ) {
197  /* Short-circuit logical AND */
198  *process_next = process_on_success;
199  return i;
200  } else if ( strcmp ( tokens[i], ";" ) == 0 ) {
201  /* Process next command unconditionally */
202  *process_next = process_always;
203  return i;
204  }
205  }
206 
207  /* End of token list */
208  *process_next = NULL;
209  return i;
210 }
211 
212 /**
213  * Set shell stop state
214  *
215  * @v stop Shell stop state
216  */
217 void shell_stop ( int stop ) {
218  stop_state = stop;
219 }
220 
221 /**
222  * Test and consume shell stop state
223  *
224  * @v stop Shell stop state to consume
225  * @v stopped Shell had been stopped
226  */
227 int shell_stopped ( int stop ) {
228  int stopped;
229 
230  /* Test to see if we need to stop */
231  stopped = ( stop_state >= stop );
232 
233  /* Consume stop state */
234  if ( stop_state <= stop )
235  stop_state = 0;
236 
237  return stopped;
238 }
239 
240 /**
241  * Expand settings within a token list
242  *
243  * @v argc Argument count
244  * @v tokens Token list
245  * @v argv Argument list to fill in
246  * @ret rc Return status code
247  */
248 static int expand_tokens ( int argc, char **tokens, char **argv ) {
249  int i;
250 
251  /* Expand each token in turn */
252  for ( i = 0 ; i < argc ; i++ ) {
253  argv[i] = expand_settings ( tokens[i] );
254  if ( ! argv[i] )
255  goto err_expand_settings;
256  }
257 
258  return 0;
259 
260  err_expand_settings:
261  assert ( argv[i] == NULL );
262  for ( ; i >= 0 ; i-- )
263  free ( argv[i] );
264  return -ENOMEM;
265 }
266 
267 /**
268  * Free an expanded token list
269  *
270  * @v argv Argument list
271  */
272 static void free_tokens ( char **argv ) {
273 
274  /* Free each expanded argument */
275  while ( *argv )
276  free ( *(argv++) );
277 }
278 
279 /**
280  * Execute command line
281  *
282  * @v command Command line
283  * @ret rc Return status code
284  *
285  * Execute the named command and arguments.
286  */
287 int system ( const char *command ) {
288  int count = split_command ( ( char * ) command, NULL );
289  char *all_tokens[ count + 1 ];
290  int ( * process_next ) ( int rc );
291  char *command_copy;
292  char **tokens;
293  int argc;
294  int process;
295  int rc = 0;
296 
297  /* Create modifiable copy of command */
298  command_copy = strdup ( command );
299  if ( ! command_copy )
300  return -ENOMEM;
301 
302  /* Split command into tokens */
303  split_command ( command_copy, all_tokens );
304  all_tokens[count] = NULL;
305 
306  /* Process individual commands */
307  process = 1;
308  for ( tokens = all_tokens ; ; tokens += ( argc + 1 ) ) {
309 
310  /* Find command terminator */
311  argc = command_terminator ( tokens, &process_next );
312 
313  /* Expand tokens and execute command */
314  if ( process ) {
315  char *argv[ argc + 1 ];
316 
317  /* Expand tokens */
318  if ( ( rc = expand_tokens ( argc, tokens, argv ) ) != 0)
319  break;
320  argv[argc] = NULL;
321 
322  /* Execute command */
323  rc = execv ( argv[0], argv );
324 
325  /* Free tokens */
326  free_tokens ( argv );
327  }
328 
329  /* Stop processing, if applicable */
331  break;
332 
333  /* Stop processing if we have reached the end of the
334  * command.
335  */
336  if ( ! process_next )
337  break;
338 
339  /* Determine whether or not to process next command */
340  process = process_next ( rc );
341  }
342 
343  /* Free modified copy of command */
344  free ( command_copy );
345 
346  return rc;
347 }
348 
349 /**
350  * Concatenate arguments
351  *
352  * @v args Argument list (NULL-terminated)
353  * @ret string Concatenated arguments
354  *
355  * The returned string is allocated with malloc(). The caller is
356  * responsible for eventually free()ing this string.
357  */
358 char * concat_args ( char **args ) {
359  char **arg;
360  size_t len;
361  char *string;
362  char *ptr;
363 
364  /* Calculate total string length */
365  len = 1 /* NUL */;
366  for ( arg = args ; *arg ; arg++ )
367  len += ( 1 /* possible space */ + strlen ( *arg ) );
368 
369  /* Allocate string */
370  string = zalloc ( len );
371  if ( ! string )
372  return NULL;
373 
374  /* Populate string */
375  ptr = string;
376  for ( arg = args ; *arg ; arg++ ) {
377  ptr += sprintf ( ptr, "%s%s",
378  ( ( arg == args ) ? "" : " " ), *arg );
379  }
380  assert ( ptr < ( string + len ) );
381 
382  return string;
383 }
384 
385 /** "echo" options */
386 struct echo_options {
387  /** Do not print trailing newline */
389 };
390 
391 /** "echo" option list */
392 static struct option_descriptor echo_opts[] = {
393  OPTION_DESC ( "n", 'n', no_argument,
394  struct echo_options, no_newline, parse_flag ),
395 };
396 
397 /** "echo" command descriptor */
400  "[...]" );
401 
402 /**
403  * "echo" command
404  *
405  * @v argc Argument count
406  * @v argv Argument list
407  * @ret rc Return status code
408  */
409 static int echo_exec ( int argc, char **argv ) {
410  struct echo_options opts;
411  char *text;
412  int rc;
413 
414  /* Parse options */
415  if ( ( rc = parse_options ( argc, argv, &echo_cmd, &opts ) ) != 0 )
416  return rc;
417 
418  /* Parse text */
419  text = concat_args ( &argv[optind] );
420  if ( ! text )
421  return -ENOMEM;
422 
423  /* Print text */
424  printf ( "%s%s", text, ( opts.no_newline ? "" : "\n" ) );
425 
426  free ( text );
427  return 0;
428 }
429 
430 /** "echo" command */
431 struct command echo_command __command = {
432  .name = "echo",
433  .exec = echo_exec,
434 };
435 
436 /** "exit" options */
437 struct exit_options {};
438 
439 /** "exit" option list */
440 static struct option_descriptor exit_opts[] = {};
441 
442 /** "exit" command descriptor */
444  COMMAND_DESC ( struct exit_options, exit_opts, 0, 1, "[<status>]" );
445 
446 /**
447  * "exit" command
448  *
449  * @v argc Argument count
450  * @v argv Argument list
451  * @ret rc Return status code
452  */
453 static int exit_exec ( int argc, char **argv ) {
454  struct exit_options opts;
455  unsigned int exit_code = 0;
456  int rc;
457 
458  /* Parse options */
459  if ( ( rc = parse_options ( argc, argv, &exit_cmd, &opts ) ) != 0 )
460  return rc;
461 
462  /* Parse exit status, if present */
463  if ( optind != argc ) {
464  if ( ( rc = parse_integer ( argv[optind], &exit_code ) ) != 0 )
465  return rc;
466  }
467 
468  /* Stop shell processing */
470 
471  return exit_code;
472 }
473 
474 /** "exit" command */
475 struct command exit_command __command = {
476  .name = "exit",
477  .exec = exit_exec,
478 };
479 
480 /** "isset" options */
481 struct isset_options {};
482 
483 /** "isset" option list */
484 static struct option_descriptor isset_opts[] = {};
485 
486 /** "isset" command descriptor */
488  COMMAND_DESC ( struct isset_options, isset_opts, 1, 1, "<value>" );
489 
490 /**
491  * "isset" command
492  *
493  * @v argc Argument count
494  * @v argv Argument list
495  * @ret rc Return status code
496  */
497 static int isset_exec ( int argc, char **argv ) {
498  struct isset_options opts;
499  int rc;
500 
501  /* Parse options */
502  if ( ( rc = parse_options ( argc, argv, &isset_cmd, &opts ) ) != 0 )
503  return rc;
504 
505  /* Return success iff argument is non-empty */
506  return ( argv[optind][0] ? 0 : -ENOENT );
507 }
508 
509 /** "isset" command */
510 struct command isset_command __command = {
511  .name = "isset",
512  .exec = isset_exec,
513 };
514 
515 /** "iseq" options */
516 struct iseq_options {};
517 
518 /** "iseq" option list */
519 static struct option_descriptor iseq_opts[] = {};
520 
521 /** "iseq" command descriptor */
523  COMMAND_DESC ( struct iseq_options, iseq_opts, 2, 2,
524  "<value1> <value2>" );
525 
526 /**
527  * "iseq" command
528  *
529  * @v argc Argument count
530  * @v argv Argument list
531  * @ret rc Return status code
532  */
533 static int iseq_exec ( int argc, char **argv ) {
534  struct iseq_options opts;
535  int rc;
536 
537  /* Parse options */
538  if ( ( rc = parse_options ( argc, argv, &iseq_cmd, &opts ) ) != 0 )
539  return rc;
540 
541  /* Return success iff arguments are equal */
542  return ( ( strcmp ( argv[optind], argv[ optind + 1 ] ) == 0 ) ?
543  0 : -ERANGE );
544 }
545 
546 /** "iseq" command */
547 struct command iseq_command __command = {
548  .name = "iseq",
549  .exec = iseq_exec,
550 };
551 
552 /** "sleep" options */
553 struct sleep_options {};
554 
555 /** "sleep" option list */
556 static struct option_descriptor sleep_opts[] = {};
557 
558 /** "sleep" command descriptor */
560  COMMAND_DESC ( struct sleep_options, sleep_opts, 1, 1, "<seconds>" );
561 
562 /**
563  * "sleep" command
564  *
565  * @v argc Argument count
566  * @v argv Argument list
567  * @ret rc Return status code
568  */
569 static int sleep_exec ( int argc, char **argv ) {
570  struct sleep_options opts;
571  unsigned int seconds;
572  int rc;
573 
574  /* Parse options */
575  if ( ( rc = parse_options ( argc, argv, &sleep_cmd, &opts ) ) != 0 )
576  return rc;
577 
578  /* Parse number of seconds */
579  if ( ( rc = parse_integer ( argv[optind], &seconds ) ) != 0 )
580  return rc;
581 
582  /* Delay for specified number of seconds */
583  if ( sleep ( seconds ) != 0 )
584  return -ECANCELED;
585 
586  return 0;
587 }
588 
589 /** "sleep" command */
590 struct command sleep_command __command = {
591  .name = "sleep",
592  .exec = sleep_exec,
593 };
A process.
Definition: process.h:17
int parse_integer(char *text, unsigned int *value)
Parse integer value.
Definition: parseopt.c:88
#define EINVAL
Invalid argument.
Definition: errno.h:428
static struct option_descriptor sleep_opts[]
"sleep" option list
Definition: exec.c:556
static struct option_descriptor exit_opts[]
"exit" option list
Definition: exec.c:440
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
Minimal command shell.
int optind
Current option index.
Definition: getopt.c:51
int no_newline
Do not print trailing newline.
Definition: exec.c:388
"iseq" options
Definition: exec.c:516
Error codes.
static int isset_exec(int argc, char **argv)
"isset" command
Definition: exec.c:497
int system(const char *command)
Execute command line.
Definition: exec.c:287
A command-line command.
Definition: command.h:9
#define ENOEXEC
Exec format error.
Definition: errno.h:519
#define sprintf(buf, fmt,...)
Write a formatted string to a buffer.
Definition: stdio.h:36
struct command echo_command __command
"echo" command
Definition: exec.c:431
static struct command_descriptor sleep_cmd
"sleep" command descriptor
Definition: exec.c:559
#define ENOENT
No such file or directory.
Definition: errno.h:514
static void free_tokens(char **argv)
Free an expanded token list.
Definition: exec.c:272
uint32_t string
Definition: multiboot.h:14
int parse_options(int argc, char **argv, struct command_descriptor *cmd, void *opts)
Parse command-line options.
Definition: parseopt.c:447
char * expand_settings(const char *string)
Expand variables within string.
Definition: settings.c:2288
Character types.
A command descriptor.
Definition: parseopt.h:76
void shell_stop(int stop)
Set shell stop state.
Definition: exec.c:217
#define ECANCELED
Operation canceled.
Definition: errno.h:343
static int expand_tokens(int argc, char **tokens, char **argv)
Expand settings within a token list.
Definition: exec.c:248
"sleep" options
Definition: exec.c:553
#define ENOMEM
Not enough space.
Definition: errno.h:534
Stop processing current command line.
Definition: shell.h:22
Assertions.
"isset" options
Definition: exec.c:481
Parse command-line options.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
static int process_always(int rc __unused)
Process next command regardless of status from previous command.
Definition: exec.c:172
static struct option_descriptor echo_opts[]
"echo" option list
Definition: exec.c:392
int errno
Global "last error" number.
Definition: errno.c:20
static int echo_exec(int argc, char **argv)
"echo" command
Definition: exec.c:409
static struct command_descriptor isset_cmd
"isset" command descriptor
Definition: exec.c:487
#define MAX_ARGUMENTS
No maximum number of arguments.
Definition: parseopt.h:96
static struct command_descriptor exit_cmd
"exit" command descriptor
Definition: exec.c:443
static struct option_descriptor isset_opts[]
"isset" option list
Definition: exec.c:484
char * concat_args(char **args)
Concatenate arguments.
Definition: exec.c:358
static int sleep_exec(int argc, char **argv)
"sleep" command
Definition: exec.c:569
static union @423 opts
"cert<xxx>" option list
Configuration settings.
int parse_flag(char *text __unused, int *flag)
Parse flag.
Definition: parseopt.c:200
#define ERANGE
Result too large.
Definition: errno.h:639
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static int process_on_failure(int rc)
Process next command only if previous command failed.
Definition: exec.c:162
char * strdup(const char *src)
Duplicate string.
Definition: string.c:350
Command line option parsing.
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:358
int isspace(int character)
Check to see if character is a space.
Definition: ctype.c:41
size_t strlen(const char *src)
Get length of string.
Definition: string.c:213
Option does not take an argument.
Definition: getopt.h:16
static struct option_descriptor iseq_opts[]
"iseq" option list
Definition: exec.c:519
static int iseq_exec(int argc, char **argv)
"iseq" command
Definition: exec.c:533
static void reset_getopt(void)
Reset getopt() internal state.
Definition: getopt.h:89
static struct command_descriptor echo_cmd
"echo" command descriptor
Definition: exec.c:398
const char * name
Name of the command.
Definition: command.h:11
int shell_stopped(int stop)
Test and consume shell stop state.
Definition: exec.c:227
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
static int exit_exec(int argc, char **argv)
"exit" command
Definition: exec.c:453
static int stop_state
Shell stop state.
Definition: exec.c:48
uint32_t len
Length.
Definition: ena.h:14
int strcmp(const char *first, const char *second)
Compare strings.
Definition: string.c:157
#define COMMANDS
Definition: command.h:22
#define OPTION_DESC(_longopt, _shortopt, _has_arg, _struct, _field, _parse)
Construct option descriptor.
Definition: parseopt.h:66
Stop processing commands.
Definition: shell.h:29
uint16_t count
Number of entries.
Definition: ena.h:22
A command-line option descriptor.
Definition: parseopt.h:22
UINT16_t seconds
Elapsed time.
Definition: pxe_api.h:81
Linker tables.
#define COMMAND_DESC(_struct, _options, _min_args, _max_args, _usage)
Construct command descriptor.
Definition: parseopt.h:107
static int command_terminator(char **tokens, int(**process_next)(int rc))
Find command terminator.
Definition: exec.c:183
static struct command_descriptor iseq_cmd
"iseq" command descriptor
Definition: exec.c:522
static int process_on_success(int rc)
Process next command only if previous command succeeded.
Definition: exec.c:152
uint8_t command
Command.
Definition: intel.h:18
static int split_command(char *command, char **tokens)
Split command line into tokens.
Definition: exec.c:121
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
"echo" options
Definition: exec.c:386
unsigned int sleep(unsigned int secs)
Sleep (interruptibly) for a fixed number of seconds.
Definition: timer.c:133
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
struct golan_eqe_cmd cmd
Definition: CIB_PRM.h:29
String functions.
struct bofm_section_header done
Definition: bofm_test.c:46
"exit" options
Definition: exec.c:437
int execv(const char *command, char *const argv[])
Execute command.
Definition: exec.c:60