busybox/util-linux/setsid.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * setsid.c -- execute a command in a new session
   4 * Rick Sladkey <jrs@world.std.com>
   5 * In the public domain.
   6 *
   7 * 1999-02-22 Arkadiusz Mickiewicz <misiek@pld.ORG.PL>
   8 * - added Native Language Support
   9 *
  10 * 2001-01-18 John Fremlin <vii@penguinpowered.com>
  11 * - fork in case we are process group leader
  12 *
  13 * 2004-11-12 Paul Fox
  14 * - busyboxed
  15 */
  16//config:config SETSID
  17//config:       bool "setsid (3.6 kb)"
  18//config:       default y
  19//config:       help
  20//config:       setsid runs a program in a new session
  21
  22//applet:IF_SETSID(APPLET(setsid, BB_DIR_USR_BIN, BB_SUID_DROP))
  23
  24//kbuild:lib-$(CONFIG_SETSID) += setsid.o
  25
  26//usage:#define setsid_trivial_usage
  27//usage:       "[-c] PROG ARGS"
  28//usage:#define setsid_full_usage "\n\n"
  29//usage:       "Run PROG in a new session. PROG will have no controlling terminal\n"
  30//usage:       "and will not be affected by keyboard signals (^C etc).\n"
  31//usage:     "\n        -c      Set controlling terminal to stdin"
  32
  33#include "libbb.h"
  34
  35int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  36int setsid_main(int argc UNUSED_PARAM, char **argv)
  37{
  38        unsigned opt;
  39
  40        /* +: stop on first non-opt */
  41        opt = getopt32(argv, "^+" "c" "\0" "-1"/* at least one arg */);
  42        argv += optind;
  43
  44        /* setsid() is allowed only when we are not a process group leader.
  45         * Otherwise our PID serves as PGID of some existing process group
  46         * and cannot be used as PGID of a new process group.
  47         *
  48         * Example: setsid() below fails when run alone in interactive shell:
  49         *  $ setsid PROG
  50         * because shell's child (setsid) is put in a new process group.
  51         * But doesn't fail if shell is not interactive
  52         * (and therefore doesn't create process groups for pipes),
  53         * or if setsid is not the first process in the process group:
  54         *  $ true | setsid PROG
  55         * or if setsid is executed in backquotes (`setsid PROG`)...
  56         */
  57        if (setsid() < 0) {
  58                pid_t pid = fork_or_rexec(argv);
  59                if (pid != 0) {
  60                        /* parent */
  61                        /* TODO:
  62                         * we can waitpid(pid, &status, 0) and then even
  63                         * emulate exitcode, making the behavior consistent
  64                         * in both forked and non forked cases.
  65                         * However, the code is larger and upstream
  66                         * does not do such trick.
  67                         */
  68                        return EXIT_SUCCESS;
  69                }
  70
  71                /* child */
  72                /* now there should be no error: */
  73                setsid();
  74        }
  75
  76        if (opt) {
  77                /* -c: set (with stealing) controlling tty */
  78                ioctl(0, TIOCSCTTY, 1);
  79        }
  80
  81        BB_EXECVP_or_die(argv);
  82}
  83