diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/nohup | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/nohup')
| -rw-r--r-- | usr/src/cmd/nohup/Makefile | 60 | ||||
| -rw-r--r-- | usr/src/cmd/nohup/Makefile.com | 80 | ||||
| -rw-r--r-- | usr/src/cmd/nohup/amd64/Makefile | 32 | ||||
| -rw-r--r-- | usr/src/cmd/nohup/i386/Makefile | 33 | ||||
| -rw-r--r-- | usr/src/cmd/nohup/nohup.c | 831 | ||||
| -rw-r--r-- | usr/src/cmd/nohup/sparc/Makefile | 33 | ||||
| -rw-r--r-- | usr/src/cmd/nohup/sparcv9/Makefile | 36 |
7 files changed, 1105 insertions, 0 deletions
diff --git a/usr/src/cmd/nohup/Makefile b/usr/src/cmd/nohup/Makefile new file mode 100644 index 0000000000..ea0801b26c --- /dev/null +++ b/usr/src/cmd/nohup/Makefile @@ -0,0 +1,60 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 1989, 2001 by Sun Microsystems, Inc. +# All rights reserved. +# +# ident "%Z%%M% %I% %E% SMI" +# +# cmd/nohup/Makefile +# + +XPG4PROG = nohup +PROG = nohup + +include ../Makefile.cmd + +.KEEP_STATE: + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint + +all: $(SUBDIRS) + +clean clobber lint: $(SUBDIRS) + +install: $(SUBDIRS) + -$(RM) $(ROOTPROG) + -$(LN) $(ISAEXEC) $(ROOTPROG) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/cmd/nohup/Makefile.com b/usr/src/cmd/nohup/Makefile.com new file mode 100644 index 0000000000..eac8162ab3 --- /dev/null +++ b/usr/src/cmd/nohup/Makefile.com @@ -0,0 +1,80 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# cmd/nohup/Makefile.com +# + +XPG4PROG = nohup +PROG = nohup + +OBJS = nohup.o +XPG4OBJS = $(OBJS:%.o=xpg4_%.o) +SRCS = $(OBJS:%.o=../%.c) +LNTS = $(OBJS:%.o=%.ln) +CLEANFILES = $(OBJS) $(XPG4OBJS) $(LNTS) + +include ../../Makefile.cmd + +CFLAGS += $(CCVERBOSE) +CFLAGS64 += $(CCVERBOSE) + +$(XPG4) := CPPFLAGS += -DXPG4 + +# not needed for xpg4/nohup +EXTRALIBS = -lproc + +TARGETS = $(PROG) $(XPG4) + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(XPG4OBJS) $(LNTS) + +all: $(PROG) $(XPG4) + +lint: + $(LINT.c) $(SRCS) $(LDLIBS) $(EXTRALIBS) + +clean: + $(RM) $(CLEANFILES) + +include ../../Makefile.targ + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(EXTRALIBS) + $(POST_PROCESS) + +$(XPG4): $(XPG4OBJS) + $(LINK.c) -o $@ $(XPG4OBJS) $(LDLIBS) + $(POST_PROCESS) + +%.o: ../%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +xpg4_%.o: ../%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) diff --git a/usr/src/cmd/nohup/amd64/Makefile b/usr/src/cmd/nohup/amd64/Makefile new file mode 100644 index 0000000000..707654ac57 --- /dev/null +++ b/usr/src/cmd/nohup/amd64/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../Makefile.cmd.64 + +install: all $(ROOTPROG64) diff --git a/usr/src/cmd/nohup/i386/Makefile b/usr/src/cmd/nohup/i386/Makefile new file mode 100644 index 0000000000..9da01cd3ad --- /dev/null +++ b/usr/src/cmd/nohup/i386/Makefile @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 2001 by Sun Microsystems, Inc. +# All rights reserved. +# +# cmd/nohup/i386/Makefile +# + +include ../Makefile.com + +install: all $(ROOTPROG32) $(ROOTXPG4PROG) diff --git a/usr/src/cmd/nohup/nohup.c b/usr/src/cmd/nohup/nohup.c new file mode 100644 index 0000000000..4ccc898617 --- /dev/null +++ b/usr/src/cmd/nohup/nohup.c @@ -0,0 +1,831 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <nl_types.h> +#include <locale.h> +#include <signal.h> +#include <string.h> +#include <limits.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <libproc.h> +#include <dirent.h> +#include <ctype.h> +#include <sys/time.h> + +#define NOHUP_PERM (S_IRUSR | S_IWUSR) + +#define NOHUP_NOEXEC 126 +#define NOHUP_ERROR 127 + +#ifdef XPG4 +#define OPTSTR "" +#else +#define OPTSTR "pFag" + +static int pnohup(int, char **); + +static struct ps_prochandle *g_proc; +static int g_wrfd; +static int g_rdfd; + +static int g_dirty; +static volatile int g_interrupt = 0; +#endif + +static int opt_p = 0; +static int opt_g = 0; +static int opt_a = 0; +static int opt_F = 0; + +static char *pname; + +static char nout[PATH_MAX] = "nohup.out"; + +static int +open_file(void) +{ + char *home; + int fd; + int flags = O_CREAT | O_WRONLY | O_APPEND; + + if ((fd = open(nout, flags, NOHUP_PERM)) < 0) { + if ((home = getenv("HOME")) == NULL) + return (-1); + + if ((snprintf(nout, sizeof (nout), + "%s/nohup.out", home) >= sizeof (nout)) || + (fd = open(nout, flags, NOHUP_PERM)) < 0) { + return (-1); + } + + } + + (void) fprintf(stderr, gettext("Sending output to %s\n"), nout); + + return (fd); +} + +int +main(int argc, char **argv) +{ + int fd = -1; + int opt; + int err; + + if ((pname = strrchr(argv[0], '/')) == NULL) + pname = argv[0]; + else + argv[0] = ++pname; /* for getopt */ + + (void) setlocale(LC_ALL, ""); + +#ifndef TEXT_DOMAIN +#define TEXT_DOMAIN "SYS_TEST" +#endif + + (void) textdomain(TEXT_DOMAIN); + + while ((opt = getopt(argc, argv, OPTSTR)) != EOF) { + switch (opt) { + case 'p': + opt_p = 1; + break; + case 'F': + opt_F = 1; + break; + case 'a': + opt_a = 1; + break; + case 'g': + opt_g = 1; + break; + default: + goto usage; + } + } + + argc -= optind; + argv += optind; + + if (argc == 0) + goto usage; /* need at least one argument */ + +#ifndef XPG4 + if (opt_p && opt_g) + goto usage; + + if (opt_p || opt_g) + return (pnohup(argc, argv)); + + if (opt_a || opt_F) + goto usage; /* only valid with -p or -g */ +#endif + + argv[argc] = NULL; + + (void) signal(SIGHUP, SIG_IGN); /* POSIX.2 only SIGHUP */ +#ifndef XPG4 + (void) signal(SIGQUIT, SIG_IGN); /* Solaris compatibility */ +#endif + + if (isatty(STDOUT_FILENO)) { + if ((fd = open_file()) < 0) + goto err; + + (void) dup2(fd, STDOUT_FILENO); + } + + if (isatty(STDERR_FILENO)) { + if (fd < 0 && (fd = open_file()) < 0) + goto err; + + (void) dup2(fd, STDERR_FILENO); + } + + if (fd >= 0) + (void) close(fd); + + (void) execvp(argv[0], argv); + err = errno; + + (void) freopen("/dev/tty", "w", stderr); + (void) fprintf(stderr, gettext("nohup: %s: %s\n"), argv[0], + strerror(err)); + + return (err == ENOENT ? NOHUP_ERROR : NOHUP_NOEXEC); + +err: + (void) fprintf(stderr, gettext("nohup: cannot open/create " + "nohup.out: %s\n"), strerror(errno)); + return (NOHUP_ERROR); + +usage: +#ifdef XPG4 + (void) fprintf(stderr, + gettext("usage: nohup command [argument ...]\n")); +#else + (void) fprintf(stderr, gettext("usage:\n" + "\tnohup command [argument ...]\n" + "\tnohup -p [-Fa] pid [pid ...]\n" + "\tnohup -g [-Fa] pgid [pgid ...]\n")); +#endif + return (NOHUP_ERROR); +} + +#ifndef XPG4 + +/* + * File descriptor iteration interface. + */ +typedef int proc_fd_iter_f(void *, int); + +static int +Pfd_iter(struct ps_prochandle *P, proc_fd_iter_f *cb, void *data) +{ + char file[64]; + dirent_t *dentp; + DIR *dirp; + int ret = 0; + + if (Pstate(P) == PS_DEAD) + return (-1); + + (void) sprintf(file, "/proc/%d/fd", (int)Pstatus(P)->pr_pid); + if ((dirp = opendir(file)) == NULL) + return (-1); + + while ((dentp = readdir(dirp)) != NULL) { + if (dentp->d_name[0] == '.') + continue; + + if ((ret = cb(data, atoi(dentp->d_name))) != 0) + break; + } + + (void) closedir(dirp); + + return (ret); +} + +/*ARGSUSED*/ +static int +fd_cb(void *data, int fd) +{ + struct stat64 sbuf; + int flags; + int *fdp; + int oflags; + char *file; + int tmpfd; + + /* + * See if this fd refers to the controlling tty. + */ + if (pr_fstat64(g_proc, fd, &sbuf) == -1 || + sbuf.st_rdev != Ppsinfo(g_proc)->pr_ttydev) + return (0); + + /* + * tty's opened for input are usually O_RDWR so that the program + * can change terminal settings. We assume that if there's a + * controlling tty in the STDIN_FILENO file descriptor that is + * effectively used only for input. If standard in gets dup'ed to + * other file descriptors, then we're out of luck unless the + * program is nice enough to fcntl it to be O_RDONLY. We close the + * file descriptor before we call open to handle the case that + * there are no available file descriptors left in the victim. If + * our call to pr_open fails, we try to reopen the controlling tty. + */ + flags = pr_fcntl(g_proc, fd, F_GETFL, NULL); + if ((flags & O_ACCMODE) == O_RDONLY || fd == STDIN_FILENO) { + fdp = &g_rdfd; + oflags = O_RDONLY; + file = "/dev/null"; + } else { + fdp = &g_wrfd; + oflags = O_RDWR | O_APPEND; + file = &nout[0]; + } + + if (*fdp < 0) { + (void) pr_close(g_proc, fd); + + tmpfd = pr_open(g_proc, file, oflags, 0); + + if (tmpfd < 0) { + (void) fprintf(stderr, + gettext("nohup: process %d cannot open %s: %s\n"), + Pstatus(g_proc)->pr_pid, file, strerror(errno)); + + goto err; + } + + if (tmpfd != fd) { + (void) pr_fcntl(g_proc, tmpfd, F_DUP2FD, + (void *)(uintptr_t)fd); + (void) pr_close(g_proc, tmpfd); + } + + *fdp = fd; + } else { + (void) pr_fcntl(g_proc, *fdp, F_DUP2FD, (void *)(uintptr_t)fd); + } + + return (0); + +err: + /* + * The victim couldn't open nohup.out so we'll have it try to reopen + * its terminal. If this fails, we are left with little recourse. + */ + tmpfd = pr_open(g_proc, "/dev/tty", O_RDWR, 0); + + if (tmpfd != fd && tmpfd >= 0) { + (void) pr_fcntl(g_proc, tmpfd, F_DUP2FD, (void *)(uintptr_t)fd); + (void) pr_close(g_proc, tmpfd); + } + + return (1); +} + +static int +lwp_restartable(short syscall) +{ + switch (syscall) { + case SYS_read: + case SYS_readv: + case SYS_pread: + case SYS_pread64: + case SYS_write: + case SYS_writev: + case SYS_pwrite: + case SYS_pwrite64: + case SYS_ioctl: + case SYS_fcntl: + case SYS_getmsg: + case SYS_getpmsg: + case SYS_putmsg: + case SYS_putpmsg: + case SYS_recv: + case SYS_recvmsg: + case SYS_recvfrom: + case SYS_send: + case SYS_sendmsg: + case SYS_sendto: + return (1); + } + + return (0); +} + +/*ARGSUSED*/ +static int +lwp_abort(void *data, const lwpstatus_t *lsp) +{ + struct ps_lwphandle *L; + int err; + + /* + * Continue if this lwp isn't asleep in a restartable syscall. + */ + if (!(lsp->pr_flags & PR_ASLEEP) || !lwp_restartable(lsp->pr_syscall)) + return (0); + + L = Lgrab(g_proc, lsp->pr_lwpid, &err); + (void) Lsetrun(L, 0, PRSABORT); + Lfree(L); + + /* + * Indicate that we have aborted a syscall. + */ + g_dirty = 1; + + return (0); +} + +/*ARGSUSED*/ +static int +lwp_restart(void *data, const lwpstatus_t *lsp) +{ + struct ps_lwphandle *L; + int err; + + /* + * If any lwp is still sleeping in a restartable syscall, it means + * the lwp is wedged and we've screwed up. + */ + if (lsp->pr_flags & PR_ASLEEP) { + if (!lwp_restartable(lsp->pr_syscall)) + return (0); + (void) fprintf(stderr, gettext("nohup: LWP %d failed " + "to abort syscall (%d) in process %d\n"), + lsp->pr_lwpid, lsp->pr_syscall, Pstatus(g_proc)->pr_pid); + return (1); + } + + if (lsp->pr_why == PR_SYSEXIT && lsp->pr_errno == EINTR) { + L = Lgrab(g_proc, lsp->pr_lwpid, &err); + (void) Lputareg(L, R_R0, ERESTART); + Lsync(L); + Lfree(L); + } + + return (0); +} + +static int +do_pnohup(struct ps_prochandle *P) +{ + int sig = 0; + struct sigaction sa; + const pstatus_t *psp; + + psp = Pstatus(P); + + /* + * Make sure there's a pending procfs stop directive. + */ + (void) Pdstop(P); + + if (Pcreate_agent(P) != 0) { + (void) fprintf(stderr, gettext("nohup: cannot control " + "process %d\n"), psp->pr_pid); + goto err_no_agent; + } + + /* + * Set the disposition of SIGHUP and SIGQUIT to SIG_IGN. If either + * signal is handled by the victim, only adjust the disposition if + * the -a flag is set. + */ + if (!opt_a && pr_sigaction(P, SIGHUP, NULL, &sa) != 0) { + (void) fprintf(stderr, gettext("nohup: cannot read " + "disposition of SIGHUP for %d\n"), psp->pr_pid); + goto no_sigs; + } + + if (!opt_a && sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN) { + (void) fprintf(stderr, gettext("nohup: SIGHUP already handled " + "by %d; use -a to force process to ignore\n"), psp->pr_pid); + goto no_sigs; + } + + if (!opt_a && pr_sigaction(P, SIGQUIT, NULL, &sa) != 0) { + (void) fprintf(stderr, gettext("nohup: cannot read " + "disposition of SIGQUIT for %d\n"), psp->pr_pid); + goto no_sigs; + } + + if (!opt_a && sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN) { + (void) fprintf(stderr, gettext("nohup: SIGQUIT already handled " + "by %d; use -a to force process to ignore\n"), psp->pr_pid); + goto no_sigs; + } + + sa.sa_handler = SIG_IGN; + + if (pr_sigaction(P, SIGHUP, &sa, NULL) != 0) { + (void) fprintf(stderr, gettext("nohup: cannot set " + "disposition of SIGHUP for %d\n"), psp->pr_pid); + goto no_sigs; + } + + if (pr_sigaction(P, SIGQUIT, &sa, NULL) != 0) { + (void) fprintf(stderr, gettext("nohup: cannot set " + "disposition of SIGQUIT for %d\n"), psp->pr_pid); + goto no_sigs; + } + +no_sigs: + Pdestroy_agent(P); + + /* + * We need to close and reassign some file descriptors, but we + * need to be careful about how we do it. If we send in the agent + * to close some fd and there's an lwp asleep in the kernel due to + * a syscall using that fd, then we have a problem. The normal + * sequence of events is the close syscall wakes up any threads + * that have the fd in question active (see kthread.t_activefd) + * and then waits for those threads to wake up and release the + * file descriptors (they then continue to user-land to return + * EBADF from the syscall). However, recall that if the agent lwp + * is present in a process, no other lwps can run, so if the agent + * lwp itself is making the call to close(2) (or something else + * like dup2 that involves a call to closeandsetf()) then we're in + * pretty bad shape. The solution is to abort and restart any lwp + * asleep in a syscall on the off chance that it may be using one + * of the file descriptors that we want to manipulate. + */ + + /* + * We may need to chase some lwps out of the kernel briefly, so we + * send SIGCONT to the process if it was previously stopped due to + * a job control signal, and save the current signal to repost it + * when we detatch from the victim. A process that is stopped due + * to job control will start running as soon as we send SIGCONT + * since there is no procfs stop command pending; we use Pdstop to + * post a procfs stop request (above). + */ + if ((psp->pr_lwp.pr_flags & PR_STOPPED) && + psp->pr_lwp.pr_why == PR_JOBCONTROL) { + sig = psp->pr_lwp.pr_what; + (void) kill(psp->pr_pid, SIGCONT); + (void) Pwait(P, 0); + } + + (void) Psysexit(P, 0, 1); + + /* + * Abort each syscall; set g_dirty if any lwp was asleep. + */ + g_dirty = 0; + g_proc = P; + (void) Plwp_iter(P, lwp_abort, NULL); + + if (g_dirty) { + /* + * Block until each lwp that was asleep in a syscall has + * wandered back up to user-land. + */ + (void) Pwait(P, 0); + + /* + * Make sure that each lwp has successfully aborted its + * syscall and that the syscall gets restarted when we + * detach later. + */ + if (Plwp_iter(P, lwp_restart, NULL) != 0) + goto err_no_agent; + } + + (void) Psysexit(P, 0, 0); + + if (Pcreate_agent(P) != 0) { + (void) fprintf(stderr, gettext("nohup: cannot control " + "process %d\n"), psp->pr_pid); + goto err_no_agent; + } + + /* + * See if the victim has access to the nohup.out file we created. + * If the user does something that would invalidate the result + * of this call from here until the call to pr_open, the process + * may be left in an inconsistent state -- we assume that the user + * is not intentionally trying to shoot himself in the foot. + */ + if (pr_access(P, nout, R_OK | W_OK) != 0) { + (void) fprintf(stderr, gettext("nohup: process %d can not " + "access %s: %s\n"), psp->pr_pid, nout, strerror(errno)); + goto err_agent; + } + + /* + * Redirect output to the controlling tty to nohup.out and tty + * input to read from /dev/null. + */ + + g_wrfd = -1; + g_rdfd = -1; + + (void) Pfd_iter(P, fd_cb, NULL); + + Pdestroy_agent(P); + if (sig != 0) + (void) kill(psp->pr_pid, sig); + + return (0); + +err_agent: + Pdestroy_agent(P); +err_no_agent: + if (sig != 0) + (void) kill(psp->pr_pid, sig); + return (-1); +} + +/*ARGSUSED*/ +static void +intr(int sig) +{ + g_interrupt = 1; +} + +static int +pnohup(int argc, char **argv) +{ + struct ps_prochandle *P; + int i, j; + int flag = 0; + int gcode; + int nh_fd = -1; + char *fname; + char *home; + int nerrs = 0; + + /* + * Catch signals from the terminal. + */ + if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) + (void) sigset(SIGHUP, intr); + if (sigset(SIGINT, SIG_IGN) == SIG_DFL) + (void) sigset(SIGINT, intr); + if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) + (void) sigset(SIGQUIT, intr); + (void) sigset(SIGPIPE, intr); + (void) sigset(SIGTERM, intr); + + if (opt_F) + flag |= PGRAB_FORCE; + + /* + * Set nout to be the full path name of nohup.out and fname to be + * the simplified path name: + * nout = /cwd/nohup.out fname = nohup.out + * nout = $HOME/nohup.out fname = $HOME/nohup.out + */ + if (getcwd(nout, sizeof (nout) - strlen("/nohup.out") - 1) != NULL) { + fname = &nout[strlen(nout)]; + (void) strcpy(fname, "/nohup.out"); + fname++; + + nh_fd = open(nout, O_WRONLY | O_CREAT, NOHUP_PERM); + } + + if (nh_fd == -1 && (home = getenv("HOME")) != NULL) { + if (snprintf(nout, sizeof (nout), + "%s/nohup.out", home) < sizeof (nout)) { + nh_fd = open(nout, O_WRONLY | O_CREAT, NOHUP_PERM); + fname = &nout[0]; + } + } + + if (nh_fd == -1) { + (void) fprintf(stderr, gettext("nohup: cannot open/create " + "nohup.out: %s\n"), strerror(errno)); + + return (NOHUP_ERROR); + } + + if (opt_g) { + pid_t *pgids; + int npgids; + int success; + + /* + * Make nohup its own process group leader so that we + * don't accidently send SIGSTOP to this process. + */ + (void) setpgid(0, 0); + + /* + * If a list of process group ids is specified, we want to + * first SIGSTOP the whole process group so that we can be + * sure not to miss any processes that belong to the group + * (it's harder to hit a moving target). We then iterate + * over all the processes on the system looking for + * members of the given process group to apply the + * do_pnohup function to. If the process was stopped due + * to our SIGSTOP, we send the process SIGCONT; if the + * process was already stopped, we leave it alone. + */ + pgids = calloc(argc, sizeof (pid_t)); + pgids[0] = getpid(); + npgids = 1; + + for (i = 0; i < argc; i++) { + dirent_t *dent; + DIR *dirp; + psinfo_t psinfo; + const pstatus_t *psp; + pid_t pgid; + char *end; + hrtime_t kill_time, stop_time; + + if (isdigit(*argv[i])) { + pgid = strtol(argv[i], &end, 10); + + /* + * kill(2) with pid = 0 or -1 has a special + * meaning, so don't let pgid be 0 or 1. + */ + if (*end == '\0' && pgid > 1) + goto pgid_ok; + } + + (void) fprintf(stderr, gettext("nohup: " + "bad process group %s\n"), argv[i]); + nerrs++; + continue; + +pgid_ok: + /* + * We don't want to nohup a process group twice. + */ + for (j = 0; j < npgids; j++) { + if (pgids[j] == pgid) + break; + } + + if (j != npgids) + continue; + + pgids[npgids++] = pgid; + + /* + * Have the kernel stop all members of the process + * group; record the time we stopped the process + * group so that we can tell if a member stopped + * because of this call to kill(2) or if it was + * already stopped when we got here. If the user + * job control stops the victim between the call + * to gethrtime(2) and kill(2), we may send + * SIGCONT when we really shouldn't -- we assume + * that the user is not trying to shoot himself in + * the foot. + */ + kill_time = gethrtime(); + if (kill(-pgid, SIGSTOP) == -1) { + (void) fprintf(stderr, gettext("nohup: cannot " + "stop process group %d: %s\n"), pgid, + errno != ESRCH ? strerror(errno) : + gettext("No such process group")); + + nerrs++; + continue; + } + + dirp = opendir("/proc"); + success = 0; + while ((dent = readdir(dirp)) != NULL && !g_interrupt) { + if (dent->d_name[0] == '.') + continue; + + if (proc_arg_psinfo(dent->d_name, + PR_ARG_PIDS, &psinfo, &gcode) == -1) + continue; + + if (psinfo.pr_pgid != pgid) + continue; + + /* + * Ignore zombies. + */ + if (psinfo.pr_nlwp == 0) + continue; + + if ((P = proc_arg_grab(dent->d_name, + PR_ARG_PIDS, flag, &gcode)) == NULL) { + (void) fprintf(stderr, gettext("nohup: " + "cannot examine %s: %s\n"), + dent->d_name, Pgrab_error(gcode)); + + (void) kill(psinfo.pr_pid, SIGCONT); + continue; + } + + /* + * This implicitly restarts any process that + * was stopped via job control any time after + * the call to kill(2). This is the desired + * behavior since nohup is busy trying to + * disassociate a process from its controlling + * terminal. + */ + psp = Pstatus(P); + if (psp->pr_lwp.pr_why == PR_JOBCONTROL) { + stop_time = + psp->pr_lwp.pr_tstamp.tv_sec; + stop_time *= (hrtime_t)NANOSEC; + stop_time += + psp->pr_lwp.pr_tstamp.tv_nsec; + } else { + stop_time = 0; + } + + if (do_pnohup(P) == 0) + success = 1; + + /* + * If the process was stopped because of + * our call to kill(2) (i.e. if it stopped + * some time after kill_time) then restart + * the process. + */ + if (kill_time <= stop_time) + (void) kill(psinfo.pr_pid, SIGCONT); + + Prelease(P, 0); + } + + /* + * If we didn't successfully nohup any member of the + * process group. + */ + if (!success) + nerrs++; + + (void) closedir(dirp); + } + } else { + for (i = 0; i < argc && !g_interrupt; i++) { + if ((P = proc_arg_grab(argv[i], PR_ARG_PIDS, flag, + &gcode)) == NULL) { + (void) fprintf(stderr, + gettext("nohup: cannot examine %s: %s\n"), + argv[i], Pgrab_error(gcode)); + + nerrs++; + continue; + } + + if (do_pnohup(P) != 0) + nerrs++; + + Prelease(P, 0); + } + } + + (void) close(nh_fd); + + if (argc == nerrs) + return (NOHUP_ERROR); + + (void) fprintf(stderr, gettext("Sending output to %s\n"), fname); + + return (0); +} + +#endif /* !XPG4 */ diff --git a/usr/src/cmd/nohup/sparc/Makefile b/usr/src/cmd/nohup/sparc/Makefile new file mode 100644 index 0000000000..4f02dbd307 --- /dev/null +++ b/usr/src/cmd/nohup/sparc/Makefile @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2003 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# cmd/nohup/sparc/Makefile +# + +include ../Makefile.com + +install: all $(ROOTXPG4PROG) diff --git a/usr/src/cmd/nohup/sparcv9/Makefile b/usr/src/cmd/nohup/sparcv9/Makefile new file mode 100644 index 0000000000..ec26a54026 --- /dev/null +++ b/usr/src/cmd/nohup/sparcv9/Makefile @@ -0,0 +1,36 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 2001 by Sun Microsystems, Inc. +# All rights reserved. +# +# cmd/nohup/sparcv9/Makefile +# + +include ../Makefile.com +include ../../Makefile.cmd.64 + +lint := LINTFLAGS64 = $(LINTFLAGS) -Xarch=v9 + +install: all $(ROOTPROG64) |
