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