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