1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991-2003 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 (p->screenhacks_count == 1)
666 /* Exactly one hack in the list */
669 else if (si->selection_mode == -1)
671 /* Select the next hack, wrapping. */
672 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
674 else if (si->selection_mode == -2)
676 /* Select the previous hack, wrapping. */
677 if (ssi->current_hack < 0)
678 new_hack = p->screenhacks_count - 1;
680 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
681 % p->screenhacks_count);
683 else if (si->selection_mode > 0)
685 /* Select a specific hack, by number (via the ACTIVATE command.) */
686 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
689 else if (p->mode == ONE_HACK &&
690 p->selected_hack >= 0)
692 /* Select a specific hack, by number (via "One Saver" mode.) */
693 new_hack = p->selected_hack;
696 else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
700 else /* (p->mode == RANDOM_HACKS) */
702 /* Select a random hack (but not the one we just ran.) */
703 while ((new_hack = random () % p->screenhacks_count)
704 == ssi->current_hack)
708 if (new_hack < 0) /* don't run a hack */
710 ssi->current_hack = -1;
711 if (si->selection_mode < 0)
712 si->selection_mode = 0;
716 ssi->current_hack = new_hack;
717 hack = p->screenhacks[ssi->current_hack];
719 /* If the hack is disabled, or there is no visual for this hack,
720 then try again (move forward, or backward, or re-randomize.)
721 Unless this hack was specified explicitly, in which case,
725 select_visual_of_hack (ssi, hack);
729 !select_visual_of_hack (ssi, hack)))
731 if (++retry_count > (p->screenhacks_count*4))
733 /* Uh, oops. Odds are, there are no suitable visuals,
734 and we're looping. Give up. (This is totally lame,
735 what we should do is make a list of suitable hacks at
736 the beginning, then only loop over them.)
740 "%s: %d: no programs enabled, or no suitable visuals.\n",
741 blurb(), ssi->number);
748 /* Turn off "next" and "prev" modes now, but "demo" mode is only
749 turned off by explicit action.
751 if (si->selection_mode < 0)
752 si->selection_mode = 0;
754 switch ((int) (forked = fork ()))
757 sprintf (buf, "%s: couldn't fork", blurb());
759 restore_real_vroot (si);
760 saver_exit (si, 1, 0);
763 close (ConnectionNumber (si->dpy)); /* close display fd */
764 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
765 hack_subproc_environment (ssi); /* set $DISPLAY */
768 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
769 blurb(), ssi->number, hack->command,
770 (unsigned long) getpid ());
772 exec_command (p->shell, hack->command, p->nice_inferior);
774 /* If that returned, we were unable to exec the subprocess.
775 Print an error message, if desired.
777 if (! p->ignore_uninstalled_p)
778 print_path_error (hack->command);
780 exit (1); /* exits child fork */
785 (void) make_job (forked, ssi->number, hack->command);
793 spawn_screenhack (saver_info *si, Bool first_time_p)
795 if (monitor_powered_on_p (si))
798 for (i = 0; i < si->nscreens; i++)
800 saver_screen_info *ssi = &si->screens[i];
801 spawn_screenhack_1 (ssi, first_time_p);
804 else if (si->prefs.verbose_p)
806 "%s: X says monitor has powered down; "
807 "not launching a hack.\n", blurb());
809 store_saver_status (si); /* store current hack numbers */
814 kill_screenhack (saver_info *si)
817 for (i = 0; i < si->nscreens; i++)
819 saver_screen_info *ssi = &si->screens[i];
821 kill_job (si, ssi->pid, SIGTERM);
828 suspend_screenhack (saver_info *si, Bool suspend_p)
830 #ifdef SIGSTOP /* older VMS doesn't have it... */
832 for (i = 0; i < si->nscreens; i++)
834 saver_screen_info *ssi = &si->screens[i];
836 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
842 /* Called when we're exiting abnormally, to kill off the subproc. */
844 emergency_kill_subproc (saver_info *si)
848 signal (SIGCHLD, SIG_IGN);
851 for (i = 0; i < si->nscreens; i++)
853 saver_screen_info *ssi = &si->screens[i];
856 kill_job (si, ssi->pid, SIGTERM);
863 screenhack_running_p (saver_info *si)
865 Bool any_running_p = False;
867 for (i = 0; i < si->nscreens; i++)
869 saver_screen_info *ssi = &si->screens[i];
870 if (ssi->pid) any_running_p = True;
872 return any_running_p;
876 /* Environment variables. */
879 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
880 is defined, the xscreensaver daemon will search that directory for hacks.
883 hack_environment (saver_info *si)
885 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
886 static const char *def_path = DEFAULT_PATH_PREFIX;
887 if (def_path && *def_path)
889 const char *opath = getenv("PATH");
890 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
891 strcpy (npath, "PATH=");
892 strcat (npath, def_path);
894 strcat (npath, opath);
899 /* don't free (npath) -- some implementations of putenv (BSD 4.4,
900 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
901 do not. So we must leak it (and/or the previous setting). Yay.
904 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
909 hack_subproc_environment (saver_screen_info *ssi)
911 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
912 the spawned processes inherit is correct. First, it must be on the same
913 host and display as the value of -display passed in on our command line
914 (which is not necessarily the same as what our $DISPLAY variable is.)
915 Second, the screen number in the $DISPLAY passed to the subprocess should
916 be the screen on which this particular hack is running -- not the display
917 specification which the driver itself is using, since the driver ignores
918 its screen number and manages all existing screens.
920 saver_info *si = ssi->global;
921 const char *odpy = DisplayString (si->dpy);
922 char *ndpy = (char *) malloc(strlen(odpy) + 20);
925 strcpy (ndpy, "DISPLAY=");
926 s = ndpy + strlen(ndpy);
929 while (*s && *s != ':') s++; /* skip to colon */
930 while (*s == ':') s++; /* skip over colons */
931 while (isdigit(*s)) s++; /* skip over dpy number */
932 while (*s == '.') s++; /* skip over dot */
933 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
934 sprintf(s, "%d", ssi->number); /* put on screen number */
936 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
937 any more, right? It's not Posix, but everyone seems to have it. */
941 /* do not free(ndpy) -- see above. */
942 #endif /* HAVE_PUTENV */
949 get_best_gl_visual (saver_screen_info *ssi)
951 saver_info *si = ssi->global;
960 av[ac++] = "xscreensaver-gl-helper";
965 perror ("error creating pipe:");
972 switch ((int) (forked = fork ()))
976 sprintf (buf, "%s: couldn't fork", blurb());
978 saver_exit (si, 1, 0);
984 close (in); /* don't need this one */
985 close (ConnectionNumber (si->dpy)); /* close display fd */
987 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
989 perror ("could not dup() a new stdout:");
992 hack_subproc_environment (ssi); /* set $DISPLAY */
994 execvp (av[0], av); /* shouldn't return. */
996 if (errno != ENOENT || si->prefs.verbose_p)
998 /* Ignore "no such file or directory" errors, unless verbose.
999 Issue all other exec errors, though. */
1000 sprintf (buf, "%s: running %s", blurb(), av[0]);
1003 exit (1); /* exits fork */
1009 int wait_status = 0;
1011 FILE *f = fdopen (in, "r");
1012 unsigned long v = 0;
1015 close (out); /* don't need this one */
1018 fgets (buf, sizeof(buf)-1, f);
1021 /* Wait for the child to die. */
1022 waitpid (-1, &wait_status, 0);
1024 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1029 if (si->prefs.verbose_p)
1031 int L = strlen(buf);
1032 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1035 if (L && buf[L-1] == '\n')
1038 fprintf (stderr, "%s: %s said: \"%s\"\n",
1039 blurb(), av[0], buf);
1045 Visual *v = id_to_visual (ssi->screen, result);
1046 if (si->prefs.verbose_p)
1047 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1048 blurb(), ssi->number,
1050 (v == ssi->default_visual ? " (default)" : ""));
1061 /* Restarting the xscreensaver process from scratch. */
1063 static char **saved_argv;
1066 save_argv (int argc, char **argv)
1068 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1069 saved_argv [argc] = 0;
1072 int i = strlen (argv [argc]) + 1;
1073 saved_argv [argc] = (char *) malloc (i);
1074 memcpy (saved_argv [argc], argv [argc], i);
1079 /* Re-execs the process with the arguments in saved_argv. Does not return.
1082 restart_process (saver_info *si)
1086 shutdown_stderr (si);
1087 if (si->prefs.verbose_p)
1090 fprintf (stderr, "%s: re-executing", blurb());
1091 for (i = 0; saved_argv[i]; i++)
1092 fprintf (stderr, " %s", saved_argv[i]);
1093 fprintf (stderr, "\n");
1095 describe_uids (si, stderr);
1096 fprintf (stderr, "\n");
1100 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1103 sprintf (buf, "%s: could not restart process", blurb());