function run_script(&$env, $cmd) { /* Only fork once, if there are many sequential script invocations. * The father returns "success", and the son will treat the rest * of the action chain. */ if (!@$env["HAS_FORKED"] && !@$env["IS_SON"] && !@$env["IS_GLOBAL"]) { global $FORKS; // clean the connection cache: mysql seems to be disturbed by fork() _db_close(); flush(); // fork a process for execution of the script $pid = pcntl_fork(); if ($pid < 0) { // error engine_error("could not fork() a new process for command '{$cmd}'"); return false; } if ($pid > 0) { // father //echo "FORK.....$pid\n"; $env["HAS_FORKED"] = true; $FORKS[$pid] = $cmd; return true; } // son $env["IS_SON"] = true; $pid = getmypid(); check_answer($env, "FORKED {$pid}"); //global $debug; $debug = true; } $pipes = array(); $descr = array(0 => array("file", "/dev/null", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w")); //echo "cmd: $cmd\n"; $proc = proc_open($cmd, $descr, $pipes); if (!$proc) { engine_error("proc_open() on command '{$cmd}' failed"); exit(-1); } $pid = proc_get_status($proc); $pid = @$pid["pid"]; $ok = true; $ok &= check_answer($env, "START {$pid} ({$cmd})"); $timeout = $env["rule_timeout"]; if ($timeout < 1) { $timeout = 3600 * 24 * 365; } do { $tests = $pipes; // create a copy, because stream_select() will modifiy it $dummy1 = null; $dummy2 = null; $status = stream_select($tests, $dummy1, $dummy2, $timeout); if (!$status) { // timeout $ok &= check_answer($env, "TIMEOUT {$pid} {$timeout}"); } $closed = 0; foreach ($tests as $stream) { if (feof($stream)) { $closed++; continue; } $line = chop(fgets($stream)); $ok &= check_answer($env, $line); } if (!$ok) { // kill it... engine_log("killing process {$pid}"); proc_terminate($proc); check_answer($env, "KILL {$pid}"); exit(1); } } while ($closed < 2); fclose($pipes[1]); fclose($pipes[2]); $has_reported = false; if (true) { $code = pcntl_waitpid($pid, $status, 0); if ($code > 0) { if (pcntl_wifsignaled($status)) { $status = pcntl_wtermsig($status); check_answer($env, "SIGNALED {$code} {$status}"); } if (pcntl_wifexited($status)) { $status = pcntl_wexitstatus($status); check_answer($env, "STATUS {$code} {$status}"); $has_reported = true; } } } if (!$has_reported) { // after waitpid(), the zombie is lost => proc_close() will no longer work $status = proc_close($proc); check_answer($env, "STATUS {$pid} {$status}"); } return true; }
function mysql_multiquery(&$env, $mysqli, $query, $cb_list) { global $ERROR; global $debug; if (!is_a($mysqli, "mysqli")) { echo "internal error: bad mysqli object "; print_r($mysqli); echo "<br>\n"; return false; } $cb = ""; if ($cb_list) { $cb = array_shift($cb_list); } $next = $mysqli->multi_query($query); if (!$next) { $ERROR .= $mysqli->error; if ($debug) { echo "<br>\nmultiquery error '{$ERROR}' on first query ({$query})<br>\n"; echo "next='"; print_r($next); echo "'<br>\n"; echo "is_bool(next)='"; print_r(is_bool($next)); echo "'<br>\n"; echo "<br>\n"; } _db_close($mysqli); return false; } elseif ($cb) { $next = $mysqli->use_result(); //print_r($next); if ($debug) { echo "first callback '{$cb}'<br>\n"; } $next = $cb($env, $next); } $env["RES"][] = $next; while ($mysqli->more_results() && !@$env["ERROR"]) { if ($cb_list) { $cb = array_shift($cb_list); } $next = $mysqli->next_result(); if (!$next) { $ERROR .= $mysqli->error; _db_close($mysqli); return false; } elseif ($cb) { $next = $mysqli->use_result(); if ($debug) { echo "next callback '{$cb}'<br>\n"; } $next = $cb($env, $next); } $env["RES"][] = $next; } if (@$env["ERROR"]) { _db_close($mysqli); return false; } return true; }