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