Bump to version 1.22.1
[platform/upstream/busybox.git] / miscutils / setsid.c
index a976fe9..637081b 100644 (file)
@@ -4,7 +4,7 @@
  * Rick Sladkey <jrs@world.std.com>
  * In the public domain.
  *
- * 1999-02-22 Arkadiusz MiΒΆkiewicz <misiek@pld.ORG.PL>
+ * 1999-02-22 Arkadiusz Mickiewicz <misiek@pld.ORG.PL>
  * - added Native Language Support
  *
  * 2001-01-18 John Fremlin <vii@penguinpowered.com>
  * - busyboxed
  */
 
+//usage:#define setsid_trivial_usage
+//usage:       "PROG ARGS"
+//usage:#define setsid_full_usage "\n\n"
+//usage:       "Run PROG in a new session. PROG will have no controlling terminal\n"
+//usage:       "and will not be affected by keyboard signals (Ctrl-C etc).\n"
+//usage:       "See setsid(2) for details."
+
 #include "libbb.h"
 
-int setsid_main(int argc, char **argv);
-int setsid_main(int argc, char **argv)
+int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int setsid_main(int argc UNUSED_PARAM, char **argv)
 {
-       if (argc < 2)
+       if (!argv[1])
                bb_show_usage();
 
-       /* Comment why is this necessary? */
-       if (getpgrp() == getpid())
-               forkexit_or_rexec(argv);
+       /* setsid() is allowed only when we are not a process group leader.
+        * Otherwise our PID serves as PGID of some existing process group
+        * and cannot be used as PGID of a new process group.
+        *
+        * Example: setsid() below fails when run alone in interactive shell:
+        *  $ setsid PROG
+        * because shell's child (setsid) is put in a new process group.
+        * But doesn't fail if shell is not interactive
+        * (and therefore doesn't create process groups for pipes),
+        * or if setsid is not the first process in the process group:
+        *  $ true | setsid PROG
+        * or if setsid is executed in backquotes (`setsid PROG`)...
+        */
+       if (setsid() < 0) {
+               pid_t pid = fork_or_rexec(argv);
+               if (pid != 0) {
+                       /* parent */
+                       /* TODO:
+                        * we can waitpid(pid, &status, 0) and then even
+                        * emulate exitcode, making the behavior consistent
+                        * in both forked and non forked cases.
+                        * However, the code is larger and upstream
+                        * does not do such trick.
+                        */
+                       return EXIT_SUCCESS;
+               }
 
-       setsid();  /* no error possible */
+               /* child */
+               /* now there should be no error: */
+               setsid();
+       }
 
-       BB_EXECVP(argv[1], argv + 1);
-       bb_perror_msg_and_die("%s", argv[1]);
+       argv++;
+       BB_EXECVP_or_die(argv);
 }