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