1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991-2002 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
21 #include <X11/Xlib.h> /* not used for much... */
27 #include <sys/time.h> /* sys/resource.h needs this for timeval */
29 #ifdef HAVE_SYS_WAIT_H
30 # include <sys/wait.h> /* for waitpid() and associated macros */
34 # include <sys/resource.h> /* for setrlimit() and RLIMIT_AS */
38 # include <processes.h>
39 # include <unixio.h> /* for close */
40 # include <unixlib.h> /* for getpid */
45 #include <signal.h> /* for the signal names */
47 #if !defined(SIGCHLD) && defined(SIGCLD)
48 # define SIGCHLD SIGCLD
51 #if 0 /* putenv() is declared in stdlib.h on modern linux systems. */
53 extern int putenv (/* const char * */); /* getenv() is in stdlib.h... */
57 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
59 /* This file doesn't need the Xt headers, so stub these types out... */
61 #define XtAppContext void*
62 #define XrmDatabase void*
63 #define XtIntervalId void*
64 #define XtPointer void*
67 #include "xscreensaver.h"
69 #include "visual.h" /* for id_to_visual() */
71 extern saver_info *global_si_kludge; /* I hate C so much... */
74 /* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size
75 of a process's address space, i.e., the maximal brk(2) and mmap(2) values.
76 Setting this lets you put a cap on how much memory a process can allocate.
78 Except the "and mmap()" part kinda makes this useless, since many GL
79 implementations end up using mmap() to pull the whole frame buffer into
80 memory (or something along those lines) making it appear processes are
81 using hundreds of megabytes when in fact they're using very little, and
82 we end up capping their mallocs prematurely. YAY!
84 #if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
85 # define RLIMIT_AS RLIMIT_VMEM
89 limit_subproc_memory (int address_space_limit, Bool verbose_p)
91 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS)
94 if (address_space_limit < 10 * 1024) /* let's not be crazy */
97 if (getrlimit (RLIMIT_AS, &r) != 0)
100 sprintf (buf, "%s: getrlimit(RLIMIT_AS) failed", blurb());
105 r.rlim_cur = address_space_limit;
107 if (setrlimit (RLIMIT_AS, &r) != 0)
110 sprintf (buf, "%s: setrlimit(RLIMIT_AS, {%lu, %lu}) failed",
111 blurb(), r.rlim_cur, r.rlim_max);
118 int i = address_space_limit;
120 if (i >= (1<<30) && i == ((i >> 30) << 30))
121 sprintf(buf, "%dG", i >> 30);
122 else if (i >= (1<<20) && i == ((i >> 20) << 20))
123 sprintf(buf, "%dM", i >> 20);
124 else if (i >= (1<<10) && i == ((i >> 10) << 10))
125 sprintf(buf, "%dK", i >> 10);
127 sprintf(buf, "%d bytes", i);
129 fprintf (stderr, "%s: limited pid %lu address space to %s.\n",
130 blurb(), (unsigned long) getpid (), buf);
133 #endif /* HAVE_SETRLIMIT && RLIMIT_AS */
137 /* Management of child processes, and de-zombification.
141 job_running, /* the process is still alive */
142 job_stopped, /* we have sent it a STOP signal */
143 job_killed, /* we have sent it a TERM signal */
144 job_dead /* we have wait()ed for it, and it's dead -- this state only
145 occurs so that we can avoid calling free() from a signal
146 handler. Shortly after going into this state, the list
147 element will be removed. */
150 struct screenhack_job {
154 enum job_status status;
155 struct screenhack_job *next;
158 static struct screenhack_job *jobs = 0;
160 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
164 struct screenhack_job *job;
165 fprintf(stderr, "%s: job list:\n", blurb());
166 for (job = jobs; job; job = job->next)
167 fprintf (stderr, " %5ld: %2d: (%s) %s\n",
170 (job->status == job_running ? "running" :
171 job->status == job_stopped ? "stopped" :
172 job->status == job_killed ? " killed" :
173 job->status == job_dead ? " dead" : " ???"),
175 fprintf (stderr, "\n");
179 static void clean_job_list (void);
181 static struct screenhack_job *
182 make_job (pid_t pid, int screen, const char *cmd)
184 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
186 static char name [1024];
187 const char *in = cmd;
195 while (isspace(*in)) in++; /* skip whitespace */
196 while (!isspace(*in) && *in != ':') {
197 if (*in == '=') got_eq = 1;
198 *out++ = *in++; /* snarf first token */
201 if (got_eq) /* if the first token was FOO=bar */
202 { /* then get the next token instead. */
209 while (isspace(*in)) in++; /* skip whitespace */
212 job->name = strdup(name);
214 job->screen = screen;
215 job->status = job_running;
224 free_job (struct screenhack_job *job)
228 else if (job == jobs)
232 struct screenhack_job *job2, *prev;
233 for (prev = 0, job2 = jobs;
235 prev = job2, job2 = job2->next)
238 prev->next = job->next;
247 /* Cleans out dead jobs from the jobs list -- this must only be called
248 from the main thread, not from a signal handler.
251 clean_job_list (void)
253 struct screenhack_job *job, *prev, *next;
254 for (prev = 0, job = jobs, next = (job ? job->next : 0);
256 prev = job, job = next, next = (job ? job->next : 0))
258 if (job->status == job_dead)
269 static struct screenhack_job *
272 struct screenhack_job *job;
273 for (job = jobs; job; job = job->next)
279 static void await_dying_children (saver_info *si);
281 static void describe_dead_child (saver_info *, pid_t, int wait_status);
285 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
286 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
288 static int block_sigchld_handler = 0;
294 #ifdef HAVE_SIGACTION
296 sigemptyset (&child_set);
297 sigaddset (&child_set, SIGCHLD);
298 sigprocmask (SIG_BLOCK, &child_set, 0);
299 #endif /* HAVE_SIGACTION */
301 block_sigchld_handler++;
305 unblock_sigchld (void)
307 #ifdef HAVE_SIGACTION
309 sigemptyset(&child_set);
310 sigaddset(&child_set, SIGCHLD);
311 sigprocmask(SIG_UNBLOCK, &child_set, 0);
312 #endif /* HAVE_SIGACTION */
314 block_sigchld_handler--;
318 kill_job (saver_info *si, pid_t pid, int signal)
320 saver_preferences *p = &si->prefs;
321 struct screenhack_job *job;
326 if (block_sigchld_handler)
327 /* This function should not be called from the signal handler. */
330 block_sigchld(); /* we control the horizontal... */
332 job = find_job (pid);
335 job->status == job_killed)
338 fprintf (stderr, "%s: no child %ld to signal!\n",
339 blurb(), (long) pid);
344 case SIGTERM: job->status = job_killed; break;
346 /* #### there must be a way to do this on VMS... */
347 case SIGSTOP: job->status = job_stopped; break;
348 case SIGCONT: job->status = job_running; break;
354 fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
355 blurb(), job->screen,
356 (job->status == job_killed ? "killing" :
357 job->status == job_stopped ? "suspending" : "resuming"),
358 (unsigned long) job->pid,
361 status = kill (job->pid, signal);
363 if (p->verbose_p && status < 0)
367 "%s: %d: child process %lu (%s) was already dead.\n",
368 blurb(), job->screen, (unsigned long) job->pid, job->name);
372 sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
373 blurb(), job->screen, (unsigned long) job->pid, job->name);
378 await_dying_children (si);
382 if (block_sigchld_handler < 0)
392 sigchld_handler (int sig)
394 saver_info *si = global_si_kludge; /* I hate C so much... */
396 if (si->prefs.debug_p)
397 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
398 (block_sigchld_handler ? " (blocked)" : ""));
400 if (block_sigchld_handler < 0)
402 else if (block_sigchld_handler == 0)
405 await_dying_children (si);
416 await_dying_children (saver_info *si)
424 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
426 if (si->prefs.debug_p)
428 if (kid < 0 && errno)
429 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
432 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
436 /* 0 means no more children to reap.
437 -1 means error -- except "interrupted system call" isn't a "real"
438 error, so if we get that, we should just try again. */
440 (kid < 0 && errno != EINTR))
443 describe_dead_child (si, kid, wait_status);
449 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
452 saver_preferences *p = &si->prefs;
453 struct screenhack_job *job = find_job (kid);
454 const char *name = job ? job->name : "<unknown>";
455 int screen_no = job ? job->screen : 0;
457 if (WIFEXITED (wait_status))
459 int exit_status = WEXITSTATUS (wait_status);
461 /* Treat exit code as a signed 8-bit quantity. */
462 if (exit_status & 0x80) exit_status |= ~0xFF;
464 /* One might assume that exiting with non-0 means something went wrong.
465 But that loser xswarm exits with the code that it was killed with, so
466 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
467 mention them) if we've just killed the subprocess. But mention them
468 if they happen on their own.
472 (p->verbose_p || job->status != job_killed)))
474 "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
475 blurb(), screen_no, (unsigned long) kid, name, exit_status);
476 else if (p->verbose_p)
477 fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
478 blurb(), screen_no, (unsigned long) kid, name);
481 job->status = job_dead;
483 else if (WIFSIGNALED (wait_status))
487 job->status != job_killed ||
488 WTERMSIG (wait_status) != SIGTERM)
489 fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
490 blurb(), screen_no, (unsigned long) kid, name,
491 signal_name (WTERMSIG(wait_status)));
494 job->status = job_dead;
496 else if (WIFSTOPPED (wait_status))
499 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
500 blurb(), (unsigned long) kid, name,
501 signal_name (WSTOPSIG (wait_status)));
504 job->status = job_stopped;
508 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
509 blurb(), (unsigned long) kid, name);
511 job->status = job_dead;
514 /* Clear out the pid so that screenhack_running_p() knows it's dead.
516 if (!job || job->status == job_dead)
517 for (i = 0; i < si->nscreens; i++)
519 saver_screen_info *ssi = &si->screens[i];
526 static void await_dying_children (saver_info *si) { return; }
535 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
537 static Bool sigchld_initialized_p = 0;
538 if (!sigchld_initialized_p)
540 struct sigaction action, old;
542 action.sa_handler = sigchld_handler;
543 sigemptyset(&action.sa_mask);
546 if (sigaction(SIGCHLD, &action, &old) < 0)
549 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
552 sigchld_initialized_p = True;
555 # else /* !HAVE_SIGACTION */
557 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
560 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
563 # endif /* !HAVE_SIGACTION */
572 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
574 saver_info *si = ssi->global;
575 saver_preferences *p = &si->prefs;
578 if (hack->visual && *hack->visual)
579 selected = select_visual(ssi, hack->visual);
581 selected = select_visual(ssi, 0);
583 if (!selected && (p->verbose_p || si->demoing_p))
586 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
587 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
589 (hack->visual && *hack->visual ? hack->visual : "???"),
597 print_path_error (const char *program)
600 char *cmd = strdup (program);
601 char *token = strchr (cmd, ' ');
603 if (token) *token = 0;
604 sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
608 if (errno == ENOENT &&
609 (token = getenv("PATH")))
613 # define PATH_MAX MAXPATHLEN
615 # define PATH_MAX 2048
619 fprintf (stderr, "\n");
621 # if defined(HAVE_GETCWD)
622 getcwd (path, sizeof(path));
623 # elif defined(HAVE_GETWD)
627 fprintf (stderr, " Current directory is: %s\n", path);
628 fprintf (stderr, " PATH is:\n");
629 token = strtok (strdup(token), ":");
632 fprintf (stderr, " %s\n", token);
633 token = strtok(0, ":");
635 fprintf (stderr, "\n");
641 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
643 saver_info *si = ssi->global;
644 saver_preferences *p = &si->prefs;
645 raise_window (si, first_time_p, True, False);
648 if (p->screenhacks_count)
659 if (p->screenhacks_count < 1)
661 /* No hacks at all */
664 else if (si->selection_mode == -1)
666 /* Select the next hack, wrapping. */
667 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
669 else if (si->selection_mode == -2)
671 /* Select the previous hack, wrapping. */
672 if (ssi->current_hack < 0)
673 new_hack = p->screenhacks_count - 1;
675 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
676 % p->screenhacks_count);
678 else if (si->selection_mode > 0)
680 /* Select a specific hack, by number (via the ACTIVATE command.) */
681 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
684 else if (p->mode == ONE_HACK &&
685 p->selected_hack >= 0)
687 /* Select a specific hack, by number (via "One Saver" mode.) */
688 new_hack = p->selected_hack;
691 else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
695 else /* (p->mode == RANDOM_HACKS) */
697 /* Select a random hack (but not the one we just ran.) */
698 while ((new_hack = random () % p->screenhacks_count)
699 == ssi->current_hack)
703 if (new_hack < 0) /* don't run a hack */
705 ssi->current_hack = -1;
706 if (si->selection_mode < 0)
707 si->selection_mode = 0;
711 ssi->current_hack = new_hack;
712 hack = p->screenhacks[ssi->current_hack];
714 /* If the hack is disabled, or there is no visual for this hack,
715 then try again (move forward, or backward, or re-randomize.)
716 Unless this hack was specified explicitly, in which case,
720 select_visual_of_hack (ssi, hack);
724 !select_visual_of_hack (ssi, hack)))
726 if (++retry_count > (p->screenhacks_count*4))
728 /* Uh, oops. Odds are, there are no suitable visuals,
729 and we're looping. Give up. (This is totally lame,
730 what we should do is make a list of suitable hacks at
731 the beginning, then only loop over them.)
735 "%s: %d: no programs enabled, or no suitable visuals.\n",
736 blurb(), ssi->number);
743 /* Turn off "next" and "prev" modes now, but "demo" mode is only
744 turned off by explicit action.
746 if (si->selection_mode < 0)
747 si->selection_mode = 0;
749 switch ((int) (forked = fork ()))
752 sprintf (buf, "%s: couldn't fork", blurb());
754 restore_real_vroot (si);
755 saver_exit (si, 1, 0);
758 close (ConnectionNumber (si->dpy)); /* close display fd */
759 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
760 hack_subproc_environment (ssi); /* set $DISPLAY */
763 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
764 blurb(), ssi->number, hack->command,
765 (unsigned long) getpid ());
767 exec_command (p->shell, hack->command, p->nice_inferior);
769 /* If that returned, we were unable to exec the subprocess.
770 Print an error message, if desired.
772 if (! p->ignore_uninstalled_p)
773 print_path_error (hack->command);
775 exit (1); /* exits child fork */
780 (void) make_job (forked, ssi->number, hack->command);
788 spawn_screenhack (saver_info *si, Bool first_time_p)
790 if (monitor_powered_on_p (si))
793 for (i = 0; i < si->nscreens; i++)
795 saver_screen_info *ssi = &si->screens[i];
796 spawn_screenhack_1 (ssi, first_time_p);
799 else if (si->prefs.verbose_p)
801 "%s: X says monitor has powered down; "
802 "not launching a hack.\n", blurb());
804 store_saver_status (si); /* store current hack numbers */
809 kill_screenhack (saver_info *si)
812 for (i = 0; i < si->nscreens; i++)
814 saver_screen_info *ssi = &si->screens[i];
816 kill_job (si, ssi->pid, SIGTERM);
823 suspend_screenhack (saver_info *si, Bool suspend_p)
825 #ifdef SIGSTOP /* older VMS doesn't have it... */
827 for (i = 0; i < si->nscreens; i++)
829 saver_screen_info *ssi = &si->screens[i];
831 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
837 /* Called when we're exiting abnormally, to kill off the subproc. */
839 emergency_kill_subproc (saver_info *si)
843 signal (SIGCHLD, SIG_IGN);
846 for (i = 0; i < si->nscreens; i++)
848 saver_screen_info *ssi = &si->screens[i];
851 kill_job (si, ssi->pid, SIGTERM);
858 screenhack_running_p (saver_info *si)
860 Bool any_running_p = False;
862 for (i = 0; i < si->nscreens; i++)
864 saver_screen_info *ssi = &si->screens[i];
865 if (ssi->pid) any_running_p = True;
867 return any_running_p;
871 /* Environment variables. */
874 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
875 is defined, the xscreensaver daemon will search that directory for hacks.
878 hack_environment (saver_info *si)
880 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
881 static const char *def_path = DEFAULT_PATH_PREFIX;
882 if (def_path && *def_path)
884 const char *opath = getenv("PATH");
885 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
886 strcpy (npath, "PATH=");
887 strcat (npath, def_path);
889 strcat (npath, opath);
894 /* don't free (npath) -- some implementations of putenv (BSD 4.4,
895 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
896 do not. So we must leak it (and/or the previous setting). Yay.
899 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
904 hack_subproc_environment (saver_screen_info *ssi)
906 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
907 the spawned processes inherit is correct. First, it must be on the same
908 host and display as the value of -display passed in on our command line
909 (which is not necessarily the same as what our $DISPLAY variable is.)
910 Second, the screen number in the $DISPLAY passed to the subprocess should
911 be the screen on which this particular hack is running -- not the display
912 specification which the driver itself is using, since the driver ignores
913 its screen number and manages all existing screens.
915 saver_info *si = ssi->global;
916 const char *odpy = DisplayString (si->dpy);
917 char *ndpy = (char *) malloc(strlen(odpy) + 20);
920 strcpy (ndpy, "DISPLAY=");
921 s = ndpy + strlen(ndpy);
924 while (*s && *s != ':') s++; /* skip to colon */
925 while (*s == ':') s++; /* skip over colons */
926 while (isdigit(*s)) s++; /* skip over dpy number */
927 while (*s == '.') s++; /* skip over dot */
928 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
929 sprintf(s, "%d", ssi->number); /* put on screen number */
931 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
932 any more, right? It's not Posix, but everyone seems to have it. */
936 /* do not free(ndpy) -- see above. */
937 #endif /* HAVE_PUTENV */
944 get_best_gl_visual (saver_screen_info *ssi)
946 saver_info *si = ssi->global;
955 av[ac++] = "xscreensaver-gl-helper";
960 perror ("error creating pipe:");
967 switch ((int) (forked = fork ()))
971 sprintf (buf, "%s: couldn't fork", blurb());
973 saver_exit (si, 1, 0);
979 close (in); /* don't need this one */
980 close (ConnectionNumber (si->dpy)); /* close display fd */
982 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
984 perror ("could not dup() a new stdout:");
987 hack_subproc_environment (ssi); /* set $DISPLAY */
989 execvp (av[0], av); /* shouldn't return. */
991 if (errno != ENOENT || si->prefs.verbose_p)
993 /* Ignore "no such file or directory" errors, unless verbose.
994 Issue all other exec errors, though. */
995 sprintf (buf, "%s: running %s", blurb(), av[0]);
998 exit (1); /* exits fork */
1004 int wait_status = 0;
1006 FILE *f = fdopen (in, "r");
1007 unsigned long v = 0;
1010 close (out); /* don't need this one */
1013 fgets (buf, sizeof(buf)-1, f);
1016 /* Wait for the child to die. */
1017 waitpid (-1, &wait_status, 0);
1019 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1024 if (si->prefs.verbose_p)
1026 int L = strlen(buf);
1027 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1030 if (L && buf[L-1] == '\n')
1033 fprintf (stderr, "%s: %s said: \"%s\"\n",
1034 blurb(), av[0], buf);
1040 Visual *v = id_to_visual (ssi->screen, result);
1041 if (si->prefs.verbose_p)
1042 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1043 blurb(), ssi->number,
1045 (v == ssi->default_visual ? " (default)" : ""));
1056 /* Restarting the xscreensaver process from scratch. */
1058 static char **saved_argv;
1061 save_argv (int argc, char **argv)
1063 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1064 saved_argv [argc] = 0;
1067 int i = strlen (argv [argc]) + 1;
1068 saved_argv [argc] = (char *) malloc (i);
1069 memcpy (saved_argv [argc], argv [argc], i);
1074 /* Re-execs the process with the arguments in saved_argv. Does not return.
1077 restart_process (saver_info *si)
1081 shutdown_stderr (si);
1082 if (si->prefs.verbose_p)
1085 fprintf (stderr, "%s: re-executing", blurb());
1086 for (i = 0; saved_argv[i]; i++)
1087 fprintf (stderr, " %s", saved_argv[i]);
1088 fprintf (stderr, "\n");
1090 describe_uids (si, stderr);
1091 fprintf (stderr, "\n");
1095 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1098 sprintf (buf, "%s: could not restart process", blurb());