ed85b30e4b3dca565fb7c81f316e0ad4d93a595a
[people/lynusvaz/gpxe.git] / src / core / exec.c
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 FILE_LICENCE ( GPL2_OR_LATER );
20
21 #include <stdint.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <unistd.h>
27 #include <getopt.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <gpxe/command.h>
31 #include <gpxe/parse.h>
32 #include <gpxe/gen_stack.h>
33
34 /** @file
35  *
36  * Command execution
37  *
38  */
39
40 /* Avoid dragging in getopt.o unless a command really uses it */
41 int optind;
42 int nextchar;
43
44 extern struct generic_stack if_stack;
45 extern int if_tos;
46
47 /**
48  * Execute command
49  *
50  * @v command           Command name
51  * @v argv              Argument list
52  * @ret rc              Command exit status
53  *
54  * Execute the named command.  Unlike a traditional POSIX execv(),
55  * this function returns the exit status of the command.
56  */
57 int execv ( const char *command, char * const argv[] ) {
58         struct command *cmd;
59         int argc;
60
61         /* Count number of arguments */
62         for ( argc = 0 ; argv[argc] ; argc++ ) {}
63
64         /* Sanity checks */
65         if ( ! command ) {
66                 DBG ( "No command\n" );
67                 return -EINVAL;
68         }
69         if ( ! argc ) {
70                 DBG ( "%s: empty argument list\n", command );
71                 return -EINVAL;
72         }
73
74         /* Reset getopt() library ready for use by the command.  This
75          * is an artefact of the POSIX getopt() API within the context
76          * of Etherboot; see the documentation for reset_getopt() for
77          * details.
78          */
79         reset_getopt();
80
81         /* Hand off to command implementation */
82         for_each_table_entry ( cmd, COMMANDS ) {
83                 if ( strcmp ( command, cmd->name ) == 0 ) {
84                         if ( !if_stack.ptr || ( ( int * ) if_stack.ptr )[if_tos] || !strcmp ( cmd->name, "if" ) || !strcmp ( cmd->name, "fi" ) || !strcmp ( cmd->name, "else" ) )
85                                 return cmd->exec ( argc, ( char ** ) argv );
86                         else
87                                 return 0;
88                 }
89         }
90
91         printf ( "%s: command not found\n", command );
92         return -ENOEXEC;
93 }
94
95 struct char_table dquote_table[3] = {
96         { .token = '"', .type = ENDQUOTES },
97         { .token = '$', .type = FUNC, .next.parse_func = dollar_expand },
98         { .token = '\\', .type = FUNC, .next.parse_func = parse_escape }
99 };
100 struct char_table squote_table[1] = {
101         { .token = '\'', .type = ENDQUOTES }
102 };
103 static struct char_table table[6] = {
104         { .token = '\\', .type = FUNC, .next.parse_func = parse_escape },
105         { .token = '"', .type = TABLE, .next = 
106                                 {.next_table = { .ntable = dquote_table, .len = 3 } } },
107         { .token = '$', .type = FUNC, .next.parse_func = dollar_expand },
108         { .token = '\'', .type = TABLE, .next = { .next_table = { .ntable = squote_table, .len = 1 } } },
109         { .token = ' ', .type = ENDTOK },
110         { .token = '\t', .type = ENDTOK }
111 };
112
113 static int expand_command ( const char *command, struct generic_stack *argv_stack ) {
114         char *head, *end;
115         char *nstring;
116         int success;
117         int argc;
118         
119         struct string expcmd = { .value = NULL };
120         
121         argc = 0;
122         init_generic_stack ( argv_stack, sizeof ( int ) );
123         
124         stringcpy ( &expcmd, command );
125         if ( ! expcmd.value ) {
126                 argc = -ENOMEM;
127                 return argc;
128         }
129         head = expcmd.value;
130         
131         /* Expand while expansions remain */
132         while ( *head ) {
133                 while ( isspace ( *head ) ) {
134                         *head = 0;
135                         head++;
136                 }
137                 if ( *head == '#' ) { /* Comment is a new word that starts with # */
138                         break;
139                 }
140                 stringcpy ( &expcmd, head );
141                 head = expcmd.value;
142                 nstring = expand_string ( &expcmd, &head, &end, table, 6, 0, &success );
143                 if ( nstring ) {
144                         if ( success ) {
145                                 argc++;
146                                 push_generic_stack ( argv_stack, &expcmd.value, 0 );
147                                 expcmd.value = NULL;
148                                 stringcpy ( &expcmd, end );
149                                 *end = 0;
150                         }
151                 } else {
152                         argc = -ENOMEM;
153                         break;
154                 }
155                 head = expcmd.value;
156         }
157         free_string ( &expcmd );
158         return argc;
159 }
160
161 /**
162  * Execute command line
163  *
164  * @v command           Command line
165  * @ret rc              Command exit status
166  *
167  * Execute the named command and arguments.
168  */
169 int system ( const char *command ) {
170         int argc;
171         int rc = 0;
172         struct generic_stack argv_stack;
173
174         argc = expand_command ( command, &argv_stack );
175         if ( argc < 0 ) {
176                 rc = argc;
177         } else {
178                 char **argv;
179                                 
180                 argv = realloc ( argv_stack.ptr, sizeof ( char * ) * ( argc + 1 ) );
181                 if ( argv ) {
182                         argv_stack.ptr = argv;
183                         argv[argc] = NULL;
184                 
185                         if ( argc > 0 )
186                                 rc = execv ( argv[0], argv );
187                 }
188         }
189         
190         free_generic_stack ( &argv_stack, 0 );
191         return rc;
192 }
193
194 /**
195  * The "echo" command
196  *
197  * @v argc              Argument count
198  * @v argv              Argument list
199  * @ret rc              Exit code
200  */
201 static int echo_exec ( int argc, char **argv ) {
202         int i;
203
204         for ( i = 1 ; i < argc ; i++ ) {
205                 printf ( "%s%s", ( ( i == 1 ) ? "" : " " ), argv[i] );
206         }
207         printf ( "\n" );
208         return 0;
209 }
210
211 /** "echo" command */
212 struct command echo_command __command = {
213         .name = "echo",
214         .exec = echo_exec,
215 };