// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // // Copyright (c) 2002, OpenBeOS // // This software is part of the OpenBeOS distribution and is covered // by the OpenBeOS 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 :). // // Compile with: LDFLAGS="-lbe" make // // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ #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 const char *roster_sig = "application/x-vnd.Be-ROST"; extern "C" void _kshutdown_(long arg); #define SHUTDOWN_HALT 0 #define SHUTDOWN_REBOOT 1 // 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} }; unsigned long time_to_sleep = 0; // -d int reboot = 0; // -r 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; static const int32 fTopMargin = 8; unsigned long fTimeLeft; }; 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(time_to_sleep) { 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 (reboot) *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() { if (fButton != NULL) delete fButton; if (fTitle != NULL) delete fTitle; if (fIcon != NULL) delete fIcon; } void SView::Pulse() { fPulseDivider--; if (fPulseDivider <= 0) { fPulseDivider = PULSE_MODULO; fTimeLeft--; fTitleStr->SetTo(""); if (reboot) *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; } /***************************/ // we get here when shutdown is cancelled. // then sleep() returns void handle_usr1(int sig) { while (0); } int main(int argc, char **argv) { int i; int quick = 0; // -q int alert = 0; // -a BMessenger msgr(roster_sig); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-q")) quick = 1; else if (!strcmp(argv[i], "-r")) reboot = 1; else if (!strcmp(argv[i], "-c")) { team_info ti; thread_info thi; int32 team_cookie = 0; int32 thread_cookie = 0; team_id myteam; get_thread_info(find_thread(NULL), &thi); myteam = thi.team; while (get_next_team_info(&team_cookie, &ti) == B_OK) { if (strstr(ti.args, "shutdown") != NULL && (ti.team != myteam)) { thread_cookie = 0; while (get_next_thread_info(ti.team, &thread_cookie, &thi) == B_OK) { if (!strcmp(thi.name, "shutdown")) { kill(thi.thread, SIGUSR1); } } } } exit (0); } else if (!strcmp(argv[i], "-a")) { alert = 1; } else if (!strcmp(argv[i], "-d") && (i+1 < argc)) { i++; time_to_sleep = strtol(argv[i], &argv[i], 10); } else { fprintf(stderr, "usage: %s [-r] [-q] [-c] [-a] [-d time] -r reboot, -q quick shutdown (don't broadcast apps), -c cancel a running shutdown, -a alerts user while waiting, -d delay shutdown by