]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/setsid.c
misc: consolidate macro style USAGE_HELP_OPTIONS
[thirdparty/util-linux.git] / sys-utils / setsid.c
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
28 static void __attribute__((__noreturn__)) usage(void)
29 {
30 FILE *out = stdout;
31 fputs(USAGE_HEADER, out);
32 fprintf(out, _(
33 " %s [options] <program> [arguments ...]\n"),
34 program_invocation_short_name);
35
36 fputs(USAGE_SEPARATOR, out);
37 fputs(_("Run a program in a new session.\n"), out);
38
39 fputs(USAGE_OPTIONS, out);
40 fputs(_(" -c, --ctty set the controlling terminal to the current one\n"), out);
41 fputs(_(" -w, --wait wait program to exit, and use the same return\n"), out);
42
43 printf(USAGE_HELP_OPTIONS(16));
44
45 printf(USAGE_MAN_TAIL("setsid(1)"));
46 exit(EXIT_SUCCESS);
47 }
48
49 int main(int argc, char **argv)
50 {
51 int ch;
52 int ctty = 0;
53 pid_t pid;
54 int status = 0;
55
56 static const struct option longopts[] = {
57 {"ctty", no_argument, NULL, 'c'},
58 {"wait", no_argument, NULL, 'w'},
59 {"version", no_argument, NULL, 'V'},
60 {"help", no_argument, NULL, 'h'},
61 {NULL, 0, NULL, 0}
62 };
63
64 setlocale(LC_ALL, "");
65 bindtextdomain(PACKAGE, LOCALEDIR);
66 textdomain(PACKAGE);
67 atexit(close_stdout);
68
69 while ((ch = getopt_long(argc, argv, "+Vhcw", longopts, NULL)) != -1)
70 switch (ch) {
71 case 'V':
72 printf(UTIL_LINUX_VERSION);
73 return EXIT_SUCCESS;
74 case 'c':
75 ctty=1;
76 break;
77 case 'w':
78 status = 1;
79 break;
80 case 'h':
81 usage();
82 default:
83 errtryhelp(EXIT_FAILURE);
84 }
85
86 if (argc - optind < 1) {
87 warnx(_("no command specified"));
88 errtryhelp(EXIT_FAILURE);
89 }
90
91 if (getpgrp() == getpid()) {
92 pid = fork();
93 switch (pid) {
94 case -1:
95 err(EXIT_FAILURE, _("fork"));
96 case 0:
97 /* child */
98 break;
99 default:
100 /* parent */
101 if (!status)
102 return EXIT_SUCCESS;
103 if (wait(&status) != pid)
104 err(EXIT_FAILURE, "wait");
105 if (WIFEXITED(status))
106 return WEXITSTATUS(status);
107 err(status, _("child %d did not exit normally"), pid);
108 }
109 }
110 if (setsid() < 0)
111 /* cannot happen */
112 err(EXIT_FAILURE, _("setsid failed"));
113
114 if (ctty && ioctl(STDIN_FILENO, TIOCSCTTY, 1))
115 err(EXIT_FAILURE, _("failed to set the controlling terminal"));
116 execvp(argv[optind], argv + optind);
117 err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
118 }