summaryrefslogtreecommitdiff
path: root/usr/src/cmd/nohup
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/nohup
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/nohup')
-rw-r--r--usr/src/cmd/nohup/Makefile60
-rw-r--r--usr/src/cmd/nohup/Makefile.com80
-rw-r--r--usr/src/cmd/nohup/amd64/Makefile32
-rw-r--r--usr/src/cmd/nohup/i386/Makefile33
-rw-r--r--usr/src/cmd/nohup/nohup.c831
-rw-r--r--usr/src/cmd/nohup/sparc/Makefile33
-rw-r--r--usr/src/cmd/nohup/sparcv9/Makefile36
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)