diff options
Diffstat (limited to 'sys-utils/setsid.c')
-rw-r--r-- | sys-utils/setsid.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/sys-utils/setsid.c b/sys-utils/setsid.c new file mode 100644 index 0000000..8b4f83d --- /dev/null +++ b/sys-utils/setsid.c @@ -0,0 +1,123 @@ +/* + * setsid.c -- execute a command in a new session + * Rick Sladkey <jrs@world.std.com> + * In the public domain. + * + * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + * + * 2001-01-18 John Fremlin <vii@penguinpowered.com> + * - fork in case we are process group leader + * + * 2008-08-20 Daniel Kahn Gillmor <dkg@fifthhorseman.net> + * - if forked, wait on child process and emit its return code. + */ + +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "c.h" +#include "nls.h" +#include "closestream.h" + +static void __attribute__((__noreturn__)) usage(void) +{ + FILE *out = stdout; + fputs(USAGE_HEADER, out); + fprintf(out, _( + " %s [options] <program> [arguments ...]\n"), + program_invocation_short_name); + + fputs(USAGE_SEPARATOR, out); + fputs(_("Run a program in a new session.\n"), out); + + fputs(USAGE_OPTIONS, out); + fputs(_(" -c, --ctty set the controlling terminal to the current one\n"), out); + fputs(_(" -f, --fork always fork\n"), out); + fputs(_(" -w, --wait wait program to exit, and use the same return\n"), out); + + printf(USAGE_HELP_OPTIONS(16)); + + printf(USAGE_MAN_TAIL("setsid(1)")); + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) +{ + int ch, forcefork = 0; + int ctty = 0; + pid_t pid; + int status = 0; + + static const struct option longopts[] = { + {"ctty", no_argument, NULL, 'c'}, + {"fork", no_argument, NULL, 'f'}, + {"wait", no_argument, NULL, 'w'}, + {"version", no_argument, NULL, 'V'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + atexit(close_stdout); + + while ((ch = getopt_long(argc, argv, "+Vhcfw", longopts, NULL)) != -1) + switch (ch) { + case 'V': + printf(UTIL_LINUX_VERSION); + return EXIT_SUCCESS; + case 'c': + ctty=1; + break; + case 'f': + forcefork = 1; + break; + case 'w': + status = 1; + break; + case 'h': + usage(); + default: + errtryhelp(EXIT_FAILURE); + } + + if (argc - optind < 1) { + warnx(_("no command specified")); + errtryhelp(EXIT_FAILURE); + } + + if (forcefork || getpgrp() == getpid()) { + pid = fork(); + switch (pid) { + case -1: + err(EXIT_FAILURE, _("fork")); + case 0: + /* child */ + break; + default: + /* parent */ + if (!status) + return EXIT_SUCCESS; + if (wait(&status) != pid) + err(EXIT_FAILURE, "wait"); + if (WIFEXITED(status)) + return WEXITSTATUS(status); + err(status, _("child %d did not exit normally"), pid); + } + } + if (setsid() < 0) + /* cannot happen */ + err(EXIT_FAILURE, _("setsid failed")); + + if (ctty && ioctl(STDIN_FILENO, TIOCSCTTY, 1)) + err(EXIT_FAILURE, _("failed to set the controlling terminal")); + execvp(argv[optind], argv + optind); + errexec(argv[optind]); +} |