1 /*
2 * setsid.c -- execute a command in a new session
3 * Rick Sladkey <jrs@world.std.com>
4 * In the public domain.
5 *
6 * 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL>
7 * - added Native Language Support
8 *
9 * 2001-01-18 John Fremlin <vii@penguinpowered.com>
10 * - fork in case we are process group leader
11 *
12 * 2008-08-20 Daniel Kahn Gillmor <dkg@fifthhorseman.net>
13 * - if forked, wait on child process and emit its return code.
14 */
15
16 #include <getopt.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23
24 #include "c.h"
25 #include "nls.h"
26 #include "closestream.h"
27
usage(FILE * out)28 static void __attribute__ ((__noreturn__)) usage(FILE * out)
29 {
30 fputs(USAGE_HEADER, out);
31 fprintf(out, _(
32 " %s [options] <program> [arguments ...]\n"),
33 program_invocation_short_name);
34
35 fputs(USAGE_OPTIONS, out);
36 fputs(_(" -c, --ctty set the controlling terminal to the current one\n"), out);
37 fputs(_(" -w, --wait wait program to exit, and use the same return\n"), out);
38
39 fputs(USAGE_HELP, out);
40 fputs(USAGE_VERSION, out);
41
42 fprintf(out, USAGE_MAN_TAIL("setsid(1)"));
43 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
44 }
45
main(int argc,char ** argv)46 int main(int argc, char **argv)
47 {
48 int ch;
49 int ctty = 0;
50 pid_t pid;
51 int status = 0;
52
53 static const struct option longopts[] = {
54 {"ctty", no_argument, NULL, 'c'},
55 {"wait", no_argument, NULL, 'w'},
56 {"version", no_argument, NULL, 'V'},
57 {"help", no_argument, NULL, 'h'},
58 {NULL, 0, NULL, 0}
59 };
60
61 setlocale(LC_ALL, "");
62 bindtextdomain(PACKAGE, LOCALEDIR);
63 textdomain(PACKAGE);
64 atexit(close_stdout);
65
66 while ((ch = getopt_long(argc, argv, "+Vhcw", longopts, NULL)) != -1)
67 switch (ch) {
68 case 'V':
69 printf(UTIL_LINUX_VERSION);
70 return EXIT_SUCCESS;
71 case 'c':
72 ctty=1;
73 break;
74 case 'w':
75 status = 1;
76 break;
77 case 'h':
78 usage(stdout);
79 default:
80 usage(stderr);
81 }
82
83 if (argc < 2)
84 usage(stderr);
85
86 if (getpgrp() == getpid()) {
87 pid = fork();
88 switch (pid) {
89 case -1:
90 err(EXIT_FAILURE, _("fork"));
91 case 0:
92 /* child */
93 break;
94 default:
95 /* parent */
96 if (!status)
97 return EXIT_SUCCESS;
98 if (wait(&status) != pid)
99 err(EXIT_FAILURE, "wait");
100 if (WIFEXITED(status))
101 return WEXITSTATUS(status);
102 err(status, _("child %d did not exit normally"), pid);
103 }
104 }
105 if (setsid() < 0)
106 /* cannot happen */
107 err(EXIT_FAILURE, _("setsid failed"));
108
109 if (ctty) {
110 if (ioctl(STDIN_FILENO, TIOCSCTTY, 1))
111 err(EXIT_FAILURE, _("failed to set the controlling terminal"));
112 }
113 execvp(argv[optind], argv + optind);
114 err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
115 }
116