xref: /haiku/src/bin/shutdown.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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
35 handle_usr1(int sig)
36 {
37 	while (0);
38 }
39 
40 
41 bool
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"))
55 		return true;
56 	if (!strcmp(unit, "m")) {
57 		gTimeToSleep *= 60;
58 		return true;
59 	}
60 
61 	return false;
62 }
63 
64 
65 void
66 usage(const char *arg0)
67 {
68 	const char *program = strrchr(arg0, '/');
69 	if (program == NULL)
70 		program = arg0;
71 	else
72 		program++;
73 
74 	fprintf(stderr, "usage: %s [-rqca] [-d time]\n"
75 		"\t-r reboot,\n"
76 		"\t-q quick shutdown (don't broadcast apps),\n"
77 		"\t-a ask user to confirm the shutdown (ignored when -q is given),\n"
78 		"\t-c cancel a running shutdown,\n"
79 		"\t-s run shutdown synchronously (only returns if shutdown is cancelled)\n"
80 		"\t-d delay shutdown by <time> seconds.\n", program);
81 	exit(1);
82 }
83 
84 
85 int
86 main(int argc, char **argv)
87 {
88 	bool askUser = false;
89 	bool quick = false;
90 	bool async = true;
91 
92 	for (int32 i = 1; i < argc; i++) {
93 		char *arg = argv[i];
94 		if (arg[0] == '-') {
95 			if (!isalpha(arg[1]))
96 				usage(argv[0]);
97 
98 			while (arg && isalpha((++arg)[0])) {
99 				switch (arg[0]) {
100 					case 'a':
101 						askUser = true;
102 						break;
103 					case 'q':
104 						quick = true;
105 						break;
106 					case 'r':
107 						gReboot = true;
108 						break;
109 					case 's':
110 						async = false;
111 						break;
112 					case 'c':
113 					{
114 						// find all running shutdown commands and signal their
115 						// shutdown threads
116 
117 						thread_info threadInfo;
118 						get_thread_info(find_thread(NULL), &threadInfo);
119 
120 						team_id thisTeam = threadInfo.team;
121 
122 						int32 team_cookie = 0;
123 						team_info teamInfo;
124 						while (get_next_team_info(&team_cookie, &teamInfo)
125 								== B_OK) {
126 							if (strstr(teamInfo.args, "shutdown") != NULL
127 								&& teamInfo.team != thisTeam) {
128 								int32 thread_cookie = 0;
129 								while (get_next_thread_info(teamInfo.team,
130 										&thread_cookie, &threadInfo) == B_OK) {
131 									if (!strcmp(threadInfo.name, "shutdown"))
132 										kill(threadInfo.thread, SIGUSR1);
133 								}
134 							}
135 						}
136 						exit(0);
137 						break;
138 					}
139 					case 'd':
140 						if (parseTime(arg + 1, argv[i + 1], &i)) {
141 							arg = NULL;
142 							break;
143 						}
144 						// supposed to fall through
145 
146 					default:
147 						usage(argv[0]);
148 				}
149 			}
150 		} else
151 			usage(argv[0]);
152 	}
153 
154 	if (gTimeToSleep > 0) {
155 		int32 left;
156 
157 		signal(SIGUSR1, handle_usr1);
158 
159 		printf("Delaying %s by %lu seconds...\n",
160 			gReboot ? "reboot" : "shutdown", gTimeToSleep);
161 
162 		left = sleep(gTimeToSleep);
163 
164 		if (left > 0) {
165 			fprintf(stderr, "Shutdown cancelled.\n");
166 			exit(0);
167 		}
168 	}
169 
170 	if (quick) {
171 		#ifdef __HAIKU__
172 		_kern_shutdown(gReboot);
173 		#endif // __HAIKU__
174 		fprintf(stderr, "Shutdown failed! (Do you have ACPI enabled?)\n");
175 		return 2;
176 	} else {
177 		BRoster roster;
178 		BRoster::Private rosterPrivate(roster);
179 		status_t error = rosterPrivate.ShutDown(gReboot, askUser, !async);
180 		if (error != B_OK)
181 			fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
182 		return 2;
183 	}
184 
185 	return 0;
186 }
187 
188