'drush_bot_start', 'description' => "Starts the bot.", ); $items['bot stop'] = array( 'callback' => 'drush_bot_stop', 'description' => "Stops the bot.", ); $items['bot status'] = array( 'callback' => 'drush_bot_status', 'description' => "Show status of the bot.", ); $items['bot restart'] = array( 'callback' => 'drush_bot_restart', 'description' => "Restarts the bot.", ); return $items; } /** * Implementation of hook_drush_help(). */ function bot_drush_help($section) { switch ($section) { case 'drush:bot start': return dt("Starts the bot."); case 'drush:bot stop': return dt("Stops the bot."); case 'drush:bot status': return dt("Show bot status."); case 'drush:bot restart': return dt("Restarts the bot."); } } /** * Command callback. Starts the bot, if not already running. */ function drush_bot_start() { $botname = variable_get('bot_nickname', ''); if (_drush_bot_is_running()) { drush_log("Bot ($botname) is already running.", "failed"); return; } declare(ticks = 1); $pid = pcntl_fork(); if ($pid == -1) { drush_log("Unable to fork.", "failed"); return; } else if ($pid) { // parent: $pid is my child's pid // get the pidfile and write the child's pid $site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT'); $pidfile = "$site_root/bot.pid"; $file = fopen($pidfile, "w"); if ($file === FALSE) { drush_log("Can't open pid file $pidfile.", "error"); exit(); } fwrite($file, $pid); fclose($file); return; } // child else {} // detatch from the controlling terminal if (posix_setsid() == -1) { drush("could not detach from terminal", "failed"); return; } // setup signal handlers /* pcntl_signal(SIGTERM, "_drush_bot_sig_handler"); pcntl_signal(SIGHUP, "_drush_bot_sig_handler"); */ //perform child task $path_to_drupal = drush_get_context('DRUSH_DRUPAL_ROOT'); $path_to_bot = drupal_get_path('module', 'bot'); $url = drush_get_context('DRUSH_URI'); $args = array( "$path_to_drupal/$path_to_bot/bot_start.php", "--root", $path_to_drupal, "--url", $url, ); drush_log("Starting bot: $botname.", "success"); $result = pcntl_exec("/usr/bin/php", $args); //NOTE: returns FALSE on failure... don't return on success drush_log("No no no, failure.", "failed"); exit(); } /** * Command callback. Stops the bot, if running. */ function drush_bot_stop() { $botname = variable_get('bot_nickname', ''); if (!_drush_bot_is_running()) { drush_log("Bot ($botname) is not running.", "failed"); return; } // get the pidfile $site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT'); $pidfile = "$site_root/bot.pid"; // get the pid $file = fopen($pidfile, "r"); $pid = fread($file, 6); fclose($file); // kill the process & delete pidfile posix_kill($pid, SIGKILL); unlink($pidfile); // message drush_log("Stopping bot: $botname.", "success"); } /** * Command callback. Prints out current bot status. * */ function drush_bot_status() { $botname = variable_get('bot_nickname', ''); if (_drush_bot_is_running()) { drush_log("Bot ($botname) is running.", "ok"); } else { drush_log("Bot ($botname) is not running.", "ok"); } } /** * Command callback. Restarts the bot. */ function drush_bot_restart() { drush_bot_stop(); drush_bot_start(); } //////////////////////////////////////////////////////////////////////////////// // BOT HELPER FUNCTIONS /** * Tells if the bot is currently running. * * This function checks if a pidfile exists. If not it is assumed the bot is not * running. If the pidfile exists it checks if the process is running. If * pidfile exists and process is not running, it removes the pidfile. */ function _drush_bot_is_running() { // does pidfile exist? $site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT'); $pidfile = "$site_root/bot.pid"; if (!file_exists($pidfile)) { return FALSE; } // get the process pid $file = fopen($pidfile, "r"); $pid = fread($file, 6); fclose($file); // is the process alive? $cmd = "ps $pid"; exec($cmd, $output, $result); if (count($output) >= 2) { //the process is alive return TRUE; } // the process is dead. let's remove the pidfile unlink($pidfile); return FALSE; } /* * Signal handler for the bot process * * This function is a callback invoked for the pcntl registered signals at * _drush_bot_start() */ /* function _drush_bot_sig_handler($signo) { switch ($signo) { case SIGTERM: // handle shutdown tasks drush_print("SIGTERM"); exit; break; case SIGHUP: drush_print("SIGHUP"); // handle restart tasks break; default: // handle all other signals drush_print("Other signal"); } } */