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 !on_path_p (hack->command) ||
958 !select_visual_of_hack (ssi, hack)))
960 if (++retry_count > (p->screenhacks_count*4))
962 /* Uh, oops. Odds are, there are no suitable visuals,
963 and we're looping. Give up. (This is totally lame,
964 what we should do is make a list of suitable hacks at
965 the beginning, then only loop over them.)
969 "%s: %d: no programs enabled, or no suitable visuals.\n",
970 blurb(), ssi->number);
977 /* Turn off "next" and "prev" modes now, but "demo" mode is only
978 turned off by explicit action.
980 if (si->selection_mode < 0)
981 si->selection_mode = 0;
983 forked = fork_and_exec (ssi, hack->command);
984 switch ((int) forked)
986 case -1: /* fork failed */
987 case 0: /* child fork (can't happen) */
988 sprintf (buf, "%s: couldn't fork", blurb());
990 restore_real_vroot (si);
991 saver_exit (si, 1, "couldn't fork");
1003 spawn_screenhack (saver_info *si, Bool first_time_p)
1005 if (monitor_powered_on_p (si))
1008 for (i = 0; i < si->nscreens; i++)
1010 saver_screen_info *ssi = &si->screens[i];
1011 spawn_screenhack_1 (ssi, first_time_p);
1014 else if (si->prefs.verbose_p)
1016 "%s: X says monitor has powered down; "
1017 "not launching a hack.\n", blurb());
1019 store_saver_status (si); /* store current hack numbers */
1024 kill_screenhack (saver_info *si)
1027 for (i = 0; i < si->nscreens; i++)
1029 saver_screen_info *ssi = &si->screens[i];
1031 kill_job (si, ssi->pid, SIGTERM);
1038 suspend_screenhack (saver_info *si, Bool suspend_p)
1040 #ifdef SIGSTOP /* older VMS doesn't have it... */
1042 for (i = 0; i < si->nscreens; i++)
1044 saver_screen_info *ssi = &si->screens[i];
1046 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1048 #endif /* SIGSTOP */
1052 /* Called when we're exiting abnormally, to kill off the subproc. */
1054 emergency_kill_subproc (saver_info *si)
1058 signal (SIGCHLD, SIG_IGN);
1059 #endif /* SIGCHLD */
1061 for (i = 0; i < si->nscreens; i++)
1063 saver_screen_info *ssi = &si->screens[i];
1066 kill_job (si, ssi->pid, SIGTERM);
1073 screenhack_running_p (saver_info *si)
1075 Bool any_running_p = False;
1077 for (i = 0; i < si->nscreens; i++)
1079 saver_screen_info *ssi = &si->screens[i];
1080 if (ssi->pid) any_running_p = True;
1082 return any_running_p;
1086 /* Environment variables. */
1089 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
1090 is defined, the xscreensaver daemon will search that directory for hacks.
1093 hack_environment (saver_info *si)
1095 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1096 static const char *def_path = DEFAULT_PATH_PREFIX;
1097 if (def_path && *def_path)
1099 const char *opath = getenv("PATH");
1100 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1101 strcpy (npath, "PATH=");
1102 strcat (npath, def_path);
1103 strcat (npath, ":");
1104 strcat (npath, opath);
1109 /* don't free (npath) -- some implementations of putenv (BSD 4.4,
1110 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1111 do not. So we must leak it (and/or the previous setting). Yay.
1114 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1119 hack_subproc_environment (saver_screen_info *ssi)
1121 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1122 the spawned processes inherit is correct. First, it must be on the same
1123 host and display as the value of -display passed in on our command line
1124 (which is not necessarily the same as what our $DISPLAY variable is.)
1125 Second, the screen number in the $DISPLAY passed to the subprocess should
1126 be the screen on which this particular hack is running -- not the display
1127 specification which the driver itself is using, since the driver ignores
1128 its screen number and manages all existing screens.
1130 Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
1131 us to (eventually) run multiple hacks in Xinerama mode, where each hack
1132 has the same $DISPLAY but a different piece of glass.
1134 saver_info *si = ssi->global;
1135 const char *odpy = DisplayString (si->dpy);
1136 char *ndpy = (char *) malloc (strlen(odpy) + 20);
1137 char *nssw = (char *) malloc (40);
1140 strcpy (ndpy, "DISPLAY=");
1141 s = ndpy + strlen(ndpy);
1144 while (*s && *s != ':') s++; /* skip to colon */
1145 while (*s == ':') s++; /* skip over colons */
1146 while (isdigit(*s)) s++; /* skip over dpy number */
1147 while (*s == '.') s++; /* skip over dot */
1148 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1149 sprintf(s, "%d", ssi->real_screen_number); /* put on screen number */
1151 sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
1152 (unsigned long) ssi->screensaver_window);
1154 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1155 any more, right? It's not Posix, but everyone seems to have it. */
1162 /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
1163 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1164 do not. So we must leak it (and/or the previous setting). Yay.
1166 #endif /* HAVE_PUTENV */
1173 get_best_gl_visual (saver_screen_info *ssi)
1175 saver_info *si = ssi->global;
1184 av[ac++] = "xscreensaver-gl-helper";
1189 perror ("error creating pipe:");
1196 switch ((int) (forked = fork ()))
1200 sprintf (buf, "%s: couldn't fork", blurb());
1202 saver_exit (si, 1, 0);
1208 close (in); /* don't need this one */
1209 close (ConnectionNumber (si->dpy)); /* close display fd */
1211 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1213 perror ("could not dup() a new stdout:");
1216 hack_subproc_environment (ssi); /* set $DISPLAY */
1218 execvp (av[0], av); /* shouldn't return. */
1220 if (errno != ENOENT || si->prefs.verbose_p)
1222 /* Ignore "no such file or directory" errors, unless verbose.
1223 Issue all other exec errors, though. */
1224 sprintf (buf, "%s: running %s", blurb(), av[0]);
1227 exit (1); /* exits fork */
1233 int wait_status = 0;
1235 FILE *f = fdopen (in, "r");
1236 unsigned long v = 0;
1239 close (out); /* don't need this one */
1242 if (! fgets (buf, sizeof(buf)-1, f))
1246 /* Wait for the child to die. */
1247 waitpid (-1, &wait_status, 0);
1249 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1254 if (si->prefs.verbose_p)
1256 int L = strlen(buf);
1257 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1260 if (L && buf[L-1] == '\n')
1263 fprintf (stderr, "%s: %s said: \"%s\"\n",
1264 blurb(), av[0], buf);
1270 Visual *v = id_to_visual (ssi->screen, result);
1271 if (si->prefs.verbose_p)
1272 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1273 blurb(), ssi->number,
1275 (v == ssi->default_visual ? " (default)" : ""));
1286 /* Restarting the xscreensaver process from scratch. */
1288 static char **saved_argv;
1291 save_argv (int argc, char **argv)
1293 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1294 saved_argv [argc] = 0;
1297 int i = strlen (argv [argc]) + 1;
1298 saved_argv [argc] = (char *) malloc (i);
1299 memcpy (saved_argv [argc], argv [argc], i);
1304 /* Re-execs the process with the arguments in saved_argv. Does not return.
1307 restart_process (saver_info *si)
1311 shutdown_stderr (si);
1312 if (si->prefs.verbose_p)
1315 fprintf (stderr, "%s: re-executing", blurb());
1316 for (i = 0; saved_argv[i]; i++)
1317 fprintf (stderr, " %s", saved_argv[i]);
1318 fprintf (stderr, "\n");
1320 describe_uids (si, stderr);
1321 fprintf (stderr, "\n");
1325 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1328 sprintf (buf, "%s: could not restart process", blurb());