xref: /haiku/src/bin/shutdown.cpp (revision e18440dc8359d3bbd771df435b393901807a61fd)
1 /*
2  * Copyright 2002-2010, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Francois Revol (mmu_man@users.sf.net)
7  */
8 
9 
10 /*!	Shuts down the system, either halting or rebooting. */
11 
12 
13 #include <syscalls.h>
14 
15 #include <OS.h>
16 #include <Roster.h>
17 #include <RosterPrivate.h>
18 
19 #include <signal.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <ctype.h>
25 
26 
27 uint32 gTimeToSleep = 0;
28 bool gReboot = false;
29 
30 
31 /*!	We get here when shutdown is cancelled.
32 	Then sleep() returns.
33 */
34 void
handle_usr1(int sig)35 handle_usr1(int sig)
36 {
37 	while (0);
38 }
39 
40 
41 bool
parseTime(char * arg,char * argv,int32 * _i)42 parseTime(char *arg, char *argv, int32 *_i)
43 {
44 	char *unit;
45 
46 	if (isdigit(arg[0])) {
47 		gTimeToSleep = strtoul(arg, &unit, 10);
48 	} else if (argv && isdigit(argv[0])) {
49 		(*_i)++;
50 		gTimeToSleep = strtoul(argv, &unit, 10);
51 	} else
52 		return false;
53 
54 	if (unit[0] == '\0' || strcmp(unit, "s") == 0)
55 		return true;
56 	if (strcmp(unit, "m") == 0) {
57 		gTimeToSleep *= 60;
58 		return true;
59 	}
60 
61 	return false;
62 }
63 
64 
65 void
usage(const char * program)66 usage(const char *program)
67 {
68 	fprintf(stderr, "usage: %s [-rqca] [-d time]\n"
69 		"\t-r reboot,\n"
70 		"\t-q quick shutdown (don't broadcast apps),\n"
71 		"\t-a ask user to confirm the shutdown (ignored when -q is given),\n"
72 		"\t-c cancel a running shutdown,\n"
73 		"\t-s run shutdown synchronously (only returns if shutdown is cancelled)\n"
74 		"\t-d delay shutdown by <time> seconds.\n", program);
75 	exit(1);
76 }
77 
78 
79 int
main(int argc,char ** argv)80 main(int argc, char **argv)
81 {
82 	bool askUser = false;
83 	bool quick = false;
84 	bool async = true;
85 
86 	const char *program = strrchr(argv[0], '/');
87 	if (program == NULL)
88 		program = argv[0];
89 	else
90 		program++;
91 
92 	// handle 'halt' and 'reboot' symlinks
93 	if (strcmp(program, "reboot") == 0)
94 		gReboot = true;
95 	if (strcmp(program, "shutdown") != 0)
96 		askUser = true;
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(program);
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 's':
116 						async = false;
117 						break;
118 					case 'c':
119 					{
120 						// find all running shutdown commands and signal their
121 						// shutdown threads
122 
123 						thread_info threadInfo;
124 						get_thread_info(find_thread(NULL), &threadInfo);
125 
126 						team_id thisTeam = threadInfo.team;
127 
128 						int32 team_cookie = 0;
129 						team_info teamInfo;
130 						while (get_next_team_info(&team_cookie, &teamInfo)
131 								== B_OK) {
132 							if (strstr(teamInfo.args, "shutdown") != NULL
133 								&& teamInfo.team != thisTeam) {
134 								int32 thread_cookie = 0;
135 								while (get_next_thread_info(teamInfo.team,
136 										&thread_cookie, &threadInfo) == B_OK) {
137 									if (strcmp(threadInfo.name, "shutdown") == 0)
138 										kill(threadInfo.thread, SIGUSR1);
139 								}
140 							}
141 						}
142 						exit(0);
143 						break;
144 					}
145 					case 'd':
146 						if (parseTime(arg + 1, argv[i + 1], &i)) {
147 							arg = NULL;
148 							break;
149 						}
150 						// supposed to fall through
151 
152 					default:
153 						usage(program);
154 				}
155 			}
156 		} else
157 			usage(program);
158 	}
159 
160 	if (gTimeToSleep > 0) {
161 		int32 left;
162 
163 		signal(SIGUSR1, handle_usr1);
164 
165 		printf("Delaying %s by %" B_PRIu32 " seconds...\n",
166 			gReboot ? "reboot" : "shutdown", gTimeToSleep);
167 
168 		left = sleep(gTimeToSleep);
169 
170 		if (left > 0) {
171 			fprintf(stderr, "Shutdown cancelled.\n");
172 			exit(0);
173 		}
174 	}
175 
176 	if (quick) {
177 		#ifdef __HAIKU__
178 		_kern_shutdown(gReboot);
179 		#endif // __HAIKU__
180 		fprintf(stderr, "Shutdown failed! (Do you have ACPI enabled?)\n");
181 		return 2;
182 	} else {
183 		BRoster roster;
184 		BRoster::Private rosterPrivate(roster);
185 		status_t error = rosterPrivate.ShutDown(gReboot, askUser, !async);
186 		if (error != B_OK) {
187 			fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
188 			return 2;
189 		}
190 	}
191 
192 	return 0;
193 }
194 
195