-/* xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>
+/* xscreensaver, Copyright (c) 1991, 1992, 1993, 1995
+ * Jamie Zawinski <jwz@netscape.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* implied warranty.
*/
+/* I would really like some error messages to show up on the screensaver window
+ itself when subprocs die, or when we can't launch them. If the process
+ produces output, but does not actually die, I would like that output to go
+ to the appropriate stdout/stderr as they do now. X and Unix conspire to
+ make this incredibly difficult.
+
+ - Not all systems have SIGIO, so we can't necessarily be signalled when a
+ process dies, so we'd have to poll it with wait() or something awful like
+ that, which would mean the main thread waking up more often than it does
+ now.
+
+ - We can't tell the difference between a process dying, and a process not
+ being launched correctly (for example, not being on $PATH) partly because
+ of the contortions we need to go through with /bin/sh in order to launch
+ it.
+
+ - We can't do X stuff from signal handlers, so we'd need to set a flag,
+ save the error message, and notice that flag in the main thread. The
+ problem is that the main thread is probably sleeping, waiting for the
+ next X event, so to do this we'd have to register a pipe FD or something,
+ and write to it when something loses.
+
+ - We could assume that any output produced by a subproc indicates an error,
+ and blast that across the screen. This means we'd need to use popen()
+ instead of forking and execing /bin/sh to run it for us. Possibly this
+ would work, but see comment in exec_screenhack() about getting pids.
+ I think we could do the "exec " trick with popen() but would SIGIO get
+ delivered correctly? Who knows. (We could register the pipe-FD with
+ Xt, and handle output on it with a callback.)
+
+ - For the simple case of the programs not being on $PATH, we could just
+ search $PATH before launching the shell, but that seems hardly worth the
+ effort... And it's broken!! Why should we have to duplicate half the
+ work of the shell? (Because it's Unix, that's why! Bend over.)
+ */
+
#if __STDC__
#include <stdlib.h>
#include <unistd.h>
extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
#endif
-# if defined(SVR4) || defined(SYSV)
-# undef PRIO_PROCESS
-# define random() rand()
-# else /* !totally-losing-SYSV */
-extern long random(); /* rand() is in stdlib.h... */
-# endif /* !totally-losing-SYSV */
-
-
+#include "yarandom.h"
#include "xscreensaver.h"
/* this must be `sh', not whatever $SHELL happens to be. */
extern Bool demo_mode_p;
static void
+#if __STDC__
+exec_screenhack (char *command)
+#else
exec_screenhack (command)
char *command;
+#endif
{
char *tmp;
char buf [512];
So, the only solution other than implementing an argument parser here
is to force the shell to exec() its inferior. What a fucking hack!
We prepend "exec " to the command string.
+
+ (Actually, Clint Wong <clint@jts.com> points out that process groups
+ might be used to take care of this problem; this may be worth considering
+ some day, except that, 1: this code works now, so why fix it, and 2: from
+ what I've seen in Emacs, dealing with process groups isn't especially
+ portable.)
*/
tmp = command;
command = (char *) malloc (strlen (tmp) + 6);
if (verbose_p)
printf ("%s: spawning \"%s\" in pid %d.\n", progname, command, getpid ());
-#if defined(SYSV) || defined(__hpux)
+#if defined(SYSV) || defined(SVR4) || defined(__hpux)
{
int old_nice = nice (0);
int n = nice_inferior - old_nice;
sprintf (buf, "%s: %sexecve() failed", progname, (verbose_p ? "## " : ""));
perror (buf);
- exit (1); /* Note this this only exits a child fork. */
+ exit (1); /* Note that this only exits a child fork. */
}
/* to avoid a race between the main thread and the SIGCHLD handler */
static char *current_hack_name P((void));
static void
+#if __STDC__
+await_child_death (Bool killed)
+#else
await_child_death (killed)
Bool killed;
+#endif
{
Bool suspended_p = False;
int status;
int exit_status = WEXITSTATUS (status);
if (exit_status & 0x80)
exit_status |= ~0xFF;
- if (exit_status != 0 && verbose_p)
- printf ("%s: child pid %d (%s) exited abnormally (code %d).\n",
- progname, pid, current_hack_name (), exit_status);
+ /* One might assume that exiting with non-0 means something went
+ wrong. But that loser xswarm exits with the code that it was
+ killed with, so it *always* exits abnormally. Treat abnormal
+ exits as "normal" (don't mention them) if we've just killed
+ the subprocess. But mention them if they happen on their own.
+ */
+ if (exit_status != 0 && (verbose_p || (! killed)))
+ fprintf (stderr,
+ "%s: %schild pid %d (%s) exited abnormally (code %d).\n",
+ progname, (verbose_p ? "## " : ""),
+ pid, current_hack_name (), exit_status);
else if (verbose_p)
printf ("%s: child pid %d (%s) exited normally.\n",
progname, pid, current_hack_name ());