Subversion Repositories tendra.SVN

Rev

Rev 7 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
7 7u83 2
 * Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
7 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
7 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
7 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
7 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
7 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
#include "config.h"
62
#include "external.h"
63
#include "filename.h"
64
#include "list.h"
65
#include "archive.h"
66
#include "execute.h"
67
#include "flags.h"
68
#include "main.h"
69
#include "utility.h"
70
 
71
 
72
/*
7 7u83 73
 * CURRENT COMMAND
74
 *
75
 * The current command is a variable sized array of strings, command. A
76
 * complete command is terminated by a null string.
77
 */
2 7u83 78
 
7 7u83 79
static char **command = null;
80
static int command_size = 0;
81
static int cmd_no = 0;
2 7u83 82
 
83
 
84
/*
7 7u83 85
 * DELAY SIGNAL HANDLING
86
 *
87
 * Because the producer occasionally dies with a signal after it has output
88
 * some useful errors it is benificial to run the tot even after the signal has
89
 * been caught. These globals and the functions below for using them tell the
90
 * execute function to delay calling the signal handler until after the tot is
91
 * called.
92
 */
2 7u83 93
 
7 7u83 94
static char *last_signaled_cmd = null;
95
static int last_signal = 0;
96
static int delay_signal_handling = 0;
2 7u83 97
 
7 7u83 98
void
99
enable_delayed_signal(void)
2 7u83 100
{
7 7u83 101
	delay_signal_handling = 1;
102
	return;
2 7u83 103
}
104
 
7 7u83 105
void
106
disable_delayed_signal(void)
2 7u83 107
{
7 7u83 108
	delay_signal_handling = 0;
109
	return;
2 7u83 110
}
111
 
7 7u83 112
void
113
process_delayed_signal(void)
2 7u83 114
{
7 7u83 115
	if (last_signal != 0) {
116
		last_command = last_signaled_cmd;
117
		handler(last_signal);
118
	}
119
	return;
2 7u83 120
}
121
 
122
 
123
/*
7 7u83 124
 * ADD A STRING TO THE CURRENT COMMAND
125
 *
126
 * This routine adds the string s to the command array. If s is null then the
127
 * array counter is reset to the beginning. The array counter is not advanced
128
 * for empty strings.
129
 */
2 7u83 130
 
7 7u83 131
void
132
cmd_string(char *s)
2 7u83 133
{
7 7u83 134
	if (cmd_no >= command_size) {
135
		command_size += 1000;
136
		command = realloc_nof(command, char *, command_size);
137
	}
138
	command[cmd_no] = s;
139
	if (s == null) {
140
		cmd_no = 0;
141
	} else if (*s) {
142
		cmd_no++;
143
	}
144
	return;
2 7u83 145
}
146
 
147
 
148
/*
7 7u83 149
 * ADD A FILENAME TO THE CURRENT COMMAND
150
 *
151
 * This routine adds the names of the files given by p to the command array.
152
 */
2 7u83 153
 
7 7u83 154
void
155
cmd_filename(filename *p)
2 7u83 156
{
7 7u83 157
	for (; p != null; p = p->next) {
158
		cmd_string(p->name);
159
	}
160
	return;
2 7u83 161
}
162
 
163
 
164
/*
7 7u83 165
 * ADD A LIST TO THE CURRENT COMMAND
166
 *
167
 * This routine adds the list of strings given by p to the command array.
168
 */
2 7u83 169
 
7 7u83 170
void
171
cmd_list(list *p)
2 7u83 172
{
7 7u83 173
	for (; p != null; p = p->next) {
174
		cmd_string(p->item);
175
	}
176
	return;
2 7u83 177
}
178
 
179
 
180
/*
7 7u83 181
 * OVERALL COMPILATION STATUS
182
 *
183
 * This flag is true is an execution error occurs.
184
 */
2 7u83 185
 
7 7u83 186
boolean exec_error = 0;
2 7u83 187
 
7 7u83 188
void
189
reset_exec_error(void)
2 7u83 190
{
7 7u83 191
	exec_error = 0;
192
	return;
2 7u83 193
}
194
 
195
 
196
/*
7 7u83 197
 * LAST COMMAND
198
 *
199
 * The name of the last command executed, and its return value (zero indicating
200
 * success) are stored.
201
 */
2 7u83 202
 
7 7u83 203
char *last_command = null;
204
int last_return = 0;
2 7u83 205
 
206
 
207
/*
7 7u83 208
 * THE CURRENT PROCESS
209
 *
210
 * When a process is active, its pid is stored as running_pid. The value -1 is
211
 * used to indicate that no process is active.
212
 */
2 7u83 213
 
214
#if FS_FORK
7 7u83 215
static long running_pid = -1;
2 7u83 216
#endif
217
 
218
 
219
/*
7 7u83 220
 * KILL ANY STRAY PROCESSES
221
 *
222
 * Occasionally a runaway process may occur. This routine is indended to deal
223
 * with these by sending the signal SIGTERM to the process. This routine is
224
 * POSIX compliant.
225
 */
2 7u83 226
 
