xref: /haiku/src/bin/shutdown.cpp (revision e18440dc8359d3bbd771df435b393901807a61fd)
1118828e7SAxel Dörfler /*
2c71183bcSAxel Dörfler  * Copyright 2002-2010, Haiku.
3118828e7SAxel Dörfler  * Distributed under the terms of the MIT License.
4118828e7SAxel Dörfler  *
5118828e7SAxel Dörfler  * Authors:
6118828e7SAxel Dörfler  *		Francois Revol (mmu_man@users.sf.net)
7118828e7SAxel Dörfler  */
8118828e7SAxel Dörfler 
9c71183bcSAxel Dörfler 
10118828e7SAxel Dörfler /*!	Shuts down the system, either halting or rebooting. */
1117049c45SAxel Dörfler 
12c71183bcSAxel Dörfler 
1317049c45SAxel Dörfler #include <syscalls.h>
1417049c45SAxel Dörfler 
1517049c45SAxel Dörfler #include <OS.h>
16925d069dSIngo Weinhold #include <Roster.h>
17925d069dSIngo Weinhold #include <RosterPrivate.h>
1817049c45SAxel Dörfler 
1917049c45SAxel Dörfler #include <signal.h>
2017049c45SAxel Dörfler #include <stdio.h>
2117049c45SAxel Dörfler #include <stdlib.h>
2217049c45SAxel Dörfler #include <string.h>
2317049c45SAxel Dörfler #include <unistd.h>
2417049c45SAxel Dörfler #include <ctype.h>
2517049c45SAxel Dörfler 
26c71183bcSAxel Dörfler 
2717049c45SAxel Dörfler uint32 gTimeToSleep = 0;
2817049c45SAxel Dörfler bool gReboot = false;
2917049c45SAxel Dörfler 
3017049c45SAxel Dörfler 
31c71183bcSAxel Dörfler /*!	We get here when shutdown is cancelled.
32c71183bcSAxel Dörfler 	Then sleep() returns.
33c71183bcSAxel Dörfler */
3417049c45SAxel Dörfler void
handle_usr1(int sig)3517049c45SAxel Dörfler handle_usr1(int sig)
3617049c45SAxel Dörfler {
3717049c45SAxel Dörfler 	while (0);
3817049c45SAxel Dörfler }
3917049c45SAxel Dörfler 
4017049c45SAxel Dörfler 
4117049c45SAxel Dörfler bool
parseTime(char * arg,char * argv,int32 * _i)4217049c45SAxel Dörfler parseTime(char *arg, char *argv, int32 *_i)
4317049c45SAxel Dörfler {
4417049c45SAxel Dörfler 	char *unit;
4517049c45SAxel Dörfler 
4617049c45SAxel Dörfler 	if (isdigit(arg[0])) {
4717049c45SAxel Dörfler 		gTimeToSleep = strtoul(arg, &unit, 10);
4817049c45SAxel Dörfler 	} else if (argv && isdigit(argv[0])) {
4917049c45SAxel Dörfler 		(*_i)++;
5017049c45SAxel Dörfler 		gTimeToSleep = strtoul(argv, &unit, 10);
5117049c45SAxel Dörfler 	} else
5217049c45SAxel Dörfler 		return false;
5317049c45SAxel Dörfler 
54fe0af420SFrançois Revol 	if (unit[0] == '\0' || strcmp(unit, "s") == 0)
5517049c45SAxel Dörfler 		return true;
56fe0af420SFrançois Revol 	if (strcmp(unit, "m") == 0) {
5717049c45SAxel Dörfler 		gTimeToSleep *= 60;
5817049c45SAxel Dörfler 		return true;
5917049c45SAxel Dörfler 	}
6017049c45SAxel Dörfler 
6117049c45SAxel Dörfler 	return false;
6217049c45SAxel Dörfler }
6317049c45SAxel Dörfler 
6417049c45SAxel Dörfler 
6517049c45SAxel Dörfler void
usage(const char * program)6606ba99b0SFrançois Revol usage(const char *program)
6717049c45SAxel Dörfler {
6817049c45SAxel Dörfler 	fprintf(stderr, "usage: %s [-rqca] [-d time]\n"
6917049c45SAxel Dörfler 		"\t-r reboot,\n"
7017049c45SAxel Dörfler 		"\t-q quick shutdown (don't broadcast apps),\n"
71a13df0dcSIngo Weinhold 		"\t-a ask user to confirm the shutdown (ignored when -q is given),\n"
7217049c45SAxel Dörfler 		"\t-c cancel a running shutdown,\n"
73118828e7SAxel Dörfler 		"\t-s run shutdown synchronously (only returns if shutdown is cancelled)\n"
7417049c45SAxel Dörfler 		"\t-d delay shutdown by <time> seconds.\n", program);
7517049c45SAxel Dörfler 	exit(1);
7617049c45SAxel Dörfler }
7717049c45SAxel Dörfler 
7817049c45SAxel Dörfler 
7917049c45SAxel Dörfler int
main(int argc,char ** argv)8017049c45SAxel Dörfler main(int argc, char **argv)
8117049c45SAxel Dörfler {
82a13df0dcSIngo Weinhold 	bool askUser = false;
8317049c45SAxel Dörfler 	bool quick = false;
84118828e7SAxel Dörfler 	bool async = true;
8517049c45SAxel Dörfler 
8606ba99b0SFrançois Revol 	const char *program = strrchr(argv[0], '/');
8706ba99b0SFrançois Revol 	if (program == NULL)
8806ba99b0SFrançois Revol 		program = argv[0];
8906ba99b0SFrançois Revol 	else
9006ba99b0SFrançois Revol 		program++;
9106ba99b0SFrançois Revol 
9206ba99b0SFrançois Revol 	// handle 'halt' and 'reboot' symlinks
93fe0af420SFrançois Revol 	if (strcmp(program, "reboot") == 0)
9406ba99b0SFrançois Revol 		gReboot = true;
95fe0af420SFrançois Revol 	if (strcmp(program, "shutdown") != 0)
9606ba99b0SFrançois Revol 		askUser = true;
9706ba99b0SFrançois Revol 
9817049c45SAxel Dörfler 	for (int32 i = 1; i < argc; i++) {
9917049c45SAxel Dörfler 		char *arg = argv[i];
10017049c45SAxel Dörfler 		if (arg[0] == '-') {
10117049c45SAxel Dörfler 			if (!isalpha(arg[1]))
10206ba99b0SFrançois Revol 				usage(program);
10317049c45SAxel Dörfler 
10417049c45SAxel Dörfler 			while (arg && isalpha((++arg)[0])) {
10517049c45SAxel Dörfler 				switch (arg[0]) {
106a13df0dcSIngo Weinhold 					case 'a':
107a13df0dcSIngo Weinhold 						askUser = true;
108a13df0dcSIngo Weinhold 						break;
10917049c45SAxel Dörfler 					case 'q':
11017049c45SAxel Dörfler 						quick = true;
11117049c45SAxel Dörfler 						break;
11217049c45SAxel Dörfler 					case 'r':
11317049c45SAxel Dörfler 						gReboot = true;
11417049c45SAxel Dörfler 						break;
115118828e7SAxel Dörfler 					case 's':
116118828e7SAxel Dörfler 						async = false;
117118828e7SAxel Dörfler 						break;
11817049c45SAxel Dörfler 					case 'c':
11917049c45SAxel Dörfler 					{
120c71183bcSAxel Dörfler 						// find all running shutdown commands and signal their
121c71183bcSAxel Dörfler 						// shutdown threads
12217049c45SAxel Dörfler 
12317049c45SAxel Dörfler 						thread_info threadInfo;
12417049c45SAxel Dörfler 						get_thread_info(find_thread(NULL), &threadInfo);
12517049c45SAxel Dörfler 
12617049c45SAxel Dörfler 						team_id thisTeam = threadInfo.team;
12717049c45SAxel Dörfler 
12817049c45SAxel Dörfler 						int32 team_cookie = 0;
12917049c45SAxel Dörfler 						team_info teamInfo;
130c71183bcSAxel Dörfler 						while (get_next_team_info(&team_cookie, &teamInfo)
131c71183bcSAxel Dörfler 								== B_OK) {
132c71183bcSAxel Dörfler 							if (strstr(teamInfo.args, "shutdown") != NULL
133c71183bcSAxel Dörfler 								&& teamInfo.team != thisTeam) {
13417049c45SAxel Dörfler 								int32 thread_cookie = 0;
135c71183bcSAxel Dörfler 								while (get_next_thread_info(teamInfo.team,
136c71183bcSAxel Dörfler 										&thread_cookie, &threadInfo) == B_OK) {
137fe0af420SFrançois Revol 									if (strcmp(threadInfo.name, "shutdown") == 0)
13817049c45SAxel Dörfler 										kill(threadInfo.thread, SIGUSR1);
13917049c45SAxel Dörfler 								}
14017049c45SAxel Dörfler 							}
14117049c45SAxel Dörfler 						}
14217049c45SAxel Dörfler 						exit(0);
14317049c45SAxel Dörfler 						break;
14417049c45SAxel Dörfler 					}
14517049c45SAxel Dörfler 					case 'd':
14617049c45SAxel Dörfler 						if (parseTime(arg + 1, argv[i + 1], &i)) {
14717049c45SAxel Dörfler 							arg = NULL;
14817049c45SAxel Dörfler 							break;
14917049c45SAxel Dörfler 						}
15017049c45SAxel Dörfler 						// supposed to fall through
15117049c45SAxel Dörfler 
15217049c45SAxel Dörfler 					default:
15306ba99b0SFrançois Revol 						usage(program);
15417049c45SAxel Dörfler 				}
15517049c45SAxel Dörfler 			}
15617049c45SAxel Dörfler 		} else
15706ba99b0SFrançois Revol 			usage(program);
15817049c45SAxel Dörfler 	}
15917049c45SAxel Dörfler 
16017049c45SAxel Dörfler 	if (gTimeToSleep > 0) {
16117049c45SAxel Dörfler 		int32 left;
16217049c45SAxel Dörfler 
16317049c45SAxel Dörfler 		signal(SIGUSR1, handle_usr1);
16417049c45SAxel Dörfler 
165*e18440dcSMurai Takashi 		printf("Delaying %s by %" B_PRIu32 " seconds...\n",
166c71183bcSAxel Dörfler 			gReboot ? "reboot" : "shutdown", gTimeToSleep);
16717049c45SAxel Dörfler 
16817049c45SAxel Dörfler 		left = sleep(gTimeToSleep);
16917049c45SAxel Dörfler 
17017049c45SAxel Dörfler 		if (left > 0) {
17117049c45SAxel Dörfler 			fprintf(stderr, "Shutdown cancelled.\n");
17217049c45SAxel Dörfler 			exit(0);
17317049c45SAxel Dörfler 		}
17417049c45SAxel Dörfler 	}
17517049c45SAxel Dörfler 
17617049c45SAxel Dörfler 	if (quick) {
177925d069dSIngo Weinhold 		#ifdef __HAIKU__
17817049c45SAxel Dörfler 		_kern_shutdown(gReboot);
179925d069dSIngo Weinhold 		#endif // __HAIKU__
180c71183bcSAxel Dörfler 		fprintf(stderr, "Shutdown failed! (Do you have ACPI enabled?)\n");
18117049c45SAxel Dörfler 		return 2;
18217049c45SAxel Dörfler 	} else {
183925d069dSIngo Weinhold 		BRoster roster;
184925d069dSIngo Weinhold 		BRoster::Private rosterPrivate(roster);
185118828e7SAxel Dörfler 		status_t error = rosterPrivate.ShutDown(gReboot, askUser, !async);
18691077c48SPhilippe Houdoin 		if (error != B_OK) {
187925d069dSIngo Weinhold 			fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
188925d069dSIngo Weinhold 			return 2;
18917049c45SAxel Dörfler 		}
19091077c48SPhilippe Houdoin 	}
19117049c45SAxel Dörfler 
19217049c45SAxel Dörfler 	return 0;
19317049c45SAxel Dörfler }
19417049c45SAxel Dörfler 
195