1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991-2005 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 /* Used when printing error/debugging messages from signal handlers.
77 no_malloc_number_to_string (long num)
79 static char string[128] = "";
81 Bool negative_p = False;
94 while ((num > 0) && (num_digits < sizeof(string - 1)))
97 digit = (int) num % 10;
99 string[sizeof(string) - 1 - num_digits] = digit + '0';
106 string[sizeof(string) - 1 - num_digits] = '-';
109 return string + sizeof(string) - 1 - num_digits;
112 /* Like write(), but runs strlen() on the arg to get the length. */
114 write_string (int fd, const char *str)
116 return write (fd, str, strlen (str));
120 write_long (int fd, long n)
122 const char *str = no_malloc_number_to_string (n);
123 return write_string (fd, str);
127 /* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size
128 of a process's address space, i.e., the maximal brk(2) and mmap(2) values.
129 Setting this lets you put a cap on how much memory a process can allocate.
131 Except the "and mmap()" part kinda makes this useless, since many GL
132 implementations end up using mmap() to pull the whole frame buffer into
133 memory (or something along those lines) making it appear processes are
134 using hundreds of megabytes when in fact they're using very little, and
135 we end up capping their mallocs prematurely. YAY!
137 #if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
138 # define RLIMIT_AS RLIMIT_VMEM
142 limit_subproc_memory (int address_space_limit, Bool verbose_p)
145 /* This has caused way more problems than it has solved...
146 Let's just completely ignore the "memoryLimit" option now.
148 #undef HAVE_SETRLIMIT
150 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS)
153 if (address_space_limit < 10 * 1024) /* let's not be crazy */
156 if (getrlimit (RLIMIT_AS, &r) != 0)
159 sprintf (buf, "%s: getrlimit(RLIMIT_AS) failed", blurb());
164 r.rlim_cur = address_space_limit;
166 if (setrlimit (RLIMIT_AS, &r) != 0)
169 sprintf (buf, "%s: setrlimit(RLIMIT_AS, {%lu, %lu}) failed",
170 blurb(), r.rlim_cur, r.rlim_max);
177 int i = address_space_limit;
179 if (i >= (1<<30) && i == ((i >> 30) << 30))
180 sprintf(buf, "%dG", i >> 30);
181 else if (i >= (1<<20) && i == ((i >> 20) << 20))
182 sprintf(buf, "%dM", i >> 20);
183 else if (i >= (1<<10) && i == ((i >> 10) << 10))
184 sprintf(buf, "%dK", i >> 10);
186 sprintf(buf, "%d bytes", i);
188 fprintf (stderr, "%s: limited pid %lu address space to %s.\n",
189 blurb(), (unsigned long) getpid (), buf);
192 #endif /* HAVE_SETRLIMIT && RLIMIT_AS */
196 /* Management of child processes, and de-zombification.
200 job_running, /* the process is still alive */
201 job_stopped, /* we have sent it a STOP signal */
202 job_killed, /* we have sent it a TERM signal */
203 job_dead /* we have wait()ed for it, and it's dead -- this state only
204 occurs so that we can avoid calling free() from a signal
205 handler. Shortly after going into this state, the list
206 element will be removed. */
209 struct screenhack_job {
213 enum job_status status;
214 struct screenhack_job *next;
217 static struct screenhack_job *jobs = 0;
219 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
223 struct screenhack_job *job;
224 fprintf(stderr, "%s: job list:\n", blurb());
225 for (job = jobs; job; job = job->next)
226 fprintf (stderr, " %5ld: %2d: (%s) %s\n",
229 (job->status == job_running ? "running" :
230 job->status == job_stopped ? "stopped" :
231 job->status == job_killed ? " killed" :
232 job->status == job_dead ? " dead" : " ???"),
234 fprintf (stderr, "\n");
238 static void clean_job_list (void);
240 static struct screenhack_job *
241 make_job (pid_t pid, int screen, const char *cmd)
243 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
245 static char name [1024];
246 const char *in = cmd;
254 while (isspace(*in)) in++; /* skip whitespace */
255 while (!isspace(*in) && *in != ':') {
256 if (*in == '=') got_eq = 1;
257 *out++ = *in++; /* snarf first token */
260 if (got_eq) /* if the first token was FOO=bar */
261 { /* then get the next token instead. */
268 while (isspace(*in)) in++; /* skip whitespace */
271 job->name = strdup(name);
273 job->screen = screen;
274 job->status = job_running;
283 free_job (struct screenhack_job *job)
287 else if (job == jobs)
291 struct screenhack_job *job2, *prev;
292 for (prev = 0, job2 = jobs;
294 prev = job2, job2 = job2->next)
297 prev->next = job->next;
306 /* Cleans out dead jobs from the jobs list -- this must only be called
307 from the main thread, not from a signal handler.
310 clean_job_list (void)
312 struct screenhack_job *job, *prev, *next;
313 for (prev = 0, job = jobs, next = (job ? job->next : 0);
315 prev = job, job = next, next = (job ? job->next : 0))
317 if (job->status == job_dead)
328 static struct screenhack_job *
331 struct screenhack_job *job;
332 for (job = jobs; job; job = job->next)
338 static void await_dying_children (saver_info *si);
340 static void describe_dead_child (saver_info *, pid_t, int wait_status);
344 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
345 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
347 static int block_sigchld_handler = 0;
350 #ifdef HAVE_SIGACTION
352 #else /* !HAVE_SIGACTION */
354 #endif /* !HAVE_SIGACTION */
357 #ifdef HAVE_SIGACTION
359 sigemptyset (&child_set);
360 sigaddset (&child_set, SIGCHLD);
361 sigaddset (&child_set, SIGPIPE);
362 sigprocmask (SIG_BLOCK, &child_set, 0);
363 #endif /* HAVE_SIGACTION */
365 block_sigchld_handler++;
367 #ifdef HAVE_SIGACTION
369 #else /* !HAVE_SIGACTION */
371 #endif /* !HAVE_SIGACTION */
375 unblock_sigchld (void)
377 #ifdef HAVE_SIGACTION
379 sigemptyset(&child_set);
380 sigaddset(&child_set, SIGCHLD);
381 sigaddset(&child_set, SIGPIPE);
382 sigprocmask(SIG_UNBLOCK, &child_set, 0);
383 #endif /* HAVE_SIGACTION */
385 block_sigchld_handler--;
389 kill_job (saver_info *si, pid_t pid, int signal)
391 saver_preferences *p = &si->prefs;
392 struct screenhack_job *job;
397 if (block_sigchld_handler)
398 /* This function should not be called from the signal handler. */
401 block_sigchld(); /* we control the horizontal... */
403 job = find_job (pid);
406 job->status == job_killed)
409 fprintf (stderr, "%s: no child %ld to signal!\n",
410 blurb(), (long) pid);
415 case SIGTERM: job->status = job_killed; break;
417 /* #### there must be a way to do this on VMS... */
418 case SIGSTOP: job->status = job_stopped; break;
419 case SIGCONT: job->status = job_running; break;
425 fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
426 blurb(), job->screen,
427 (job->status == job_killed ? "killing" :
428 job->status == job_stopped ? "suspending" : "resuming"),
429 (unsigned long) job->pid,
432 status = kill (job->pid, signal);
434 if (p->verbose_p && status < 0)
438 "%s: %d: child process %lu (%s) was already dead.\n",
439 blurb(), job->screen, (unsigned long) job->pid, job->name);
443 sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
444 blurb(), job->screen, (unsigned long) job->pid, job->name);
449 await_dying_children (si);
453 if (block_sigchld_handler < 0)
463 sigchld_handler (int sig)
465 saver_info *si = global_si_kludge; /* I hate C so much... */
467 if (si->prefs.debug_p)
469 /* Don't call fprintf() from signal handlers, as it might malloc.
470 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
471 (block_sigchld_handler ? " (blocked)" : ""));
473 write_string (STDERR_FILENO, blurb());
474 write_string (STDERR_FILENO, ": got SIGCHLD");
476 if (block_sigchld_handler)
477 write_string (STDERR_FILENO, " (blocked)\n");
479 write_string (STDERR_FILENO, "\n");
482 if (block_sigchld_handler < 0)
484 else if (block_sigchld_handler == 0)
487 await_dying_children (si);
499 await_dying_children (saver_info *si)
507 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
509 if (si->prefs.debug_p)
511 if (kid < 0 && errno)
513 /* Don't call fprintf() from signal handlers, as it might malloc.
514 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
517 write_string (STDERR_FILENO, blurb());
518 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
519 write_long (STDERR_FILENO, (long) kid);
520 write_string (STDERR_FILENO, " (");
521 write_long (STDERR_FILENO, (long) errno);
522 write_string (STDERR_FILENO, ")\n");
526 /* Don't call fprintf() from signal handlers, as it might malloc.
527 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
530 write_string (STDERR_FILENO, blurb());
531 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
532 write_long (STDERR_FILENO, (long) kid);
533 write_string (STDERR_FILENO, "\n");
537 /* 0 means no more children to reap.
538 -1 means error -- except "interrupted system call" isn't a "real"
539 error, so if we get that, we should just try again. */
541 (kid < 0 && errno != EINTR))
544 describe_dead_child (si, kid, wait_status);
550 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
553 saver_preferences *p = &si->prefs;
554 struct screenhack_job *job = find_job (kid);
555 const char *name = job ? job->name : "<unknown>";
556 int screen_no = job ? job->screen : 0;
558 if (WIFEXITED (wait_status))
560 int exit_status = WEXITSTATUS (wait_status);
562 /* Treat exit code as a signed 8-bit quantity. */
563 if (exit_status & 0x80) exit_status |= ~0xFF;
565 /* One might assume that exiting with non-0 means something went wrong.
566 But that loser xswarm exits with the code that it was killed with, so
567 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
568 mention them) if we've just killed the subprocess. But mention them
569 if they happen on their own.
573 (p->verbose_p || job->status != job_killed)))
575 /* Don't call fprintf() from signal handlers, as it might malloc.
577 "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
578 blurb(), screen_no, (unsigned long) kid, name, exit_status);
580 write_string (STDERR_FILENO, blurb());
581 write_string (STDERR_FILENO, ": ");
582 write_long (STDERR_FILENO, (long) screen_no);
583 write_string (STDERR_FILENO, ": child pid ");
584 write_long (STDERR_FILENO, (long) kid);
585 write_string (STDERR_FILENO, " (");
586 write_string (STDERR_FILENO, name);
587 write_string (STDERR_FILENO, ") exited abnormally (code ");
588 write_long (STDERR_FILENO, (long) exit_status);
589 write_string (STDERR_FILENO, ").\n");
591 else if (p->verbose_p)
593 /* Don't call fprintf() from signal handlers, as it might malloc.
594 fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
595 blurb(), screen_no, (unsigned long) kid, name);
597 write_string (STDERR_FILENO, blurb());
598 write_string (STDERR_FILENO, ": ");
599 write_long (STDERR_FILENO, (long) screen_no);
600 write_string (STDERR_FILENO, ": child pid ");
601 write_long (STDERR_FILENO, (long) kid);
602 write_string (STDERR_FILENO, " (");
603 write_string (STDERR_FILENO, name);
604 write_string (STDERR_FILENO, ") exited normally.\n");
608 job->status = job_dead;
610 else if (WIFSIGNALED (wait_status))
614 job->status != job_killed ||
615 WTERMSIG (wait_status) != SIGTERM)
617 /* Don't call fprintf() from signal handlers, as it might malloc.
618 fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
619 blurb(), screen_no, (unsigned long) kid, name,
620 signal_name (WTERMSIG(wait_status)));
622 write_string (STDERR_FILENO, blurb());
623 write_string (STDERR_FILENO, ": ");
624 write_long (STDERR_FILENO, (long) screen_no);
625 write_string (STDERR_FILENO, ": child pid ");
626 write_long (STDERR_FILENO, (long) kid);
627 write_string (STDERR_FILENO, " (");
628 write_string (STDERR_FILENO, name);
629 write_string (STDERR_FILENO, ") terminated with signal ");
630 write_long (STDERR_FILENO, WTERMSIG(wait_status));
631 write_string (STDERR_FILENO, ".\n");
635 job->status = job_dead;
637 else if (WIFSTOPPED (wait_status))
641 /* Don't call fprintf() from signal handlers, as it might malloc.
642 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
643 blurb(), (unsigned long) kid, name,
644 signal_name (WSTOPSIG (wait_status)));
646 write_string (STDERR_FILENO, blurb());
647 write_string (STDERR_FILENO, ": ");
648 write_long (STDERR_FILENO, (long) screen_no);
649 write_string (STDERR_FILENO, ": child pid ");
650 write_long (STDERR_FILENO, (long) kid);
651 write_string (STDERR_FILENO, " (");
652 write_string (STDERR_FILENO, name);
653 write_string (STDERR_FILENO, ") stopped with signal ");
654 write_long (STDERR_FILENO, WSTOPSIG(wait_status));
655 write_string (STDERR_FILENO, ".\n");
659 job->status = job_stopped;
663 /* Don't call fprintf() from signal handlers, as it might malloc.
664 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
665 blurb(), (unsigned long) kid, name);
667 write_string (STDERR_FILENO, blurb());
668 write_string (STDERR_FILENO, ": ");
669 write_long (STDERR_FILENO, (long) screen_no);
670 write_string (STDERR_FILENO, ": child pid ");
671 write_long (STDERR_FILENO, (long) kid);
672 write_string (STDERR_FILENO, " (");
673 write_string (STDERR_FILENO, name);
674 write_string (STDERR_FILENO, ") died in a mysterious way!");
676 job->status = job_dead;
679 /* Clear out the pid so that screenhack_running_p() knows it's dead.
681 if (!job || job->status == job_dead)
682 for (i = 0; i < si->nscreens; i++)
684 saver_screen_info *ssi = &si->screens[i];
691 static void await_dying_children (saver_info *si) { return; }
700 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
702 static Bool sigchld_initialized_p = 0;
703 if (!sigchld_initialized_p)
705 struct sigaction action, old;
707 action.sa_handler = sigchld_handler;
708 sigemptyset(&action.sa_mask);
711 if (sigaction(SIGCHLD, &action, &old) < 0)
714 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
717 sigchld_initialized_p = True;
720 # else /* !HAVE_SIGACTION */
722 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
725 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
728 # endif /* !HAVE_SIGACTION */
737 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
739 saver_info *si = ssi->global;
740 saver_preferences *p = &si->prefs;
743 if (hack->visual && *hack->visual)
744 selected = select_visual(ssi, hack->visual);
746 selected = select_visual(ssi, 0);
748 if (!selected && (p->verbose_p || si->demoing_p))
751 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
752 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
754 (hack->visual && *hack->visual ? hack->visual : "???"),
762 print_path_error (const char *program)
765 char *cmd = strdup (program);
766 char *token = strchr (cmd, ' ');
768 if (token) *token = 0;
769 sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
773 if (errno == ENOENT &&
774 (token = getenv("PATH")))
778 # define PATH_MAX MAXPATHLEN
780 # define PATH_MAX 2048
784 fprintf (stderr, "\n");
786 # if defined(HAVE_GETCWD)
787 if (! getcwd (path, sizeof(path)))
789 # elif defined(HAVE_GETWD)
793 fprintf (stderr, " Current directory is: %s\n", path);
794 fprintf (stderr, " PATH is:\n");
795 token = strtok (strdup(token), ":");
798 fprintf (stderr, " %s\n", token);
799 token = strtok(0, ":");
801 fprintf (stderr, "\n");
806 /* Executes the command in another process.
807 Command may be any single command acceptable to /bin/sh.
808 It may include wildcards, but no semicolons.
809 If successful, the pid of the other process is returned.
810 Otherwise, -1 is returned and an error may have been
814 fork_and_exec (saver_screen_info *ssi, const char *command)
816 saver_info *si = ssi->global;
817 saver_preferences *p = &si->prefs;
820 switch ((int) (forked = fork ()))
825 sprintf (buf, "%s: couldn't fork", blurb());
831 close (ConnectionNumber (si->dpy)); /* close display fd */
832 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
833 hack_subproc_environment (ssi); /* set $DISPLAY */
836 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
837 blurb(), ssi->number, command,
838 (unsigned long) getpid ());
840 exec_command (p->shell, command, p->nice_inferior);
842 /* If that returned, we were unable to exec the subprocess.
843 Print an error message, if desired.
845 if (! p->ignore_uninstalled_p)
846 print_path_error (command);
848 exit (1); /* exits child fork */
851 default: /* parent */
852 (void) make_job (forked, ssi->number, command);
861 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
863 saver_info *si = ssi->global;
864 saver_preferences *p = &si->prefs;
865 raise_window (si, first_time_p, True, False);
868 if (p->screenhacks_count)
879 if (p->screenhacks_count < 1)
881 /* No hacks at all */
884 else if (p->screenhacks_count == 1)
886 /* Exactly one hack in the list */
889 else if (si->selection_mode == -1)
891 /* Select the next hack, wrapping. */
892 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
894 else if (si->selection_mode == -2)
896 /* Select the previous hack, wrapping. */
897 if (ssi->current_hack < 0)
898 new_hack = p->screenhacks_count - 1;
900 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
901 % p->screenhacks_count);
903 else if (si->selection_mode > 0)
905 /* Select a specific hack, by number (via the ACTIVATE command.) */
906 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
909 else if (p->mode == ONE_HACK &&
910 p->selected_hack >= 0)
912 /* Select a specific hack, by number (via "One Saver" mode.) */
913 new_hack = p->selected_hack;
916 else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
920 else if (p->mode == RANDOM_HACKS_SAME &&
923 /* Use the same hack that's running on screen 0.
924 (Assumes this function was called on screen 0 first.)
926 new_hack = si->screens[0].current_hack;
928 else /* (p->mode == RANDOM_HACKS) */
930 /* Select a random hack (but not the one we just ran.) */
931 while ((new_hack = random () % p->screenhacks_count)
932 == ssi->current_hack)
936 if (new_hack < 0) /* don't run a hack */
938 ssi->current_hack = -1;
939 if (si->selection_mode < 0)
940 si->selection_mode = 0;
944 ssi->current_hack = new_hack;
945 hack = p->screenhacks[ssi->current_hack];
947 /* If the hack is disabled, or there is no visual for this hack,
948 then try again (move forward, or backward, or re-randomize.)
949 Unless this hack was specified explicitly, in which case,
953 select_visual_of_hack (ssi, hack);
957 !select_visual_of_hack (ssi, hack)))
959 if (++retry_count > (p->screenhacks_count*4))
961 /* Uh, oops. Odds are, there are no suitable visuals,
962 and we're looping. Give up. (This is totally lame,
963 what we should do is make a list of suitable hacks at
964 the beginning, then only loop over them.)
968 "%s: %d: no programs enabled, or no suitable visuals.\n",
969 blurb(), ssi->number);
976 /* Turn off "next" and "prev" modes now, but "demo" mode is only
977 turned off by explicit action.
979 if (si->selection_mode < 0)
980 si->selection_mode = 0;
982 forked = fork_and_exec (ssi, hack->command);
983 switch ((int) forked)
985 case -1: /* fork failed */
986 case 0: /* child fork (can't happen) */
987 sprintf (buf, "%s: couldn't fork", blurb());
989 restore_real_vroot (si);
990 saver_exit (si, 1, "couldn't fork");
1002 spawn_screenhack (saver_info *si, Bool first_time_p)
1004 if (monitor_powered_on_p (si))
1007 for (i = 0; i < si->nscreens; i++)
1009 saver_screen_info *ssi = &si->screens[i];
1010 spawn_screenhack_1 (ssi, first_time_p);
1013 else if (si->prefs.verbose_p)
1015 "%s: X says monitor has powered down; "
1016 "not launching a hack.\n", blurb());
1018 store_saver_status (si); /* store current hack numbers */
1023 kill_screenhack (saver_info *si)
1026 for (i = 0; i < si->nscreens; i++)
1028 saver_screen_info *ssi = &si->screens[i];
1030 kill_job (si, ssi->pid, SIGTERM);
1037 suspend_screenhack (saver_info *si, Bool suspend_p)
1039 #ifdef SIGSTOP /* older VMS doesn't have it... */
1041 for (i = 0; i < si->nscreens; i++)
1043 saver_screen_info *ssi = &si->screens[i];
1045 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1047 #endif /* SIGSTOP */
1051 /* Called when we're exiting abnormally, to kill off the subproc. */
1053 emergency_kill_subproc (saver_info *si)
1057 signal (SIGCHLD, SIG_IGN);
1058 #endif /* SIGCHLD */
1060 for (i = 0; i < si->nscreens; i++)
1062 saver_screen_info *ssi = &si->screens[i];
1065 kill_job (si, ssi->pid, SIGTERM);
1072 screenhack_running_p (saver_info *si)
1074 Bool any_running_p = False;
1076 for (i = 0; i < si->nscreens; i++)
1078 saver_screen_info *ssi = &si->screens[i];
1079 if (ssi->pid) any_running_p = True;
1081 return any_running_p;
1085 /* Environment variables. */
1088 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
1089 is defined, the xscreensaver daemon will search that directory for hacks.
1092 hack_environment (saver_info *si)
1094 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1095 static const char *def_path = DEFAULT_PATH_PREFIX;
1096 if (def_path && *def_path)
1098 const char *opath = getenv("PATH");
1099 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1100 strcpy (npath, "PATH=");
1101 strcat (npath, def_path);
1102 strcat (npath, ":");
1103 strcat (npath, opath);
1108 /* don't free (npath) -- some implementations of putenv (BSD 4.4,
1109 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1110 do not. So we must leak it (and/or the previous setting). Yay.
1113 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1118 hack_subproc_environment (saver_screen_info *ssi)
1120 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1121 the spawned processes inherit is correct. First, it must be on the same
1122 host and display as the value of -display passed in on our command line
1123 (which is not necessarily the same as what our $DISPLAY variable is.)
1124 Second, the screen number in the $DISPLAY passed to the subprocess should
1125 be the screen on which this particular hack is running -- not the display
1126 specification which the driver itself is using, since the driver ignores
1127 its screen number and manages all existing screens.
1129 Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
1130 us to (eventually) run multiple hacks in Xinerama mode, where each hack
1131 has the same $DISPLAY but a different piece of glass.
1133 saver_info *si = ssi->global;
1134 const char *odpy = DisplayString (si->dpy);
1135 char *ndpy = (char *) malloc (strlen(odpy) + 20);
1136 char *nssw = (char *) malloc (40);
1139 strcpy (ndpy, "DISPLAY=");
1140 s = ndpy + strlen(ndpy);
1143 while (*s && *s != ':') s++; /* skip to colon */
1144 while (*s == ':') s++; /* skip over colons */
1145 while (isdigit(*s)) s++; /* skip over dpy number */
1146 while (*s == '.') s++; /* skip over dot */
1147 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1148 sprintf(s, "%d", ssi->real_screen_number); /* put on screen number */
1150 sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
1151 (unsigned long) ssi->screensaver_window);
1153 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1154 any more, right? It's not Posix, but everyone seems to have it. */
1161 /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
1162 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1163 do not. So we must leak it (and/or the previous setting). Yay.
1165 #endif /* HAVE_PUTENV */
1172 get_best_gl_visual (saver_screen_info *ssi)
1174 saver_info *si = ssi->global;
1183 av[ac++] = "xscreensaver-gl-helper";
1188 perror ("error creating pipe:");
1195 switch ((int) (forked = fork ()))
1199 sprintf (buf, "%s: couldn't fork", blurb());
1201 saver_exit (si, 1, 0);
1207 close (in); /* don't need this one */
1208 close (ConnectionNumber (si->dpy)); /* close display fd */
1210 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1212 perror ("could not dup() a new stdout:");
1215 hack_subproc_environment (ssi); /* set $DISPLAY */
1217 execvp (av[0], av); /* shouldn't return. */
1219 if (errno != ENOENT || si->prefs.verbose_p)
1221 /* Ignore "no such file or directory" errors, unless verbose.
1222 Issue all other exec errors, though. */
1223 sprintf (buf, "%s: running %s", blurb(), av[0]);
1226 exit (1); /* exits fork */
1232 int wait_status = 0;
1234 FILE *f = fdopen (in, "r");
1235 unsigned long v = 0;
1238 close (out); /* don't need this one */
1241 if (! fgets (buf, sizeof(buf)-1, f))
1245 /* Wait for the child to die. */
1246 waitpid (-1, &wait_status, 0);
1248 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1253 if (si->prefs.verbose_p)
1255 int L = strlen(buf);
1256 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1259 if (L && buf[L-1] == '\n')
1262 fprintf (stderr, "%s: %s said: \"%s\"\n",
1263 blurb(), av[0], buf);
1269 Visual *v = id_to_visual (ssi->screen, result);
1270 if (si->prefs.verbose_p)
1271 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1272 blurb(), ssi->number,
1274 (v == ssi->default_visual ? " (default)" : ""));
1285 /* Restarting the xscreensaver process from scratch. */
1287 static char **saved_argv;
1290 save_argv (int argc, char **argv)
1292 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1293 saved_argv [argc] = 0;
1296 int i = strlen (argv [argc]) + 1;
1297 saved_argv [argc] = (char *) malloc (i);
1298 memcpy (saved_argv [argc], argv [argc], i);
1303 /* Re-execs the process with the arguments in saved_argv. Does not return.
1306 restart_process (saver_info *si)
1310 shutdown_stderr (si);
1311 if (si->prefs.verbose_p)
1314 fprintf (stderr, "%s: re-executing", blurb());
1315 for (i = 0; saved_argv[i]; i++)
1316 fprintf (stderr, " %s", saved_argv[i]);
1317 fprintf (stderr, "\n");
1319 describe_uids (si, stderr);
1320 fprintf (stderr, "\n");
1324 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1327 sprintf (buf, "%s: could not restart process", blurb());