6 * Execute system command
11 * Sudo command, if the cmd needs escalated privileges
17 * Executable of the cmd
23 * Passthrough cmd output
35 * Return code of cmd run
41 * @param string $command
44 public function __construct($command, $verbose = false) {
45 $this->command
= $command;
46 $this->verbose
= $verbose;
50 * (Re-)set sudo command
53 public function setSu($sudo = false) {
58 * Execute a program with escalated privileges handling interactive password prompt
59 * @param string $command
60 * @param bool $verbose
61 * @return int exit status
63 private function suExec($command, $verbose = null) {
64 if (!($proc = proc_open($command, [STDIN
,["pipe","w"],["pipe","w"]], $pipes))) {
66 throw new Exception("Failed to run {$command}");
73 while (!feof($stdout)) {
74 $R = [$stdout]; $W = []; $E = [];
75 if (!stream_select($R, $W, $E, null)) {
78 $data = fread($stdout, 0x1000);
79 /* only check a few times */
80 if ($passwd < $checks) {
82 if (stristr($data, "password")) {
83 $passwd = $checks +
1;
84 printf("\n%s", $data);
87 } elseif ($passwd > $checks) {
88 /* new line after pw entry */
93 if ($verbose === null) {
94 print $this->progress($data, 0);
97 printf("%s\n", $data);
99 $this->output
.= $data;
102 if ($verbose === null) {
103 $this->progress("", PHP_OUTPUT_HANDLER_FINAL
);
105 return $this->status
= proc_close($proc);
109 * Output handler that displays some progress while soaking output
110 * @param string $string
114 private function progress($string, $flags) {
116 static $s = ["\\","|","/","-"];
118 $this->output
.= $string;
120 return $flags & PHP_OUTPUT_HANDLER_FINAL
122 : sprintf(" %s\r", $s[$c++ %
count($s)]);
128 * @return \pharext\ExecCmd self
129 * @throws \pharext\Exception
131 public function run(array $args = null) {
132 $exec = escapeshellcmd($this->command
);
134 $exec .= " ". implode(" ", array_map("escapeshellarg", (array) $args));
138 $this->suExec(sprintf($this->sudo
." 2>&1", $exec), $this->verbose
);
139 } elseif ($this->verbose
) {
140 ob_start(function($s) {
144 passthru($exec, $this->status
);
146 } elseif ($this->verbose
!== false /* !quiet */) {
147 ob_start([$this, "progress"], 1);
148 passthru($exec . " 2>&1", $this->status
);
151 exec($exec ." 2>&1", $output, $this->status
);
152 $this->output
= implode("\n", $output);
156 throw new Exception("Command {$exec} failed ({$this->status})");
163 * Retrieve exit code of cmd run
166 public function getStatus() {
167 return $this->status
;
171 * Retrieve output of cmd run
174 public function getOutput() {
175 return $this->output
;