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
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_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 */
49static 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 */
61int 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 */
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 */
122static 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 */
153static 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 */
163static 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 */
173static 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 */
184static 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 */
218void 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 */
228int 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 */
249static 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 */
273static 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 */
288int 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 */
359char * 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 */
388 /** Do not print trailing newline */
390};
391
392/** "echo" option list */
393static 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 */
410static 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 */
433
434/** "exit" options */
435struct exit_options {};
436
437/** "exit" option list */
438static 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 */
451static 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 */
474
475/** "isset" options */
477
478/** "isset" option list */
479static 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 */
492static 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 */
506
507/** "iseq" options */
508struct iseq_options {};
509
510/** "iseq" option list */
511static 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 */
525static 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 */
540
541/** "sleep" options */
543
544/** "sleep" option list */
545static 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 */
558static 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 */
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct golan_eqe_cmd cmd
Definition CIB_PRM.h:1
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
struct bofm_section_header done
Definition bofm_test.c:46
static union @024010030001061367220137227263210031030210157031 opts
"cert<xxx>" option list
#define COMMAND(name, exec)
Definition command.h:27
#define COMMANDS
Definition command.h:23
int isspace(int character)
Check to see if character is a space.
Definition ctype.c:42
Character types.
ring len
Length.
Definition dwmac.h:226
int errno
Global "last error" number.
Definition errno.c:21
Error codes.
uint8_t system[ETH_ALEN]
System identifier.
Definition eth_slow.h:13
static int process_always(int rc __unused)
Process next command regardless of status from previous command.
Definition exec.c:173
static int stop_state
Shell stop state.
Definition exec.c:49
static struct option_descriptor exit_opts[]
"exit" option list
Definition exec.c:438
int execv(const char *command, char *const argv[])
Execute command.
Definition exec.c:61
static struct command_descriptor sleep_cmd
"sleep" command descriptor
Definition exec.c:548
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
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 struct option_descriptor echo_opts[]
"echo" option list
Definition exec.c:393
static struct command_descriptor isset_cmd
"isset" command descriptor
Definition exec.c:482
char * concat_args(char **args)
Concatenate arguments.
Definition exec.c:359
static int exit_exec(int argc, char **argv)
"exit" command
Definition exec.c:451
static int echo_exec(int argc, char **argv)
"echo" command
Definition exec.c:410
static struct command_descriptor iseq_cmd
"iseq" command descriptor
Definition exec.c:514
static int isset_exec(int argc, char **argv)
"isset" command
Definition exec.c:492
static struct option_descriptor sleep_opts[]
"sleep" option list
Definition exec.c:545
static int expand_tokens(int argc, char **tokens, char **argv)
Expand settings within a token list.
Definition exec.c:249
static int process_on_failure(int rc)
Process next command only if previous command failed.
Definition exec.c:163
static struct option_descriptor isset_opts[]
"isset" option list
Definition exec.c:479
static void free_tokens(char **argv)
Free an expanded token list.
Definition exec.c:273
void shell_stop(int stop)
Set shell stop state.
Definition exec.c:218
static int split_command(char *command, char **tokens)
Split command line into tokens.
Definition exec.c:122
static int command_terminator(char **tokens, int(**process_next)(int rc))
Find command terminator.
Definition exec.c:184
static int process_on_success(int rc)
Process next command only if previous command succeeded.
Definition exec.c:153
static int sleep_exec(int argc, char **argv)
"sleep" command
Definition exec.c:558
static struct command_descriptor exit_cmd
"exit" command descriptor
Definition exec.c:441
int optind
Current option index.
Definition getopt.c:52
Parse command-line options.
static void reset_getopt(void)
Reset getopt() internal state.
Definition getopt.h:90
@ no_argument
Option does not take an argument.
Definition getopt.h:17
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOENT
No such file or directory.
Definition errno.h:515
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOEXEC
Exec format error.
Definition errno.h:520
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ECANCELED
Operation canceled.
Definition errno.h:344
#define ERANGE
Result too large.
Definition errno.h:640
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Configuration settings.
String functions.
int echo(void)
Definition kb.c:133
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
uint32_t string
Definition multiboot.h:2
int parse_flag(char *text __unused, int *flag)
Parse flag.
Definition parseopt.c:227
int parse_integer(char *text, unsigned int *value)
Parse integer value.
Definition parseopt.c:92
int parse_options(int argc, char **argv, struct command_descriptor *cmd, void *opts)
Parse command-line options.
Definition parseopt.c:485
Command line option parsing.
#define MAX_ARGUMENTS
No maximum number of arguments.
Definition parseopt.h:98
#define COMMAND_DESC(_struct, _options, _min_args, _max_args, _usage)
Construct command descriptor.
Definition parseopt.h:109
#define OPTION_DESC(_longopt, _shortopt, _has_arg, _struct, _field, _parse)
Construct option descriptor.
Definition parseopt.h:68
UINT16_t seconds
Elapsed time.
Definition pxe_api.h:24
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
char * expand_settings(const char *string)
Expand variables within string.
Definition settings.c:2331
Minimal command shell.
@ SHELL_STOP_COMMAND
Stop processing current command line.
Definition shell.h:23
@ SHELL_STOP_COMMAND_SEQUENCE
Stop processing commands.
Definition shell.h:30
#define sprintf(buf, fmt,...)
Write a formatted string to a buffer.
Definition stdio.h:37
int strcmp(const char *first, const char *second)
Compare strings.
Definition string.c:174
char * strdup(const char *src)
Duplicate string.
Definition string.c:394
size_t strlen(const char *src)
Get length of string.
Definition string.c:244
A command descriptor.
Definition parseopt.h:78
A command-line command.
Definition command.h:10
"echo" options
Definition exec.c:387
int no_newline
Do not print trailing newline.
Definition exec.c:389
"exit" options
Definition exec.c:435
"iseq" options
Definition exec.c:508
"isset" options
Definition exec.c:476
A command-line option descriptor.
Definition parseopt.h:24
A process.
Definition process.h:18
"sleep" options
Definition exec.c:542
Linker tables.
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386
unsigned int sleep(unsigned int secs)
Sleep (interruptibly) for a fixed number of seconds.
Definition timer.c:134
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition vsprintf.c:465