7 7u83 227
void
228
kill_stray(void)
2 7u83 229
{
230
#if FS_FORK
7 7u83 231
	if (running_pid == -1) {
232
		return;
233
	}
234
	IGNORE kill((pid_t)running_pid, SIGTERM);
235
	running_pid = -1;
2 7u83 236
#endif
7 7u83 237
	return;
2 7u83 238
}
239
 
240
 
241
/*
7 7u83 242
 * LIST OF FILES TO BE REMOVED BY REMOVE_JUNK
243
 *
244
 * This gives the list of the files which are to be removed if an error occurs.
245
 */
2 7u83 246
 
7 7u83 247
static filename *junk = null;
2 7u83 248
 
249
 
250
/*
7 7u83 251
 * REMOVE ANY INCOMPLETE OUTPUT FILES
252
 *
253
 * Any files which are being created when an error occurs should be removed.
254
 */
2 7u83 255
 
7 7u83 256
void
257
remove_junk(void)
2 7u83 258
{
7 7u83 259
	if (!dry_run && !flag_keep_err) {
260
		filename *p;
261
		for (p = junk; p != null; p = p->next) {
262
			if (p->storage == OUTPUT_FILE) {
263
				IGNORE remove(p->name);
264
			}
265
		}
2 7u83 266
	}
7 7u83 267
	junk = null;
268
	return;
2 7u83 269
}
270
 
271
 
272
/*
7 7u83 273
 * PRINT COMMAND INTO BUFFER
274
 *
275
 * This routine prints the current command into a buffer and returns a pointer
276
 * to the result.
277
 */
2 7u83 278
 
7 7u83 279
static void
280
print_cmd(char *b)
2 7u83 281
{
7 7u83 282
	char **s;
283
	for (s = command; *s != null; s++) {
284
		*b = ' ';
285
		IGNORE strcpy(b + 1, *s);
286
		b += strlen(b);
287
	}
288
	return;
2 7u83 289
}
290
 
291
 
292
/*
7 7u83 293
 * EXECUTE THE CURRENT COMMAND
294
 *
295
 * This routine executes the command given by the command array. It returns
296
 * either output, the list of all output files, if successful, or null,
297
 * otherwise. The routine is POSIX compliant. It uses fork and execv from
298
 * unistd.h to fork a process and various routines from sys/wait.h to analyse
299
 * the result. The interface with sys/wait.h has been abstracted to also allow
300
 * the BSD implementation.
301
 */
2 7u83 302
 
