// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // // Copyright (c) 2002, Haiku // // This software is part of the Haiku distribution and is covered // by the MIT license. // // File: shutdown.cpp // Author: Francois Revol (mmu_man@users.sf.net) // Description: shuts down the system, either halting or rebooting. // // Notes: // This program behaves identically as the BeOS R5 version, with these // added arguments: // // -a alert user while counting down // -c cancels any running shutdown // // There seem to be a race condition (sometimes crashes on quit with // "the looper must be locked"), if you find it, tell me, // tried 3 hours to find it. // Some code from Shard's Archiver from BeBits (was BSD/MIT too :). // // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // ToDo: I think we should remove the shutdown alert again - we already have one // in the roster, and that should really be enough. // Also, I don't quite see a lot of sense in the delayed shutdown, either -- axeld. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // timer should be handled better (with system_time()) #define PULSE_RATE 100000 #define PULSE_MODULO 10 //from bdb-ing /bin/shutdown: #define B_SYSTEM_SHUTDOWN 0x12d #define B_SYSTEM_REBOOT 0x12e static const char *kRosterSignature = "application/x-vnd.Be-ROST"; // globals const char kIconBits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x2f, 0xeb, 0x2f, 0x30, 0x2f, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x2f, 0xeb, 0x2c, 0x2b, 0x2c, 0x2d, 0x30, 0x2f, 0x2f, 0x00, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x2f, 0x2b, 0x2a, 0x2b, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x2f, 0x2b, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2d, 0x2d, 0x2f, 0x30, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x2f, 0x2b, 0x2b, 0x3f, 0x2b, 0x2a, 0x2c, 0x2d, 0x2d, 0xeb, 0x30, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x2f, 0x2c, 0x2b, 0x2b, 0x2a, 0x2b, 0x2c, 0x2c, 0x2e, 0x2f, 0x2f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x2f, 0x2d, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, 0x2d, 0x2d, 0x2f, 0x30, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x2f, 0xeb, 0x2d, 0x2d, 0x2c, 0x2c, 0x2d, 0x2d, 0xeb, 0x2f, 0x2f, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x30, 0x2e, 0x2c, 0x2d, 0x2d, 0x2d, 0x2f, 0x2f, 0x2f, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0x2f, 0x2f, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x2f, 0x2f, 0x00, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x2f, 0x2f, 0x30, 0x2f, 0x2f, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; const char kElectronBits[] = { 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x25, 0x24, 0x26, 0x00, 0xff, 0xff, 0x00, 0x25, 0x21, 0x21, 0x22, 0x26, 0x00, 0xff, 0x00, 0x21, 0x3f, 0x22, 0x22, 0x25, 0x00, 0xff, 0x00, 0x25, 0x22, 0x22, 0x24, 0x24, 0x00, 0xff, 0xff, 0x00, 0x23, 0x23, 0x25, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; #define EL_POS_COUNT 17 static const int electron1_table[][2] = { {3, 8}, {7, 8}, {12, 8}, {17, 10}, {22, 12}, {26, 16}, {28, 20}, {28, 24}, {26, 26}, {22, 27}, {18, 26}, {14, 25}, {10, 24}, {5, 22}, {3, 18}, {1, 14}, {1, 10}, {-1, -1} }; static const int electron2_table[][2] = { {23, 18}, {21, 22}, {18, 25}, {14, 27}, {10, 27}, {5, 26}, {0, 25}, {1, 18}, {4, 15}, {8, 12}, {12, 10}, {16, 8}, {20, 8}, {24, 9}, {28, 11}, {27, 13}, {25, 15}, {-1, -1} }; uint32 gTimeToSleep = 0; bool gReboot = false; class SView : public BView { public: SView(BRect frame); ~SView(); void Draw(BRect updateRect); void Pulse(); BButton *fButton; BString *fTitleStr; BStringView *fTitle; BBitmap *fIcon; BBitmap *fElectron; int fElectronPos; int fPulseDivider; int32 fWidth; int32 fHeight; int32 fLeftMargin; unsigned long fTimeLeft; static const int32 fTopMargin = 8; }; class ShutdownWindow : public BWindow { public: ShutdownWindow(thread_id id); ~ShutdownWindow(); void MessageReceived(BMessage *msg); bool QuitRequested(); private: SView *fView; thread_id fShutdownThread; }; class ShutdownApp : public BApplication { public: ShutdownApp(thread_id id); ~ShutdownApp(); private: ShutdownWindow *fWindow; }; SView::SView(BRect frame) :BView(frame, "SView", B_FOLLOW_LEFT_RIGHT, B_PULSE_NEEDED | B_WILL_DRAW), fButton(NULL), fTitleStr(NULL), fTitle(NULL), fIcon(NULL), fElectron(NULL), fElectronPos(0), fPulseDivider(PULSE_MODULO+1), fWidth(0), fHeight(0), fLeftMargin(B_LARGE_ICON + 8), fTimeLeft(gTimeToSleep) { SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); SetLowColor(ViewColor()); SetDrawingMode(B_OP_OVER); fIcon = new BBitmap(BRect(0, 0, B_LARGE_ICON-1, B_LARGE_ICON-1), B_CMAP8); fIcon->SetBits(kIconBits, B_LARGE_ICON*B_LARGE_ICON, 0, B_CMAP8); fElectron = new BBitmap(BRect(0, 0, 7, 7), B_CMAP8); fElectron->SetBits(kElectronBits, 8*8, 0, B_CMAP8); fTitleStr = new BString; if (gReboot) *fTitleStr << "Rebooting in " << (int32)fTimeLeft << " seconds !"; else *fTitleStr << "Shutting down in " << (int32)fTimeLeft << " seconds !"; fTitle = new BStringView(BRect(55, 10, 260, 35), "", fTitleStr->String()); fButton = new BButton(BRect(159, 42, 259, 66), "quit", "Cancel", new BMessage('_QRQ')); fButton->MakeDefault(true); AddChild(fTitle); AddChild(fButton); } SView::~SView() { delete fButton; delete fTitle; delete fIcon; } void SView::Pulse() { fPulseDivider--; if (fPulseDivider <= 0) { fPulseDivider = PULSE_MODULO; fTimeLeft--; fTitleStr->SetTo(""); if (gReboot) *fTitleStr << "Rebooting in " << (int32)fTimeLeft << " seconds !"; else *fTitleStr << "Shutting down in " << (int32)fTimeLeft << " seconds !"; fTitle->SetText(fTitleStr->String()); } fElectronPos += 1; fElectronPos %= EL_POS_COUNT; Invalidate(); } void SView::Draw(BRect updateRect) { BRect bounds = Bounds(); // left margin background // SetHighColor(tint_color(ViewColor(), B_HIGHLIGHT_BACKGROUND_TINT)); SetHighColor(0xB8, 0xB8, 0xB8); // same color as the registrar shutdown dialog FillRect(BRect(0, 0, B_LARGE_ICON, bounds.bottom)); if (fIcon != NULL) DrawBitmap(fIcon, BPoint((B_LARGE_ICON / 2), fTopMargin)); if (fIcon != NULL) { DrawBitmap(fElectron, BPoint((B_LARGE_ICON / 2) + electron1_table[fElectronPos][0], fTopMargin + electron1_table[fElectronPos][1])); DrawBitmap(fElectron, BPoint((B_LARGE_ICON / 2) + electron2_table[fElectronPos][0], fTopMargin + electron2_table[fElectronPos][1])); } if (Window()) Window()->Flush(); } ShutdownWindow::ShutdownWindow(thread_id id) : BWindow(BRect( 139, 81, 407, 156), "Shutdown Status", B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS), fView(NULL) { fShutdownThread = id; SetPulseRate(PULSE_RATE); fView = new SView(Bounds()); AddChild(fView); } ShutdownWindow::~ShutdownWindow() { fView->LockLooper(); fView->RemoveSelf(); delete fView; } void ShutdownWindow::MessageReceived(BMessage *msg) { switch (msg->what) { default: BWindow::MessageReceived(msg); break; } } bool ShutdownWindow::QuitRequested() { SetPulseRate(0); kill(fShutdownThread, SIGUSR1); return true; } ShutdownApp::ShutdownApp(thread_id id) : BApplication("application/x-vnd.ShutDown-app") { fWindow = new ShutdownWindow(id); fWindow->SetWorkspaces(0xFFFFFFFF); fWindow->Show(); } ShutdownApp::~ShutdownApp() { } int32 app_thread(void *arg) { thread_id tid = (thread_id) arg; (new ShutdownApp(tid))->Run(); delete be_app; return B_OK; } // #pragma mark - // we get here when shutdown is cancelled. // then sleep() returns void handle_usr1(int sig) { while (0); } bool parseTime(char *arg, char *argv, int32 *_i) { char *unit; if (isdigit(arg[0])) { gTimeToSleep = strtoul(arg, &unit, 10); } else if (argv && isdigit(argv[0])) { (*_i)++; gTimeToSleep = strtoul(argv, &unit, 10); } else return false; if (unit[0] == '\0' || !strcmp(unit, "s")) return true; if (!strcmp(unit, "m")) { gTimeToSleep *= 60; return true; } return false; } void usage(const char *arg0) { const char *program = strrchr(arg0, '/'); if (program == NULL) program = arg0; else program++; fprintf(stderr, "usage: %s [-rqca] [-d time]\n" "\t-r reboot,\n" "\t-q quick shutdown (don't broadcast apps),\n" "\t-c cancel a running shutdown,\n" "\t-a alerts user while waiting,\n" "\t-d delay shutdown by