/* detach - detach the current process group from its controlling tty * * According to POSIX 3.2.2.2, orphaned process groups (becoming orphaned due to * the exit of its process group leader) that do have a controlling tty receive * a SIGHUP (or SIGCONT respectively). 'detach' can be used to circumvent the * signal sending. * * * Copyright (C) 2016 AVM Audiovisuelles Marketing und Computersysteme GmbH, nsc * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include static void die(const char *format, ...) __attribute__((noreturn,format(printf,1,2))); static void die(const char *format, ...) { va_list ap; char *fmt; va_start(ap, format); asprintf(&fmt, "%s: %s%s\n", program_invocation_short_name, format, errno ? ": %m" : ""); vfprintf(stderr, fmt, ap); free(fmt); va_end(ap); exit(EXIT_FAILURE); } static int detach_controlling_tty(void) { int fd; fd = open("/dev/tty", O_RDWR); if (fd < 0) return 0; if (ioctl(fd, TIOCNOTTY, 0)) return -1; close(fd); return 0; } static int steal_controlling_tty(void) { return ioctl(STDIN_FILENO, TIOCSCTTY, 1); } static int do_fork(int wait_for_child_exit) { siginfo_t info; pid_t pid = fork(); int ret; if (!pid) /* child */ return 0; if (pid < 0) /* error, not forked */ return errno; /* parent */ ret = wait_for_child_exit ? waitid(P_PID, pid, &info, WEXITED), info.si_status : 0; _exit(ret); } int main(int argc, char **argv) { if (sigignore(SIGTTOU)) die("sigignore(SIGTTOU)"); if (detach_controlling_tty()) die("Unable to detach controlling tty"); if (do_fork(1)) die("fork"); if (setsid() < 0) die("setsid"); if (steal_controlling_tty()) die("Unable to steal controlling tty"); if (argc < 2) exit(0); if (do_fork(0)) die("fork"); execvp(argv[1], argv+1); die("Unable to exec %s", argv[1]); }