7 7u83 303
filename *
304
execute(filename *input, filename *output)
2 7u83 305
{
7 7u83 306
	char *cmd;
307
	int err = 0;
308
	boolean filled_buff = 0;
309
	char buff[buffer_size];
2 7u83 310
 
7 7u83 311
	cmd_string((char *)null);
312
	cmd = command[0];
313
	if (cmd == null) {
314
		error(INTERNAL, "Empty command");
315
		return (null);
2 7u83 316
	}
7 7u83 317
	last_command = cmd;
318
	last_return = 0;
319
	junk = output;
2 7u83 320
 
7 7u83 321
	if (taciturn) {
322
		/* Print input files if in taciturn mode */
323
		filename *p;
324
		for (p = input; p != null; p = p->next) {
325
			if (p->storage == INPUT_FILE) {
326
				comment(1, "%s:\n", p->name);
327
			}
2 7u83 328
		}
329
	}
330
 
7 7u83 331
	if (verbose) {
332
		/* Print command if in verbose mode */
333
		print_cmd(buff);
334
		filled_buff = 1;
335
		comment(1, "%s\n", buff + 1);
336
	}
337
 
338
	if (cmd && strneq(cmd, "builtin/", 8)) {
339
		/* Check built in commands */
340
		cmd += 8;
341
		switch (*cmd) {
342
		case 'b':
343
			if (streq(cmd, "build_archive")) {
344
				err = build_archive(command[1], command + 2);
345
				goto execute_error;
346
			}
347
			break;
348
		case 'c':
349
			if (streq(cmd, "cat")) {
350
				err = cat_file(command[1]);
351
				goto execute_error;
352
			}
353
			break;
354
		case 'm':
355
			if (streq(cmd, "mkdir")) {
356
				err = make_dir(command[1]);
357
				goto execute_error;
358
			}
359
			if (streq(cmd, "move")) {
360
				err = move_file(command[1], command[2]);
361
				goto execute_error;
362
			}
363
			break;
364
		case 'r':
365
			if (streq(cmd, "remove")) {
366
				err = remove_file(command[1]);
367
				goto execute_error;
368
			}
369
			break;
370
		case 's':
371
			if (streq(cmd, "split_archive")) {
372
				err = split_archive(command[1], &output);
373
				goto execute_error;
374
			}
375
			break;
376
		case 't':
377
			if (streq(cmd, "touch")) {
378
				err = touch_file(command[1], command[2]);
379
				goto execute_error;
380
			}
381
			break;
382
		case 'u':
383
			if (streq(cmd, "undef")) {
384
				int sev;
385
				if (dry_run) {
386
					sev = WARNING;
387
				} else {
388
					sev = INTERNAL;
389
					err = 1;
390
				}
391
				cmd = command[1];
392
				error(sev, "The tool '%s' is not available", cmd);
393
				goto execute_error;
394
			}
395
			break;
396
		}
397
		error(SERIOUS, "Built-in '%s' command not implemented", cmd);
398
		err = 1;
399
 
400
	} else if (!dry_run) {
401
		/* Call system commands */
2 7u83 402
#if FS_FORK
7 7u83 403
		pid_t pid = fork();
404
		if (pid == (pid_t) -1) {
405
			error(SERIOUS, "Can't fork process");
406
			err = 1;
407
		} else {
408
			if (pid) {
409
				wait_type status;
410
				running_pid = (long)pid;
411
				while (process_wait ( &status ) != pid ) {
412
					;	/* empty */
413
				}
414
				running_pid = -1;
415
				if (process_exited(status)) {
416
					err = process_exit_value(status);
417
					/* This only returns if there was no
418
					 * remembered signal. */
419
					process_delayed_signal();
420
				} else {
421
					if (process_signaled(status)) {
422
						/* delay_signal_handling is a
423
						 * global that tells us
424
						 * that it is ok to let the
425
						 * next call to execute report
426
						 * that the command received a
427
						 * signal. This supports the
428
						 * way that the producer is
429
						 * called. */
430
						int sig = process_signal_value(status);
431
						if (delay_signal_handling &&
432
						    last_signal == 0) {
433
							last_signaled_cmd =
434
							    string_copy(cmd);
435
							last_signal = sig;
436
						} else {
437
							handler(sig);
438
						}
439
					}
440
					err = 1;
441
				}
442
				goto execute_error;
2 7u83 443
			}
7 7u83 444
 
445
			/* print tool chain commands sent to execv */
446
			if (tool_chain) {
447
				char **curr = command;
448
				IGNORE printf ("\n%s \\\n", *curr++);
449
 
450
				while (*curr) {
451
					IGNORE printf ("\t%s", *curr++);
452
 
453
					if (*curr) {
454
						IGNORE printf (" \\");
455
					}
456
 
457
					IGNORE printf ("\n");
458
				}
459
			}
460
 
461
			/* print environment values sent to execv */
462
			if (tool_chain_environ) {
463
				char **curr = environment;
464
				IGNORE printf ("\n\tEnvironment dump");
465
 
466
				if (!tool_chain) {
467
					IGNORE printf (" for cmd %s", cmd);
468
				}
469
 
470
				IGNORE printf ("\n");
471
 
472
				while (*curr) {
473
					IGNORE printf ("\t%s\n", *curr);
474
					curr++;
475
				}
476
			}
477
 
478
			IGNORE execve(cmd, command, environment);
479
			running_pid = -1;
480
			error(SERIOUS, "Can't execute '%s'", cmd);
481
			exit(2);
2 7u83 482
		}
483
#else
89 7u83 484
		typedef int wait_type;
7 7u83 485
		wait_type status;
486
		if (!filled_buff) {
487
			print_cmd(buff);
488
			filled_buff = 1;
2 7u83 489
		}
7 7u83 490
		err = system(buff + 1);
89 7u83 491
/*		process_return(status, err);
7 7u83 492
		if (process_exited(status)) {
493
			err = process_exit_value(status);
494
			process_delayed_signal();
495
		} else {
496
			if (process_signaled(status)) {
89 7u83 497
				\* delay_signal_handling is a global that tells
7 7u83 498
				 * us that it is ok to let the next call to
499
				 * execute report that the command received a
500
				 * signal. This supports the way that the
89 7u83 501
				 * producer is called. *\/
7 7u83 502
				int sig = process_signal_value(status);
503
				if (delay_signal_handling &&
504
				    last_signal == 0) {
505
					last_signaled_cmd = string_copy(cmd);
506
					last_signal = sig;
507
				} else {
508
					handler(sig);
509
				}
510
			}
511
			err = 1;
89 7u83 512
		}*/
7 7u83 513
#endif
2 7u83 514
	}
515
 
7 7u83 516
	/* Deal with errors */
517
execute_error:
518
	disable_delayed_signal();
519
	last_return = err;
520
	if (tidy_up) {
521
		/* Remove unneeded files */
522
		filename *p;
523
		for (p = input; p != null; p = p->next) {
524
			if (p->storage == TEMP_FILE && p->type != BINARY_OBJ) {
525
				IGNORE remove(p->name);
526
			}
2 7u83 527
		}
528
	}
7 7u83 529
	if (err) {
530
		exec_error = 1;
531
		exit_status = EXIT_FAILURE;
532
		if (show_errors) {
533
			/* Show when the error occurred */
534
			if (!filled_buff) {
535
				print_cmd(buff);
536
			}
537
			error(INFO, "Error in '%s'", buff + 1);
538
		}
539
		remove_junk();
540
		return (null);
2 7u83 541
	}
7 7u83 542
	junk = null;
543
	return (output);
2 7u83 544
}