1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991-2016 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 */
28 #include <sys/param.h> /* for PATH_MAX */
30 #ifdef HAVE_SYS_WAIT_H
31 # include <sys/wait.h> /* for waitpid() and associated macros */
35 # include <sys/resource.h> /* for setrlimit() and RLIMIT_AS */
39 # include <processes.h>
40 # include <unixio.h> /* for close */
41 # include <unixlib.h> /* for getpid */
46 #include <signal.h> /* for the signal names */
49 #if !defined(SIGCHLD) && defined(SIGCLD)
50 # define SIGCHLD SIGCLD
53 #if 0 /* putenv() is declared in stdlib.h on modern linux systems. */
55 extern int putenv (/* const char * */); /* getenv() is in stdlib.h... */
59 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
61 /* This file doesn't need the Xt headers, so stub these types out... */
63 #define XtAppContext void*
64 #define XrmDatabase void*
65 #define XtIntervalId void*
66 #define XtPointer void*
69 #include "xscreensaver.h"
72 #include "visual.h" /* for id_to_visual() */
74 extern saver_info *global_si_kludge; /* I hate C so much... */
77 /* Used when printing error/debugging messages from signal handlers.
80 no_malloc_number_to_string (long num)
82 static char string[128] = "";
84 Bool negative_p = False;
97 while ((num > 0) && (num_digits < sizeof(string) - 1))
100 digit = (int) num % 10;
102 string[sizeof(string) - 1 - num_digits] = digit + '0';
109 string[sizeof(string) - 1 - num_digits] = '-';
112 return string + sizeof(string) - 1 - num_digits;
115 /* Like write(), but runs strlen() on the arg to get the length. */
117 write_string (int fd, const char *str)
119 return write (fd, str, strlen (str));
123 write_long (int fd, long n)
125 const char *str = no_malloc_number_to_string (n);
126 return write_string (fd, str);
130 /* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size
131 of a process's address space, i.e., the maximal brk(2) and mmap(2) values.
132 Setting this lets you put a cap on how much memory a process can allocate.
134 Except the "and mmap()" part kinda makes this useless, since many GL
135 implementations end up using mmap() to pull the whole frame buffer into
136 memory (or something along those lines) making it appear processes are
137 using hundreds of megabytes when in fact they're using very little, and
138 we end up capping their mallocs prematurely. YAY!
140 #if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
141 # define RLIMIT_AS RLIMIT_VMEM
145 limit_subproc_memory (int address_space_limit, Bool verbose_p)
148 /* This has caused way more problems than it has solved...
149 Let's just completely ignore the "memoryLimit" option now.
151 #undef HAVE_SETRLIMIT
153 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS)
156 if (address_space_limit < 10 * 1024) /* let's not be crazy */
159 if (getrlimit (RLIMIT_AS, &r) != 0)
162 sprintf (buf, "%s: getrlimit(RLIMIT_AS) failed", blurb());
167 r.rlim_cur = address_space_limit;
169 if (setrlimit (RLIMIT_AS, &r) != 0)
172 sprintf (buf, "%s: setrlimit(RLIMIT_AS, {%lu, %lu}) failed",
173 blurb(), r.rlim_cur, r.rlim_max);
180 int i = address_space_limit;
182 if (i >= (1<<30) && i == ((i >> 30) << 30))
183 sprintf(buf, "%dG", i >> 30);
184 else if (i >= (1<<20) && i == ((i >> 20) << 20))
185 sprintf(buf, "%dM", i >> 20);
186 else if (i >= (1<<10) && i == ((i >> 10) << 10))
187 sprintf(buf, "%dK", i >> 10);
189 sprintf(buf, "%d bytes", i);
191 fprintf (stderr, "%s: limited pid %lu address space to %s.\n",
192 blurb(), (unsigned long) getpid (), buf);
195 #endif /* HAVE_SETRLIMIT && RLIMIT_AS */
199 /* Management of child processes, and de-zombification.
203 job_running, /* the process is still alive */
204 job_stopped, /* we have sent it a STOP signal */
205 job_killed, /* we have sent it a TERM signal */
206 job_dead /* we have wait()ed for it, and it's dead -- this state only
207 occurs so that we can avoid calling free() from a signal
208 handler. Shortly after going into this state, the list
209 element will be removed. */
212 struct screenhack_job {
216 enum job_status status;
217 time_t launched, killed;
218 struct screenhack_job *next;
221 static struct screenhack_job *jobs = 0;
223 /* for debugging -- nothing calls this, but it's useful to invoke from gdb.
225 void show_job_list (void);
230 struct screenhack_job *job;
231 fprintf(stderr, "%s: job list:\n", blurb());
232 for (job = jobs; job; job = job->next)
234 char b[] = " ??:??:?? ";
235 char *t = (job->killed ? timestring (job->killed) :
236 job->launched ? timestring (job->launched) : b);
239 fprintf (stderr, " %5ld: %2d: (%s) %s %s\n",
242 (job->status == job_running ? "running" :
243 job->status == job_stopped ? "stopped" :
244 job->status == job_killed ? " killed" :
245 job->status == job_dead ? " dead" : " ???"),
248 fprintf (stderr, "\n");
252 static void clean_job_list (void);
254 static struct screenhack_job *
255 make_job (pid_t pid, int screen, const char *cmd)
257 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
259 static char name [1024];
260 const char *in = cmd;
268 while (isspace(*in)) in++; /* skip whitespace */
269 while (!isspace(*in) && *in != ':') {
270 if (*in == '=') got_eq = 1;
271 *out++ = *in++; /* snarf first token */
274 if (got_eq) /* if the first token was FOO=bar */
275 { /* then get the next token instead. */
282 while (isspace(*in)) in++; /* skip whitespace */
285 job->name = strdup(name);
287 job->screen = screen;
288 job->status = job_running;
289 job->launched = time ((time_t *) 0);
299 free_job (struct screenhack_job *job)
303 else if (job == jobs)
307 struct screenhack_job *job2, *prev;
308 for (prev = 0, job2 = jobs;
310 prev = job2, job2 = job2->next)
313 prev->next = job->next;
322 /* Cleans out dead jobs from the jobs list -- this must only be called
323 from the main thread, not from a signal handler.
326 clean_job_list (void)
328 struct screenhack_job *job, *prev, *next;
329 time_t now = time ((time_t *) 0);
330 static time_t last_warn = 0;
331 Bool warnedp = False;
333 for (prev = 0, job = jobs, next = (job ? job->next : 0);
335 prev = job, job = next, next = (job ? job->next : 0))
337 if (job->status == job_dead)
344 else if (job->status == job_killed &&
345 now - job->killed > 10 &&
346 now - last_warn > 10)
349 "%s: WARNING: pid %ld (%s) sent SIGTERM %ld seconds ago"
350 " and did not die!\n",
354 (long) (now - job->killed));
358 if (warnedp) last_warn = now;
362 static struct screenhack_job *
365 struct screenhack_job *job;
366 for (job = jobs; job; job = job->next)
372 static void await_dying_children (saver_info *si);
374 static void describe_dead_child (saver_info *, pid_t, int wait_status);
378 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
379 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
381 static int block_sigchld_handler = 0;
384 #ifdef HAVE_SIGACTION
386 #else /* !HAVE_SIGACTION */
388 #endif /* !HAVE_SIGACTION */
391 #ifdef HAVE_SIGACTION
395 memset (&sa, 0, sizeof (sa));
396 sa.sa_handler = SIG_IGN;
397 sigaction (SIGPIPE, &sa, NULL);
399 sigemptyset (&child_set);
400 sigaddset (&child_set, SIGCHLD);
401 sigprocmask (SIG_BLOCK, &child_set, 0);
403 #else /* !HAVE_SIGACTION */
404 signal (SIGPIPE, SIG_IGN);
405 #endif /* !HAVE_SIGACTION */
407 block_sigchld_handler++;
409 #ifdef HAVE_SIGACTION
411 #else /* !HAVE_SIGACTION */
413 #endif /* !HAVE_SIGACTION */
417 unblock_sigchld (void)
419 if (block_sigchld_handler <= 0)
422 if (block_sigchld_handler <= 1) /* only unblock if count going to 0 */
424 #ifdef HAVE_SIGACTION
428 memset(&sa, 0, sizeof (sa));
429 sa.sa_handler = SIG_DFL;
430 sigaction(SIGPIPE, &sa, NULL);
432 sigemptyset(&child_set);
433 sigaddset(&child_set, SIGCHLD);
434 sigprocmask(SIG_UNBLOCK, &child_set, 0);
436 #else /* !HAVE_SIGACTION */
437 signal(SIGPIPE, SIG_DFL);
438 #endif /* !HAVE_SIGACTION */
441 block_sigchld_handler--;
445 kill_job (saver_info *si, pid_t pid, int signal)
447 saver_preferences *p = &si->prefs;
448 struct screenhack_job *job;
453 if (in_signal_handler_p)
454 /* This function should not be called from the signal handler. */
457 block_sigchld(); /* we control the horizontal... */
459 job = find_job (pid);
462 job->status == job_killed)
465 fprintf (stderr, "%s: no child %ld to signal!\n",
466 blurb(), (long) pid);
472 job->status = job_killed;
473 job->killed = time ((time_t *) 0);
476 /* #### there must be a way to do this on VMS... */
477 case SIGSTOP: job->status = job_stopped; break;
478 case SIGCONT: job->status = job_running; break;
484 fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
485 blurb(), job->screen,
486 (job->status == job_killed ? "killing" :
487 job->status == job_stopped ? "suspending" : "resuming"),
488 (unsigned long) job->pid,
491 status = kill (job->pid, signal);
493 if (p->verbose_p && status < 0)
497 "%s: %d: child process %lu (%s) was already dead.\n",
498 blurb(), job->screen, (unsigned long) job->pid, job->name);
502 sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
503 blurb(), job->screen, (unsigned long) job->pid, job->name);
508 await_dying_children (si);
512 if (block_sigchld_handler < 0)
522 sigchld_handler (int sig)
524 saver_info *si = global_si_kludge; /* I hate C so much... */
525 in_signal_handler_p++;
527 if (si->prefs.debug_p)
529 /* Don't call fprintf() from signal handlers, as it might malloc.
530 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
531 (block_sigchld_handler ? " (blocked)" : ""));
533 write_string (STDERR_FILENO, blurb());
534 write_string (STDERR_FILENO, ": got SIGCHLD");
536 if (block_sigchld_handler)
537 write_string (STDERR_FILENO, " (blocked)\n");
539 write_string (STDERR_FILENO, "\n");
542 if (block_sigchld_handler < 0)
544 else if (block_sigchld_handler == 0)
547 await_dying_children (si);
552 in_signal_handler_p--;
560 await_dying_children (saver_info *si)
568 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
570 if (si->prefs.debug_p)
572 if (kid < 0 && errno)
574 /* Don't call fprintf() from signal handlers, as it might malloc.
575 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
578 write_string (STDERR_FILENO, blurb());
579 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
580 write_long (STDERR_FILENO, (long) kid);
581 write_string (STDERR_FILENO, " (");
582 write_long (STDERR_FILENO, (long) errno);
583 write_string (STDERR_FILENO, ")\n");
587 /* Don't call fprintf() from signal handlers, as it might malloc.
588 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
591 write_string (STDERR_FILENO, blurb());
592 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
593 write_long (STDERR_FILENO, (long) kid);
594 write_string (STDERR_FILENO, "\n");
598 /* 0 means no more children to reap.
599 -1 means error -- except "interrupted system call" isn't a "real"
600 error, so if we get that, we should just try again. */
602 (kid < 0 && errno != EINTR))
605 describe_dead_child (si, kid, wait_status);
611 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
614 saver_preferences *p = &si->prefs;
615 struct screenhack_job *job = find_job (kid);
616 const char *name = job ? job->name : "<unknown>";
617 int screen_no = job ? job->screen : 0;
619 if (WIFEXITED (wait_status))
621 int exit_status = WEXITSTATUS (wait_status);
623 /* Treat exit code as a signed 8-bit quantity. */
624 if (exit_status & 0x80) exit_status |= ~0xFF;
626 /* One might assume that exiting with non-0 means something went wrong.
627 But that loser xswarm exits with the code that it was killed with, so
628 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
629 mention them) if we've just killed the subprocess. But mention them
630 if they happen on their own.
634 (p->verbose_p || job->status != job_killed)))
636 /* Don't call fprintf() from signal handlers, as it might malloc.
638 "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
639 blurb(), screen_no, (unsigned long) kid, name, exit_status);
641 write_string (STDERR_FILENO, blurb());
642 write_string (STDERR_FILENO, ": ");
643 write_long (STDERR_FILENO, (long) screen_no);
644 write_string (STDERR_FILENO, ": child pid ");
645 write_long (STDERR_FILENO, (long) kid);
646 write_string (STDERR_FILENO, " (");
647 write_string (STDERR_FILENO, name);
648 write_string (STDERR_FILENO, ") exited abnormally (code ");
649 write_long (STDERR_FILENO, (long) exit_status);
650 write_string (STDERR_FILENO, ").\n");
652 else if (p->verbose_p)
654 /* Don't call fprintf() from signal handlers, as it might malloc.
655 fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
656 blurb(), screen_no, (unsigned long) kid, name);
658 write_string (STDERR_FILENO, blurb());
659 write_string (STDERR_FILENO, ": ");
660 write_long (STDERR_FILENO, (long) screen_no);
661 write_string (STDERR_FILENO, ": child pid ");
662 write_long (STDERR_FILENO, (long) kid);
663 write_string (STDERR_FILENO, " (");
664 write_string (STDERR_FILENO, name);
665 write_string (STDERR_FILENO, ") exited normally.\n");
669 job->status = job_dead;
671 else if (WIFSIGNALED (wait_status))
675 job->status != job_killed ||
676 WTERMSIG (wait_status) != SIGTERM)
678 /* Don't call fprintf() from signal handlers, as it might malloc.
679 fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
680 blurb(), screen_no, (unsigned long) kid, name,
681 signal_name (WTERMSIG(wait_status)));
683 write_string (STDERR_FILENO, blurb());
684 write_string (STDERR_FILENO, ": ");
685 write_long (STDERR_FILENO, (long) screen_no);
686 write_string (STDERR_FILENO, ": child pid ");
687 write_long (STDERR_FILENO, (long) kid);
688 write_string (STDERR_FILENO, " (");
689 write_string (STDERR_FILENO, name);
690 write_string (STDERR_FILENO, ") terminated with signal ");
691 write_long (STDERR_FILENO, WTERMSIG(wait_status));
692 write_string (STDERR_FILENO, ".\n");
696 job->status = job_dead;
698 else if (WIFSTOPPED (wait_status))
702 /* Don't call fprintf() from signal handlers, as it might malloc.
703 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
704 blurb(), (unsigned long) kid, name,
705 signal_name (WSTOPSIG (wait_status)));
707 write_string (STDERR_FILENO, blurb());
708 write_string (STDERR_FILENO, ": ");
709 write_long (STDERR_FILENO, (long) screen_no);
710 write_string (STDERR_FILENO, ": child pid ");
711 write_long (STDERR_FILENO, (long) kid);
712 write_string (STDERR_FILENO, " (");
713 write_string (STDERR_FILENO, name);
714 write_string (STDERR_FILENO, ") stopped with signal ");
715 write_long (STDERR_FILENO, WSTOPSIG(wait_status));
716 write_string (STDERR_FILENO, ".\n");
720 job->status = job_stopped;
724 /* Don't call fprintf() from signal handlers, as it might malloc.
725 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
726 blurb(), (unsigned long) kid, name);
728 write_string (STDERR_FILENO, blurb());
729 write_string (STDERR_FILENO, ": ");
730 write_long (STDERR_FILENO, (long) screen_no);
731 write_string (STDERR_FILENO, ": child pid ");
732 write_long (STDERR_FILENO, (long) kid);
733 write_string (STDERR_FILENO, " (");
734 write_string (STDERR_FILENO, name);
735 write_string (STDERR_FILENO, ") died in a mysterious way!");
737 job->status = job_dead;
740 /* Clear out the pid so that screenhack_running_p() knows it's dead.
742 if (!job || job->status == job_dead)
743 for (i = 0; i < si->nscreens; i++)
745 saver_screen_info *ssi = &si->screens[i];
752 static void await_dying_children (saver_info *si) { return; }
761 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
763 static Bool sigchld_initialized_p = 0;
764 if (!sigchld_initialized_p)
766 struct sigaction action, old;
768 action.sa_handler = sigchld_handler;
769 sigemptyset(&action.sa_mask);
772 if (sigaction(SIGCHLD, &action, &old) < 0)
775 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
778 sigchld_initialized_p = True;
781 # else /* !HAVE_SIGACTION */
783 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
786 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
789 # endif /* !HAVE_SIGACTION */
798 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
800 saver_info *si = ssi->global;
801 saver_preferences *p = &si->prefs;
804 if (hack->visual && *hack->visual)
805 selected = select_visual(ssi, hack->visual);
807 selected = select_visual(ssi, 0);
809 if (!selected && (p->verbose_p || si->demoing_p))
812 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
813 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
815 (hack->visual && *hack->visual ? hack->visual : "???"),
823 print_path_error (const char *program)
826 char *cmd = strdup (program);
827 char *token = strchr (cmd, ' ');
829 if (token) *token = 0;
830 sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
834 if (errno == ENOENT &&
835 (token = getenv("PATH")))
839 # define PATH_MAX MAXPATHLEN
841 # define PATH_MAX 2048
845 fprintf (stderr, "\n");
847 # if defined(HAVE_GETCWD)
848 if (! getcwd (path, sizeof(path)))
850 # elif defined(HAVE_GETWD)
854 fprintf (stderr, " Current directory is: %s\n", path);
855 fprintf (stderr, " PATH is:\n");
856 token = strtok (strdup(token), ":");
859 fprintf (stderr, " %s\n", token);
860 token = strtok(0, ":");
862 fprintf (stderr, "\n");
867 /* Executes the command in another process.
868 Command may be any single command acceptable to /bin/sh.
869 It may include wildcards, but no semicolons.
870 If successful, the pid of the other process is returned.
871 Otherwise, -1 is returned and an error may have been
875 fork_and_exec (saver_screen_info *ssi, const char *command)
877 saver_info *si = ssi->global;
878 saver_preferences *p = &si->prefs;
881 switch ((int) (forked = fork ()))
886 sprintf (buf, "%s: couldn't fork", blurb());
892 close (ConnectionNumber (si->dpy)); /* close display fd */
893 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
894 hack_subproc_environment (ssi->screen, ssi->screensaver_window);
897 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
898 blurb(), ssi->number, command,
899 (unsigned long) getpid ());
901 exec_command (p->shell, command, p->nice_inferior);
903 /* If that returned, we were unable to exec the subprocess.
904 Print an error message, if desired.
906 if (! p->ignore_uninstalled_p)
907 print_path_error (command);
909 exit (1); /* exits child fork */
912 default: /* parent */
913 (void) make_job (forked, ssi->number, command);
922 spawn_screenhack (saver_screen_info *ssi)
924 saver_info *si = ssi->global;
925 saver_preferences *p = &si->prefs;
928 if (!monitor_powered_on_p (si))
930 if (si->prefs.verbose_p)
932 "%s: %d: X says monitor has powered down; "
933 "not launching a hack.\n", blurb(), ssi->number);
937 if (p->screenhacks_count)
948 if (p->screenhacks_count < 1)
950 /* No hacks at all */
953 else if (p->screenhacks_count == 1)
955 /* Exactly one hack in the list */
958 else if (si->selection_mode == -1)
960 /* Select the next hack, wrapping. */
961 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
963 else if (si->selection_mode == -2)
965 /* Select the previous hack, wrapping. */
966 if (ssi->current_hack < 0)
967 new_hack = p->screenhacks_count - 1;
969 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
970 % p->screenhacks_count);
972 else if (si->selection_mode > 0)
974 /* Select a specific hack, by number (via the ACTIVATE command.) */
975 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
978 else if (p->mode == ONE_HACK &&
979 p->selected_hack >= 0)
981 /* Select a specific hack, by number (via "One Saver" mode.) */
982 new_hack = p->selected_hack;
985 else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
989 else if (p->mode == RANDOM_HACKS_SAME &&
992 /* Use the same hack that's running on screen 0.
993 (Assumes this function was called on screen 0 first.)
995 new_hack = si->screens[0].current_hack;
997 else /* (p->mode == RANDOM_HACKS) */
999 /* Select a random hack (but not the one we just ran.) */
1000 while ((new_hack = random () % p->screenhacks_count)
1001 == ssi->current_hack)
1005 if (new_hack < 0) /* don't run a hack */
1007 ssi->current_hack = -1;
1008 if (si->selection_mode < 0)
1009 si->selection_mode = 0;
1013 ssi->current_hack = new_hack;
1014 hack = p->screenhacks[ssi->current_hack];
1016 /* If the hack is disabled, or there is no visual for this hack,
1017 then try again (move forward, or backward, or re-randomize.)
1018 Unless this hack was specified explicitly, in which case,
1022 select_visual_of_hack (ssi, hack);
1025 (!hack->enabled_p ||
1026 !on_path_p (hack->command) ||
1027 !select_visual_of_hack (ssi, hack)))
1029 if (++retry_count > (p->screenhacks_count*4))
1031 /* Uh, oops. Odds are, there are no suitable visuals,
1032 and we're looping. Give up. (This is totally lame,
1033 what we should do is make a list of suitable hacks at
1034 the beginning, then only loop over them.)
1038 "%s: %d: no programs enabled, or no suitable visuals.\n",
1039 blurb(), ssi->number);
1046 /* Turn off "next" and "prev" modes now, but "demo" mode is only
1047 turned off by explicit action.
1049 if (si->selection_mode < 0)
1050 si->selection_mode = 0;
1052 forked = fork_and_exec (ssi, hack->command);
1053 switch ((int) forked)
1055 case -1: /* fork failed */
1056 case 0: /* child fork (can't happen) */
1057 sprintf (buf, "%s: couldn't fork", blurb());
1059 restore_real_vroot (si);
1060 saver_exit (si, 1, "couldn't fork");
1069 store_saver_status (si); /* store current hack number */
1074 kill_screenhack (saver_screen_info *ssi)
1076 saver_info *si = ssi->global;
1078 kill_job (si, ssi->pid, SIGTERM);
1084 suspend_screenhack (saver_screen_info *ssi, Bool suspend_p)
1086 #ifdef SIGSTOP /* older VMS doesn't have it... */
1087 saver_info *si = ssi->global;
1089 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1090 #endif /* SIGSTOP */
1094 /* Called when we're exiting abnormally, to kill off the subproc. */
1096 emergency_kill_subproc (saver_info *si)
1100 signal (SIGCHLD, SIG_IGN);
1101 #endif /* SIGCHLD */
1103 for (i = 0; i < si->nscreens; i++)
1105 saver_screen_info *ssi = &si->screens[i];
1108 kill_job (si, ssi->pid, SIGTERM);
1115 screenhack_running_p (saver_info *si)
1117 Bool any_running_p = False;
1119 for (i = 0; i < si->nscreens; i++)
1121 saver_screen_info *ssi = &si->screens[i];
1122 if (ssi->pid) any_running_p = True;
1124 return any_running_p;
1128 /* Environment variables. */
1131 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
1132 is defined, the xscreensaver daemon will search that directory for hacks.
1135 hack_environment (saver_info *si)
1137 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1138 static const char *def_path = DEFAULT_PATH_PREFIX;
1139 if (def_path && *def_path)
1141 const char *opath = getenv("PATH");
1143 if (! opath) opath = "/bin:/usr/bin"; /* WTF */
1144 npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1145 strcpy (npath, "PATH=");
1146 strcat (npath, def_path);
1147 strcat (npath, ":");
1148 strcat (npath, opath);
1153 /* don't free (npath) -- some implementations of putenv (BSD 4.4,
1154 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1155 do not. So we must leak it (and/or the previous setting). Yay.
1158 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1163 hack_subproc_environment (Screen *screen, Window saver_window)
1165 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1166 the spawned processes inherit is correct. First, it must be on the same
1167 host and display as the value of -display passed in on our command line
1168 (which is not necessarily the same as what our $DISPLAY variable is.)
1169 Second, the screen number in the $DISPLAY passed to the subprocess should
1170 be the screen on which this particular hack is running -- not the display
1171 specification which the driver itself is using, since the driver ignores
1172 its screen number and manages all existing screens.
1174 Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
1175 us to (eventually) run multiple hacks in Xinerama mode, where each hack
1176 has the same $DISPLAY but a different piece of glass.
1178 Display *dpy = DisplayOfScreen (screen);
1179 const char *odpy = DisplayString (dpy);
1180 char *ndpy = (char *) malloc (strlen(odpy) + 20);
1181 char *nssw = (char *) malloc (40);
1184 strcpy (ndpy, "DISPLAY=");
1185 s = ndpy + strlen(ndpy);
1188 /* We have to find the last colon since it is the boundary between
1189 hostname & screen - IPv6 numeric format addresses may have many
1190 colons before that point, and DECnet addresses always have two colons */
1191 c = strrchr(s,':'); /* skip to last colon */
1192 if (c != NULL) s = c+1;
1193 while (isdigit(*s)) s++; /* skip over dpy number */
1194 while (*s == '.') s++; /* skip over dot */
1195 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1196 sprintf(s, "%d", screen_number (screen)); /* put on screen number */
1198 sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", (unsigned long) saver_window);
1200 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1201 any more, right? It's not Posix, but everyone seems to have it. */
1208 /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
1209 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1210 do not. So we must leak it (and/or the previous setting). Yay.
1212 #endif /* HAVE_PUTENV */
1219 get_best_gl_visual (saver_info *si, Screen *screen)
1225 int errin = -1, errout = -1;
1231 av[ac++] = "xscreensaver-gl-helper";
1236 perror ("error creating pipe:");
1243 if (!si->prefs.verbose_p)
1247 perror ("error creating pipe:");
1252 errout = errfds [1];
1255 block_sigchld(); /* This blocks it in the parent and child, to avoid
1256 racing. It is never unblocked in the child before
1257 the child exits, but that doesn't matter.
1260 switch ((int) (forked = fork ()))
1264 sprintf (buf, "%s: couldn't fork", blurb());
1266 saver_exit (si, 1, 0);
1270 close (in); /* don't need this one */
1271 close (ConnectionNumber (si->dpy)); /* close display fd */
1273 if (dup2 (out, STDOUT_FILENO) < 0) /* pipe stdout */
1275 perror ("could not dup() a new stdout:");
1279 if (! si->prefs.verbose_p)
1282 if (dup2 (errout, STDERR_FILENO) < 0)
1284 perror ("could not dup() a new stderr:");
1289 hack_subproc_environment (screen, 0); /* set $DISPLAY */
1291 execvp (av[0], av); /* shouldn't return. */
1293 if (errno != ENOENT /* || si->prefs.verbose_p */ )
1295 /* Ignore "no such file or directory" errors.
1296 Issue all other exec errors, though. */
1297 sprintf (buf, "%s: running %s", blurb(), av[0]);
1300 exit (1); /* exits fork */
1306 int wait_status = 0;
1309 FILE *f = fdopen (in, "r");
1310 unsigned long v = 0;
1313 close (out); /* don't need this one */
1316 if (! fgets (buf, sizeof(buf)-1, f))
1320 if (! si->prefs.verbose_p)
1326 /* Wait for the child to die - wait for this pid only, not others. */
1327 pid = waitpid (forked, &wait_status, 0);
1328 if (si->prefs.debug_p)
1330 write_string (STDERR_FILENO, blurb());
1331 write_string (STDERR_FILENO, ": waitpid(");
1332 write_long (STDERR_FILENO, (long) forked);
1333 write_string (STDERR_FILENO, ") ==> ");
1334 write_long (STDERR_FILENO, (long) pid);
1335 write_string (STDERR_FILENO, "\n");
1338 unblock_sigchld(); /* child is dead and waited, unblock now. */
1340 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1345 if (si->prefs.verbose_p)
1347 int L = strlen(buf);
1348 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1351 if (L && buf[L-1] == '\n')
1354 fprintf (stderr, "%s: %s said: \"%s\"\n",
1355 blurb(), av[0], buf);
1361 Visual *v = id_to_visual (screen, result);
1362 if (si->prefs.verbose_p)
1363 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1364 blurb(), screen_number (screen),
1366 (v == DefaultVisualOfScreen (screen)
1367 ? " (default)" : ""));
1378 /* Restarting the xscreensaver process from scratch. */
1380 static char **saved_argv;
1383 save_argv (int argc, char **argv)
1385 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1386 saved_argv [argc] = 0;
1389 int i = strlen (argv [argc]) + 1;
1390 saved_argv [argc] = (char *) malloc (i);
1391 memcpy (saved_argv [argc], argv [argc], i);
1396 /* Re-execs the process with the arguments in saved_argv. Does not return.
1399 restart_process (saver_info *si)
1403 shutdown_stderr (si);
1404 if (si->prefs.verbose_p)
1407 fprintf (stderr, "%s: re-executing", blurb());
1408 for (i = 0; saved_argv[i]; i++)
1409 fprintf (stderr, " %s", saved_argv[i]);
1410 fprintf (stderr, "\n");
1412 describe_uids (si, stderr);
1413 fprintf (stderr, "\n");
1417 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1420 sprintf (buf, "%s: could not restart process", blurb());