How to get terminal text from gnu screen session?

78 Views Asked by At

How do i get the terminal text from a GNU Screen session in PHP? I am puzzled because GitHub CoPilot suggest i can do

function getTerminalTextFromGnuScreen(string $screenName): string
{
    $screenText = shell_exec("screen -S " . escapeshellarg($screenName) . " -X hardcopy -h");
    return $screenText;
}

but that does not actually get me anything, just emptystring. I came up with a much more complex, convoluted, and dodgy implementation, which works, but i hope, as CoPilot suggest, that there is a much easier way to do this, hence asking here: how should it be done? my dodgy implementation:

function getTerminalTextFromGnuScreenDodgy(string $screenName, bool $skipTerminalSizeControlCharacters = true): string
{
    // the double escapeshellarg is intentional.
    $cmd = 'script --command ' . escapeshellarg('screen -x -r ' . escapeshellarg($screenName)) . ' /dev/null ';
    $proc = proc_open($cmd, [['pipe', 'rb'], ['pipe', 'wb'], ['pipe', 'wb']], $pipes);
    stream_set_blocking($pipes[1], true);
    fgets($pipes[1]); // skip "Script started, output log file is '/dev/null'." line
    $ret = '';
    if ($skipTerminalSizeControlCharacters) {
        $ret = fgets($pipes[1]); // contains terminal size characters
        $lastControlCharacter = strrpos($ret, "\x1b"); // THIS IS NOT 100% RELIABLE, and i don't know how to make it reliable either :(
        $ret = substr($ret, $lastControlCharacter + strlen("\x1b[2J")); // skip terminal size characters
    }
    stream_set_blocking($pipes[1], false);
    for (;;) {
        $r = [$pipes[1]];        
        $w = $e = null;
        $sel = stream_select($r, $w, $e, 0, 10000);
        $tmp = stream_get_contents($pipes[1]);
        if ($tmp === false || $tmp === '') {
            break;
        }
        $ret .= $tmp;
    }
    fclose($pipes[1]);
    // send ctrl+AD... why is \x01 equivalent to ctrl+AD? i have no idea! but it seems to work
    fwrite($pipes[0], "\x01");
    fclose($pipes[0]);
    fclose($pipes[2]); // contains a "script: write error" message.. no idea why.
    proc_close($proc);
    return $ret;
}
1

There are 1 best solutions below

0
hanshenrik On

so much wasted effort.. the answer is indeed -X hardcopy, but the the code refuse to writes to both stdout and /dev/stdout, and if you tell it to write to the filename - which traditionally means stdout, it will write to ./-, and if no file is given it default to the filename "hardcopy.n" -

Why? I have no idea, but regardless, use tmpfile() to get a output file for -X hardcopy:

function getTerminalTextFromGnuScreen(string $screenName)
{
    $tmph = tmpfile();
    $tmpf = stream_get_meta_data($tmph)['uri'];
    shell_exec("screen -S " . escapeshellarg($screenName) . " -X hardcopy " . escapeshellarg($tmpf));
    $screenText = file_get_contents($tmpf);
    fclose($tmph);
    return $screenText;
}

‘-h num’

Set the history scrollback buffer to be num lines high. Equivalent to the defscrollback command (see Copy).