/* * Copyright 2002-2025, Haiku Inc. * Distributed under the terms of the MIT license. * * Authors: * François Revol (mmu_man) * Humdinger, humdinger@mailbox.org */ #include #include #include #include #include #include #include #include static int sExitValue = EXIT_FAILURE; static const char* kProgramName = "waitfor"; static const char* kProgramSig = "application/x-vnd.haiku-waitfor"; #define INTERVAL 100000 // 0.1sec #define CHECK 'chck' enum command { NONE, APP_RUNNING, NETWORK, THREAD_STARTED, THREAD_ENDED }; class WaitforApp : public BApplication { public: WaitforApp(); virtual ~WaitforApp(); virtual void ReadyToRun(); virtual void ArgvReceived(int32 argc, char** argv); virtual void MessageReceived(BMessage* message); private: void _Usage(); bool _CheckNetworkConnection(); BMessageRunner* fRunner; BString fThreadName; BString fAppSig; command fOption; }; WaitforApp::WaitforApp() : BApplication(kProgramSig), fThreadName(NULL), fAppSig(NULL), fOption(NONE) { BMessage message(CHECK); fRunner = new BMessageRunner(this, &message, INTERVAL); } WaitforApp::~WaitforApp() { stop_watching_network(this); delete fRunner; } void WaitforApp::ArgvReceived(int32 argc, char** argv) { if (argc == 2 && strcmp(argv[1], "-n") == 0) { fOption = NETWORK; } else if (argc == 2) { fOption = THREAD_STARTED; fThreadName = argv[1]; } else if (argc == 3 && strcmp(argv[1], "-e") == 0) { fOption = THREAD_ENDED; fThreadName = argv[2]; } else if (argc == 3 && strcmp(argv[1], "-m") == 0) { fOption = APP_RUNNING; fAppSig = argv[2]; } else fOption = NONE; } void WaitforApp::MessageReceived(BMessage* message) { switch (message->what) { case CHECK: { switch (fOption) { case APP_RUNNING: { BMessenger messenger(fAppSig); if (messenger.IsValid()) { sExitValue = EXIT_SUCCESS; PostMessage(B_QUIT_REQUESTED); } break; } case THREAD_STARTED: { if (find_thread(fThreadName) >= 0) { sExitValue = EXIT_SUCCESS; PostMessage(B_QUIT_REQUESTED); } break; } case THREAD_ENDED: { if (find_thread(fThreadName) < 0) { sExitValue = EXIT_SUCCESS; PostMessage(B_QUIT_REQUESTED); } break; } case NONE: { _Usage(); PostMessage(B_QUIT_REQUESTED); break; } default: break; } break; } case B_NETWORK_MONITOR: { if (_CheckNetworkConnection()) PostMessage(B_QUIT_REQUESTED); break; } default: { BApplication::MessageReceived(message); break; } } } void WaitforApp::ReadyToRun() { if (fOption == NETWORK) { if (_CheckNetworkConnection()) PostMessage(B_QUIT_REQUESTED); else { start_watching_network( B_WATCH_NETWORK_INTERFACE_CHANGES | B_WATCH_NETWORK_LINK_CHANGES, this); } } } bool WaitforApp::_CheckNetworkConnection() { BNetworkRoster& roster = BNetworkRoster::Default(); BNetworkInterface interface; uint32 cookie = 0; while (roster.GetNextInterface(&cookie, interface) == B_OK) { uint32 flags = interface.Flags(); if ((flags & IFF_LOOPBACK) == 0 && (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) { sExitValue = EXIT_SUCCESS; return true; } } // No network connection detected return false; } void WaitforApp::_Usage() { BString usageText("Usage:\n" " %s \n" " wait until a thread with 'thread_name' has been started.\n\n" " %s -e \n" " wait until all threads with thread_name have ended.\n\n" " %s -m \n" " wait until the application specified by 'app_signature' is " "ready to receive messages.\n\n" " %s -n\n" " wait until the network connection is up.\n"); usageText.ReplaceAll("%s", kProgramName); fprintf(stderr, usageText); } int main(int argc, char** argv) { WaitforApp waitforApp; waitforApp.Run(); return sExitValue; }