소스 검색

[cmdline] Match user expectations for &&, ||, goto, and exit

The && and || operators should be left-associative, since that is how
they are treated in most other languages (including C and Unix
shell).  For example, in the command:

  dhcp net0 && goto dhcp_ok || echo No DHCP on net0

if the "dhcp net0" fails then the "echo" should be executed.

After an "exit" or a successful "goto", further commands on the same
line should never be executed.  For example:

  goto somewhere && echo This should never be printed
  exit 0 && echo This should never be printed
  exit 1 && echo This should never be printed

An "exit" should cause the current shell or script to terminate and
return the specified exit status to its caller.  For example:

  chain test.ipxe && echo Success || echo Failure
    [in test.ipxe]
    #!ipxe
    exit 0

should echo "Success".

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 년 전
부모
커밋
7bebe9579e
5개의 변경된 파일94개의 추가작업 그리고 52개의 파일을 삭제
  1. 65
    41
      src/core/exec.c
  2. 1
    2
      src/hci/shell.c
  3. 6
    7
      src/image/script.c
  4. 0
    2
      src/include/ipxe/command.h
  5. 22
    0
      src/include/ipxe/shell.h

+ 65
- 41
src/core/exec.c 파일 보기

@@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
31 31
 #include <ipxe/command.h>
32 32
 #include <ipxe/parseopt.h>
33 33
 #include <ipxe/settings.h>
34
+#include <ipxe/shell.h>
34 35
 
35 36
 /** @file
36 37
  *
@@ -38,15 +39,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
38 39
  *
39 40
  */
40 41
 
41
-/** Shell exit flag */
42
-int shell_exit;
42
+/** Shell stop state */
43
+static int stop_state;
43 44
 
44 45
 /**
45 46
  * Execute command
46 47
  *
47 48
  * @v command		Command name
48 49
  * @v argv		Argument list
49
- * @ret rc		Command exit status
50
+ * @ret rc		Return status code
50 51
  *
51 52
  * Execute the named command.  Unlike a traditional POSIX execv(),
52 53
  * this function returns the exit status of the command.
@@ -196,32 +197,22 @@ static int split_command ( char *command, char **tokens ) {
196 197
 }
197 198
 
198 199
 /**
199
- * Terminate command unconditionally
200
- *
201
- * @v rc		Status of previous command
202
- * @ret terminate	Terminate command
203
- */
204
-static int terminate_always ( int rc __unused ) {
205
-	return 1;
206
-}
207
-
208
-/**
209
- * Terminate command only if previous command succeeded
200
+ * Process next command only if previous command succeeded
210 201
  *
211 202
  * @v rc		Status of previous command
212
- * @ret terminate	Terminate command
203
+ * @ret process		Process next command
213 204
  */
