1 /* trace(1) - the MINIX3 system call tracer - by D.C. van Moolenbroek */ 2 3 #include "inc.h" 4 5 #include <signal.h> 6 #include <sys/wait.h> 7 #include <unistd.h> 8 #include <err.h> 9 10 /* Global variables, used only for a subset of the command line options. */ 11 int allnames; /* FALSE = structure field names, TRUE = all names */ 12 unsigned int valuesonly; /* 0 = normal, 1 = no symbols, 2 = no structures */ 13 unsigned int verbose; /* 0 = essentials, 1 = elaborate, 2 = everything */ 14 15 /* Local variables, for signal handling. */ 16 static int got_signal, got_info; 17 18 /* 19 * Signal handler for signals that are supposed to make us terminate. Let the 20 * main loop do the actual work, since it might be in the middle of processing 21 * a process status change right now. 22 */ 23 static void 24 sig_handler(int __unused sig) 25 { 26 27 got_signal = TRUE; 28 29 } 30 31 /* 32 * Signal handler for the SIGINFO signal. Let the main loop report on all 33 * processes currenty being traced. Since SIGINFO is sent to the current 34 * process group, traced children may get the signal as well. This is both 35 * intentional and impossible to prevent. 36 */ 37 static void 38 info_handler(int __unused sig) 39 { 40 41 got_info = TRUE; 42 } 43 44 /* 45 * Print a list of traced processes and their call status. We must not 46 * interfere with actual process output, so perform out-of-band printing 47 * (with info lines rather than lines prefixed by each process's PID). 48 */ 49 static void 50 list_info(void) 51 { 52 struct trace_proc *proc; 53 int no_call, in_call; 54 55 put_newline(); 56 57 for (proc = proc_next(NULL); proc != NULL; proc = proc_next(proc)) { 58 /* 59 * When attaching to an existing process, there is no way to 60 * find out whether the process is in a system call or not. 61 */ 62 no_call = (proc->trace_flags & TF_NOCALL); 63 in_call = (proc->trace_flags & TF_INCALL); 64 assert(!in_call || !no_call); 65 66 put_fmt(NULL, "Tracing %s (pid %d), %s%s%s", proc->name, 67 proc->pid, no_call ? "call status unknown" : 68 (in_call ? "in a " : "not in a call"), 69 in_call ? call_name(proc) : "", 70 in_call ? " call" : ""); 71 put_newline(); 72 } 73 } 74 75 /* 76 * Either we have just started or attached to the given process, it the process 77 * has performed a successful execve() call. Obtain the new process name, and 78 * print a banner for it. 79 */ 80 static void 81 new_exec(struct trace_proc * proc) 82 { 83 84 /* Failure to obtain the process name is worrisome, but not fatal.. */ 85 if (kernel_get_name(proc->pid, proc->name, sizeof(proc->name)) < 0) 86 strlcpy(proc->name, "<unknown>", sizeof(proc->name)); 87 88 put_newline(); 89 put_fmt(proc, "Tracing %s (pid %d)", proc->name, proc->pid); 90 put_newline(); 91 } 92 93 /* 94 * We have started or attached to a process. Set the appropriate flags, and 95 * print a banner showing that we are now tracing it. 96 */ 97 static void 98 new_proc(struct trace_proc * proc, int follow_fork) 99 { 100 int fl; 101 102 /* Set the desired tracing options. */ 103 fl = TO_ALTEXEC; 104 if (follow_fork) fl |= TO_TRACEFORK; 105 106 (void)ptrace(T_SETOPT, proc->pid, 0, fl); 107 108 /* 109 * When attaching to an arbitrary process, this process might be in the 110 * middle of an execve(). Now that we have enabled TO_ALTEXEC, we may 111 * now get a SIGSTOP signal next. Guard against this by marking the 112 * first system call as a possible execve(). 113 */ 114 if ((proc->trace_flags & (TF_ATTACH | TF_STOPPING)) == TF_ATTACH) 115 proc->trace_flags |= TF_EXEC; 116 117 new_exec(proc); 118 } 119 120 /* 121 * A process has terminated or is being detached. Print the resulting status. 122 */ 123 static void 124 discard_proc(struct trace_proc * proc, int status) 125 { 126 const char *signame; 127 128 /* 129 * The exit() calls are of type no-return, meaning they are expected 130 * not to return. However, calls of this type may in fact return an 131 * error, in which case the error must be printed. Thus, such calls 132 * are not actually finished until the end of the call-leave phase. 133 * For exit() calls, a successful call will never get to the call-leave 134 * phase. The result is that such calls will end up being shown as 135 * suspended, which is unintuitive. To counter this, we pretend that a 136 * clean process exit is in fact preceded by a call-leave event, thus 137 * allowing the call to be printed without suspension. An example: 138 * 139 * 3| exit(0) <..> 140 * 2| setsid() = 2 141 * [A] 3| exit(0) 142 * 3| Process exited normally with code 0 143 * 144 * The [A] line is the result of the following code. 145 */ 146 if (WIFEXITED(status) && (proc->trace_flags & TF_INCALL)) 147 call_leave(proc, TRUE /*skip*/); 148 149 put_newline(); 150 if (WIFEXITED(status)) { 151 put_fmt(proc, "Process exited normally with code %d", 152 WEXITSTATUS(status)); 153 } else if (WIFSIGNALED(status)) { 154 if ((signame = get_signal_name(WTERMSIG(status))) != NULL) 155 put_fmt(proc, "Process terminated from signal %s", 156 signame); 157 else 158 put_fmt(proc, "Process terminated from signal %d", 159 WTERMSIG(status)); 160 } else if (WIFSTOPPED(status)) 161 put_text(proc, "Process detached"); 162 else 163 put_fmt(proc, "Bogus wait result (%04x)", status); 164 put_newline(); 165 166 proc_del(proc); 167 } 168 169 /* 170 * The given process has been stopped on a system call, either entering or 171 * leaving that call. 172 */ 173 static void 174 handle_call(struct trace_proc * proc, int show_stack) 175 { 176 reg_t pc, sp; 177 int class, skip, new_ctx; 178 179 proc->trace_flags &= ~TF_NOCALL; 180 181 if (proc->trace_flags & TF_SKIP) { 182 /* Skip the call leave phase after a successful execve(). */ 183 proc->trace_flags &= ~(TF_INCALL | TF_SKIP); 184 } else if (!(proc->trace_flags & TF_INCALL)) { 185 /* 186 * The call_enter call returns the class of the call: 187 * TC_NORMAL, TC_EXEC, or TC_SIGRET. TC_EXEC means that an 188 * execve() call is being performed. This means that if a 189 * SIGSTOP follows for the current process, the process has 190 * successfully started a different executable. TC_SIGRET 191 * means that if successful, the call will have a bogus return 192 * value. TC_NORMAL means that the call requires no exception. 193 */ 194 class = call_enter(proc, show_stack); 195 196 switch (class) { 197 case TC_NORMAL: 198 break; 199 case TC_EXEC: 200 proc->trace_flags |= TF_EXEC; 201 break; 202 case TC_SIGRET: 203 proc->trace_flags |= TF_CTX_SKIP; 204 break; 205 default: 206 assert(0); 207 } 208 209 /* Save the current program counter and stack pointer. */ 210 if (!kernel_get_context(proc->pid, &pc, &sp, NULL /*fp*/)) { 211 proc->last_pc = pc; 212 proc->last_sp = sp; 213 } else 214 proc->last_pc = proc->last_sp = 0; 215 216 proc->trace_flags |= TF_INCALL; 217 } else { 218 /* 219 * Check if the program counter or stack pointer have changed 220 * during the system call. If so, this is a strong indication 221 * that a sigreturn call has succeeded, and thus its result 222 * must be skipped, since the result register will not contain 223 * the result of the call. 224 */ 225 new_ctx = (proc->last_pc != 0 && 226 !kernel_get_context(proc->pid, &pc, &sp, NULL /*fp*/) && 227 (pc != proc->last_pc || sp != proc->last_sp)); 228 229 skip = ((proc->trace_flags & TF_CTX_SKIP) && new_ctx); 230 231 call_leave(proc, skip); 232 233 /* 234 * On such context changes, also print a short dashed line. 235 * This helps in identifying signal handler invocations, 236 * although it is not reliable for that purpose: no dashed line 237 * will be printed if a signal handler is invoked while the 238 * process is not making a system call. 239 */ 240 if (new_ctx) { 241 put_text(proc, "---"); 242 put_newline(); 243 } 244 245 proc->trace_flags &= ~(TF_INCALL | TF_CTX_SKIP | TF_EXEC); 246 } 247 } 248 249 /* 250 * The given process has received the given signal. Report the receipt. Due 251 * to the way that signal handling with traced processes works, the signal may 252 * in fact be delivered to the process much later, or never--a problem inherent 253 * to the way signals are handled in PM right now (namely, deferring signal 254 * delivery would let the traced process block signals meant for the tracer). 255 */ 256 static void 257 report_signal(struct trace_proc * proc, int sig, int show_stack) 258 { 259 const char *signame; 260 261 /* 262 * Print a stack trace only if we are not in a call; otherwise, we 263 * would simply get the same stack trace twice and mess up the output 264 * in the process, because call suspension is not expected if we are 265 * tracing a single process only. 266 * FIXME: the check should be for whether we actually print the call.. 267 */ 268 if (show_stack && !(proc->trace_flags & TF_INCALL)) 269 kernel_put_stacktrace(proc); 270 271 /* 272 * If this process is in the middle of a call, the signal will be 273 * printed within the call. This will always happen on the call split, 274 * that is, between the call's entering (out) and leaving (in) phases. 275 * This also means that the recording of the call-enter phase may be 276 * replayed more than once, and the call may be suspended more than 277 * once--after all, a signal is not necessarily followed immediately 278 * by the call result. If the process is not in the middle of a call, 279 * the signal will end up on a separate line. In both cases, multiple 280 * consecutive signals may be printed right after one another. The 281 * following scenario shows a number of possible combinations: 282 * 283 * 2| foo(<..> 284 * 3| ** SIGHUP ** ** SIGUSR1 ** 285 * 3| bar() = <..> 286 * 2|*foo(** SIGUSR1 ** ** SIGUSR2 ** <..> 287 * 3|*bar() = ** SIGCHLD ** 0 288 * 2|*foo(** SIGINT ** &0xef852000) = -1 [EINTR] 289 * 3| kill(3, SIGTERM) = ** SIGTERM ** <..> 290 * 3| Process terminated from signal SIGTERM 291 */ 292 293 call_replay(proc); 294 295 if (!valuesonly && (signame = get_signal_name(sig)) != NULL) 296 put_fmt(proc, "** %s **", signame); 297 else 298 put_fmt(proc, "** SIGNAL %d **", sig); 299 300 put_space(proc); 301 302 output_flush(); 303 } 304 305 /* 306 * Wait for the given process ID to stop on the given signal. Upon success, 307 * the function will return zero. Upon failure, it will return -1, and errno 308 * will be either set to an error code, or to zero in order to indicate that 309 * the process exited instead. 310 */ 311 static int 312 wait_sig(pid_t pid, int sig) 313 { 314 int status; 315 316 for (;;) { 317 if (waitpid(pid, &status, 0) == -1) { 318 if (errno == EINTR) continue; 319 320 return -1; 321 } 322 323 if (!WIFSTOPPED(status)) { 324 /* The process terminated just now. */ 325 errno = 0; 326 327 return -1; 328 } 329 330 if (WSTOPSIG(status) == sig) 331 break; 332 333 (void)ptrace(T_RESUME, pid, 0, WSTOPSIG(status)); 334 } 335 336 return 0; 337 } 338 339 /* 340 * Attach to the given process, and wait for the resulting SIGSTOP signal. 341 * Other signals may arrive first; we pass these on to the process without 342 * reporting them, thus logically modelling them as having arrived before we 343 * attached to the process. The process might also exit in the meantime, 344 * typically as a result of a lethal signal; following the same logical model, 345 * we pretend the process did not exist in the first place. Since the SIGSTOP 346 * signal will be pending right after attaching to the process, this procedure 347 * will never block. 348 */ 349 static int 350 attach(pid_t pid) 351 { 352 353 if (ptrace(T_ATTACH, pid, 0, 0) != 0) { 354 warn("Unable to attach to pid %d", pid); 355 356 return -1; 357 } 358 359 if (wait_sig(pid, SIGSTOP) != 0) { 360 /* If the process terminated, report it as not found. */ 361 if (errno == 0) 362 errno = ESRCH; 363 364 warn("Unable to attach to pid %d", pid); 365 366 return -1; 367 } 368 369 /* Verify that we can read values from the kernel at all. */ 370 if (kernel_check(pid) == FALSE) { 371 (void)ptrace(T_DETACH, pid, 0, 0); 372 373 warnx("Kernel magic check failed, recompile trace(1)"); 374 375 return -1; 376 } 377 378 /* 379 * System services are managed by RS, which prevents them from 380 * being traced properly by PM. Attaching to a service could 381 * therefore cause problems, so we should detach immediately. 382 */ 383 if (kernel_is_service(pid) == TRUE) { 384 (void)ptrace(T_DETACH, pid, 0, 0); 385 386 warnx("Cannot attach to system services!"); 387 388 return -1; 389 } 390 391 return 0; 392 } 393 394 /* 395 * Detach from all processes, knowning that they were all processes to which we 396 * attached explicitly (i.e., not started by us) and are all currently stopped. 397 */ 398 static void 399 detach_stopped(void) 400 { 401 struct trace_proc *proc; 402 403 for (proc = proc_next(NULL); proc != NULL; proc = proc_next(proc)) 404 (void)ptrace(T_DETACH, proc->pid, 0, 0); 405 } 406 407 /* 408 * Start detaching from all processes to which we previously attached. The 409 * function is expected to return before detaching is completed, and the caller 410 * must deal with the new situation appropriately. Do not touch any processes 411 * started by us (to allow graceful termination), unless force is set, in which 412 * case those processes are killed. 413 */ 414 static void 415 detach_running(int force) 416 { 417 struct trace_proc *proc; 418 419 for (proc = proc_next(NULL); proc != NULL; proc = proc_next(proc)) { 420 if (proc->trace_flags & TF_ATTACH) { 421 /* Already detaching? Then do nothing. */ 422 if (proc->trace_flags & TF_DETACH) 423 continue; 424 425 if (!(proc->trace_flags & TF_STOPPING)) 426 (void)kill(proc->pid, SIGSTOP); 427 428 proc->trace_flags |= TF_DETACH | TF_STOPPING; 429 } else { 430 /* 431 * The child processes may be ignoring SIGINTs, so upon 432 * the second try, force them to terminate. 433 */ 434 if (force) 435 (void)kill(proc->pid, SIGKILL); 436 } 437 } 438 } 439 440 /* 441 * Print command usage. 442 */ 443 static void __dead 444 usage(void) 445 { 446 447 (void)fprintf(stderr, "usage: %s [-fgNsVv] [-o file] [-p pid] " 448 "[command]\n", getprogname()); 449 450 exit(EXIT_FAILURE); 451 } 452 453 /* 454 * The main function of the system call tracer. 455 */ 456 int 457 main(int argc, char * argv[]) 458 { 459 struct trace_proc *proc; 460 const char *output_file; 461 int status, sig, follow_fork, show_stack, grouping, first_signal; 462 pid_t pid, last_pid; 463 int c, error; 464 465 setprogname(argv[0]); 466 467 proc_init(); 468 469 follow_fork = FALSE; 470 show_stack = FALSE; 471 grouping = FALSE; 472 output_file = NULL; 473 474 allnames = FALSE; 475 verbose = 0; 476 valuesonly = 0; 477 478 while ((c = getopt(argc, argv, "fgNsVvo:p:")) != -1) { 479 switch (c) { 480 case 'f': 481 follow_fork = TRUE; 482 break; 483 case 'g': 484 grouping = TRUE; 485 break; 486 case 'N': 487 allnames = TRUE; 488 break; 489 case 's': 490 show_stack = TRUE; 491 break; 492 case 'V': 493 valuesonly++; 494 break; 495 case 'v': 496 verbose++; 497 break; 498 case 'o': 499 output_file = optarg; 500 break; 501 case 'p': 502 pid = atoi(optarg); 503 if (pid <= 0) 504 usage(); 505 506 if (proc_get(pid) == NULL && proc_add(pid) == NULL) 507 err(EXIT_FAILURE, NULL); 508 509 break; 510 default: 511 usage(); 512 } 513 } 514 515 argv += optind; 516 argc -= optind; 517 518 first_signal = TRUE; 519 got_signal = FALSE; 520 got_info = FALSE; 521 522 signal(SIGINT, sig_handler); 523 signal(SIGINFO, info_handler); 524 525 /* Attach to any processes for which PIDs were given. */ 526 for (proc = proc_next(NULL); proc != NULL; proc = proc_next(proc)) { 527 if (attach(proc->pid) != 0) { 528 /* 529 * Detach from the processes that we have attached to 530 * so far, i.e. the ones with the TF_ATTACH flag. 531 */ 532 detach_stopped(); 533 534 return EXIT_FAILURE; 535 } 536 537 proc->trace_flags = TF_ATTACH | TF_NOCALL; 538 } 539 540 /* If a command is given, start a child that executes the command. */ 541 if (argc >= 1) { 542 pid = fork(); 543 544 switch (pid) { 545 case -1: 546 warn("Unable to fork"); 547 548 detach_stopped(); 549 550 return EXIT_FAILURE; 551 552 case 0: 553 (void)ptrace(T_OK, 0, 0, 0); 554 555 (void)execvp(argv[0], argv); 556 557 err(EXIT_FAILURE, "Unable to start %s", argv[0]); 558 559 default: 560 break; 561 } 562 563 /* 564 * The first signal will now be SIGTRAP from the execvp(), 565 * unless that fails, in which case the child will terminate. 566 */ 567 if (wait_sig(pid, SIGTRAP) != 0) { 568 /* 569 * If the child exited, the most likely cause is a 570 * failure to execute the command. Let the child 571 * report the error, and do not say anything here. 572 */ 573 if (errno != 0) 574 warn("Unable to start process"); 575 576 detach_stopped(); 577 578 return EXIT_FAILURE; 579 } 580 581 /* If we haven't already, perform the kernel magic check. */ 582 if (proc_count() == 0 && kernel_check(pid) == FALSE) { 583 warnx("Kernel magic check failed, recompile trace(1)"); 584 585 (void)kill(pid, SIGKILL); 586 587 detach_stopped(); 588 589 return EXIT_FAILURE; 590 } 591 592 if ((proc = proc_add(pid)) == NULL) { 593 warn(NULL); 594 595 (void)kill(pid, SIGKILL); 596 597 detach_stopped(); 598 599 return EXIT_FAILURE; 600 } 601 602 proc->trace_flags = 0; 603 } else 604 pid = -1; 605 606 /* The user will have to give us at least one process to trace. */ 607 if (proc_count() == 0) 608 usage(); 609 610 /* 611 * Open an alternative output file if needed. After that, standard 612 * error should no longer be used directly, and all output has to go 613 * through the output module. 614 */ 615 if (output_init(output_file) < 0) { 616 warn("Unable to open output file"); 617 618 if (pid > 0) 619 (void)kill(pid, SIGKILL); 620 621 detach_stopped(); 622 623 return EXIT_FAILURE; 624 } 625 626 /* 627 * All the traced processes are currently stopped. Initialize, report, 628 * and resume them. 629 */ 630 for (proc = proc_next(NULL); proc != NULL; proc = proc_next(proc)) { 631 new_proc(proc, follow_fork); 632 633 (void)ptrace(T_SYSCALL, proc->pid, 0, 0); 634 } 635 636 /* 637 * Handle events until there are no traced processes left. 638 */ 639 last_pid = 0; 640 error = FALSE; 641 642 for (;;) { 643 /* If an output error occurred, exit as soon as possible. */ 644 if (!error && output_error()) { 645 detach_running(TRUE /*force*/); 646 647 error = TRUE; 648 } 649 650 /* 651 * If the user pressed ^C once, start detaching the processes 652 * that we did not start, if any. If the user pressed ^C 653 * twice, kill the process that we did start, if any. 654 */ 655 if (got_signal) { 656 detach_running(!first_signal); 657 658 got_signal = FALSE; 659 first_signal = FALSE; 660 } 661 662 /* Upon getting SIGINFO, print a list of traced processes. */ 663 if (got_info) { 664 list_info(); 665 666 got_info = FALSE; 667 } 668 669 /* 670 * Block until something happens to a traced process. If 671 * enabled from the command line, first try waiting for the 672 * last process for which we got results, so as to reduce call 673 * suspensions a bit. 674 */ 675 if (grouping && last_pid > 0 && 676 waitpid(last_pid, &status, WNOHANG) > 0) 677 pid = last_pid; 678 else 679 if ((pid = waitpid(-1, &status, 0)) <= 0) { 680 if (pid == -1 && errno == EINTR) continue; 681 if (pid == -1 && errno == ECHILD) break; /* all done */ 682 683 put_fmt(NULL, "Unexpected waitpid failure: %s", 684 (pid == 0) ? "No result" : strerror(errno)); 685 put_newline(); 686 687 /* 688 * We need waitpid to function correctly in order to 689 * detach from any attached processes, so we can do 690 * little more than just exit, effectively killing all 691 * traced processes. 692 */ 693 return EXIT_FAILURE; 694 } 695 696 last_pid = 0; 697 698 /* Get the trace data structure for the process. */ 699 if ((proc = proc_get(pid)) == NULL) { 700 /* 701 * The waitpid() call returned the status of a process 702 * that we have not yet seen. This must be a newly 703 * forked child. If it is not stopped, it must have 704 * died immediately, and we choose not to report it. 705 */ 706 if (!WIFSTOPPED(status)) 707 continue; 708 709 if ((proc = proc_add(pid)) == NULL) { 710 put_fmt(NULL, 711 "Error attaching to new child %d: %s", 712 pid, strerror(errno)); 713 put_newline(); 714 715 /* 716 * Out of memory allocating a new child object! 717 * We can not trace this child, so just let it 718 * run free by detaching from it. 719 */ 720 if (WSTOPSIG(status) != SIGSTOP) { 721 (void)ptrace(T_RESUME, pid, 0, 722 WSTOPSIG(status)); 723 724 if (wait_sig(pid, SIGSTOP) != 0) 725 continue; /* it died.. */ 726 } 727 728 (void)ptrace(T_DETACH, pid, 0, 0); 729 730 continue; 731 } 732 733 /* 734 * We must specify TF_ATTACH here, even though it may 735 * be a child of a process we started, in which case it 736 * should be killed when we exit. We do not keep track 737 * of ancestry though, so better safe than sorry. 738 */ 739 proc->trace_flags = TF_ATTACH | TF_STOPPING; 740 741 new_proc(proc, follow_fork); 742 743 /* Repeat entering the fork call for the child. */ 744 handle_call(proc, show_stack); 745 } 746 747 /* If the process died, report its status and clean it up. */ 748 if (!WIFSTOPPED(status)) { 749 discard_proc(proc, status); 750 751 continue; 752 } 753 754 sig = WSTOPSIG(status); 755 756 if (sig == SIGSTOP && (proc->trace_flags & TF_STOPPING)) { 757 /* We expected the process to be stopped; now it is. */ 758 proc->trace_flags &= ~TF_STOPPING; 759 760 if (proc->trace_flags & TF_DETACH) { 761 if (ptrace(T_DETACH, proc->pid, 0, 0) == 0) 762 discard_proc(proc, status); 763 764 /* 765 * If detaching failed, the process must have 766 * died, and we'll get notified through wait(). 767 */ 768 continue; 769 } 770 771 sig = 0; 772 } else if (sig == SIGSTOP && (proc->trace_flags & TF_EXEC)) { 773 /* The process has performed a successful execve(). */ 774 call_leave(proc, TRUE /*skip*/); 775 776 put_text(proc, "---"); 777 778 new_exec(proc); 779 780 /* 781 * A successful execve() has no result, in the sense 782 * that there is no reply message. We should therefore 783 * not even try to copy in the reply message from the 784 * original location, because it will be invalid. 785 * Thus, we skip the exec's call leave phase entirely. 786 */ 787 proc->trace_flags &= ~TF_EXEC; 788 proc->trace_flags |= TF_SKIP; 789 790 sig = 0; 791 } else if (sig == SIGTRAP) { 792 /* The process is entering or leaving a system call. */ 793 if (!(proc->trace_flags & TF_DETACH)) 794 handle_call(proc, show_stack); 795 796 sig = 0; 797 } else { 798 /* The process has received a signal. */ 799 report_signal(proc, sig, show_stack); 800 801 /* 802 * Only in this case do we pass the signal to the 803 * traced process. 804 */ 805 } 806 807 /* 808 * Resume process execution. If this call fails, the process 809 * has probably died. We will find out soon enough. 810 */ 811 (void)ptrace(T_SYSCALL, proc->pid, 0, sig); 812 813 last_pid = proc->pid; 814 } 815 816 return (error) ? EXIT_FAILURE : EXIT_SUCCESS; 817 } 818