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