]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - sys-utils/setsid.c
scriptreplay: cleanup usage()
[thirdparty/util-linux.git] / sys-utils / setsid.c
index 52ad38f3ecb72613e0328d5bd5a3bde56f21e331..5725e80090f9d515c2a70079bfda03de3f5882c9 100644 (file)
@@ -3,12 +3,14 @@
  * Rick Sladkey <jrs@world.std.com>
  * In the public domain.
  *
- * 1999-02-22 Arkadiusz Mikiewicz <misiek@pld.ORG.PL>
+ * 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 <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(FILE * out)
+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(_(" -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);
 
-       fputs(USAGE_HELP, out);
-       fputs(USAGE_VERSION, out);
+       printf(USAGE_HELP_OPTIONS(16));
 
-       fprintf(out, USAGE_MAN_TAIL("setsid(1)"));
-       exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+       printf(USAGE_MAN_TAIL("setsid(1)"));
+       exit(EXIT_SUCCESS);
 }
 
 int main(int argc, char **argv)
 {
-       int ch;
+       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}
@@ -54,27 +66,36 @@ int main(int argc, char **argv)
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       atexit(close_stdout);
+       close_stdout_atexit();
 
-       while ((ch = getopt_long(argc, argv, "+Vhc", longopts, NULL)) != -1)
+       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(stdout);
+                       usage();
+               case 'V':
+                       print_version(EXIT_SUCCESS);
                default:
-                       usage(stderr);
+                       errtryhelp(EXIT_FAILURE);
                }
 
-       if (argc < 2)
-               usage(stderr);
+       if (argc - optind < 1) {
+               warnx(_("no command specified"));
+               errtryhelp(EXIT_FAILURE);
+       }
 
-       if (getpgrp() == getpid()) {
-               switch (fork()) {
+       if (forcefork || getpgrp() == getpid()) {
+               pid = fork();
+               switch (pid) {
                case -1:
                        err(EXIT_FAILURE, _("fork"));
                case 0:
@@ -82,17 +103,21 @@ int main(int argc, char **argv)
                        break;
                default:
                        /* parent */
-                       return 0;
+                       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) {
-               if (ioctl(STDIN_FILENO, TIOCSCTTY, 1))
-                       warn(_("failed to set the controlling terminal"));
-       }
-       execvp(argv[optind], argv + optind + 1);
-       err(EXIT_FAILURE, _("execvp 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]);
 }