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
27uint32 gTimeToSleep = 0;
28bool gReboot = false;
29
30
31/*!	We get here when shutdown is cancelled.
32	Then sleep() returns.
33*/
34void
35handle_usr1(int sig)
36{
37	while (0);
38}
39
40
41bool
42parseTime(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
65void
66usage(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
79int
80main(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