1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <nl_types.h> 35 #include <locale.h> 36 #include <signal.h> 37 #include <string.h> 38 #include <limits.h> 39 #include <errno.h> 40 #include <unistd.h> 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <libproc.h> 44 #include <dirent.h> 45 #include <ctype.h> 46 #include <sys/time.h> 47 48 #define NOHUP_PERM (S_IRUSR | S_IWUSR) 49 50 #define NOHUP_NOEXEC 126 51 #define NOHUP_ERROR 127 52 53 #ifdef XPG4 54 #define OPTSTR "" 55 #else 56 #define OPTSTR "pFag" 57 58 static int pnohup(int, char **); 59 60 static struct ps_prochandle *g_proc; 61 static int g_wrfd; 62 static int g_rdfd; 63 64 static int g_dirty; 65 static volatile int g_interrupt = 0; 66 #endif 67 68 static int opt_p = 0; 69 static int opt_g = 0; 70 static int opt_a = 0; 71 static int opt_F = 0; 72 73 static char *pname; 74 75 static char nout[PATH_MAX] = "nohup.out"; 76 77 static int 78 open_file(void) 79 { 80 char *home; 81 int fd; 82 int flags = O_CREAT | O_WRONLY | O_APPEND; 83 84 if ((fd = open(nout, flags, NOHUP_PERM)) < 0) { 85 if ((home = getenv("HOME")) == NULL) 86 return (-1); 87 88 if ((snprintf(nout, sizeof (nout), 89 "%s/nohup.out", home) >= sizeof (nout)) || 90 (fd = open(nout, flags, NOHUP_PERM)) < 0) { 91 return (-1); 92 } 93 94 } 95 96 (void) fprintf(stderr, gettext("Sending output to %s\n"), nout); 97 98 return (fd); 99 } 100 101 int 102 main(int argc, char **argv) 103 { 104 int fd = -1; 105 int opt; 106 int err; 107 108 if ((pname = strrchr(argv[0], '/')) == NULL) 109 pname = argv[0]; 110 else 111 argv[0] = ++pname; /* for getopt */ 112 113 (void) setlocale(LC_ALL, ""); 114 115 #ifndef TEXT_DOMAIN 116 #define TEXT_DOMAIN "SYS_TEST" 117 #endif 118 119 (void) textdomain(TEXT_DOMAIN); 120 121 while ((opt = getopt(argc, argv, OPTSTR)) != EOF) { 122 switch (opt) { 123 case 'p': 124 opt_p = 1; 125 break; 126 case 'F': 127 opt_F = 1; 128 break; 129 case 'a': 130 opt_a = 1; 131 break; 132 case 'g': 133 opt_g = 1; 134 break; 135 default: 136 goto usage; 137 } 138 } 139 140 argc -= optind; 141 argv += optind; 142 143 if (argc == 0) 144 goto usage; /* need at least one argument */ 145 146 #ifndef XPG4 147 if (opt_p && opt_g) 148 goto usage; 149 150 if (opt_p || opt_g) 151 return (pnohup(argc, argv)); 152 153 if (opt_a || opt_F) 154 goto usage; /* only valid with -p or -g */ 155 #endif 156 157 argv[argc] = NULL; 158 159 (void) signal(SIGHUP, SIG_IGN); /* POSIX.2 only SIGHUP */ 160 #ifndef XPG4 161 (void) signal(SIGQUIT, SIG_IGN); /* Solaris compatibility */ 162 #endif 163 164 if (isatty(STDOUT_FILENO)) { 165 if ((fd = open_file()) < 0) 166 goto err; 167 168 (void) dup2(fd, STDOUT_FILENO); 169 } 170 171 if (isatty(STDERR_FILENO)) { 172 if (fd < 0 && (fd = open_file()) < 0) 173 goto err; 174 175 (void) dup2(fd, STDERR_FILENO); 176 } 177 178 if (fd >= 0) 179 (void) close(fd); 180 181 (void) execvp(argv[0], argv); 182 err = errno; 183 184 (void) freopen("/dev/tty", "w", stderr); 185 (void) fprintf(stderr, gettext("nohup: %s: %s\n"), argv[0], 186 strerror(err)); 187 188 return (err == ENOENT ? NOHUP_ERROR : NOHUP_NOEXEC); 189 190 err: 191 (void) fprintf(stderr, gettext("nohup: cannot open/create " 192 "nohup.out: %s\n"), strerror(errno)); 193 return (NOHUP_ERROR); 194 195 usage: 196 #ifdef XPG4 197 (void) fprintf(stderr, 198 gettext("usage: nohup command [argument ...]\n")); 199 #else 200 (void) fprintf(stderr, gettext("usage:\n" 201 "\tnohup command [argument ...]\n" 202 "\tnohup -p [-Fa] pid [pid ...]\n" 203 "\tnohup -g [-Fa] pgid [pgid ...]\n")); 204 #endif 205 return (NOHUP_ERROR); 206 } 207 208 #ifndef XPG4 209 210 /* 211 * File descriptor iteration interface. 212 */ 213 typedef int proc_fd_iter_f(void *, int); 214 215 static int 216 Pfd_iter(struct ps_prochandle *P, proc_fd_iter_f *cb, void *data) 217 { 218 char file[64]; 219 dirent_t *dentp; 220 DIR *dirp; 221 int ret = 0; 222 223 if (Pstate(P) == PS_DEAD) 224 return (-1); 225 226 (void) sprintf(file, "/proc/%d/fd", (int)Pstatus(P)->pr_pid); 227 if ((dirp = opendir(file)) == NULL) 228 return (-1); 229 230 while ((dentp = readdir(dirp)) != NULL) { 231 if (dentp->d_name[0] == '.') 232 continue; 233 234 if ((ret = cb(data, atoi(dentp->d_name))) != 0) 235 break; 236 } 237 238 (void) closedir(dirp); 239 240 return (ret); 241 } 242 243 /*ARGSUSED*/ 244 static int 245 fd_cb(void *data, int fd) 246 { 247 struct stat64 sbuf; 248 int flags; 249 int *fdp; 250 int oflags; 251 char *file; 252 int tmpfd; 253 254 /* 255 * See if this fd refers to the controlling tty. 256 */ 257 if (pr_fstat64(g_proc, fd, &sbuf) == -1 || 258 sbuf.st_rdev != Ppsinfo(g_proc)->pr_ttydev) 259 return (0); 260 261 /* 262 * tty's opened for input are usually O_RDWR so that the program 263 * can change terminal settings. We assume that if there's a 264 * controlling tty in the STDIN_FILENO file descriptor that is 265 * effectively used only for input. If standard in gets dup'ed to 266 * other file descriptors, then we're out of luck unless the 267 * program is nice enough to fcntl it to be O_RDONLY. We close the 268 * file descriptor before we call open to handle the case that 269 * there are no available file descriptors left in the victim. If 270 * our call to pr_open fails, we try to reopen the controlling tty. 271 */ 272 flags = pr_fcntl(g_proc, fd, F_GETFL, NULL); 273 if ((flags & O_ACCMODE) == O_RDONLY || fd == STDIN_FILENO) { 274 fdp = &g_rdfd; 275 oflags = O_RDONLY; 276 file = "/dev/null"; 277 } else { 278 fdp = &g_wrfd; 279 oflags = O_RDWR | O_APPEND; 280 file = &nout[0]; 281 } 282 283 if (*fdp < 0) { 284 (void) pr_close(g_proc, fd); 285 286 tmpfd = pr_open(g_proc, file, oflags, 0); 287 288 if (tmpfd < 0) { 289 (void) fprintf(stderr, 290 gettext("nohup: process %d cannot open %s: %s\n"), 291 Pstatus(g_proc)->pr_pid, file, strerror(errno)); 292 293 goto err; 294 } 295 296 if (tmpfd != fd) { 297 (void) pr_fcntl(g_proc, tmpfd, F_DUP2FD, 298 (void *)(uintptr_t)fd); 299 (void) pr_close(g_proc, tmpfd); 300 } 301 302 *fdp = fd; 303 } else { 304 (void) pr_fcntl(g_proc, *fdp, F_DUP2FD, (void *)(uintptr_t)fd); 305 } 306 307 return (0); 308 309 err: 310 /* 311 * The victim couldn't open nohup.out so we'll have it try to reopen 312 * its terminal. If this fails, we are left with little recourse. 313 */ 314 tmpfd = pr_open(g_proc, "/dev/tty", O_RDWR, 0); 315 316 if (tmpfd != fd && tmpfd >= 0) { 317 (void) pr_fcntl(g_proc, tmpfd, F_DUP2FD, (void *)(uintptr_t)fd); 318 (void) pr_close(g_proc, tmpfd); 319 } 320 321 return (1); 322 } 323 324 static int 325 lwp_restartable(short syscall) 326 { 327 switch (syscall) { 328 case SYS_read: 329 case SYS_readv: 330 case SYS_pread: 331 case SYS_pread64: 332 case SYS_write: 333 case SYS_writev: 334 case SYS_pwrite: 335 case SYS_pwrite64: 336 case SYS_ioctl: 337 case SYS_fcntl: 338 case SYS_getmsg: 339 case SYS_getpmsg: 340 case SYS_putmsg: 341 case SYS_putpmsg: 342 case SYS_recv: 343 case SYS_recvmsg: 344 case SYS_recvfrom: 345 case SYS_send: 346 case SYS_sendmsg: 347 case SYS_sendto: 348 return (1); 349 } 350 351 return (0); 352 } 353 354 /*ARGSUSED*/ 355 static int 356 lwp_abort(void *data, const lwpstatus_t *lsp) 357 { 358 struct ps_lwphandle *L; 359 int err; 360 361 /* 362 * Continue if this lwp isn't asleep in a restartable syscall. 363 */ 364 if (!(lsp->pr_flags & PR_ASLEEP) || !lwp_restartable(lsp->pr_syscall)) 365 return (0); 366 367 L = Lgrab(g_proc, lsp->pr_lwpid, &err); 368 (void) Lsetrun(L, 0, PRSABORT); 369 Lfree(L); 370 371 /* 372 * Indicate that we have aborted a syscall. 373 */ 374 g_dirty = 1; 375 376 return (0); 377 } 378 379 /*ARGSUSED*/ 380 static int 381 lwp_restart(void *data, const lwpstatus_t *lsp) 382 { 383 struct ps_lwphandle *L; 384 int err; 385 386 /* 387 * If any lwp is still sleeping in a restartable syscall, it means 388 * the lwp is wedged and we've screwed up. 389 */ 390 if (lsp->pr_flags & PR_ASLEEP) { 391 if (!lwp_restartable(lsp->pr_syscall)) 392 return (0); 393 (void) fprintf(stderr, gettext("nohup: LWP %d failed " 394 "to abort syscall (%d) in process %d\n"), 395 lsp->pr_lwpid, lsp->pr_syscall, Pstatus(g_proc)->pr_pid); 396 return (1); 397 } 398 399 if (lsp->pr_why == PR_SYSEXIT && lsp->pr_errno == EINTR) { 400 L = Lgrab(g_proc, lsp->pr_lwpid, &err); 401 (void) Lputareg(L, R_R0, ERESTART); 402 Lsync(L); 403 Lfree(L); 404 } 405 406 return (0); 407 } 408 409 static int 410 do_pnohup(struct ps_prochandle *P) 411 { 412 int sig = 0; 413 struct sigaction sa; 414 const pstatus_t *psp; 415 416 psp = Pstatus(P); 417 418 /* 419 * Make sure there's a pending procfs stop directive. 420 */ 421 (void) Pdstop(P); 422 423 if (Pcreate_agent(P) != 0) { 424 (void) fprintf(stderr, gettext("nohup: cannot control " 425 "process %d\n"), psp->pr_pid); 426 goto err_no_agent; 427 } 428 429 /* 430 * Set the disposition of SIGHUP and SIGQUIT to SIG_IGN. If either 431 * signal is handled by the victim, only adjust the disposition if 432 * the -a flag is set. 433 */ 434 if (!opt_a && pr_sigaction(P, SIGHUP, NULL, &sa) != 0) { 435 (void) fprintf(stderr, gettext("nohup: cannot read " 436 "disposition of SIGHUP for %d\n"), psp->pr_pid); 437 goto no_sigs; 438 } 439 440 if (!opt_a && sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN) { 441 (void) fprintf(stderr, gettext("nohup: SIGHUP already handled " 442 "by %d; use -a to force process to ignore\n"), psp->pr_pid); 443 goto no_sigs; 444 } 445 446 if (!opt_a && pr_sigaction(P, SIGQUIT, NULL, &sa) != 0) { 447 (void) fprintf(stderr, gettext("nohup: cannot read " 448 "disposition of SIGQUIT for %d\n"), psp->pr_pid); 449 goto no_sigs; 450 } 451 452 if (!opt_a && sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN) { 453 (void) fprintf(stderr, gettext("nohup: SIGQUIT already handled " 454 "by %d; use -a to force process to ignore\n"), psp->pr_pid); 455 goto no_sigs; 456 } 457 458 sa.sa_handler = SIG_IGN; 459 460 if (pr_sigaction(P, SIGHUP, &sa, NULL) != 0) { 461 (void) fprintf(stderr, gettext("nohup: cannot set " 462 "disposition of SIGHUP for %d\n"), psp->pr_pid); 463 goto no_sigs; 464 } 465 466 if (pr_sigaction(P, SIGQUIT, &sa, NULL) != 0) { 467 (void) fprintf(stderr, gettext("nohup: cannot set " 468 "disposition of SIGQUIT for %d\n"), psp->pr_pid); 469 goto no_sigs; 470 } 471 472 no_sigs: 473 Pdestroy_agent(P); 474 475 /* 476 * We need to close and reassign some file descriptors, but we 477 * need to be careful about how we do it. If we send in the agent 478 * to close some fd and there's an lwp asleep in the kernel due to 479 * a syscall using that fd, then we have a problem. The normal 480 * sequence of events is the close syscall wakes up any threads 481 * that have the fd in question active (see kthread.t_activefd) 482 * and then waits for those threads to wake up and release the 483 * file descriptors (they then continue to user-land to return 484 * EBADF from the syscall). However, recall that if the agent lwp 485 * is present in a process, no other lwps can run, so if the agent 486 * lwp itself is making the call to close(2) (or something else 487 * like dup2 that involves a call to closeandsetf()) then we're in 488 * pretty bad shape. The solution is to abort and restart any lwp 489 * asleep in a syscall on the off chance that it may be using one 490 * of the file descriptors that we want to manipulate. 491 */ 492 493 /* 494 * We may need to chase some lwps out of the kernel briefly, so we 495 * send SIGCONT to the process if it was previously stopped due to 496 * a job control signal, and save the current signal to repost it 497 * when we detatch from the victim. A process that is stopped due 498 * to job control will start running as soon as we send SIGCONT 499 * since there is no procfs stop command pending; we use Pdstop to 500 * post a procfs stop request (above). 501 */ 502 if ((psp->pr_lwp.pr_flags & PR_STOPPED) && 503 psp->pr_lwp.pr_why == PR_JOBCONTROL) { 504 sig = psp->pr_lwp.pr_what; 505 (void) kill(psp->pr_pid, SIGCONT); 506 (void) Pwait(P, 0); 507 } 508 509 (void) Psysexit(P, 0, 1); 510 511 /* 512 * Abort each syscall; set g_dirty if any lwp was asleep. 513 */ 514 g_dirty = 0; 515 g_proc = P; 516 (void) Plwp_iter(P, lwp_abort, NULL); 517 518 if (g_dirty) { 519 /* 520 * Block until each lwp that was asleep in a syscall has 521 * wandered back up to user-land. 522 */ 523 (void) Pwait(P, 0); 524 525 /* 526 * Make sure that each lwp has successfully aborted its 527 * syscall and that the syscall gets restarted when we 528 * detach later. 529 */ 530 if (Plwp_iter(P, lwp_restart, NULL) != 0) 531 goto err_no_agent; 532 } 533 534 (void) Psysexit(P, 0, 0); 535 536 if (Pcreate_agent(P) != 0) { 537 (void) fprintf(stderr, gettext("nohup: cannot control " 538 "process %d\n"), psp->pr_pid); 539 goto err_no_agent; 540 } 541 542 /* 543 * See if the victim has access to the nohup.out file we created. 544 * If the user does something that would invalidate the result 545 * of this call from here until the call to pr_open, the process 546 * may be left in an inconsistent state -- we assume that the user 547 * is not intentionally trying to shoot himself in the foot. 548 */ 549 if (pr_access(P, nout, R_OK | W_OK) != 0) { 550 (void) fprintf(stderr, gettext("nohup: process %d can not " 551 "access %s: %s\n"), psp->pr_pid, nout, strerror(errno)); 552 goto err_agent; 553 } 554 555 /* 556 * Redirect output to the controlling tty to nohup.out and tty 557 * input to read from /dev/null. 558 */ 559 560 g_wrfd = -1; 561 g_rdfd = -1; 562 563 (void) Pfd_iter(P, fd_cb, NULL); 564 565 Pdestroy_agent(P); 566 if (sig != 0) 567 (void) kill(psp->pr_pid, sig); 568 569 return (0); 570 571 err_agent: 572 Pdestroy_agent(P); 573 err_no_agent: 574 if (sig != 0) 575 (void) kill(psp->pr_pid, sig); 576 return (-1); 577 } 578 579 /*ARGSUSED*/ 580 static void 581 intr(int sig) 582 { 583 g_interrupt = 1; 584 } 585 586 static int 587 pnohup(int argc, char **argv) 588 { 589 struct ps_prochandle *P; 590 int i, j; 591 int flag = 0; 592 int gcode; 593 int nh_fd = -1; 594 char *fname; 595 char *home; 596 int nerrs = 0; 597 598 /* 599 * Catch signals from the terminal. 600 */ 601 if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 602 (void) sigset(SIGHUP, intr); 603 if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 604 (void) sigset(SIGINT, intr); 605 if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 606 (void) sigset(SIGQUIT, intr); 607 (void) sigset(SIGPIPE, intr); 608 (void) sigset(SIGTERM, intr); 609 610 if (opt_F) 611 flag |= PGRAB_FORCE; 612 613 /* 614 * Set nout to be the full path name of nohup.out and fname to be 615 * the simplified path name: 616 * nout = /cwd/nohup.out fname = nohup.out 617 * nout = $HOME/nohup.out fname = $HOME/nohup.out 618 */ 619 if (getcwd(nout, sizeof (nout) - strlen("/nohup.out") - 1) != NULL) { 620 fname = &nout[strlen(nout)]; 621 (void) strcpy(fname, "/nohup.out"); 622 fname++; 623 624 nh_fd = open(nout, O_WRONLY | O_CREAT, NOHUP_PERM); 625 } 626 627 if (nh_fd == -1 && (home = getenv("HOME")) != NULL) { 628 if (snprintf(nout, sizeof (nout), 629 "%s/nohup.out", home) < sizeof (nout)) { 630 nh_fd = open(nout, O_WRONLY | O_CREAT, NOHUP_PERM); 631 fname = &nout[0]; 632 } 633 } 634 635 if (nh_fd == -1) { 636 (void) fprintf(stderr, gettext("nohup: cannot open/create " 637 "nohup.out: %s\n"), strerror(errno)); 638 639 return (NOHUP_ERROR); 640 } 641 642 if (opt_g) { 643 pid_t *pgids; 644 int npgids; 645 int success; 646 647 /* 648 * Make nohup its own process group leader so that we 649 * don't accidently send SIGSTOP to this process. 650 */ 651 (void) setpgid(0, 0); 652 653 /* 654 * If a list of process group ids is specified, we want to 655 * first SIGSTOP the whole process group so that we can be 656 * sure not to miss any processes that belong to the group 657 * (it's harder to hit a moving target). We then iterate 658 * over all the processes on the system looking for 659 * members of the given process group to apply the 660 * do_pnohup function to. If the process was stopped due 661 * to our SIGSTOP, we send the process SIGCONT; if the 662 * process was already stopped, we leave it alone. 663 */ 664 pgids = calloc(argc, sizeof (pid_t)); 665 pgids[0] = getpid(); 666 npgids = 1; 667 668 for (i = 0; i < argc; i++) { 669 dirent_t *dent; 670 DIR *dirp; 671 psinfo_t psinfo; 672 const pstatus_t *psp; 673 pid_t pgid; 674 char *end; 675 hrtime_t kill_time, stop_time; 676 677 if (isdigit(*argv[i])) { 678 pgid = strtol(argv[i], &end, 10); 679 680 /* 681 * kill(2) with pid = 0 or -1 has a special 682 * meaning, so don't let pgid be 0 or 1. 683 */ 684 if (*end == '\0' && pgid > 1) 685 goto pgid_ok; 686 } 687 688 (void) fprintf(stderr, gettext("nohup: " 689 "bad process group %s\n"), argv[i]); 690 nerrs++; 691 continue; 692 693 pgid_ok: 694 /* 695 * We don't want to nohup a process group twice. 696 */ 697 for (j = 0; j < npgids; j++) { 698 if (pgids[j] == pgid) 699 break; 700 } 701 702 if (j != npgids) 703 continue; 704 705 pgids[npgids++] = pgid; 706 707 /* 708 * Have the kernel stop all members of the process 709 * group; record the time we stopped the process 710 * group so that we can tell if a member stopped 711 * because of this call to kill(2) or if it was 712 * already stopped when we got here. If the user 713 * job control stops the victim between the call 714 * to gethrtime(2) and kill(2), we may send 715 * SIGCONT when we really shouldn't -- we assume 716 * that the user is not trying to shoot himself in 717 * the foot. 718 */ 719 kill_time = gethrtime(); 720 if (kill(-pgid, SIGSTOP) == -1) { 721 (void) fprintf(stderr, gettext("nohup: cannot " 722 "stop process group %d: %s\n"), pgid, 723 errno != ESRCH ? strerror(errno) : 724 gettext("No such process group")); 725 726 nerrs++; 727 continue; 728 } 729 730 dirp = opendir("/proc"); 731 success = 0; 732 while ((dent = readdir(dirp)) != NULL && !g_interrupt) { 733 if (dent->d_name[0] == '.') 734 continue; 735 736 if (proc_arg_psinfo(dent->d_name, 737 PR_ARG_PIDS, &psinfo, &gcode) == -1) 738 continue; 739 740 if (psinfo.pr_pgid != pgid) 741 continue; 742 743 /* 744 * Ignore zombies. 745 */ 746 if (psinfo.pr_nlwp == 0) 747 continue; 748 749 if ((P = proc_arg_grab(dent->d_name, 750 PR_ARG_PIDS, flag, &gcode)) == NULL) { 751 (void) fprintf(stderr, gettext("nohup: " 752 "cannot examine %s: %s\n"), 753 dent->d_name, Pgrab_error(gcode)); 754 755 (void) kill(psinfo.pr_pid, SIGCONT); 756 continue; 757 } 758 759 /* 760 * This implicitly restarts any process that 761 * was stopped via job control any time after 762 * the call to kill(2). This is the desired 763 * behavior since nohup is busy trying to 764 * disassociate a process from its controlling 765 * terminal. 766 */ 767 psp = Pstatus(P); 768 if (psp->pr_lwp.pr_why == PR_JOBCONTROL) { 769 stop_time = 770 psp->pr_lwp.pr_tstamp.tv_sec; 771 stop_time *= (hrtime_t)NANOSEC; 772 stop_time += 773 psp->pr_lwp.pr_tstamp.tv_nsec; 774 } else { 775 stop_time = 0; 776 } 777 778 if (do_pnohup(P) == 0) 779 success = 1; 780 781 /* 782 * If the process was stopped because of 783 * our call to kill(2) (i.e. if it stopped 784 * some time after kill_time) then restart 785 * the process. 786 */ 787 if (kill_time <= stop_time) 788 (void) kill(psinfo.pr_pid, SIGCONT); 789 790 Prelease(P, 0); 791 } 792 793 /* 794 * If we didn't successfully nohup any member of the 795 * process group. 796 */ 797 if (!success) 798 nerrs++; 799 800 (void) closedir(dirp); 801 } 802 } else { 803 for (i = 0; i < argc && !g_interrupt; i++) { 804 if ((P = proc_arg_grab(argv[i], PR_ARG_PIDS, flag, 805 &gcode)) == NULL) { 806 (void) fprintf(stderr, 807 gettext("nohup: cannot examine %s: %s\n"), 808 argv[i], Pgrab_error(gcode)); 809 810 nerrs++; 811 continue; 812 } 813 814 if (do_pnohup(P) != 0) 815 nerrs++; 816 817 Prelease(P, 0); 818 } 819 } 820 821 (void) close(nh_fd); 822 823 if (argc == nerrs) 824 return (NOHUP_ERROR); 825 826 (void) fprintf(stderr, gettext("Sending output to %s\n"), fname); 827 828 return (0); 829 } 830 831 #endif /* !XPG4 */ 832