pfr Try:
runx.sh
#!/bin/sh
set -eu -o pipefail
die() { echo >&2 "$0: $*"; exit 1; }
test -e /tmp/.X0-lock && die "X server already running"
export XAUTHORITY=$HOME/.Xauthority # judge dredd
SA=$(mktemp $HOME/.serverauth.XXXXXX) # more XXXs => more hardcore
CK=$(/usr/bin/openssl rand -hex 16) # make cookie
test -z "$CK" && die "couldn't make cookie"
trap "rm -f '$SA' '$XAUTHORITY'" EXIT HUP INT QUIT ILL TRAP BUS TERM
# trap "" TSTP # no shell with Ctrl-Z
echo "add :0 . $CK" | xauth -q -f $SA # guts
unset CK # leave no cookie behind
cp -fp $SA $XAUTHORITY # assume 1 server 1 session
# off to the races
xinit $HOME/.xinitrc -- /usr/X11R7/bin/X :0 -auth $SA
runsafe.c
/**
* Run a program/script safe from interruption by Ctrl-C:
* - fork.
* - do setsid() in the child (so signals are never delivered to it).
* - ignore signals _only_ in parent (so that, if needed, the child
* can still be killed by sending it a SIGINT).
*
* The program is meant to prevent scripts like startx(1) from granting
* shell-access via Ctrl-C/Ctrl-Z (and you don't want, for some reason,
* to run the X server with: Option DontVTSwitch "on").
* These shell scripts, or the xinit(1) program:
* a) are long-running
* b) are non-interactive, so the don't need a controlling terminal,
* and
* c) spawn many other processes which should not be run with those
* signals ignored (as they would be (usually) if you ignored the
* signals in the calling script using: trap '' TSTP).
*
* Usage: in startx(1), ignore SIGTSTP and add runsafe before the xinit(1)
* command (full path required.):
*
* trap '' TSTP # ignore Ctrl-Z in shell & runsafe
* runsafe /usr/X11R7/bin/xinit ~/.xinitrc -- /usr/X11R7/bin/X :0
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <err.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void
dummy(int signo)
{
(void)signo;
}
int
main(int argc, char* argv[])
{
pid_t pid = -1;
int status = 0;
if (argc < 2) {
fprintf(stderr, "Usage: %s prog args...\n", *argv);
return EXIT_FAILURE;
}
switch (pid = fork()) {
case -1:
err(EXIT_FAILURE, "fork failed");
case 0: /* child */
signal(SIGINT, SIG_DFL); /* default SIGINT */
signal(SIGTSTP, SIG_DFL); /* default SIGTSTP */
if (setsid() == -1)
err(EXIT_FAILURE, "setsid failed");
execv(argv[1], argv + 1);
err(EXIT_FAILURE, "%s: execv failed", argv[1]);
default: /* parent */
signal(SIGINT, SIG_IGN); /* ignore Ctrl-C */
/*
* do an orderly shutdown on SIGTERM;
* other signals deliberately left as-is.
*/
signal(SIGTERM, dummy);
siginterrupt(SIGTERM, 1);
if (wait(&status) != pid)
warn("warning: wait failed");
if ((pid = getpgid(pid)) == 0)
killpg(pid, SIGTERM); /* kill pgrp stragglers */
break;
}
return WIFEXITED(status) ? WEXITSTATUS(status) : 128+WTERMSIG(status);
}