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