xref: /haiku/src/bin/shutdown.cpp (revision fef6144999c2fa611f59ee6ffe6dd7999501385c)
1 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
2 //
3 //  Copyright (c) 2002-2005, Haiku
4 //
5 //  This software is part of the Haiku distribution and is covered
6 //  by the MIT license.
7 //
8 //  File:        shutdown.cpp
9 //  Author:      Francois Revol (mmu_man@users.sf.net)
10 //  Description: shuts down the system, either halting or rebooting.
11 //
12 //  Notes:
13 //  This program behaves identically as the BeOS R5 version, with these
14 //  added arguments:
15 //
16 //  -a asks the user to confirm the shutdown
17 //  -c cancels any running shutdown
18 //
19 //  Some code from Shard's Archiver from BeBits (was BSD/MIT too :).
20 //
21 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
22 
23 #include <syscalls.h>
24 
25 #include <OS.h>
26 #include <Roster.h>
27 #include <RosterPrivate.h>
28 
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <ctype.h>
35 
36 uint32 gTimeToSleep = 0;
37 bool gReboot = false;
38 
39 // we get here when shutdown is cancelled.
40 // then sleep() returns
41 
42 void
43 handle_usr1(int sig)
44 {
45 	while (0);
46 }
47 
48 
49 bool
50 parseTime(char *arg, char *argv, int32 *_i)
51 {
52 	char *unit;
53 
54 	if (isdigit(arg[0])) {
55 		gTimeToSleep = strtoul(arg, &unit, 10);
56 	} else if (argv && isdigit(argv[0])) {
57 		(*_i)++;
58 		gTimeToSleep = strtoul(argv, &unit, 10);
59 	} else
60 		return false;
61 
62 	if (unit[0] == '\0' || !strcmp(unit, "s"))
63 		return true;
64 	if (!strcmp(unit, "m")) {
65 		gTimeToSleep *= 60;
66 		return true;
67 	}
68 
69 	return false;
70 }
71 
72 
73 void
74 usage(const char *arg0)
75 {
76 	const char *program = strrchr(arg0, '/');
77 	if (program == NULL)
78 		program = arg0;
79 	else
80 		program++;
81 
82 	fprintf(stderr, "usage: %s [-rqca] [-d time]\n"
83 		"\t-r reboot,\n"
84 		"\t-q quick shutdown (don't broadcast apps),\n"
85 		"\t-a ask user to confirm the shutdown (ignored when -q is given),\n"
86 		"\t-c cancel a running shutdown,\n"
87 		"\t-d delay shutdown by <time> seconds.\n", program);
88 	exit(1);
89 }
90 
91 
92 int
93 main(int argc, char **argv)
94 {
95 	bool askUser = false;
96 	bool quick = false;
97 
98 	for (int32 i = 1; i < argc; i++) {
99 		char *arg = argv[i];
100 		if (arg[0] == '-') {
101 			if (!isalpha(arg[1]))
102 				usage(argv[0]);
103 
104 			while (arg && isalpha((++arg)[0])) {
105 				switch (arg[0]) {
106 					case 'a':
107 						askUser = true;
108 						break;
109 					case 'q':
110 						quick = true;
111 						break;
112 					case 'r':
113 						gReboot = true;
114 						break;
115 					case 'c':
116 					{
117 						// find all running shutdown command and signal its shutdown thread
118 
119 						thread_info threadInfo;
120 						get_thread_info(find_thread(NULL), &threadInfo);
121 
122 						team_id thisTeam = threadInfo.team;
123 
124 						int32 team_cookie = 0;
125 						team_info teamInfo;
126 						while (get_next_team_info(&team_cookie, &teamInfo) == B_OK) {
127 							if (strstr(teamInfo.args, "shutdown") != NULL && teamInfo.team != thisTeam) {
128 								int32 thread_cookie = 0;
129 								while (get_next_thread_info(teamInfo.team, &thread_cookie, &threadInfo) == B_OK) {
130 									if (!strcmp(threadInfo.name, "shutdown"))
131 										kill(threadInfo.thread, SIGUSR1);
132 								}
133 							}
134 						}
135 						exit(0);
136 						break;
137 					}
138 					case 'd':
139 						if (parseTime(arg + 1, argv[i + 1], &i)) {
140 							arg = NULL;
141 							break;
142 						}
143 						// supposed to fall through
144 
145 					default:
146 						usage(argv[0]);
147 				}
148 			}
149 		} else
150 			usage(argv[0]);
151 	}
152 
153 	if (gTimeToSleep > 0) {
154 		int32 left;
155 
156 		signal(SIGUSR1, handle_usr1);
157 
158 		printf("Delaying %s by %lu seconds...\n", gReboot ? "reboot" : "shutdown", gTimeToSleep);
159 
160 		left = sleep(gTimeToSleep);
161 
162 		if (left > 0) {
163 			fprintf(stderr, "Shutdown cancelled.\n");
164 			exit(0);
165 		}
166 	}
167 
168 	if (quick) {
169 		#ifdef __HAIKU__
170 		_kern_shutdown(gReboot);
171 		#endif // __HAIKU__
172 		fprintf(stderr, "Shutdown failed!\n");
173 		return 2;
174 	} else {
175 		BRoster roster;
176 		BRoster::Private rosterPrivate(roster);
177 		status_t error = rosterPrivate.ShutDown(gReboot, askUser, true);
178 		fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
179 		return 2;
180 	}
181 
182 	return 0;
183 }
184 
185