Print this page
make: remove SCCS ident stuff
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/make/lib/mksh/src/dosys.cc
+++ new/usr/src/cmd/make/lib/mksh/src/dosys.cc
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 -/*
26 - * @(#)dosys.cc 1.38 06/12/12
27 - */
28 25
29 -#pragma ident "@(#)dosys.cc 1.38 06/12/12"
30 26
31 27 /*
32 28 * dosys.cc
33 29 *
34 30 * Execute one commandline
35 31 */
36 32
37 33 /*
38 34 * Included files
39 35 */
40 36 #include <sys/wait.h> /* WIFEXITED(status) */
41 37 #include <avo/avo_alloca.h> /* alloca() */
42 38
43 39 #if defined(TEAMWARE_MAKE_CMN) || defined(MAKETOOL) /* tolik */
44 40 # include <avo/strings.h> /* AVO_STRDUP() */
45 41 #if defined(DISTRIBUTED)
46 42 # include <dm/Avo_CmdOutput.h>
47 43 # include <rw/xdrstrea.h>
48 44 #endif
49 45 #endif
50 46
51 47 #include <stdio.h> /* errno */
52 48 #include <errno.h> /* errno */
53 49 #include <fcntl.h> /* open() */
54 50 #include <mksh/dosys.h>
55 51 #include <mksh/macro.h> /* getvar() */
56 52 #include <mksh/misc.h> /* getmem(), fatal_mksh(), errmsg() */
57 53 #include <mksdmsi18n/mksdmsi18n.h> /* libmksdmsi18n_init() */
58 54 #include <sys/signal.h> /* SIG_DFL */
59 55 #include <sys/stat.h> /* open() */
60 56 #include <sys/wait.h> /* wait() */
61 57 #include <ulimit.h> /* ulimit() */
62 58 #include <unistd.h> /* close(), dup2() */
63 59
64 60 #if defined (HP_UX) || defined (linux)
65 61 # include <sys/param.h>
66 62 # include <wctype.h>
67 63 # include <wchar.h>
68 64 #endif
69 65
70 66 #if defined (linux)
71 67 # define wslen(x) wcslen(x)
72 68 # define wscpy(x,y) wcscpy(x,y)
73 69 #endif
74 70
75 71 /*
76 72 * Defined macros
77 73 */
78 74 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
79 75 #define SEND_MTOOL_MSG(cmds) \
80 76 if (send_mtool_msgs) { \
81 77 cmds \
82 78 }
83 79 #else
84 80 #define SEND_MTOOL_MSG(cmds)
85 81 #endif
86 82
87 83 /*
88 84 * typedefs & structs
89 85 */
90 86
91 87 /*
92 88 * Static variables
93 89 */
94 90
95 91 /*
96 92 * File table of contents
97 93 */
98 94 static Boolean exec_vp(register char *name, register char **argv, char **envp, register Boolean ignore_error, pathpt vroot_path);
99 95
100 96 /*
101 97 * Workaround for NFS bug. Sometimes, when running 'open' on a remote
102 98 * dmake server, it fails with "Stale NFS file handle" error.
103 99 * The second attempt seems to work.
104 100 */
105 101 int
106 102 my_open(const char *path, int oflag, mode_t mode) {
107 103 int res = open(path, oflag, mode);
108 104 #ifdef linux
109 105 // Workaround for NFS problem: even when all directories in 'path'
110 106 // exist, 'open' (file creation) fails with ENOENT.
111 107 int nattempt = 0;
112 108 while (res < 0 && (errno == ESTALE || errno == EAGAIN || errno == ENOENT)) {
113 109 nattempt++;
114 110 if(nattempt > 30) {
115 111 break;
116 112 }
117 113 sleep(1);
118 114 #else
119 115 if (res < 0 && (errno == ESTALE || errno == EAGAIN)) {
120 116 #endif
121 117 /* Stale NFS file handle. Try again */
122 118 res = open(path, oflag, mode);
123 119 }
124 120 return res;
125 121 }
126 122
127 123 /*
128 124 * void
129 125 * redirect_io(char *stdout_file, char *stderr_file)
130 126 *
131 127 * Redirects stdout and stderr for a child mksh process.
132 128 */
133 129 void
134 130 redirect_io(char *stdout_file, char *stderr_file)
135 131 {
136 132 long descriptor_limit;
137 133 int i;
138 134
139 135 #if defined (HP_UX) || defined (linux)
140 136 /*
141 137 * HP-UX does not support the UL_GDESLIM command for ulimit().
142 138 * NOFILE == max num open files per process (from <sys/param.h>)
143 139 */
144 140 descriptor_limit = NOFILE;
145 141 #else
146 142 if ((descriptor_limit = ulimit(UL_GDESLIM)) < 0) {
147 143 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 89, "ulimit() failed: %s"), errmsg(errno));
148 144 }
149 145 #endif
150 146 for (i = 3; i < descriptor_limit; i++) {
151 147 (void) close(i);
152 148 }
153 149 if ((i = my_open(stdout_file,
154 150 O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC,
155 151 S_IREAD | S_IWRITE)) < 0) {
156 152 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 90, "Couldn't open standard out temp file `%s': %s"),
157 153 stdout_file,
158 154 errmsg(errno));
159 155 } else {
160 156 if (dup2(i, 1) == -1) {
161 157 fatal_mksh(NOCATGETS("*** Error: dup2(3, 1) failed: %s"),
162 158 errmsg(errno));
163 159 }
164 160 close(i);
165 161 }
166 162 if (stderr_file == NULL) {
167 163 if (dup2(1, 2) == -1) {
168 164 fatal_mksh(NOCATGETS("*** Error: dup2(1, 2) failed: %s"),
169 165 errmsg(errno));
170 166 }
171 167 } else if ((i = my_open(stderr_file,
172 168 O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC,
173 169 S_IREAD | S_IWRITE)) < 0) {
174 170 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 91, "Couldn't open standard error temp file `%s': %s"),
175 171 stderr_file,
176 172 errmsg(errno));
177 173 } else {
178 174 if (dup2(i, 2) == -1) {
179 175 fatal_mksh(NOCATGETS("*** Error: dup2(3, 2) failed: %s"),
180 176 errmsg(errno));
181 177 }
182 178 close(i);
183 179 }
184 180 }
185 181
186 182 /*
187 183 * dosys_mksh(command, ignore_error, call_make, silent_error, target)
188 184 *
189 185 * Check if command string contains meta chars and dispatch to
190 186 * the proper routine for executing one command line.
191 187 *
192 188 * Return value:
193 189 * Indicates if the command execution failed
194 190 *
195 191 * Parameters:
196 192 * command The command to run
197 193 * ignore_error Should we abort when an error is seen?
198 194 * call_make Did command reference $(MAKE) ?
199 195 * silent_error Should error messages be suppressed for dmake?
200 196 * target Target we are building
201 197 *
202 198 * Global variables used:
203 199 * do_not_exec_rule Is -n on?
204 200 * working_on_targets We started processing real targets
205 201 */
206 202 Doname
207 203 dosys_mksh(register Name command, register Boolean ignore_error, register Boolean call_make, Boolean silent_error, Boolean always_exec, Name target, Boolean redirect_out_err, char *stdout_file, char *stderr_file, pathpt vroot_path, int nice_prio)
208 204 {
209 205 register int length = command->hash.length;
210 206 register wchar_t *p;
211 207 register wchar_t *q;
212 208 register wchar_t *cmd_string;
213 209 struct stat before;
214 210 Doname result;
215 211 Boolean working_on_targets_mksh = true;
216 212 Wstring wcb(command);
217 213 p = wcb.get_string();
218 214 cmd_string = p;
219 215
220 216 /* Strip spaces from head of command string */
221 217 while (iswspace(*p)) {
222 218 p++, length--;
223 219 }
224 220 if (*p == (int) nul_char) {
225 221 return build_failed;
226 222 }
227 223 /* If we are faking it we just return */
228 224 if (do_not_exec_rule &&
229 225 working_on_targets_mksh &&
230 226 !call_make &&
231 227 !always_exec) {
232 228 return build_ok;
233 229 }
234 230
235 231 /* Copy string to make it OK to write it. */
236 232 q = ALLOC_WC(length + 1);
237 233 (void) wscpy(q, p);
238 234 /* Write the state file iff this command uses make. */
239 235 /* XXX - currently does not support recursive make's, $(MAKE)'s
240 236 if (call_make && command_changed) {
241 237 write_state_file(0, false);
242 238 }
243 239 (void) stat(make_state->string_mb, &before);
244 240 */
245 241 /*
246 242 * Run command directly if it contains no shell meta chars,
247 243 * else run it using the shell.
248 244 */
249 245 /* XXX - command->meta *may* not be set correctly */
250 246 if (await(ignore_error,
251 247 silent_error,
252 248 target,
253 249 cmd_string,
254 250 command->meta ?
255 251 doshell(q, ignore_error, redirect_out_err, stdout_file, stderr_file, nice_prio) :
256 252 doexec(q, ignore_error, redirect_out_err, stdout_file, stderr_file, vroot_path, nice_prio),
257 253 false,
258 254 NULL,
259 255 -1)) {
260 256
261 257 #ifdef PRINT_EXIT_STATUS
262 258 warning_mksh(NOCATGETS("I'm in dosys_mksh(), and await() returned result of build_ok."));
263 259 #endif
264 260
265 261 result = build_ok;
266 262 } else {
267 263
268 264 #ifdef PRINT_EXIT_STATUS
269 265 warning_mksh(NOCATGETS("I'm in dosys_mksh(), and await() returned result of build_failed."));
270 266 #endif
271 267
272 268 result = build_failed;
273 269 }
274 270 retmem(q);
275 271
276 272 /* XXX - currently does not support recursive make's, $(MAKE)'s
277 273 if ((report_dependencies_level == 0) &&
278 274 call_make) {
279 275 make_state->stat.time = (time_t)file_no_time;
280 276 (void)exists(make_state);
281 277 if (before.st_mtime == make_state->stat.time) {
282 278 return result;
283 279 }
284 280 makefile_type = reading_statefile;
285 281 if (read_trace_level > 1) {
286 282 trace_reader = true;
287 283 }
288 284 (void) read_simple_file(make_state,
289 285 false,
290 286 false,
291 287 false,
292 288 false,
293 289 false,
294 290 true);
295 291 trace_reader = false;
296 292 }
297 293 */
298 294 return result;
299 295 }
300 296
301 297 /*
302 298 * doshell(command, ignore_error)
303 299 *
304 300 * Used to run command lines that include shell meta-characters.
305 301 * The make macro SHELL is supposed to contain a path to the shell.
306 302 *
307 303 * Return value:
308 304 * The pid of the process we started
309 305 *
310 306 * Parameters:
311 307 * command The command to run
312 308 * ignore_error Should we abort on error?
313 309 *
314 310 * Global variables used:
315 311 * filter_stderr If -X is on we redirect stderr
316 312 * shell_name The Name "SHELL", used to get the path to shell
317 313 */
318 314 int
319 315 doshell(wchar_t *command, register Boolean ignore_error, Boolean redirect_out_err, char *stdout_file, char *stderr_file, int nice_prio)
320 316 {
321 317 char *argv[6];
322 318 int argv_index = 0;
323 319 int cmd_argv_index;
324 320 int length;
325 321 char nice_prio_buf[MAXPATHLEN];
326 322 register Name shell = getvar(shell_name);
327 323 register char *shellname;
328 324 char *tmp_mbs_buffer;
329 325
330 326
331 327 if (IS_EQUAL(shell->string_mb, "")) {
332 328 shell = shell_name;
333 329 }
334 330 if ((shellname = strrchr(shell->string_mb, (int) slash_char)) == NULL) {
335 331 shellname = shell->string_mb;
336 332 } else {
337 333 shellname++;
338 334 }
339 335
340 336 /*
341 337 * Only prepend the /usr/bin/nice command to the original command
342 338 * if the nice priority, nice_prio, is NOT zero (0).
343 339 * Nice priorities can be a positive or a negative number.
344 340 */
345 341 if (nice_prio != 0) {
346 342 argv[argv_index++] = NOCATGETS("nice");
347 343 (void) sprintf(nice_prio_buf, NOCATGETS("-%d"), nice_prio);
348 344 argv[argv_index++] = strdup(nice_prio_buf);
349 345 }
350 346 argv[argv_index++] = shellname;
351 347 #if defined(linux)
352 348 if(0 == strcmp(shell->string_mb, (char*)NOCATGETS("/bin/sh"))) {
353 349 argv[argv_index++] = (char*)(ignore_error ? NOCATGETS("-c") : NOCATGETS("-ce"));
354 350 } else {
355 351 argv[argv_index++] = (char*)NOCATGETS("-c");
356 352 }
357 353 #else
358 354 argv[argv_index++] = (char*)(ignore_error ? NOCATGETS("-c") : NOCATGETS("-ce"));
359 355 #endif
360 356 if ((length = wslen(command)) >= MAXPATHLEN) {
361 357 tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
362 358 (void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1);
363 359 cmd_argv_index = argv_index;
364 360 argv[argv_index++] = strdup(tmp_mbs_buffer);
365 361 retmem_mb(tmp_mbs_buffer);
366 362 } else {
367 363 WCSTOMBS(mbs_buffer, command);
368 364 cmd_argv_index = argv_index;
369 365 #if defined(linux)
370 366 int mbl = strlen(mbs_buffer);
371 367 if(mbl > 2) {
372 368 if(mbs_buffer[mbl-1] == '\n' && mbs_buffer[mbl-2] == '\\') {
373 369 mbs_buffer[mbl] = '\n';
374 370 mbs_buffer[mbl+1] = 0;
375 371 }
376 372 }
377 373 #endif
378 374 argv[argv_index++] = strdup(mbs_buffer);
379 375 }
380 376 argv[argv_index] = NULL;
381 377 (void) fflush(stdout);
382 378 if ((childPid = fork()) == 0) {
383 379 enable_interrupt((void (*) (int)) SIG_DFL);
384 380 if (redirect_out_err) {
385 381 redirect_io(stdout_file, stderr_file);
386 382 }
387 383 #if 0
388 384 if (filter_stderr) {
389 385 redirect_stderr();
390 386 }
391 387 #endif
392 388 if (nice_prio != 0) {
393 389 (void) execve(NOCATGETS("/usr/bin/nice"), argv, environ);
394 390 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 92, "Could not load `/usr/bin/nice': %s"),
395 391 errmsg(errno));
396 392 } else {
397 393 (void) execve(shell->string_mb, argv, environ);
398 394 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 93, "Could not load Shell from `%s': %s"),
399 395 shell->string_mb,
400 396 errmsg(errno));
401 397 }
402 398 }
403 399 if (childPid == -1) {
404 400 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 94, "fork failed: %s"),
405 401 errmsg(errno));
406 402 }
407 403 retmem_mb(argv[cmd_argv_index]);
408 404 return childPid;
409 405 }
410 406
411 407 /*
412 408 * exec_vp(name, argv, envp, ignore_error)
413 409 *
414 410 * Like execve, but does path search.
415 411 * This starts command when make invokes it directly (without a shell).
416 412 *
417 413 * Return value:
418 414 * Returns false if the exec failed
419 415 *
420 416 * Parameters:
421 417 * name The name of the command to run
422 418 * argv Arguments for the command
423 419 * envp The environment for it
424 420 * ignore_error Should we abort on error?
425 421 *
426 422 * Global variables used:
427 423 * shell_name The Name "SHELL", used to get the path to shell
428 424 * vroot_path The path used by the vroot package
429 425 */
430 426 static Boolean
431 427 exec_vp(register char *name, register char **argv, char **envp, register Boolean ignore_error, pathpt vroot_path)
432 428 {
433 429 register Name shell = getvar(shell_name);
434 430 register char *shellname;
435 431 char *shargv[4];
436 432 Name tmp_shell;
437 433
438 434 if (IS_EQUAL(shell->string_mb, "")) {
439 435 shell = shell_name;
440 436 }
441 437
442 438 for (int i = 0; i < 5; i++) {
443 439 (void) execve_vroot(name,
444 440 argv + 1,
445 441 envp,
446 442 vroot_path,
447 443 VROOT_DEFAULT);
448 444 switch (errno) {
449 445 case ENOEXEC:
450 446 case ENOENT:
451 447 /* That failed. Let the shell handle it */
452 448 shellname = strrchr(shell->string_mb, (int) slash_char);
453 449 if (shellname == NULL) {
454 450 shellname = shell->string_mb;
455 451 } else {
456 452 shellname++;
457 453 }
458 454 shargv[0] = shellname;
459 455 shargv[1] = (char*)(ignore_error ? NOCATGETS("-c") : NOCATGETS("-ce"));
460 456 shargv[2] = argv[0];
461 457 shargv[3] = NULL;
462 458 tmp_shell = getvar(shell_name);
463 459 if (IS_EQUAL(tmp_shell->string_mb, "")) {
464 460 tmp_shell = shell_name;
465 461 }
466 462 (void) execve_vroot(tmp_shell->string_mb,
467 463 shargv,
468 464 envp,
469 465 vroot_path,
470 466 VROOT_DEFAULT);
471 467 return failed;
472 468 case ETXTBSY:
473 469 /*
474 470 * The program is busy (debugged?).
475 471 * Wait and then try again.
476 472 */
477 473 (void) sleep((unsigned) i);
478 474 case EAGAIN:
479 475 break;
480 476 default:
481 477 return failed;
482 478 }
483 479 }
484 480 return failed;
485 481 }
486 482
487 483 /*
488 484 * doexec(command, ignore_error)
489 485 *
490 486 * Will scan an argument string and split it into words
491 487 * thus building an argument list that can be passed to exec_ve()
492 488 *
493 489 * Return value:
494 490 * The pid of the process started here
495 491 *
496 492 * Parameters:
497 493 * command The command to run
498 494 * ignore_error Should we abort on error?
499 495 *
500 496 * Global variables used:
501 497 * filter_stderr If -X is on we redirect stderr
502 498 */
503 499 int
504 500 doexec(register wchar_t *command, register Boolean ignore_error, Boolean redirect_out_err, char *stdout_file, char *stderr_file, pathpt vroot_path, int nice_prio)
505 501 {
506 502 int arg_count = 5;
507 503 char **argv;
508 504 int length;
509 505 char nice_prio_buf[MAXPATHLEN];
510 506 register char **p;
511 507 wchar_t *q;
512 508 register wchar_t *t;
513 509 char *tmp_mbs_buffer;
514 510
515 511 /*
516 512 * Only prepend the /usr/bin/nice command to the original command
517 513 * if the nice priority, nice_prio, is NOT zero (0).
518 514 * Nice priorities can be a positive or a negative number.
519 515 */
520 516 if (nice_prio != 0) {
521 517 arg_count += 2;
522 518 }
523 519 for (t = command; *t != (int) nul_char; t++) {
524 520 if (iswspace(*t)) {
525 521 arg_count++;
526 522 }
527 523 }
528 524 argv = (char **)alloca(arg_count * (sizeof(char *)));
529 525 /*
530 526 * Reserve argv[0] for sh in case of exec_vp failure.
531 527 * Don't worry about prepending /usr/bin/nice command to argv[0].
532 528 * In fact, doing it may cause the sh command to fail!
533 529 */
534 530 p = &argv[1];
535 531 if ((length = wslen(command)) >= MAXPATHLEN) {
536 532 tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
537 533 (void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1);
538 534 argv[0] = strdup(tmp_mbs_buffer);
539 535 retmem_mb(tmp_mbs_buffer);
540 536 } else {
541 537 WCSTOMBS(mbs_buffer, command);
542 538 argv[0] = strdup(mbs_buffer);
543 539 }
544 540
545 541 if (nice_prio != 0) {
546 542 *p++ = strdup(NOCATGETS("/usr/bin/nice"));
547 543 (void) sprintf(nice_prio_buf, NOCATGETS("-%d"), nice_prio);
548 544 *p++ = strdup(nice_prio_buf);
549 545 }
550 546 /* Build list of argument words. */
551 547 for (t = command; *t;) {
552 548 if (p >= &argv[arg_count]) {
553 549 /* This should never happen, right? */
554 550 WCSTOMBS(mbs_buffer, command);
555 551 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 95, "Command `%s' has more than %d arguments"),
556 552 mbs_buffer,
557 553 arg_count);
558 554 }
559 555 q = t;
560 556 while (!iswspace(*t) && (*t != (int) nul_char)) {
561 557 t++;
562 558 }
563 559 if (*t) {
564 560 for (*t++ = (int) nul_char; iswspace(*t); t++);
565 561 }
566 562 if ((length = wslen(q)) >= MAXPATHLEN) {
567 563 tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
568 564 (void) wcstombs(tmp_mbs_buffer, q, (length * MB_LEN_MAX) + 1);
569 565 *p++ = strdup(tmp_mbs_buffer);
570 566 retmem_mb(tmp_mbs_buffer);
571 567 } else {
572 568 WCSTOMBS(mbs_buffer, q);
573 569 *p++ = strdup(mbs_buffer);
574 570 }
575 571 }
576 572 *p = NULL;
577 573
578 574 /* Then exec the command with that argument list. */
579 575 (void) fflush(stdout);
580 576 if ((childPid = fork()) == 0) {
581 577 enable_interrupt((void (*) (int)) SIG_DFL);
582 578 if (redirect_out_err) {
583 579 redirect_io(stdout_file, stderr_file);
584 580 }
585 581 #if 0
586 582 if (filter_stderr) {
587 583 redirect_stderr();
588 584 }
589 585 #endif
590 586 (void) exec_vp(argv[1], argv, environ, ignore_error, vroot_path);
591 587 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 96, "Cannot load command `%s': %s"), argv[1], errmsg(errno));
592 588 }
593 589 if (childPid == -1) {
594 590 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 97, "fork failed: %s"),
595 591 errmsg(errno));
596 592 }
597 593 for (int i = 0; argv[i] != NULL; i++) {
598 594 retmem_mb(argv[i]);
599 595 }
600 596 return childPid;
601 597 }
602 598
603 599 /*
604 600 * await(ignore_error, silent_error, target, command, running_pid)
605 601 *
606 602 * Wait for one child process and analyzes
607 603 * the returned status when the child process terminates.
608 604 *
609 605 * Return value:
610 606 * Returns true if commands ran OK
611 607 *
612 608 * Parameters:
613 609 * ignore_error Should we abort on error?
614 610 * silent_error Should error messages be suppressed for dmake?
615 611 * target The target we are building, for error msgs
616 612 * command The command we ran, for error msgs
617 613 * running_pid The pid of the process we are waiting for
618 614 *
619 615 * Static variables used:
620 616 * filter_file The fd for the filter file
621 617 * filter_file_name The name of the filter file
622 618 *
623 619 * Global variables used:
624 620 * filter_stderr Set if -X is on
625 621 */
626 622 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
627 623 Boolean
628 624 await(register Boolean ignore_error, register Boolean silent_error, Name target, wchar_t *command, pid_t running_pid, Boolean send_mtool_msgs, XDR *xdrs_p, int job_msg_id)
629 625 #else
630 626 Boolean
631 627 await(register Boolean ignore_error, register Boolean silent_error, Name target, wchar_t *command, pid_t running_pid, Boolean send_mtool_msgs, void *xdrs_p, int job_msg_id)
632 628 #endif
633 629 {
634 630 #ifdef SUN5_0
635 631 int status;
636 632 #else
637 633 #ifndef WEXITSTATUS
638 634 #define WEXITSTATUS(stat) stat.w_T.w_Retcode
639 635 #endif
640 636 #ifndef WTERMSIG
641 637 #define WTERMSIG(stat) stat.w_T.w_Termsig
642 638 #endif
643 639 #ifndef WCOREDUMP
644 640 #define WCOREDUMP(stat) stat.w_T.w_Coredump
645 641 #endif
646 642 #if defined (HP_UX) || defined (linux)
647 643 int status;
648 644 #else
649 645 union wait status;
650 646 #endif
651 647 #endif
652 648 char *buffer;
653 649 int core_dumped;
654 650 int exit_status;
655 651 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
656 652 Avo_CmdOutput *make_output_msg;
657 653 #endif
658 654 FILE *outfp;
659 655 register pid_t pid;
660 656 struct stat stat_buff;
661 657 int termination_signal;
662 658 char tmp_buf[MAXPATHLEN];
663 659 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
664 660 RWCollectable *xdr_msg;
665 661 #endif
666 662
667 663 while ((pid = wait(&status)) != running_pid) {
668 664 if (pid == -1) {
669 665 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 98, "wait() failed: %s"), errmsg(errno));
670 666 }
671 667 }
672 668 (void) fflush(stdout);
673 669 (void) fflush(stderr);
674 670
675 671 #if defined(SUN5_0) || defined(HP_UX) || defined(linux)
676 672 if (status == 0) {
677 673
678 674 #ifdef PRINT_EXIT_STATUS
679 675 warning_mksh(NOCATGETS("I'm in await(), and status is 0."));
680 676 #endif
681 677
682 678 return succeeded;
683 679 }
684 680
685 681 #ifdef PRINT_EXIT_STATUS
686 682 warning_mksh(NOCATGETS("I'm in await(), and status is *NOT* 0."));
687 683 #endif
688 684
689 685 #else
690 686 if (status.w_status == 0) {
691 687 return succeeded;
692 688 }
693 689 #endif
694 690
695 691 exit_status = WEXITSTATUS(status);
696 692
697 693 #ifdef PRINT_EXIT_STATUS
698 694 warning_mksh(NOCATGETS("I'm in await(), and exit_status is %d."), exit_status);
699 695 #endif
700 696
701 697 termination_signal = WTERMSIG(status);
702 698 core_dumped = WCOREDUMP(status);
703 699
704 700 /*
705 701 * If the child returned an error, we now try to print a
706 702 * nice message about it.
707 703 */
708 704 SEND_MTOOL_MSG(
709 705 make_output_msg = new Avo_CmdOutput();
710 706 (void) sprintf(tmp_buf, "%d", job_msg_id);
711 707 make_output_msg->appendOutput(AVO_STRDUP(tmp_buf));
712 708 );
713 709
714 710 tmp_buf[0] = (int) nul_char;
715 711 if (!silent_error) {
716 712 if (exit_status != 0) {
717 713 (void) fprintf(stdout,
718 714 catgets(libmksdmsi18n_catd, 1, 103, "*** Error code %d"),
719 715 exit_status);
720 716 SEND_MTOOL_MSG(
721 717 (void) sprintf(&tmp_buf[strlen(tmp_buf)],
722 718 catgets(libmksdmsi18n_catd, 1, 104, "*** Error code %d"),
723 719 exit_status);
724 720 );
725 721 } else {
726 722 #if ! defined(SUN5_0) && ! defined(HP_UX) && ! defined(linux)
727 723 if (termination_signal > NSIG) {
728 724 #endif
729 725 (void) fprintf(stdout,
730 726 catgets(libmksdmsi18n_catd, 1, 105, "*** Signal %d"),
731 727 termination_signal);
732 728 SEND_MTOOL_MSG(
733 729 (void) sprintf(&tmp_buf[strlen(tmp_buf)],
734 730 catgets(libmksdmsi18n_catd, 1, 106, "*** Signal %d"),
735 731 termination_signal);
736 732 );
737 733 #if ! defined(SUN5_0) && ! defined(HP_UX) && ! defined(linux)
738 734 } else {
739 735 (void) fprintf(stdout,
740 736 "*** %s",
741 737 sys_siglist[termination_signal]);
742 738 SEND_MTOOL_MSG(
743 739 (void) sprintf(&tmp_buf[strlen(tmp_buf)],
744 740 "*** %s",
745 741 sys_siglist[termination_signal]);
746 742 );
747 743 }
748 744 #endif
749 745 if (core_dumped) {
750 746 (void) fprintf(stdout,
751 747 catgets(libmksdmsi18n_catd, 1, 107, " - core dumped"));
752 748 SEND_MTOOL_MSG(
753 749 (void) sprintf(&tmp_buf[strlen(tmp_buf)],
754 750 catgets(libmksdmsi18n_catd, 1, 108, " - core dumped"));
755 751 );
756 752 }
757 753 }
758 754 if (ignore_error) {
759 755 (void) fprintf(stdout,
760 756 catgets(libmksdmsi18n_catd, 1, 109, " (ignored)"));
761 757 SEND_MTOOL_MSG(
762 758 (void) sprintf(&tmp_buf[strlen(tmp_buf)],
763 759 catgets(libmksdmsi18n_catd, 1, 110, " (ignored)"));
764 760 );
765 761 }
766 762 (void) fprintf(stdout, "\n");
767 763 (void) fflush(stdout);
768 764 SEND_MTOOL_MSG(
769 765 make_output_msg->appendOutput(AVO_STRDUP(tmp_buf));
770 766 );
771 767 }
772 768 SEND_MTOOL_MSG(
773 769 xdr_msg = (RWCollectable*) make_output_msg;
774 770 xdr(xdrs_p, xdr_msg);
775 771 delete make_output_msg;
776 772 );
777 773
778 774 #ifdef PRINT_EXIT_STATUS
779 775 warning_mksh(NOCATGETS("I'm in await(), returning failed."));
780 776 #endif
781 777
782 778 return failed;
783 779 }
784 780
785 781 /*
786 782 * sh_command2string(command, destination)
787 783 *
788 784 * Run one sh command and capture the output from it.
789 785 *
790 786 * Return value:
791 787 *
792 788 * Parameters:
793 789 * command The command to run
794 790 * destination Where to deposit the output from the command
795 791 *
796 792 * Static variables used:
797 793 *
798 794 * Global variables used:
799 795 */
800 796 void
801 797 sh_command2string(register String command, register String destination)
802 798 {
803 799 register FILE *fd;
804 800 register int chr;
805 801 int status;
806 802 Boolean command_generated_output = false;
807 803
808 804 command->text.p = (int) nul_char;
809 805 WCSTOMBS(mbs_buffer, command->buffer.start);
810 806 if ((fd = popen(mbs_buffer, "r")) == NULL) {
811 807 WCSTOMBS(mbs_buffer, command->buffer.start);
812 808 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 111, "Could not run command `%s' for :sh transformation"),
813 809 mbs_buffer);
814 810 }
815 811 while ((chr = getc(fd)) != EOF) {
816 812 if (chr == (int) newline_char) {
817 813 chr = (int) space_char;
818 814 }
819 815 command_generated_output = true;
820 816 append_char(chr, destination);
821 817 }
822 818
823 819 /*
824 820 * We don't want to keep the last LINE_FEED since usually
825 821 * the output of the 'sh:' command is used to evaluate
826 822 * some MACRO. ( /bin/sh and other shell add a line feed
827 823 * to the output so that the prompt appear in the right place.
828 824 * We don't need that
829 825 */
830 826 if (command_generated_output){
831 827 if ( *(destination->text.p-1) == (int) space_char) {
832 828 * (-- destination->text.p) = '\0';
833 829 }
834 830 } else {
835 831 /*
836 832 * If the command didn't generate any output,
837 833 * set the buffer to a null string.
838 834 */
839 835 *(destination->text.p) = '\0';
840 836 }
841 837
842 838 status = pclose(fd);
843 839 if (status != 0) {
844 840 WCSTOMBS(mbs_buffer, command->buffer.start);
845 841 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 112, "The command `%s' returned status `%d'"),
846 842 mbs_buffer,
847 843 WEXITSTATUS(status));
848 844 }
849 845 }
850 846
851 847
↓ open down ↓ |
812 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX