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