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
open_file(void)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
main(int argc,char ** argv)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
Pfd_iter(struct ps_prochandle * P,proc_fd_iter_f * cb,void * data)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
fd_cb(void * data,int fd)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
lwp_restartable(short syscall)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
lwp_abort(void * data,const lwpstatus_t * lsp)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
lwp_restart(void * data,const lwpstatus_t * lsp)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
do_pnohup(struct ps_prochandle * P)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
intr(int sig)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
pnohup(int argc,char ** argv)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