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