214
-static int terminate_on_success ( int rc ) {
205
+static int process_on_success ( int rc ) {
215 206
 	return ( rc == 0 );
216 207
 }
217 208
 
218 209
 /**
219
- * Terminate command only if previous command failed
210
+ * Process next command only if previous command failed
220 211
  *
221 212
  * @v rc		Status of previous command
222
- * @ret terminate	Terminate command
213
+ * @ret process		Process next command
223 214
  */
224
-static int terminate_on_failure ( int rc ) {
215
+static int process_on_failure ( int rc ) {
225 216
 	return ( rc != 0 );
226 217
 }
227 218
 
@@ -229,54 +220,79 @@ static int terminate_on_failure ( int rc ) {
229 220
  * Find command terminator
230 221
  *
231 222
  * @v tokens		Token list
232
- * @ret terminator	Terminator type
223
+ * @ret process_next	"Should next command be processed?" function
233 224
  * @ret argc		Argument count
234 225
  */
235 226
 static int command_terminator ( char **tokens,
236
-				int ( **terminator ) ( int rc ) ) {
227
+				int ( **process_next ) ( int rc ) ) {
237 228
 	unsigned int i;
238 229
 
239 230
 	/* Find first terminating token */
240 231
 	for ( i = 0 ; tokens[i] ; i++ ) {
241 232
 		if ( tokens[i][0] == '#' ) {
242 233
 			/* Start of a comment */
243
-			*terminator = terminate_always;
244
-			return i;
234
+			break;
245 235
 		} else if ( strcmp ( tokens[i], "||" ) == 0 ) {
246 236
 			/* Short-circuit logical OR */
247
-			*terminator = terminate_on_success;
237
+			*process_next = process_on_failure;
248 238
 			return i;
249 239
 		} else if ( strcmp ( tokens[i], "&&" ) == 0 ) {
250 240
 			/* Short-circuit logical AND */
251
-			*terminator = terminate_on_failure;
241
+			*process_next = process_on_success;
252 242
 			return i;
253 243
 		}
254 244
 	}
255 245
 
256 246
 	/* End of token list */
257
-	*terminator = terminate_always;
247
+	*process_next = NULL;
258 248
 	return i;
259 249
 }
260 250
 
251
+/**
252
+ * Set shell stop state
253
+ *
254
+ * @v stop		Shell stop state
255
+ */
256
+void shell_stop ( int stop ) {
257
+	stop_state = stop;
258
+}
259
+
260
+/**
261
+ * Test and consume shell stop state
262
+ *
263
+ * @v stop		Shell stop state to consume
264
+ * @v stopped		Shell had been stopped
265
+ */
266
+int shell_stopped ( int stop ) {
267
+	int stopped;
268
+
269
+	/* Test to see if we need to stop */
270
+	stopped = ( stop_state >= stop );
271
+
272
+	/* Consume stop state */
273
+	if ( stop_state <= stop )
274
+		stop_state = 0;
275
+
276
+	return stopped;
277
+}
278
+
261 279
 /**
262 280
  * Execute command line
263 281
  *
264 282
  * @v command		Command line
265
- * @ret rc		Command exit status
283
+ * @ret rc		Return status code
266 284
  *
267 285
  * Execute the named command and arguments.
268 286
  */
269 287
 int system ( const char *command ) {
270
-	int ( * terminator ) ( int rc );
288
+	int ( * process_next ) ( int rc );
271 289
 	char *expcmd;
272 290
 	char **argv;
273 291
 	int argc;
274 292
 	int count;
293
+	int process;
275 294
 	int rc = 0;
276 295
 
277
-	/* Reset exit flag */
278
-	shell_exit = 0;
279
-
280 296
 	/* Perform variable expansion */
281 297
 	expcmd = expand_command ( command );
282 298
 	if ( ! expcmd )
@@ -291,23 +307,31 @@ int system ( const char *command ) {
291 307
 		
292 308
 		split_command ( expcmd, tokens );
293 309
 		tokens[count] = NULL;
310
+		process = 1;
294 311
 
295 312
 		for ( argv = tokens ; ; argv += ( argc + 1 ) ) {
296 313
 
297 314
 			/* Find command terminator */
298
-			argc = command_terminator ( argv, &terminator );
315
+			argc = command_terminator ( argv, &process_next );
299 316
 
300 317
 			/* Execute command */
301
-			argv[argc] = NULL;
302
-			rc = execv ( argv[0], argv );
318
+			if ( process ) {
319
+				argv[argc] = NULL;
320
+				rc = execv ( argv[0], argv );
321
+			}
303 322
 
304
-			/* Check exit flag */
305
-			if ( shell_exit )
323
+			/* Stop processing, if applicable */
324
+			if ( shell_stopped ( SHELL_STOP_COMMAND ) )
306 325
 				break;
307 326
 
308
-			/* Handle terminator */
309
-			if ( terminator ( rc ) )
327
+			/* Stop processing if we have reached the end
328
+			 * of the command.
329
+			 */
330
+			if ( ! process_next )
310 331
 				break;
332
+
333
+			/* Determine whether or not to process next command */
334
+			process = process_next ( rc );
311 335
 		}
312 336
 	}
313 337
 
@@ -322,7 +346,7 @@ int system ( const char *command ) {
322 346
  *
323 347
  * @v argc		Argument count
324 348
  * @v argv		Argument list
325
- * @ret rc		Exit code
349
+ * @ret rc		Return status code
326 350
  */
327 351
 static int echo_exec ( int argc, char **argv ) {
328 352
 	int i;
@@ -373,8 +397,8 @@ static int exit_exec ( int argc, char **argv ) {
373 397
 			return rc;
374 398
 	}
375 399
 
376
-	/* Set exit flag */
377
-	shell_exit = 1;
400
+	/* Stop shell processing */
401
+	shell_stop ( SHELL_STOP_COMMAND_SEQUENCE );
378 402
 
379 403
 	return exit_code;
380 404
 }

+ 1
- 2
src/hci/shell.c 파일 보기

@@ -84,8 +84,7 @@ int shell ( void ) {
84 84
 			rc = system ( line );
85 85
 			free ( line );
86 86
 		}
87
-	} while ( shell_exit == 0 );
88
-	shell_exit = 0;
87
+	} while ( ! shell_stopped ( SHELL_STOP_COMMAND_SEQUENCE ) );
89 88
 
90 89
 	return rc;
91 90
 }

+ 6
- 7
src/image/script.c 파일 보기

@@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
34 34
 #include <ipxe/command.h>
35 35
 #include <ipxe/parseopt.h>
36 36
 #include <ipxe/image.h>
37
+#include <ipxe/shell.h>
37 38
 
38 39
 struct image_type script_image_type __image_type ( PROBE_NORMAL );
39 40
 
@@ -106,13 +107,8 @@ static int process_script ( int ( * process_line ) ( const char *line ),
106 107
  */
107 108
 static int terminate_on_exit_or_failure ( int rc ) {
108 109
 
109
-	/* Check and consume exit flag */
110
-	if ( shell_exit ) {
111
-		shell_exit = 0;
112
-		return 1;
113
-	}
114
-
115
-	return ( rc != 0 );
110
+	return ( shell_stopped ( SHELL_STOP_COMMAND_SEQUENCE ) ||
111
+		 ( rc != 0 ) );
116 112
 }
117 113
 
118 114
 /**
@@ -292,6 +288,9 @@ static int goto_exec ( int argc, char **argv ) {
292 288
 		return rc;
293 289
 	}
294 290
 
291
+	/* Terminate processing of current command */
292
+	shell_stop ( SHELL_STOP_COMMAND );
293
+
295 294
 	return 0;
296 295
 }
297 296
 

+ 0
- 2
src/include/ipxe/command.h 파일 보기

@@ -23,6 +23,4 @@ struct command {
23 23
 
24 24
 #define __command __table_entry ( COMMANDS, 01 )
25 25
 
26
-extern int shell_exit;
27
-
28 26
 #endif /* _IPXE_COMMAND_H */

+ 22
- 0
src/include/ipxe/shell.h 파일 보기

@@ -9,6 +9,28 @@
9 9
 
10 10
 FILE_LICENCE ( GPL2_OR_LATER );
11 11
 
12
+/** Shell stop states */
13
+enum shell_stop_state {
14
+	/** Continue processing */
15
+	SHELL_CONTINUE = 0,
16
+	/**
17
+	 * Stop processing current command line
18
+	 *
19
+	 * This is the stop state entered by commands that change the flow
20
+	 * of execution, such as "goto".
21
+	 */
22
+	SHELL_STOP_COMMAND = 1,
23
+	/**
24
+	 * Stop processing commands
25
+	 *
26
+	 * This is the stop state entered by commands that terminate
27
+	 * the flow of execution, such as "exit".
28
+	 */
29
+	SHELL_STOP_COMMAND_SEQUENCE = 2,
30
+};
31
+
32
+extern void shell_stop ( int stop );
33
+extern int shell_stopped ( int stop );
12 34
 extern int shell ( void );
13 35
 
14 36
 #endif /* _IPXE_SHELL_H */

Loading…
취소
저장