Shell Script That Runs Forever

    #!/bin/sh
    echo yes
    sleep 42

Critics will point out that this script will not run forever due to e.g. the heat death of the universe, the hardware running the script failing, the human getting bored, etc. However given a running system this script will (probably) run forever, the lite version of forever that ignores our daystar going all red giant.

The script does need a bit of help to run "forever". One lever is that shell scripts take pains to operate line-by-line, to ape an ape at a terminal. Either shells read single bytes to find where the next line is, or they read chunks and use lseek(2) to scoot the file pointer back to the start of the current line. This can be observed under ktrace(1) or similar, which is a great way to learn what system calls a process makes while going about its business. Especially if there are too many lines of code to easily follow what some too complicated shell is doing.

    $ echo echo echo | ktrace sh -
    echo
    $ kdump | fgrep 'read 1'
     32926 sh       GIO   fd 3 read 1499 bytes
     32926 sh       RET   read 1499/0x5db
     32926 sh       GIO   fd 0 read 1 bytes
     32926 sh       RET   read 1
     32926 sh       GIO   fd 0 read 1 bytes
     32926 sh       RET   read 1
    ...
Another bit of information you may need to know is that some file descriptors are shared between processes. This is what dup(2) is going on about:

> The object referenced by the descriptor does not distinguish between oldd and newd in any way.  Thus if newd and oldd are duplicate references to an open file, read(2), write(2) and lseek(2) calls all move a single pointer into the file, and append mode, non-blocking I/O and asynchronous I/O options are shared between the references.  If a separate pointer into the file is desired, a different object reference to the file must be obtained by issuing an additional open(2) call.
=> http://man.openbsd.org/man2/dup.2

Therefore, given a file descriptor that is shared between a shell and some other program, the other program can periodically lseek(2) the file descriptor back to the beginning of the file, which will cause the script to run "forever".

#!/usr/bin/env perl

use File::Temp 'tempfile';

my $fh = tempfile();

print $fh <<'FOREVER';

#!/bin/sh

echo yes

sleep 42

FOREVER

seek $fh, 0, 0;

my $pid = fork // die "Aaaaaaargh: $!\n";

if ( $pid == 0 ) {

    close STDIN;

    open STDIN, '<&', $fh;

    exec 'sh';

    die "Aaaaaaargh: $!\n";

}

while (1) { seek $fh, 0, 0; sleep 1 }

Proxy Information
Original URL
gemini://thrig.me/blog/2023/06/09/shell-script-that-runs-forever.gmi
Status Code
Success (20)
Meta
text/gemini
Capsule Response Time
1013.960106 milliseconds
Gemini-to-HTML Time
0.541775 milliseconds

This content has been proxied by September (3851b).