[scripting] Added for loops
[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 struct generic_stack command_list;
46 extern int prog_ctr;
47
48 /**
49  * Execute command
50  *
51  * @v command           Command name
52  * @v argv              Argument list
53  * @ret rc              Command exit status
54  *
55  * Execute the named command.  Unlike a traditional POSIX execv(),
56  * this function returns the exit status of the command.
57  */
58 int execv ( const char *command, char * const argv[] ) {
59         struct command *cmd;
60         int argc;
61
62         /* Count number of arguments */
63         for ( argc = 0 ; argv[argc] ; argc++ ) {}
64
65         /* Sanity checks */
66         if ( ! command ) {
67                 DBG ( "No command\n" );
68                 return -EINVAL;
69         }
70         if ( ! argc ) {
71                 DBG ( "%s: empty argument list\n", command );
72                 return -EINVAL;
73         }
74
75         /* Reset getopt() library ready for use by the command.  This
76          * is an artefact of the POSIX getopt() API within the context
77          * of Etherboot; see the documentation for reset_getopt() for
78          * details.
79          */
80         reset_getopt();
81
82         /* Hand off to command implementation */
83         for_each_table_entry ( cmd, COMMANDS ) {
84                 if ( strcmp ( command, cmd->name ) == 0 ) {
85                         if ( TOP_GEN_STACK_INT ( &if_stack ) == 1 || !strcmp ( cmd->name, "if" ) || !strcmp ( cmd->name, "fi" ) || !strcmp ( cmd->name, "else" )
86                                 || !strcmp ( cmd->name, "while" ) || !strcmp ( cmd->name, "for" ) || !strcmp ( cmd->name, "done" ) )
87                                 return cmd->exec ( argc, ( char ** ) argv );
88                         else
89                                 return 0;
90                 }
91         }
92
93         printf ( "%s: command not found\n", command );
94         return -ENOEXEC;
95 }
96
97 static int expand_command ( const char *command, struct generic_stack *argv_stack ) {
98         char *head, *end;
99         int success;
100         int argc;
101         
102         struct string expcmd = { .value = NULL };
103         
104         argc = 0;
105         init_generic_stack ( argv_stack, sizeof ( char * ) );
106         
107         if ( !stringcpy ( &expcmd, command ) ) {
108                 argc = -ENOMEM;
109                 return argc;
110         }
111         head = expcmd.value;
112         
113         /* Expand while expansions remain */
114         while ( *head ) {
115                 while ( isspace ( *head ) ) {
116                         *head = 0;
117                         head++;
118                 }
119                 if ( *head == '#' ) { /* Comment is a new word that starts with # */
120                         break;
121                 }
122                 if ( !stringcpy ( &expcmd, head ) ) {
123                         argc = -ENOMEM;
124                         break;
125                 }
126                 head = expcmd.value;
127                 end = expand_string ( &expcmd, head, table, 6, 0, &success );
128                 if ( end ) {
129                         if ( success ) {
130                                 char *argv = expcmd.value;
131                                 argc++;
132                                 expcmd.value = NULL;
133                                 if ( push_generic_stack ( argv_stack, &argv, 0 ) < 0 || !stringcpy ( &expcmd, end ) ) {
134                                         argc = -ENOMEM;
135                                         break;
136                                 }
137                                 *end = 0;
138                                 /*
139                                 So if the command is: word1 word2 word3
140                                 argv_stack:     word1\0word2 word3
141                                                         word2\0word3
142                                                         word3
143                                 */
144                         }
145                 } else {
146                         argc = -ENOMEM;
147                         break;
148                 }
149                 head = expcmd.value;
150         }
151         free_string ( &expcmd );
152         return argc;
153 }
154
155 /**
156  * Execute command line
157  *
158  * @v command           Command line
159  * @ret rc              Command exit status
160  *
161  * Execute the named command and arguments.
162  */
163 int system ( const char *command ) {
164         int argc;
165         int rc = 0;
166         struct generic_stack argv_stack;
167         
168         if ( prog_ctr == SIZE_GEN_STACK ( &command_list ) ) {
169                 push_generic_stack ( &command_list, &command, 1 );
170                 //printf ( "appending %s at %d\n", TOP_GEN_STACK_STRING ( &command_list ), prog_ctr );
171         }
172
173         argc = expand_command ( command, &argv_stack );
174         if ( argc < 0 ) {
175                 rc = argc;
176         } else {
177                 char **argv;
178                 if ( ! push_generic_stack ( &argv_stack, NULL, 0 ) ) {
179                         argv = ( char ** ) argv_stack.ptr;
180                         if ( argc > 0 )
181                                 rc = execv ( argv[0], argv );
182                 }
183         }
184         prog_ctr++;
185         free_generic_stack ( &argv_stack, 1 );
186         return rc;
187 }
188
189 /**
190  * The "echo" command
191  *
192  * @v argc              Argument count
193  * @v argv              Argument list
194  * @ret rc              Exit code
195  */
196 static int echo_exec ( int argc, char **argv ) {
197         int i;
198
199         for ( i = 1 ; i < argc ; i++ ) {
200                 printf ( "%s%s", ( ( i == 1 ) ? "" : " " ), argv[i] );
201         }
202         printf ( "\n" );
203         return 0;
204 }
205
206 /** "echo" command */
207 struct command echo_command __command = {
208         .name = "echo",
209         .exec = echo_exec,
210 };