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) + 6);
173 memcpy (command2, "exec ", 5);
174 memcpy (command2 + 5, command, strlen (command) + 1);
176 /* Invoke the shell as "/bin/sh -c 'exec prog -arg -arg ...'" */
177 av [ac++] = (char *) shell;
179 av [ac++] = command2;
182 execvp (av[0], av); /* shouldn't return. */
186 sprintf (buf, "%s: execvp(\"%s\") failed", blurb(), av[0]);
190 exit (1); /* Note that this only exits a child fork. */
197 exec_vms_command (const char *command)
202 exit (1); /* Note that this only exits a child fork. */
209 exec_screenhack (saver_info *si, const char *command)
211 /* I don't believe what a sorry excuse for an operating system UNIX is!
213 - I want to spawn a process.
214 - I want to know it's pid so that I can kill it.
215 - I would like to receive a message when it dies of natural causes.
216 - I want the spawned process to have user-specified arguments.
218 If shell metacharacters are present (wildcards, backquotes, etc), the
219 only way to parse those arguments is to run a shell to do the parsing
222 And the only way to know the pid of the process is to fork() and exec()
223 it in the spawned side of the fork.
225 But if you're running a shell to parse your arguments, this gives you
226 the pid of the *shell*, not the pid of the *process* that you're
227 actually interested in, which is an *inferior* of the shell. This also
228 means that the SIGCHLD you get applies to the shell, not its inferior.
229 (Why isn't that sufficient? I don't remember any more, but it turns
232 So, the only solution, when metacharacters are present, is to force the
233 shell to exec() its inferior. What a fucking hack! We prepend "exec "
234 to the command string, and hope it doesn't contain unquoted semicolons
235 or ampersands (we don't search for them, because we don't want to
236 prohibit their use in quoted strings (messages, for example) and parsing
237 out the various quote characters is too much of a pain.)
239 (Actually, Clint Wong <clint@jts.com> points out that process groups
240 might be used to take care of this problem; this may be worth considering
241 some day, except that, 1: this code works now, so why fix it, and 2: from
242 what I've seen in Emacs, dealing with process groups isn't especially
245 saver_preferences *p = &si->prefs;
248 Bool hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"=");
249 /* note: = is in the above because of the sh syntax "FOO=bar cmd". */
251 if (getuid() == (uid_t) 0 || geteuid() == (uid_t) 0)
253 /* If you're thinking of commenting this out, think again.
254 If you do so, you will open a security hole. Mail jwz
255 so that he may enlighten you as to the error of your ways.
257 fprintf (stderr, "%s: we're still running as root! Disaster!\n",
259 saver_exit (si, 1, 0);
263 fprintf (stderr, "%s: spawning \"%s\" in pid %lu%s.\n",
264 blurb(), command, (unsigned long) getpid (),
265 (hairy_p ? " (via shell)" : ""));
268 /* If it contains any shell metacharacters, do it the hard way,
269 and fork a shell to parse the arguments for us. */
270 exec_complex_command (p->shell, command);
272 /* Otherwise, we can just exec the program directly. */
273 exec_simple_command (command);
277 fprintf (stderr, "%s: spawning \"%s\" in pid %lu.\n",
278 blurb(), command, getpid());
279 exec_vms_command (command);
282 abort(); /* that shouldn't have returned. */
287 /* Management of child processes, and de-zombification.
291 job_running, /* the process is still alive */
292 job_stopped, /* we have sent it a STOP signal */
293 job_killed, /* we have sent it a TERM signal */
294 job_dead /* we have wait()ed for it, and it's dead -- this state only
295 occurs so that we can avoid calling free() from a signal
296 handler. Shortly after going into this state, the list
297 element will be removed. */
300 struct screenhack_job {
303 enum job_status status;
304 struct screenhack_job *next;
307 static struct screenhack_job *jobs = 0;
309 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
313 struct screenhack_job *job;
314 fprintf(stderr, "%s: job list:\n", blurb());
315 for (job = jobs; job; job = job->next)
316 fprintf (stderr, " %5ld: (%s) %s\n",
318 (job->status == job_running ? "running" :
319 job->status == job_stopped ? "stopped" :
320 job->status == job_killed ? " killed" :
321 job->status == job_dead ? " dead" : " ???"),
323 fprintf (stderr, "\n");
327 static void clean_job_list (void);
329 static struct screenhack_job *
330 make_job (pid_t pid, const char *cmd)
332 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
334 static char name [1024];
335 const char *in = cmd;
340 while (isspace(*in)) in++; /* skip whitespace */
341 while (!isspace(*in) && *in != ':')
342 *out++ = *in++; /* snarf first token */
343 while (isspace(*in)) in++; /* skip whitespace */
344 if (*in == ':') /* token was a visual name; skip it. */
348 while (isspace(*in)) in++; /* skip whitespace */
349 while (!isspace(*in)) *out++ = *in++; /* snarf first token */
353 job->name = strdup(name);
355 job->status = job_running;
364 free_job (struct screenhack_job *job)
368 else if (job == jobs)
372 struct screenhack_job *job2, *prev;
373 for (prev = 0, job2 = jobs;
375 prev = job2, job2 = job2->next)
378 prev->next = job->next;
387 /* Cleans out dead jobs from the jobs list -- this must only be called
388 from the main thread, not from a signal handler.
391 clean_job_list (void)
393 struct screenhack_job *job, *prev, *next;
394 for (prev = 0, job = jobs, next = (job ? job->next : 0);
396 prev = job, job = next, next = (job ? job->next : 0))
398 if (job->status == job_dead)
409 static struct screenhack_job *
412 struct screenhack_job *job;
413 for (job = jobs; job; job = job->next)
419 static void await_dying_children (saver_info *si);
421 static void describe_dead_child (saver_info *, pid_t, int wait_status);
425 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
426 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
428 static int block_sigchld_handler = 0;
434 #ifdef HAVE_SIGACTION
436 sigemptyset (&child_set);
437 sigaddset (&child_set, SIGCHLD);
438 sigprocmask (SIG_BLOCK, &child_set, 0);
439 #endif /* HAVE_SIGACTION */
441 block_sigchld_handler++;
445 unblock_sigchld (void)
447 #ifdef HAVE_SIGACTION
449 sigemptyset(&child_set);
450 sigaddset(&child_set, SIGCHLD);
451 sigprocmask(SIG_UNBLOCK, &child_set, 0);
452 #endif /* HAVE_SIGACTION */
454 block_sigchld_handler--;
458 kill_job (saver_info *si, pid_t pid, int signal)
460 saver_preferences *p = &si->prefs;
461 struct screenhack_job *job;
466 if (block_sigchld_handler)
467 /* This function should not be called from the signal handler. */
470 block_sigchld(); /* we control the horizontal... */
472 job = find_job (pid);
475 job->status == job_killed)
478 fprintf (stderr, "%s: no child %ld to signal!\n",
479 blurb(), (long) pid);
484 case SIGTERM: job->status = job_killed; break;
486 /* #### there must be a way to do this on VMS... */
487 case SIGSTOP: job->status = job_stopped; break;
488 case SIGCONT: job->status = job_running; break;
495 fprintf (stderr, "%s: %s pid %lu.\n", blurb(),
496 (signal == SIGTERM ? "killing" :
497 signal == SIGSTOP ? "suspending" :
498 signal == SIGCONT ? "resuming" : "signalling"),
499 (unsigned long) job->pid);
502 fprintf (stderr, "%s: %s pid %lu.\n", blurb(), "killing",
503 (unsigned long) job->pid);
504 #endif /* !SIGSTOP */
506 status = kill (job->pid, signal);
508 if (p->verbose_p && status < 0)
511 fprintf (stderr, "%s: child process %lu (%s) was already dead.\n",
512 blurb(), job->pid, job->name);
516 sprintf (buf, "%s: couldn't kill child process %lu (%s)",
517 blurb(), job->pid, job->name);
522 await_dying_children (si);
526 if (block_sigchld_handler < 0)
536 sigchld_handler (int sig)
538 saver_info *si = global_si_kludge; /* I hate C so much... */
540 if (si->prefs.debug_p)
541 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
542 (block_sigchld_handler ? " (blocked)" : ""));
544 if (block_sigchld_handler < 0)
546 else if (block_sigchld_handler == 0)
549 await_dying_children (si);
560 await_dying_children (saver_info *si)
568 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
570 if (si->prefs.debug_p)
572 if (kid < 0 && errno)
573 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
576 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
580 /* 0 means no more children to reap.
581 -1 means error -- except "interrupted system call" isn't a "real"
582 error, so if we get that, we should just try again. */
584 (kid < 0 && errno != EINTR))
587 describe_dead_child (si, kid, wait_status);
593 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
596 saver_preferences *p = &si->prefs;
597 struct screenhack_job *job = find_job (kid);
598 const char *name = job ? job->name : "<unknown>";
600 if (WIFEXITED (wait_status))
602 int exit_status = WEXITSTATUS (wait_status);
604 /* Treat exit code as a signed 8-bit quantity. */
605 if (exit_status & 0x80) exit_status |= ~0xFF;
607 /* One might assume that exiting with non-0 means something went wrong.
608 But that loser xswarm exits with the code that it was killed with, so
609 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
610 mention them) if we've just killed the subprocess. But mention them
611 if they happen on their own.
615 (p->verbose_p || job->status != job_killed)))
617 "%s: child pid %lu (%s) exited abnormally (code %d).\n",
618 blurb(), (unsigned long) kid, name, exit_status);
619 else if (p->verbose_p)
620 fprintf (stderr, "%s: child pid %lu (%s) exited normally.\n",
621 blurb(), (unsigned long) kid, name);
624 job->status = job_dead;
626 else if (WIFSIGNALED (wait_status))
630 job->status != job_killed ||
631 WTERMSIG (wait_status) != SIGTERM)
632 fprintf (stderr, "%s: child pid %lu (%s) terminated with %s.\n",
633 blurb(), (unsigned long) kid, name,
634 signal_name (WTERMSIG(wait_status)));
637 job->status = job_dead;
639 else if (WIFSTOPPED (wait_status))
642 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
643 blurb(), (unsigned long) kid, name,
644 signal_name (WSTOPSIG (wait_status)));
647 job->status = job_stopped;
651 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
652 blurb(), (unsigned long) kid, name);
654 job->status = job_dead;
657 /* Clear out the pid so that screenhack_running_p() knows it's dead.
659 if (!job || job->status == job_dead)
660 for (i = 0; i < si->nscreens; i++)
662 saver_screen_info *ssi = &si->screens[i];
669 static void await_dying_children (saver_info *si) { return; }
678 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
680 static Bool sigchld_initialized_p = 0;
681 if (!sigchld_initialized_p)
683 struct sigaction action, old;
685 action.sa_handler = sigchld_handler;
686 sigemptyset(&action.sa_mask);
689 if (sigaction(SIGCHLD, &action, &old) < 0)
692 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
695 sigchld_initialized_p = True;
698 # else /* !HAVE_SIGACTION */
700 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
703 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
706 # endif /* !HAVE_SIGACTION */
715 hack_enabled_p (const char *hack)
717 const char *s = hack;
718 while (isspace(*s)) s++;
723 select_visual_of_hack (saver_screen_info *ssi, const char *hack)
725 saver_info *si = ssi->global;
726 saver_preferences *p = &si->prefs;
728 static char vis [1024];
729 const char *in = hack;
731 while (isspace(*in)) in++; /* skip whitespace */
732 if (*in == '-') in++; /* skip optional "-" */
733 while (isspace(*in)) in++; /* skip whitespace */
735 while (!isspace(*in) && *in != ':')
736 *out++ = *in++; /* snarf first token */
737 while (isspace(*in)) in++; /* skip whitespace */
741 selected = select_visual(ssi, vis);
743 selected = select_visual(ssi, 0);
745 if (!selected && (p->verbose_p || si->demoing_p))
747 if (*in == ':') in++;
748 while (isspace(*in)) in++;
751 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
752 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
753 blurb(), (*vis ? vis : "???"), in);
761 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
763 saver_info *si = ssi->global;
764 saver_preferences *p = &si->prefs;
765 raise_window (si, first_time_p, True, False);
768 if (p->screenhacks_count)
779 if (p->screenhacks_count == 1)
780 /* If there is only one hack in the list, there is no choice. */
783 else if (si->selection_mode == -1)
784 /* Select the next hack, wrapping. */
785 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
787 else if (si->selection_mode == -2)
788 /* Select the previous hack, wrapping. */
789 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
790 % p->screenhacks_count);
792 else if (si->selection_mode > 0)
793 /* Select a specific hack, by number. No negotiation. */
795 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
800 /* Select a random hack (but not the one we just ran.) */
801 while ((new_hack = random () % p->screenhacks_count)
802 == ssi->current_hack)
806 ssi->current_hack = new_hack;
807 hack = p->screenhacks[ssi->current_hack];
809 /* If the hack is disabled, or there is no visual for this hack,
810 then try again (move forward, or backward, or re-randomize.)
811 Unless this hack was specified explicitly, in which case,
815 select_visual_of_hack (ssi, hack);
818 (!hack_enabled_p (hack) ||
819 !select_visual_of_hack (ssi, hack)))
821 if (++retry_count > (p->screenhacks_count*4))
823 /* Uh, oops. Odds are, there are no suitable visuals,
824 and we're looping. Give up. (This is totally lame,
825 what we should do is make a list of suitable hacks at
826 the beginning, then only loop over them.)
830 "%s: no suitable visuals for these programs.\n",
838 /* Turn off "next" and "prev" modes now, but "demo" mode is only
839 turned off by explicit action.
841 if (si->selection_mode < 0)
842 si->selection_mode = 0;
845 /* If there's a visual description on the front of the command, nuke it.
849 while (isspace(*in)) in++; /* skip whitespace */
850 if (*in == '-') in++; /* skip optional "-" */
851 while (isspace(*in)) in++; /* skip whitespace */
853 while (!isspace(*in) && *in != ':') in++; /* snarf first token */
854 while (isspace(*in)) in++; /* skip whitespace */
858 while (isspace(*in)) in++;
863 switch ((int) (forked = fork ()))
866 sprintf (buf, "%s: couldn't fork", blurb());
868 restore_real_vroot (si);
869 saver_exit (si, 1, 0);
872 close (ConnectionNumber (si->dpy)); /* close display fd */
873 nice_subproc (p->nice_inferior); /* change process priority */
874 hack_subproc_environment (ssi); /* set $DISPLAY */
875 exec_screenhack (si, hack); /* this does not return */
881 (void) make_job (forked, hack);
889 spawn_screenhack (saver_info *si, Bool first_time_p)
893 if (!monitor_powered_on_p (si))
895 if (si->prefs.verbose_p)
897 "%s: server reports that monitor has powered down; "
898 "not launching a new hack.\n", blurb());
902 for (i = 0; i < si->nscreens; i++)
904 saver_screen_info *ssi = &si->screens[i];
905 spawn_screenhack_1 (ssi, first_time_p);
911 kill_screenhack (saver_info *si)
914 for (i = 0; i < si->nscreens; i++)
916 saver_screen_info *ssi = &si->screens[i];
918 kill_job (si, ssi->pid, SIGTERM);
925 suspend_screenhack (saver_info *si, Bool suspend_p)
927 #ifdef SIGSTOP /* older VMS doesn't have it... */
929 for (i = 0; i < si->nscreens; i++)
931 saver_screen_info *ssi = &si->screens[i];
933 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
939 /* Called when we're exiting abnormally, to kill off the subproc. */
941 emergency_kill_subproc (saver_info *si)
945 signal (SIGCHLD, SIG_IGN);
948 for (i = 0; i < si->nscreens; i++)
950 saver_screen_info *ssi = &si->screens[i];
953 kill_job (si, ssi->pid, SIGTERM);
960 screenhack_running_p (saver_info *si)
964 for (i = 0; i < si->nscreens; i++)
966 saver_screen_info *ssi = &si->screens[i];
974 /* Environment variables. */
977 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
978 is defined, the xscreensaver daemon will search that directory for hacks.
981 hack_environment (saver_info *si)
983 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
984 static const char *def_path = DEFAULT_PATH_PREFIX;
985 if (def_path && *def_path)
987 const char *opath = getenv("PATH");
988 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
989 strcpy (npath, "PATH=");
990 strcat (npath, def_path);
992 strcat (npath, opath);
997 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1002 hack_subproc_environment (saver_screen_info *ssi)
1004 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1005 the spawned processes inherit is correct. First, it must be on the same
1006 host and display as the value of -display passed in on our command line
1007 (which is not necessarily the same as what our $DISPLAY variable is.)
1008 Second, the screen number in the $DISPLAY passed to the subprocess should
1009 be the screen on which this particular hack is running -- not the display
1010 specification which the driver itself is using, since the driver ignores
1011 its screen number and manages all existing screens.
1013 saver_info *si = ssi->global;
1014 const char *odpy = DisplayString (si->dpy);
1015 char *ndpy = (char *) malloc(strlen(odpy) + 20);
1019 for (screen_number = 0; screen_number < si->nscreens; screen_number++)
1020 if (ssi == &si->screens[screen_number])
1023 strcpy (ndpy, "DISPLAY=");
1024 s = ndpy + strlen(ndpy);
1027 while (*s && *s != ':') s++; /* skip to colon */
1028 while (*s == ':') s++; /* skip over colons */
1029 while (isdigit(*s)) s++; /* skip over dpy number */
1030 while (*s == '.') s++; /* skip over dot */
1031 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1032 sprintf(s, "%d", screen_number); /* put on screen number */
1034 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1035 any more, right? It's not Posix, but everyone seems to have it. */
1039 #endif /* HAVE_PUTENV */
1043 /* Restarting the xscreensaver process from scratch. */
1045 static char **saved_argv;
1048 save_argv (int argc, char **argv)
1050 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1051 saved_argv [argc] = 0;
1054 int i = strlen (argv [argc]) + 1;
1055 saved_argv [argc] = (char *) malloc (i);
1056 memcpy (saved_argv [argc], argv [argc], i);
1061 /* Re-execs the process with the arguments in saved_argv.
1062 Does not return unless there was an error.
1065 restart_process (saver_info *si)
1067 if (si->prefs.verbose_p)
1070 fprintf (real_stderr, "%s: re-executing", blurb());
1071 for (i = 0; saved_argv[i]; i++)
1072 fprintf (real_stderr, " %s", saved_argv[i]);
1073 fprintf (real_stderr, "\n");
1075 describe_uids (si, real_stderr);
1076 fprintf (real_stderr, "\n");
1078 fflush (real_stdout);
1079 fflush (real_stderr);
1080 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1083 sprintf (buf, "%s: could not restart process", blurb());