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 */
398 if (first && *in == ':') /* token was a visual name; skip it. */
406 job->name = strdup(name);
408 job->status = job_running;
417 free_job (struct screenhack_job *job)
421 else if (job == jobs)
425 struct screenhack_job *job2, *prev;
426 for (prev = 0, job2 = jobs;
428 prev = job2, job2 = job2->next)
431 prev->next = job->next;
440 /* Cleans out dead jobs from the jobs list -- this must only be called
441 from the main thread, not from a signal handler.
444 clean_job_list (void)
446 struct screenhack_job *job, *prev, *next;
447 for (prev = 0, job = jobs, next = (job ? job->next : 0);
449 prev = job, job = next, next = (job ? job->next : 0))
451 if (job->status == job_dead)
462 static struct screenhack_job *
465 struct screenhack_job *job;
466 for (job = jobs; job; job = job->next)
472 static void await_dying_children (saver_info *si);
474 static void describe_dead_child (saver_info *, pid_t, int wait_status);
478 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
479 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
481 static int block_sigchld_handler = 0;
487 #ifdef HAVE_SIGACTION
489 sigemptyset (&child_set);
490 sigaddset (&child_set, SIGCHLD);
491 sigprocmask (SIG_BLOCK, &child_set, 0);
492 #endif /* HAVE_SIGACTION */
494 block_sigchld_handler++;
498 unblock_sigchld (void)
500 #ifdef HAVE_SIGACTION
502 sigemptyset(&child_set);
503 sigaddset(&child_set, SIGCHLD);
504 sigprocmask(SIG_UNBLOCK, &child_set, 0);
505 #endif /* HAVE_SIGACTION */
507 block_sigchld_handler--;
511 kill_job (saver_info *si, pid_t pid, int signal)
513 saver_preferences *p = &si->prefs;
514 struct screenhack_job *job;
519 if (block_sigchld_handler)
520 /* This function should not be called from the signal handler. */
523 block_sigchld(); /* we control the horizontal... */
525 job = find_job (pid);
528 job->status == job_killed)
531 fprintf (stderr, "%s: no child %ld to signal!\n",
532 blurb(), (long) pid);
537 case SIGTERM: job->status = job_killed; break;
539 /* #### there must be a way to do this on VMS... */
540 case SIGSTOP: job->status = job_stopped; break;
541 case SIGCONT: job->status = job_running; break;
548 fprintf (stderr, "%s: %s pid %lu.\n", blurb(),
549 (signal == SIGTERM ? "killing" :
550 signal == SIGSTOP ? "suspending" :
551 signal == SIGCONT ? "resuming" : "signalling"),
552 (unsigned long) job->pid);
555 fprintf (stderr, "%s: %s pid %lu.\n", blurb(), "killing",
556 (unsigned long) job->pid);
557 #endif /* !SIGSTOP */
559 status = kill (job->pid, signal);
561 if (p->verbose_p && status < 0)
564 fprintf (stderr, "%s: child process %lu (%s) was already dead.\n",
565 blurb(), job->pid, job->name);
569 sprintf (buf, "%s: couldn't kill child process %lu (%s)",
570 blurb(), job->pid, job->name);
575 await_dying_children (si);
579 if (block_sigchld_handler < 0)
589 sigchld_handler (int sig)
591 saver_info *si = global_si_kludge; /* I hate C so much... */
593 if (si->prefs.debug_p)
594 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
595 (block_sigchld_handler ? " (blocked)" : ""));
597 if (block_sigchld_handler < 0)
599 else if (block_sigchld_handler == 0)
602 await_dying_children (si);
613 await_dying_children (saver_info *si)
621 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
623 if (si->prefs.debug_p)
625 if (kid < 0 && errno)
626 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
629 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
633 /* 0 means no more children to reap.
634 -1 means error -- except "interrupted system call" isn't a "real"
635 error, so if we get that, we should just try again. */
637 (kid < 0 && errno != EINTR))
640 describe_dead_child (si, kid, wait_status);
646 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
649 saver_preferences *p = &si->prefs;
650 struct screenhack_job *job = find_job (kid);
651 const char *name = job ? job->name : "<unknown>";
653 if (WIFEXITED (wait_status))
655 int exit_status = WEXITSTATUS (wait_status);
657 /* Treat exit code as a signed 8-bit quantity. */
658 if (exit_status & 0x80) exit_status |= ~0xFF;
660 /* One might assume that exiting with non-0 means something went wrong.
661 But that loser xswarm exits with the code that it was killed with, so
662 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
663 mention them) if we've just killed the subprocess. But mention them
664 if they happen on their own.
668 (p->verbose_p || job->status != job_killed)))
670 "%s: child pid %lu (%s) exited abnormally (code %d).\n",
671 blurb(), (unsigned long) kid, name, exit_status);
672 else if (p->verbose_p)
673 fprintf (stderr, "%s: child pid %lu (%s) exited normally.\n",
674 blurb(), (unsigned long) kid, name);
677 job->status = job_dead;
679 else if (WIFSIGNALED (wait_status))
683 job->status != job_killed ||
684 WTERMSIG (wait_status) != SIGTERM)
685 fprintf (stderr, "%s: child pid %lu (%s) terminated with %s.\n",
686 blurb(), (unsigned long) kid, name,
687 signal_name (WTERMSIG(wait_status)));
690 job->status = job_dead;
692 else if (WIFSTOPPED (wait_status))
695 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
696 blurb(), (unsigned long) kid, name,
697 signal_name (WSTOPSIG (wait_status)));
700 job->status = job_stopped;
704 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
705 blurb(), (unsigned long) kid, name);
707 job->status = job_dead;
710 /* Clear out the pid so that screenhack_running_p() knows it's dead.
712 if (!job || job->status == job_dead)
713 for (i = 0; i < si->nscreens; i++)
715 saver_screen_info *ssi = &si->screens[i];
722 static void await_dying_children (saver_info *si) { return; }
731 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
733 static Bool sigchld_initialized_p = 0;
734 if (!sigchld_initialized_p)
736 struct sigaction action, old;
738 action.sa_handler = sigchld_handler;
739 sigemptyset(&action.sa_mask);
742 if (sigaction(SIGCHLD, &action, &old) < 0)
745 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
748 sigchld_initialized_p = True;
751 # else /* !HAVE_SIGACTION */
753 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
756 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
759 # endif /* !HAVE_SIGACTION */
768 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
770 saver_info *si = ssi->global;
771 saver_preferences *p = &si->prefs;
774 if (hack->visual && *hack->visual == ':')
775 selected = select_visual(ssi, hack->visual);
777 selected = select_visual(ssi, 0);
779 if (!selected && (p->verbose_p || si->demoing_p))
782 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
783 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
785 (hack->visual && *hack->visual ? hack->visual : "???"),
793 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
795 saver_info *si = ssi->global;
796 saver_preferences *p = &si->prefs;
797 raise_window (si, first_time_p, True, False);
800 if (p->screenhacks_count)
811 if (p->screenhacks_count == 1)
812 /* If there is only one hack in the list, there is no choice. */
815 else if (si->selection_mode == -1)
816 /* Select the next hack, wrapping. */
817 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
819 else if (si->selection_mode == -2)
820 /* Select the previous hack, wrapping. */
821 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
822 % p->screenhacks_count);
824 else if (si->selection_mode > 0)
825 /* Select a specific hack, by number. No negotiation. */
827 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
832 /* Select a random hack (but not the one we just ran.) */
833 while ((new_hack = random () % p->screenhacks_count)
834 == ssi->current_hack)
838 ssi->current_hack = new_hack;
839 hack = p->screenhacks[ssi->current_hack];
841 /* If the hack is disabled, or there is no visual for this hack,
842 then try again (move forward, or backward, or re-randomize.)
843 Unless this hack was specified explicitly, in which case,
847 select_visual_of_hack (ssi, hack);
851 !select_visual_of_hack (ssi, hack)))
853 if (++retry_count > (p->screenhacks_count*4))
855 /* Uh, oops. Odds are, there are no suitable visuals,
856 and we're looping. Give up. (This is totally lame,
857 what we should do is make a list of suitable hacks at
858 the beginning, then only loop over them.)
862 "%s: no suitable visuals for these programs.\n",
870 /* Turn off "next" and "prev" modes now, but "demo" mode is only
871 turned off by explicit action.
873 if (si->selection_mode < 0)
874 si->selection_mode = 0;
876 switch ((int) (forked = fork ()))
879 sprintf (buf, "%s: couldn't fork", blurb());
881 restore_real_vroot (si);
882 saver_exit (si, 1, 0);
885 close (ConnectionNumber (si->dpy)); /* close display fd */
886 nice_subproc (p->nice_inferior); /* change process priority */
887 hack_subproc_environment (ssi); /* set $DISPLAY */
888 exec_screenhack (si, hack->command); /* this does not return */
894 (void) make_job (forked, hack->command);
902 spawn_screenhack (saver_info *si, Bool first_time_p)
904 if (monitor_powered_on_p (si))
907 for (i = 0; i < si->nscreens; i++)
909 saver_screen_info *ssi = &si->screens[i];
910 spawn_screenhack_1 (ssi, first_time_p);
913 else if (si->prefs.verbose_p)
915 "%s: server reports that monitor has powered down; "
916 "not launching a new hack.\n", blurb());
918 store_saver_status (si); /* store current hack numbers */
923 kill_screenhack (saver_info *si)
926 for (i = 0; i < si->nscreens; i++)
928 saver_screen_info *ssi = &si->screens[i];
930 kill_job (si, ssi->pid, SIGTERM);
937 suspend_screenhack (saver_info *si, Bool suspend_p)
939 #ifdef SIGSTOP /* older VMS doesn't have it... */
941 for (i = 0; i < si->nscreens; i++)
943 saver_screen_info *ssi = &si->screens[i];
945 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
951 /* Called when we're exiting abnormally, to kill off the subproc. */
953 emergency_kill_subproc (saver_info *si)
957 signal (SIGCHLD, SIG_IGN);
960 for (i = 0; i < si->nscreens; i++)
962 saver_screen_info *ssi = &si->screens[i];
965 kill_job (si, ssi->pid, SIGTERM);
972 screenhack_running_p (saver_info *si)
976 for (i = 0; i < si->nscreens; i++)
978 saver_screen_info *ssi = &si->screens[i];
986 /* Environment variables. */
989 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
990 is defined, the xscreensaver daemon will search that directory for hacks.
993 hack_environment (saver_info *si)
995 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
996 static const char *def_path = DEFAULT_PATH_PREFIX;
997 if (def_path && *def_path)
999 const char *opath = getenv("PATH");
1000 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1001 strcpy (npath, "PATH=");
1002 strcat (npath, def_path);
1003 strcat (npath, ":");
1004 strcat (npath, opath);
1009 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1014 hack_subproc_environment (saver_screen_info *ssi)
1016 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1017 the spawned processes inherit is correct. First, it must be on the same
1018 host and display as the value of -display passed in on our command line
1019 (which is not necessarily the same as what our $DISPLAY variable is.)
1020 Second, the screen number in the $DISPLAY passed to the subprocess should
1021 be the screen on which this particular hack is running -- not the display
1022 specification which the driver itself is using, since the driver ignores
1023 its screen number and manages all existing screens.
1025 saver_info *si = ssi->global;
1026 const char *odpy = DisplayString (si->dpy);
1027 char *ndpy = (char *) malloc(strlen(odpy) + 20);
1031 for (screen_number = 0; screen_number < si->nscreens; screen_number++)
1032 if (ssi == &si->screens[screen_number])
1035 strcpy (ndpy, "DISPLAY=");
1036 s = ndpy + strlen(ndpy);
1039 while (*s && *s != ':') s++; /* skip to colon */
1040 while (*s == ':') s++; /* skip over colons */
1041 while (isdigit(*s)) s++; /* skip over dpy number */
1042 while (*s == '.') s++; /* skip over dot */
1043 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1044 sprintf(s, "%d", screen_number); /* put on screen number */
1046 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1047 any more, right? It's not Posix, but everyone seems to have it. */
1051 #endif /* HAVE_PUTENV */
1055 /* Restarting the xscreensaver process from scratch. */
1057 static char **saved_argv;
1060 save_argv (int argc, char **argv)
1062 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1063 saved_argv [argc] = 0;
1066 int i = strlen (argv [argc]) + 1;
1067 saved_argv [argc] = (char *) malloc (i);
1068 memcpy (saved_argv [argc], argv [argc], i);
1073 /* Re-execs the process with the arguments in saved_argv.
1074 Does not return unless there was an error.
1077 restart_process (saver_info *si)
1079 if (si->prefs.verbose_p)
1082 fprintf (real_stderr, "%s: re-executing", blurb());
1083 for (i = 0; saved_argv[i]; i++)
1084 fprintf (real_stderr, " %s", saved_argv[i]);
1085 fprintf (real_stderr, "\n");
1087 describe_uids (si, real_stderr);
1088 fprintf (real_stderr, "\n");
1090 fflush (real_stdout);
1091 fflush (real_stderr);
1092 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1095 sprintf (buf, "%s: could not restart process", blurb());