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