Browse Source

[cmdline] Expand settings within each command-line token individually

Perform settings expansion after tokenisation, and only at the point
of executing each command.  This allows statements such as

   dhcp && echo ${net0/ip}

to work correctly.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
b5f5f735c1
1 changed files with 79 additions and 35 deletions
  1. 79
    35
      src/core/exec.c

+ 79
- 35
src/core/exec.c View File

@@ -216,6 +216,45 @@ int shell_stopped ( int stop ) {
216 216
 	return stopped;
217 217
 }
218 218
 
219
+/**
220
+ * Expand settings within a token list
221
+ *
222
+ * @v argc		Argument count
223
+ * @v tokens		Token list
224
+ * @v argv		Argument list to fill in
225
+ * @ret rc		Return status code
226
+ */
227
+static int expand_tokens ( int argc, char **tokens, char **argv ) {
228
+	int i;
229
+
230
+	/* Expand each token in turn */
231
+	for ( i = 0 ; i < argc ; i++ ) {
232
+		argv[i] = expand_settings ( tokens[i] );
233
+		if ( ! argv[i] )
234
+			goto err_expand_settings;
235
+	}
236
+
237
+	return 0;
238
+
239
+ err_expand_settings:
240
+	assert ( argv[i] == NULL );
241
+	for ( ; i >= 0 ; i-- )
242
+		free ( argv[i] );
243
+	return -ENOMEM;
244
+}
245
+
246
+/**
247
+ * Free an expanded token list
248
+ *
249
+ * @v argv		Argument list
250
+ */
251
+static void free_tokens ( char **argv ) {
252
+
253
+	/* Free each expanded argument */
254
+	while ( *argv )
255
+		free ( *(argv++) );
256
+}
257
+
219 258
 /**
220 259
  * Execute command line
221 260
  *
@@ -225,58 +264,63 @@ int shell_stopped ( int stop ) {
225 264
  * Execute the named command and arguments.
226 265
  */
227 266
 int system ( const char *command ) {
267
+	int count = split_command ( ( char * ) command, NULL );
268
+	char *all_tokens[ count + 1 ];
228 269
 	int ( * process_next ) ( int rc );
229
-	char *expcmd;
230
-	char **argv;
270
+	char *command_copy;
271
+	char **tokens;
231 272
 	int argc;
232
-	int count;
233 273
 	int process;
234 274
 	int rc = 0;
235 275
 
236
-	/* Perform variable expansion */
237
-	expcmd = expand_settings ( command );
238
-	if ( ! expcmd )
276
+	/* Create modifiable copy of command */
277
+	command_copy = strdup ( command );
278
+	if ( ! command_copy )
239 279
 		return -ENOMEM;
240 280
 
241
-	/* Count tokens */
242
-	count = split_command ( expcmd, NULL );
243
-
244
-	/* Create token array */
245
-	if ( count ) {
246
-		char * tokens[count + 1];
247
-		
248
-		split_command ( expcmd, tokens );
249
-		tokens[count] = NULL;
250
-		process = 1;
281
+	/* Split command into tokens */
282
+	split_command ( command_copy, all_tokens );
283
+	all_tokens[count] = NULL;
251 284
 
252
-		for ( argv = tokens ; ; argv += ( argc + 1 ) ) {
285
+	/* Process individual commands */
286
+	process = 1;
287
+	for ( tokens = all_tokens ; ; tokens += ( argc + 1 ) ) {
253 288
 
254
-			/* Find command terminator */
255
-			argc = command_terminator ( argv, &process_next );
289
+		/* Find command terminator */
290
+		argc = command_terminator ( tokens, &process_next );
256 291
 
257
-			/* Execute command */
258
-			if ( process ) {
259
-				argv[argc] = NULL;
260
-				rc = execv ( argv[0], argv );
261
-			}
292
+		/* Expand tokens and execute command */
293
+		if ( process ) {
294
+			char *argv[ argc + 1 ];
262 295
 
263
-			/* Stop processing, if applicable */
264
-			if ( shell_stopped ( SHELL_STOP_COMMAND ) )
296
+			/* Expand tokens */
297
+			if ( ( rc = expand_tokens ( argc, tokens, argv ) ) != 0)
265 298
 				break;
299
+			argv[argc] = NULL;
266 300
 
267
-			/* Stop processing if we have reached the end
268
-			 * of the command.
269
-			 */
270
-			if ( ! process_next )
271
-				break;
301
+			/* Execute command */
302
+			rc = execv ( argv[0], argv );
272 303
 
273
-			/* Determine whether or not to process next command */
274
-			process = process_next ( rc );
304
+			/* Free tokens */
305
+			free_tokens ( argv );
275 306
 		}
307
+
308
+		/* Stop processing, if applicable */
309
+		if ( shell_stopped ( SHELL_STOP_COMMAND ) )
310
+			break;
311
+
312
+		/* Stop processing if we have reached the end of the
313
+		 * command.
314
+		 */
315
+		if ( ! process_next )
316
+			break;
317
+
318
+		/* Determine whether or not to process next command */
319
+		process = process_next ( rc );
276 320
 	}
277 321
 
278
-	/* Free expanded command */
279
-	free ( expcmd );
322
+	/* Free modified copy of command */
323
+	free ( command_copy );
280 324
 
281 325
 	return rc;
282 326
 }

Loading…
Cancel
Save