I'd like to be able to check progress and output of my existing screen
sessions, but in a read-only manner, so as to prevent something from going wrong due to user error. Is there a way to do this?

- 39,676
-
https://www.gnu.org/software/screen/manual/screen.html#Multiuser-Session set ACLs per user have fun - stay free like a GNU – Dominik Jun 11 '20 at 11:57
7 Answers
Unfortunately, I think the answer is no. The asker of this question switched to tmux specifically because it has that feature (you pass the -r
flag when attaching), so if you have the option to switch multiplexers it's probably your best choice

- 93,103
- 40
- 240
- 233
You can try:
aclchg username -w "#"
if you run screen
in multi user mode (but I didn't have to do anything special to make it work when testing it as a single attached user). If you do need to enter multiuser mode, use multiuser on
.
You can use *
for the username to affect all users.
Using +w
instead of -w
enables write mode.
From man screen
:
aclchg usernames permbits list
chacl usernames permbits listChange permissions for a comma separated list of users. Permission bits are represented as 'r', 'w' and 'x'. Prefixing '+' grants the permission, '-' removes it. The third parameter is a comma separated list of commands and/or windows (specified either by number or title). The special list '#' refers to all windows, '?' to all commands. if usernames consists of a single '*', all known users are affected. A command can be executed when the user has the 'x' bit for it. The user can type input to a window when he has its 'w' bit set and no other user obtains a writelock for this window. Other bits are currently ignored. To withdraw the writelock from another user in window 2: 'aclchg username -w+w 2'. To allow read-only access to the session: 'aclchg username -w "#"'. As soon as a user's name is known to screen he can attach to the session and (per default) has full permissions for all command and windows. Execution permission for the acl commands, `at' and others should also be removed or the user may be able to regain write permission. Rights of the special username nobody cannot be changed (see the "su" command). 'Chacl' is a synonym to 'aclchg'. Multi user mode only.

- 6,680
-
While that works, it makes
screen
readonly everywhere the screen session is attached which looks like is different from what the OP asked. – Stéphane Chazelas Jan 22 '13 at 22:05 -
1@StephaneChazelas: I don't see any indication in the question that the OP is concerned about writability in other instances of a multiply-attached session. Besides, the
aclcng
command can specify particular users, particular commands and/or particular windows so that's fairly fine granularity. So that's not "everywhere". – Dennis Williamson Jan 23 '13 at 01:59
I have found a fairly simple work-around that allows one to monitor the output safely.
Run the following commands immediately after entering the screen session:
echo /tmp/$STY
touch /tmp/$STY
chmod 0600 /tmp/$STY
script -a -f /tmp/$STY
Detach the session with Ctrl-A d and follow the script output, e.g.:
tail -f /tmp/10751.test

- 151
My current solution to this is to set the Terminal View to ReadOnly.
Maybe it's too obvious. However, the question didn't require a solution by screen
itself.

- 119
-
2looks good to me, with a terminal emulator that supports read-only mode. unfortunately, many terminals does not (gnome/kde terminal does not iirc), but some do (like xfce4-terminal) – hanshenrik Dec 08 '18 at 21:47
I just tested the answer provided by "Paused until further notice." It works, but may require context. Here are the steps I followed on Debian 10:
# chmod 4755 /usr/bin/screen # screen requires setuid for multiuser mode
# chmod 0755 /run/screen # screen requires this if setuid
$ screen -dR oneway # run as normaluser
^A:multiuser on # enable multiuser mode
^A:acladd readonlyuser # allow access by readonlyuser
^A:aclchg readonlyuser -w '#' # drop write access for readonlyuser
$
$ screen -x normaluser/oneway # run as readonlyuser
$ [enter] # try to enter text - should fail
write: permission denied (user readonlyuser)

- 11
- 1
yes, that's possible. just set a log file for screen to write. the read-only user can tail into that file.
Start screen session with log:
screen -S mysession -L
command above will create a file screenlog.0 in current directory.
the read-only user can check to the log file to check on-going activities :
tail -f screenlog.0

- 11
i wrote a php script called readscreen
to... attach to screen sessions in read-only mode. save it to /usr/bin/readscreen
and run chmod 0555 /usr/bin/readscreen
, and make sure to have php-cli installed with php-pcntl extension, and you can write readscreen
followed by whatever command you'd use to connect with normal screen, for example:
readscreen -S foo -x
and you'll be connected to the foo session in a read-only fashion. note that it's not extensively tested, but seems to work fine. readscreen source code:
#!/usr/bin/env php
<?php
declare(ticks = 1);
init_signals ();
$args = $argv;
unset ( $args [0] );
$args = implode ( " ", array_map ( 'escapeshellarg', $args ) );
// var_dump ( $argc, $argv, $args );
$cmd = "screen {$args}";
echo "executing cmd: $cmd\n";
$descriptorspec = array (
0 => array (
"pipe",
"rb"
) // stdin
);
$cwd = NULL;
$env = NULL;
global $screen;
$screen = proc_open ( "script --quiet --return --command " . escapeshellarg ( $cmd )." /dev/null", $descriptorspec, $pipes, $cwd, $env );
global $screen_stdin;
$screen_stdin = $pipes [0];
if (false === $screen) {
echo ("error: failed creating screen process: ");
var_dump ( error_get_last () );
die ( 1 );
}
//fclose(STDIN);
while ( 1 ) {
//echo ".";
sleep ( 1 );
if (! proc_get_status ( $screen ) ['running']) {
echo "error: screen stopped.\n";
cleanup ();
die ( 1 );
}
}
function cleanup() {
global $screen;
global $screen_stdin;
echo "detaching from screen. (running cleanup() )\n";
fwrite ( $screen_stdin, "\01" ); // equivalent of ctrl+AD apparently.
fclose ( $screen_stdin );
$exited = false;
// give it a few seconds to exit itself before killing it
for($i = 0; $i < 3; ++ $i) {
if (! proc_get_status ( $screen ) ['running']) {
$exited = true;
break;
}
sleep ( 1 );
}
if (! $exited) {
echo "Warning: screen did not exit gracefully, killing it now..";
proc_terminate ( $screen, SIGKILL );
while ( proc_get_status ( $screen ) ['running'] ) {
echo ".";
sleep ( 1 );
}
echo "killed.";
}
proc_close ( $screen );
}
function init_signals() {
global $signals;
// all signals that cause termination by default.
$signals = [
"SIGABRT",
"SIGALRM",
"SIGFPE",
"SIGHUP",
"SIGILL",
"SIGINT",
// "SIGKILL",
"SIGPIPE",
"SIGQUIT",
"SIGSEGV",
"SIGTERM",
"SIGUSR1",
"SIGUSR2",
"SIGBUS",
"SIGPOLL",
"SIGPROF",
"SIGSYS",
"SIGTRAP",
"SIGVTALRM",
"SIGXCPU",
"SIGXFSZ"
];
$signals_new = [ ];
foreach ( $signals as $key => $signal ) {
$tmp = constant ( $signal );
if ($tmp === null) {
fprintf ( STDERR, "warning: unknown signal \"%s\", may not be able to handle it without passing it to screen...\n", $singal );
unset ( $signals [$key] );
continue;
}
$signals_new [$signal] = $tmp;
}
$signals = $signals_new;
unset ( $signals_new );
foreach ( $signals as $num ) {
pcntl_signal ( $num, "signal_handler" );
}
}
function signal_handler($signo, $siginfo) {
global $signals;
$sname = array_search ( $signo, $signals, false );
if ($sname === false) {
$sname = "unknown signal";
}
echo "\n\nerror: got signal " . $signo . " (" . $sname . "), exiting screen session & returning.\n";
var_dump ( $siginfo );
cleanup ();
die ();
}

- 615