1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991, 1992, 1993, 1995, 1997, 1998
3 * Jamie Zawinski <jwz@jwz.org>
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation. No representations are made about the suitability of this
10 * software for any purpose. It is provided "as is" without express or
22 #include <X11/Xlib.h> /* not used for much... */
28 #include <sys/time.h> /* sys/resource.h needs this for timeval */
30 #ifdef HAVE_SYS_WAIT_H
31 # include <sys/wait.h> /* for waitpid() and associated macros */
34 #if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
35 # include <sys/resource.h> /* for setpriority() and PRIO_PROCESS */
39 # include <processes.h>
40 # include <unixio.h> /* for close */
41 # include <unixlib.h> /* for getpid */
46 #include <signal.h> /* for the signal names */
48 #if !defined(SIGCHLD) && defined(SIGCLD)
49 # define SIGCHLD SIGCLD
52 #if 0 /* putenv() is declared in stdlib.h on modern linux systems. */
54 extern int putenv (/* const char * */); /* getenv() is in stdlib.h... */
58 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
60 /* This file doesn't need the Xt headers, so stub these types out... */
62 #define XtAppContext void*
63 #define XrmDatabase void*
64 #define XtIntervalId void*
65 #define XtPointer void*
68 #include "xscreensaver.h"
72 extern saver_info *global_si_kludge; /* I hate C so much... */
75 nice_subproc (int nice_level)
80 #if defined(HAVE_NICE)
82 int old_nice = nice (0);
83 int n = nice_level - old_nice;
85 if (nice (n) == -1 && errno != 0)
88 sprintf (buf, "%s: nice(%d) failed", blurb(), n);
92 #elif defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
93 if (setpriority (PRIO_PROCESS, getpid(), nice_level) != 0)
96 sprintf (buf, "%s: setpriority(PRIO_PROCESS, %lu, %d) failed",
97 blurb(), (unsigned long) getpid(), nice_level);
102 "%s: don't know how to change process priority on this system.\n",
112 exec_simple_command (const char *command)
116 char *token = strtok (strdup(command), " \t");
120 token = strtok(0, " \t");
124 execvp (av[0], av); /* shouldn't return. */
128 sprintf (buf, "%s: could not execute \"%s\"", blurb(), av[0]);
131 if (errno == ENOENT &&
132 (token = getenv("PATH")))
136 # define PATH_MAX MAXPATHLEN
138 # define PATH_MAX 2048
142 fprintf (stderr, "\n");
144 # if defined(HAVE_GETCWD)
145 getcwd (path, sizeof(path));
146 # elif defined(HAVE_GETWD)
150 fprintf (stderr, " Current directory is: %s\n", path);
151 fprintf (stderr, " PATH is:\n");
152 token = strtok (strdup(token), ":");
155 fprintf (stderr, " %s\n", token);
156 token = strtok(0, ":");
158 fprintf (stderr, "\n");
163 exit (1); /* Note that this only exits a child fork. */
168 exec_complex_command (const char *shell, const char *command)
172 char *command2 = (char *) malloc (strlen (command) + 10);
175 const char *after_vars;
177 /* Skip leading whitespace.
179 while (*command == ' ' || *command == '\t')
182 /* If the string has a series of tokens with "=" in them at them, set
183 `after_vars' to point into the string after those tokens and any
184 trailing whitespace. Otherwise, after_vars == command.
186 after_vars = command;
187 for (s = command; *s; s++)
189 if (*s == '=') got_eq = 1;
194 while (*s == ' ' || *s == '\t')
205 strncat (command2, command, after_vars - command);
206 strcat (command2, "exec ");
207 strcat (command2, after_vars);
209 /* We have now done these transformations:
210 "foo -x -y" ==> "exec foo -x -y"
211 "BLAT=foop foo -x" ==> "BLAT=foop exec foo -x"
212 "BLAT=foop A=b foo -x" ==> "BLAT=foop A=b exec foo -x"
216 /* Invoke the shell as "/bin/sh -c 'exec prog -arg -arg ...'" */
217 av [ac++] = (char *) shell;
219 av [ac++] = command2;
222 execvp (av[0], av); /* shouldn't return. */
226 sprintf (buf, "%s: execvp(\"%s\") failed", blurb(), av[0]);
230 exit (1); /* Note that this only exits a child fork. */
237 exec_vms_command (const char *command)
242 exit (1); /* Note that this only exits a child fork. */
249 exec_screenhack (saver_info *si, const char *command)
251 /* I don't believe what a sorry excuse for an operating system UNIX is!
253 - I want to spawn a process.
254 - I want to know it's pid so that I can kill it.
255 - I would like to receive a message when it dies of natural causes.
256 - I want the spawned process to have user-specified arguments.
258 If shell metacharacters are present (wildcards, backquotes, etc), the
259 only way to parse those arguments is to run a shell to do the parsing
262 And the only way to know the pid of the process is to fork() and exec()
263 it in the spawned side of the fork.
265 But if you're running a shell to parse your arguments, this gives you
266 the pid of the *shell*, not the pid of the *process* that you're
267 actually interested in, which is an *inferior* of the shell. This also
268 means that the SIGCHLD you get applies to the shell, not its inferior.
269 (Why isn't that sufficient? I don't remember any more, but it turns
272 So, the only solution, when metacharacters are present, is to force the
273 shell to exec() its inferior. What a fucking hack! We prepend "exec "
274 to the command string, and hope it doesn't contain unquoted semicolons
275 or ampersands (we don't search for them, because we don't want to
276 prohibit their use in quoted strings (messages, for example) and parsing
277 out the various quote characters is too much of a pain.)
279 (Actually, Clint Wong <clint@jts.com> points out that process groups
280 might be used to take care of this problem; this may be worth considering
281 some day, except that, 1: this code works now, so why fix it, and 2: from
282 what I've seen in Emacs, dealing with process groups isn't especially
285 saver_preferences *p = &si->prefs;
288 Bool hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"=");
289 /* note: = is in the above because of the sh syntax "FOO=bar cmd". */
291 if (getuid() == (uid_t) 0 || geteuid() == (uid_t) 0)
293 /* If you're thinking of commenting this out, think again.
294 If you do so, you will open a security hole. Mail jwz
295 so that he may enlighten you as to the error of your ways.
297 fprintf (stderr, "%s: we're still running as root! Disaster!\n",
299 saver_exit (si, 1, 0);
303 fprintf (stderr, "%s: spawning \"%s\" in pid %lu%s.\n",
304 blurb(), command, (unsigned long) getpid (),
305 (hairy_p ? " (via shell)" : ""));
308 /* If it contains any shell metacharacters, do it the hard way,
309 and fork a shell to parse the arguments for us. */
310 exec_complex_command (p->shell, command);
312 /* Otherwise, we can just exec the program directly. */
313 exec_simple_command (command);
317 fprintf (stderr, "%s: spawning \"%s\" in pid %lu.\n",
318 blurb(), command, getpid());
319 exec_vms_command (command);
322 abort(); /* that shouldn't have returned. */
327 /* Management of child processes, and de-zombification.
331 job_running, /* the process is still alive */
332 job_stopped, /* we have sent it a STOP signal */
333 job_killed, /* we have sent it a TERM signal */
334 job_dead /* we have wait()ed for it, and it's dead -- this state only
335 occurs so that we can avoid calling free() from a signal
336 handler. Shortly after going into this state, the list
337 element will be removed. */
340 struct screenhack_job {
343 enum job_status status;
344 struct screenhack_job *next;
347 static struct screenhack_job *jobs = 0;
349 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
353 struct screenhack_job *job;
354 fprintf(stderr, "%s: job list:\n", blurb());
355 for (job = jobs; job; job = job->next)
356 fprintf (stderr, " %5ld: (%s) %s\n",
358 (job->status == job_running ? "running" :
359 job->status == job_stopped ? "stopped" :
360 job->status == job_killed ? " killed" :
361 job->status == job_dead ? " dead" : " ???"),
363 fprintf (stderr, "\n");
367 static void clean_job_list (void);
369 static struct screenhack_job *
370 make_job (pid_t pid, const char *cmd)
372 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
374 static char name [1024];
375 const char *in = cmd;
383 while (isspace(*in)) in++; /* skip whitespace */
384 while (!isspace(*in) && *in != ':') {
385 if (*in == '=') got_eq = 1;
386 *out++ = *in++; /* snarf first token */
389 if (got_eq) /* if the first token was FOO=bar */
390 { /* then get the next token instead. */
397 while (isspace(*in)) in++; /* skip whitespace */
400 job->name = strdup(name);
402 job->status = job_running;
411 free_job (struct screenhack_job *job)
415 else if (job == jobs)
419 struct screenhack_job *job2, *prev;
420 for (prev = 0, job2 = jobs;
422 prev = job2, job2 = job2->next)
425 prev->next = job->next;
434 /* Cleans out dead jobs from the jobs list -- this must only be called
435 from the main thread, not from a signal handler.
438 clean_job_list (void)
440 struct screenhack_job *job, *prev, *next;
441 for (prev = 0, job = jobs, next = (job ? job->next : 0);
443 prev = job, job = next, next = (job ? job->next : 0))
445 if (job->status == job_dead)
456 static struct screenhack_job *
459 struct screenhack_job *job;
460 for (job = jobs; job; job = job->next)
466 static void await_dying_children (saver_info *si);
468 static void describe_dead_child (saver_info *, pid_t, int wait_status);
472 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
473 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
475 static int block_sigchld_handler = 0;
481 #ifdef HAVE_SIGACTION
483 sigemptyset (&child_set);
484 sigaddset (&child_set, SIGCHLD);
485 sigprocmask (SIG_BLOCK, &child_set, 0);
486 #endif /* HAVE_SIGACTION */
488 block_sigchld_handler++;
492 unblock_sigchld (void)
494 #ifdef HAVE_SIGACTION
496 sigemptyset(&child_set);
497 sigaddset(&child_set, SIGCHLD);
498 sigprocmask(SIG_UNBLOCK, &child_set, 0);
499 #endif /* HAVE_SIGACTION */
501 block_sigchld_handler--;
505 kill_job (saver_info *si, pid_t pid, int signal)
507 saver_preferences *p = &si->prefs;
508 struct screenhack_job *job;
513 if (block_sigchld_handler)
514 /* This function should not be called from the signal handler. */
517 block_sigchld(); /* we control the horizontal... */
519 job = find_job (pid);
522 job->status == job_killed)
525 fprintf (stderr, "%s: no child %ld to signal!\n",
526 blurb(), (long) pid);
531 case SIGTERM: job->status = job_killed; break;
533 /* #### there must be a way to do this on VMS... */
534 case SIGSTOP: job->status = job_stopped; break;
535 case SIGCONT: job->status = job_running; break;
542 fprintf (stderr, "%s: %s pid %lu.\n", blurb(),
543 (signal == SIGTERM ? "killing" :
544 signal == SIGSTOP ? "suspending" :
545 signal == SIGCONT ? "resuming" : "signalling"),
546 (unsigned long) job->pid);
549 fprintf (stderr, "%s: %s pid %lu.\n", blurb(), "killing",
550 (unsigned long) job->pid);
551 #endif /* !SIGSTOP */
553 status = kill (job->pid, signal);
555 if (p->verbose_p && status < 0)
558 fprintf (stderr, "%s: child process %lu (%s) was already dead.\n",
559 blurb(), job->pid, job->name);
563 sprintf (buf, "%s: couldn't kill child process %lu (%s)",
564 blurb(), job->pid, job->name);
569 await_dying_children (si);
573 if (block_sigchld_handler < 0)
583 sigchld_handler (int sig)
585 saver_info *si = global_si_kludge; /* I hate C so much... */
587 if (si->prefs.debug_p)
588 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
589 (block_sigchld_handler ? " (blocked)" : ""));
591 if (block_sigchld_handler < 0)
593 else if (block_sigchld_handler == 0)
596 await_dying_children (si);
607 await_dying_children (saver_info *si)
615 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
617 if (si->prefs.debug_p)
619 if (kid < 0 && errno)
620 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
623 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
627 /* 0 means no more children to reap.
628 -1 means error -- except "interrupted system call" isn't a "real"
629 error, so if we get that, we should just try again. */
631 (kid < 0 && errno != EINTR))
634 describe_dead_child (si, kid, wait_status);
640 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
643 saver_preferences *p = &si->prefs;
644 struct screenhack_job *job = find_job (kid);
645 const char *name = job ? job->name : "<unknown>";
647 if (WIFEXITED (wait_status))
649 int exit_status = WEXITSTATUS (wait_status);
651 /* Treat exit code as a signed 8-bit quantity. */
652 if (exit_status & 0x80) exit_status |= ~0xFF;
654 /* One might assume that exiting with non-0 means something went wrong.
655 But that loser xswarm exits with the code that it was killed with, so
656 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
657 mention them) if we've just killed the subprocess. But mention them
658 if they happen on their own.
662 (p->verbose_p || job->status != job_killed)))
664 "%s: child pid %lu (%s) exited abnormally (code %d).\n",
665 blurb(), (unsigned long) kid, name, exit_status);
666 else if (p->verbose_p)
667 fprintf (stderr, "%s: child pid %lu (%s) exited normally.\n",
668 blurb(), (unsigned long) kid, name);
671 job->status = job_dead;
673 else if (WIFSIGNALED (wait_status))
677 job->status != job_killed ||
678 WTERMSIG (wait_status) != SIGTERM)
679 fprintf (stderr, "%s: child pid %lu (%s) terminated with %s.\n",
680 blurb(), (unsigned long) kid, name,
681 signal_name (WTERMSIG(wait_status)));
684 job->status = job_dead;
686 else if (WIFSTOPPED (wait_status))
689 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
690 blurb(), (unsigned long) kid, name,
691 signal_name (WSTOPSIG (wait_status)));
694 job->status = job_stopped;
698 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
699 blurb(), (unsigned long) kid, name);
701 job->status = job_dead;
704 /* Clear out the pid so that screenhack_running_p() knows it's dead.
706 if (!job || job->status == job_dead)
707 for (i = 0; i < si->nscreens; i++)
709 saver_screen_info *ssi = &si->screens[i];
716 static void await_dying_children (saver_info *si) { return; }
725 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
727 static Bool sigchld_initialized_p = 0;
728 if (!sigchld_initialized_p)
730 struct sigaction action, old;
732 action.sa_handler = sigchld_handler;
733 sigemptyset(&action.sa_mask);
736 if (sigaction(SIGCHLD, &action, &old) < 0)
739 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
742 sigchld_initialized_p = True;
745 # else /* !HAVE_SIGACTION */
747 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
750 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
753 # endif /* !HAVE_SIGACTION */
762 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
764 saver_info *si = ssi->global;
765 saver_preferences *p = &si->prefs;
768 if (hack->visual && *hack->visual)
769 selected = select_visual(ssi, hack->visual);
771 selected = select_visual(ssi, 0);
773 if (!selected && (p->verbose_p || si->demoing_p))
776 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
777 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
779 (hack->visual && *hack->visual ? hack->visual : "???"),
787 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
789 saver_info *si = ssi->global;
790 saver_preferences *p = &si->prefs;
791 raise_window (si, first_time_p, True, False);
794 if (p->screenhacks_count)
805 if (p->screenhacks_count == 1)
806 /* If there is only one hack in the list, there is no choice. */
809 else if (si->selection_mode == -1)
810 /* Select the next hack, wrapping. */
811 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
813 else if (si->selection_mode == -2)
814 /* Select the previous hack, wrapping. */
815 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
816 % p->screenhacks_count);
818 else if (si->selection_mode > 0)
819 /* Select a specific hack, by number. No negotiation. */
821 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
826 /* Select a random hack (but not the one we just ran.) */
827 while ((new_hack = random () % p->screenhacks_count)
828 == ssi->current_hack)
832 ssi->current_hack = new_hack;
833 hack = p->screenhacks[ssi->current_hack];
835 /* If the hack is disabled, or there is no visual for this hack,
836 then try again (move forward, or backward, or re-randomize.)
837 Unless this hack was specified explicitly, in which case,
841 select_visual_of_hack (ssi, hack);
845 !select_visual_of_hack (ssi, hack)))
847 if (++retry_count > (p->screenhacks_count*4))
849 /* Uh, oops. Odds are, there are no suitable visuals,
850 and we're looping. Give up. (This is totally lame,
851 what we should do is make a list of suitable hacks at
852 the beginning, then only loop over them.)
856 "%s: no suitable visuals for these programs.\n",
864 /* Turn off "next" and "prev" modes now, but "demo" mode is only
865 turned off by explicit action.
867 if (si->selection_mode < 0)
868 si->selection_mode = 0;
870 switch ((int) (forked = fork ()))
873 sprintf (buf, "%s: couldn't fork", blurb());
875 restore_real_vroot (si);
876 saver_exit (si, 1, 0);
879 close (ConnectionNumber (si->dpy)); /* close display fd */
880 nice_subproc (p->nice_inferior); /* change process priority */
881 hack_subproc_environment (ssi); /* set $DISPLAY */
882 exec_screenhack (si, hack->command); /* this does not return */
888 (void) make_job (forked, hack->command);
896 spawn_screenhack (saver_info *si, Bool first_time_p)
898 if (monitor_powered_on_p (si))
901 for (i = 0; i < si->nscreens; i++)
903 saver_screen_info *ssi = &si->screens[i];
904 spawn_screenhack_1 (ssi, first_time_p);
907 else if (si->prefs.verbose_p)
909 "%s: X says monitor has powered down; "
910 "not launching a hack.\n", blurb());
912 store_saver_status (si); /* store current hack numbers */
917 kill_screenhack (saver_info *si)
920 for (i = 0; i < si->nscreens; i++)
922 saver_screen_info *ssi = &si->screens[i];
924 kill_job (si, ssi->pid, SIGTERM);
931 suspend_screenhack (saver_info *si, Bool suspend_p)
933 #ifdef SIGSTOP /* older VMS doesn't have it... */
935 for (i = 0; i < si->nscreens; i++)
937 saver_screen_info *ssi = &si->screens[i];
939 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
945 /* Called when we're exiting abnormally, to kill off the subproc. */
947 emergency_kill_subproc (saver_info *si)
951 signal (SIGCHLD, SIG_IGN);
954 for (i = 0; i < si->nscreens; i++)
956 saver_screen_info *ssi = &si->screens[i];
959 kill_job (si, ssi->pid, SIGTERM);
966 screenhack_running_p (saver_info *si)
968 Bool any_running_p = False;
970 for (i = 0; i < si->nscreens; i++)
972 saver_screen_info *ssi = &si->screens[i];
973 if (ssi->pid) any_running_p = True;
975 return any_running_p;
979 /* Environment variables. */
982 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
983 is defined, the xscreensaver daemon will search that directory for hacks.
986 hack_environment (saver_info *si)
988 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
989 static const char *def_path = DEFAULT_PATH_PREFIX;
990 if (def_path && *def_path)
992 const char *opath = getenv("PATH");
993 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
994 strcpy (npath, "PATH=");
995 strcat (npath, def_path);
997 strcat (npath, opath);
1002 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1007 hack_subproc_environment (saver_screen_info *ssi)
1009 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1010 the spawned processes inherit is correct. First, it must be on the same
1011 host and display as the value of -display passed in on our command line
1012 (which is not necessarily the same as what our $DISPLAY variable is.)
1013 Second, the screen number in the $DISPLAY passed to the subprocess should
1014 be the screen on which this particular hack is running -- not the display
1015 specification which the driver itself is using, since the driver ignores
1016 its screen number and manages all existing screens.
1018 saver_info *si = ssi->global;
1019 const char *odpy = DisplayString (si->dpy);
1020 char *ndpy = (char *) malloc(strlen(odpy) + 20);
1024 for (screen_number = 0; screen_number < si->nscreens; screen_number++)
1025 if (ssi == &si->screens[screen_number])
1028 strcpy (ndpy, "DISPLAY=");
1029 s = ndpy + strlen(ndpy);
1032 while (*s && *s != ':') s++; /* skip to colon */
1033 while (*s == ':') s++; /* skip over colons */
1034 while (isdigit(*s)) s++; /* skip over dpy number */
1035 while (*s == '.') s++; /* skip over dot */
1036 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1037 sprintf(s, "%d", screen_number); /* put on screen number */
1039 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1040 any more, right? It's not Posix, but everyone seems to have it. */
1044 #endif /* HAVE_PUTENV */
1048 /* Restarting the xscreensaver process from scratch. */
1050 static char **saved_argv;
1053 save_argv (int argc, char **argv)
1055 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1056 saved_argv [argc] = 0;
1059 int i = strlen (argv [argc]) + 1;
1060 saved_argv [argc] = (char *) malloc (i);
1061 memcpy (saved_argv [argc], argv [argc], i);
1066 /* Re-execs the process with the arguments in saved_argv.
1067 Does not return unless there was an error.
1070 restart_process (saver_info *si)
1072 if (si->prefs.verbose_p)
1075 fprintf (real_stderr, "%s: re-executing", blurb());
1076 for (i = 0; saved_argv[i]; i++)
1077 fprintf (real_stderr, " %s", saved_argv[i]);
1078 fprintf (real_stderr, "\n");
1080 describe_uids (si, real_stderr);
1081 fprintf (real_stderr, "\n");
1083 fflush (real_stdout);
1084 fflush (real_stderr);
1085 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1088 sprintf (buf, "%s: could not restart process", blurb());