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 */
48 #if !defined(SIGCHLD) && defined(SIGCLD)
49 # define SIGCHLD SIGCLD
52 #if 0 /* putenv() is declared in stdlib.h on modern linux systems. */
54 extern int putenv (/* const char * */); /* getenv() is in stdlib.h... */
58 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
60 /* This file doesn't need the Xt headers, so stub these types out... */
62 #define XtAppContext void*
63 #define XrmDatabase void*
64 #define XtIntervalId void*
65 #define XtPointer void*
68 #include "xscreensaver.h"
71 #include "visual.h" /* for id_to_visual() */
73 extern saver_info *global_si_kludge; /* I hate C so much... */
76 /* Used when printing error/debugging messages from signal handlers.
79 no_malloc_number_to_string (long num)
81 static char string[128] = "";
83 Bool negative_p = False;
96 while ((num > 0) && (num_digits < sizeof(string) - 1))
99 digit = (int) num % 10;
101 string[sizeof(string) - 1 - num_digits] = digit + '0';
108 string[sizeof(string) - 1 - num_digits] = '-';
111 return string + sizeof(string) - 1 - num_digits;
114 /* Like write(), but runs strlen() on the arg to get the length. */
116 write_string (int fd, const char *str)
118 return write (fd, str, strlen (str));
122 write_long (int fd, long n)
124 const char *str = no_malloc_number_to_string (n);
125 return write_string (fd, str);
129 /* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size
130 of a process's address space, i.e., the maximal brk(2) and mmap(2) values.
131 Setting this lets you put a cap on how much memory a process can allocate.
133 Except the "and mmap()" part kinda makes this useless, since many GL
134 implementations end up using mmap() to pull the whole frame buffer into
135 memory (or something along those lines) making it appear processes are
136 using hundreds of megabytes when in fact they're using very little, and
137 we end up capping their mallocs prematurely. YAY!
139 #if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
140 # define RLIMIT_AS RLIMIT_VMEM
144 limit_subproc_memory (int address_space_limit, Bool verbose_p)
147 /* This has caused way more problems than it has solved...
148 Let's just completely ignore the "memoryLimit" option now.
150 #undef HAVE_SETRLIMIT
152 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS)
155 if (address_space_limit < 10 * 1024) /* let's not be crazy */
158 if (getrlimit (RLIMIT_AS, &r) != 0)
161 sprintf (buf, "%s: getrlimit(RLIMIT_AS) failed", blurb());
166 r.rlim_cur = address_space_limit;
168 if (setrlimit (RLIMIT_AS, &r) != 0)
171 sprintf (buf, "%s: setrlimit(RLIMIT_AS, {%lu, %lu}) failed",
172 blurb(), r.rlim_cur, r.rlim_max);
179 int i = address_space_limit;
181 if (i >= (1<<30) && i == ((i >> 30) << 30))
182 sprintf(buf, "%dG", i >> 30);
183 else if (i >= (1<<20) && i == ((i >> 20) << 20))
184 sprintf(buf, "%dM", i >> 20);
185 else if (i >= (1<<10) && i == ((i >> 10) << 10))
186 sprintf(buf, "%dK", i >> 10);
188 sprintf(buf, "%d bytes", i);
190 fprintf (stderr, "%s: limited pid %lu address space to %s.\n",
191 blurb(), (unsigned long) getpid (), buf);
194 #endif /* HAVE_SETRLIMIT && RLIMIT_AS */
198 /* Management of child processes, and de-zombification.
202 job_running, /* the process is still alive */
203 job_stopped, /* we have sent it a STOP signal */
204 job_killed, /* we have sent it a TERM signal */
205 job_dead /* we have wait()ed for it, and it's dead -- this state only
206 occurs so that we can avoid calling free() from a signal
207 handler. Shortly after going into this state, the list
208 element will be removed. */
211 struct screenhack_job {
215 enum job_status status;
216 time_t launched, killed;
217 struct screenhack_job *next;
220 static struct screenhack_job *jobs = 0;
222 /* for debugging -- nothing calls this, but it's useful to invoke from gdb.
224 void show_job_list (void);
229 struct screenhack_job *job;
230 fprintf(stderr, "%s: job list:\n", blurb());
231 for (job = jobs; job; job = job->next)
233 char b[] = " ??:??:?? ";
234 char *t = (job->killed ? timestring (job->killed) :
235 job->launched ? timestring (job->launched) : b);
238 fprintf (stderr, " %5ld: %2d: (%s) %s %s\n",
241 (job->status == job_running ? "running" :
242 job->status == job_stopped ? "stopped" :
243 job->status == job_killed ? " killed" :
244 job->status == job_dead ? " dead" : " ???"),
247 fprintf (stderr, "\n");
251 static void clean_job_list (void);
253 static struct screenhack_job *
254 make_job (pid_t pid, int screen, const char *cmd)
256 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
258 static char name [1024];
259 const char *in = cmd;
267 while (isspace(*in)) in++; /* skip whitespace */
268 while (!isspace(*in) && *in != ':') {
269 if (*in == '=') got_eq = 1;
270 *out++ = *in++; /* snarf first token */
273 if (got_eq) /* if the first token was FOO=bar */
274 { /* then get the next token instead. */
281 while (isspace(*in)) in++; /* skip whitespace */
284 job->name = strdup(name);
286 job->screen = screen;
287 job->status = job_running;
288 job->launched = time ((time_t *) 0);
298 free_job (struct screenhack_job *job)
302 else if (job == jobs)
306 struct screenhack_job *job2, *prev;
307 for (prev = 0, job2 = jobs;
309 prev = job2, job2 = job2->next)
312 prev->next = job->next;
321 /* Cleans out dead jobs from the jobs list -- this must only be called
322 from the main thread, not from a signal handler.
325 clean_job_list (void)
327 struct screenhack_job *job, *prev, *next;
328 time_t now = time ((time_t *) 0);
329 static time_t last_warn = 0;
330 Bool warnedp = False;
332 for (prev = 0, job = jobs, next = (job ? job->next : 0);
334 prev = job, job = next, next = (job ? job->next : 0))
336 if (job->status == job_dead)
343 else if (job->status == job_killed &&
344 now - job->killed > 10 &&
345 now - last_warn > 10)
348 "%s: WARNING: pid %ld (%s) sent SIGTERM %ld seconds ago"
349 " and did not die!\n",
353 (long) (now - job->killed));
357 if (warnedp) last_warn = now;
361 static struct screenhack_job *
364 struct screenhack_job *job;
365 for (job = jobs; job; job = job->next)
371 static void await_dying_children (saver_info *si);
373 static void describe_dead_child (saver_info *, pid_t, int wait_status);
377 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
378 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
380 static int block_sigchld_handler = 0;
383 #ifdef HAVE_SIGACTION
385 #else /* !HAVE_SIGACTION */
387 #endif /* !HAVE_SIGACTION */
390 #ifdef HAVE_SIGACTION
394 memset (&sa, 0, sizeof (sa));
395 sa.sa_handler = SIG_IGN;
396 sigaction (SIGPIPE, &sa, NULL);
398 sigemptyset (&child_set);
399 sigaddset (&child_set, SIGCHLD);
400 sigprocmask (SIG_BLOCK, &child_set, 0);
402 #else /* !HAVE_SIGACTION */
403 signal (SIGPIPE, SIG_IGN);
404 #endif /* !HAVE_SIGACTION */
406 block_sigchld_handler++;
408 #ifdef HAVE_SIGACTION
410 #else /* !HAVE_SIGACTION */
412 #endif /* !HAVE_SIGACTION */
416 unblock_sigchld (void)
418 if (block_sigchld_handler <= 0)
421 if (block_sigchld_handler <= 1) /* only unblock if count going to 0 */
423 #ifdef HAVE_SIGACTION
427 memset(&sa, 0, sizeof (sa));
428 sa.sa_handler = SIG_DFL;
429 sigaction(SIGPIPE, &sa, NULL);
431 sigemptyset(&child_set);
432 sigaddset(&child_set, SIGCHLD);
433 sigprocmask(SIG_UNBLOCK, &child_set, 0);
435 #else /* !HAVE_SIGACTION */
436 signal(SIGPIPE, SIG_DFL);
437 #endif /* !HAVE_SIGACTION */
440 block_sigchld_handler--;
444 kill_job (saver_info *si, pid_t pid, int signal)
446 saver_preferences *p = &si->prefs;
447 struct screenhack_job *job;
452 if (in_signal_handler_p)
453 /* This function should not be called from the signal handler. */
456 block_sigchld(); /* we control the horizontal... */
458 job = find_job (pid);
461 job->status == job_killed)
464 fprintf (stderr, "%s: no child %ld to signal!\n",
465 blurb(), (long) pid);
471 job->status = job_killed;
472 job->killed = time ((time_t *) 0);
475 /* #### there must be a way to do this on VMS... */
476 case SIGSTOP: job->status = job_stopped; break;
477 case SIGCONT: job->status = job_running; break;
483 fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
484 blurb(), job->screen,
485 (job->status == job_killed ? "killing" :
486 job->status == job_stopped ? "suspending" : "resuming"),
487 (unsigned long) job->pid,
490 status = kill (job->pid, signal);
492 if (p->verbose_p && status < 0)
496 "%s: %d: child process %lu (%s) was already dead.\n",
497 blurb(), job->screen, (unsigned long) job->pid, job->name);
501 sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
502 blurb(), job->screen, (unsigned long) job->pid, job->name);
507 await_dying_children (si);
511 if (block_sigchld_handler < 0)
521 sigchld_handler (int sig)
523 saver_info *si = global_si_kludge; /* I hate C so much... */
524 in_signal_handler_p++;
526 if (si->prefs.debug_p)
528 /* Don't call fprintf() from signal handlers, as it might malloc.
529 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
530 (block_sigchld_handler ? " (blocked)" : ""));
532 write_string (STDERR_FILENO, blurb());
533 write_string (STDERR_FILENO, ": got SIGCHLD");
535 if (block_sigchld_handler)
536 write_string (STDERR_FILENO, " (blocked)\n");
538 write_string (STDERR_FILENO, "\n");
541 if (block_sigchld_handler < 0)
543 else if (block_sigchld_handler == 0)
546 await_dying_children (si);
551 in_signal_handler_p--;
559 await_dying_children (saver_info *si)
567 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
569 if (si->prefs.debug_p)
571 if (kid < 0 && errno)
573 /* Don't call fprintf() from signal handlers, as it might malloc.
574 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
577 write_string (STDERR_FILENO, blurb());
578 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
579 write_long (STDERR_FILENO, (long) kid);
580 write_string (STDERR_FILENO, " (");
581 write_long (STDERR_FILENO, (long) errno);
582 write_string (STDERR_FILENO, ")\n");
586 /* Don't call fprintf() from signal handlers, as it might malloc.
587 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
590 write_string (STDERR_FILENO, blurb());
591 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
592 write_long (STDERR_FILENO, (long) kid);
593 write_string (STDERR_FILENO, "\n");
597 /* 0 means no more children to reap.
598 -1 means error -- except "interrupted system call" isn't a "real"
599 error, so if we get that, we should just try again. */
601 (kid < 0 && errno != EINTR))
604 describe_dead_child (si, kid, wait_status);
610 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
613 saver_preferences *p = &si->prefs;
614 struct screenhack_job *job = find_job (kid);
615 const char *name = job ? job->name : "<unknown>";
616 int screen_no = job ? job->screen : 0;
618 if (WIFEXITED (wait_status))
620 int exit_status = WEXITSTATUS (wait_status);
622 /* Treat exit code as a signed 8-bit quantity. */
623 if (exit_status & 0x80) exit_status |= ~0xFF;
625 /* One might assume that exiting with non-0 means something went wrong.
626 But that loser xswarm exits with the code that it was killed with, so
627 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
628 mention them) if we've just killed the subprocess. But mention them
629 if they happen on their own.
633 (p->verbose_p || job->status != job_killed)))
635 /* Don't call fprintf() from signal handlers, as it might malloc.
637 "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
638 blurb(), screen_no, (unsigned long) kid, name, exit_status);
640 write_string (STDERR_FILENO, blurb());
641 write_string (STDERR_FILENO, ": ");
642 write_long (STDERR_FILENO, (long) screen_no);
643 write_string (STDERR_FILENO, ": child pid ");
644 write_long (STDERR_FILENO, (long) kid);
645 write_string (STDERR_FILENO, " (");
646 write_string (STDERR_FILENO, name);
647 write_string (STDERR_FILENO, ") exited abnormally (code ");
648 write_long (STDERR_FILENO, (long) exit_status);
649 write_string (STDERR_FILENO, ").\n");
651 else if (p->verbose_p)
653 /* Don't call fprintf() from signal handlers, as it might malloc.
654 fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
655 blurb(), screen_no, (unsigned long) kid, name);
657 write_string (STDERR_FILENO, blurb());
658 write_string (STDERR_FILENO, ": ");
659 write_long (STDERR_FILENO, (long) screen_no);
660 write_string (STDERR_FILENO, ": child pid ");
661 write_long (STDERR_FILENO, (long) kid);
662 write_string (STDERR_FILENO, " (");
663 write_string (STDERR_FILENO, name);
664 write_string (STDERR_FILENO, ") exited normally.\n");
668 job->status = job_dead;
670 else if (WIFSIGNALED (wait_status))
674 job->status != job_killed ||
675 WTERMSIG (wait_status) != SIGTERM)
677 /* Don't call fprintf() from signal handlers, as it might malloc.
678 fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
679 blurb(), screen_no, (unsigned long) kid, name,
680 signal_name (WTERMSIG(wait_status)));
682 write_string (STDERR_FILENO, blurb());
683 write_string (STDERR_FILENO, ": ");
684 write_long (STDERR_FILENO, (long) screen_no);
685 write_string (STDERR_FILENO, ": child pid ");
686 write_long (STDERR_FILENO, (long) kid);
687 write_string (STDERR_FILENO, " (");
688 write_string (STDERR_FILENO, name);
689 write_string (STDERR_FILENO, ") terminated with signal ");
690 write_long (STDERR_FILENO, WTERMSIG(wait_status));
691 write_string (STDERR_FILENO, ".\n");
695 job->status = job_dead;
697 else if (WIFSTOPPED (wait_status))
701 /* Don't call fprintf() from signal handlers, as it might malloc.
702 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
703 blurb(), (unsigned long) kid, name,
704 signal_name (WSTOPSIG (wait_status)));
706 write_string (STDERR_FILENO, blurb());
707 write_string (STDERR_FILENO, ": ");
708 write_long (STDERR_FILENO, (long) screen_no);
709 write_string (STDERR_FILENO, ": child pid ");
710 write_long (STDERR_FILENO, (long) kid);
711 write_string (STDERR_FILENO, " (");
712 write_string (STDERR_FILENO, name);
713 write_string (STDERR_FILENO, ") stopped with signal ");
714 write_long (STDERR_FILENO, WSTOPSIG(wait_status));
715 write_string (STDERR_FILENO, ".\n");
719 job->status = job_stopped;
723 /* Don't call fprintf() from signal handlers, as it might malloc.
724 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
725 blurb(), (unsigned long) kid, name);
727 write_string (STDERR_FILENO, blurb());
728 write_string (STDERR_FILENO, ": ");
729 write_long (STDERR_FILENO, (long) screen_no);
730 write_string (STDERR_FILENO, ": child pid ");
731 write_long (STDERR_FILENO, (long) kid);
732 write_string (STDERR_FILENO, " (");
733 write_string (STDERR_FILENO, name);
734 write_string (STDERR_FILENO, ") died in a mysterious way!");
736 job->status = job_dead;
739 /* Clear out the pid so that screenhack_running_p() knows it's dead.
741 if (!job || job->status == job_dead)
742 for (i = 0; i < si->nscreens; i++)
744 saver_screen_info *ssi = &si->screens[i];
751 static void await_dying_children (saver_info *si) { return; }
760 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
762 static Bool sigchld_initialized_p = 0;
763 if (!sigchld_initialized_p)
765 struct sigaction action, old;
767 action.sa_handler = sigchld_handler;
768 sigemptyset(&action.sa_mask);
771 if (sigaction(SIGCHLD, &action, &old) < 0)
774 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
777 sigchld_initialized_p = True;
780 # else /* !HAVE_SIGACTION */
782 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
785 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
788 # endif /* !HAVE_SIGACTION */
797 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
799 saver_info *si = ssi->global;
800 saver_preferences *p = &si->prefs;
803 if (hack->visual && *hack->visual)
804 selected = select_visual(ssi, hack->visual);
806 selected = select_visual(ssi, 0);
808 if (!selected && (p->verbose_p || si->demoing_p))
811 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
812 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
814 (hack->visual && *hack->visual ? hack->visual : "???"),
822 print_path_error (const char *program)
825 char *cmd = strdup (program);
826 char *token = strchr (cmd, ' ');
828 if (token) *token = 0;
829 sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
833 if (errno == ENOENT &&
834 (token = getenv("PATH")))
838 # define PATH_MAX MAXPATHLEN
840 # define PATH_MAX 2048
844 fprintf (stderr, "\n");
846 # if defined(HAVE_GETCWD)
847 if (! getcwd (path, sizeof(path)))
849 # elif defined(HAVE_GETWD)
853 fprintf (stderr, " Current directory is: %s\n", path);
854 fprintf (stderr, " PATH is:\n");
855 token = strtok (strdup(token), ":");
858 fprintf (stderr, " %s\n", token);
859 token = strtok(0, ":");
861 fprintf (stderr, "\n");
866 /* Executes the command in another process.
867 Command may be any single command acceptable to /bin/sh.
868 It may include wildcards, but no semicolons.
869 If successful, the pid of the other process is returned.
870 Otherwise, -1 is returned and an error may have been
874 fork_and_exec (saver_screen_info *ssi, const char *command)
876 saver_info *si = ssi->global;
877 saver_preferences *p = &si->prefs;
880 switch ((int) (forked = fork ()))
885 sprintf (buf, "%s: couldn't fork", blurb());
891 close (ConnectionNumber (si->dpy)); /* close display fd */
892 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
893 hack_subproc_environment (ssi->screen, ssi->screensaver_window);
896 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
897 blurb(), ssi->number, command,
898 (unsigned long) getpid ());
900 exec_command (p->shell, command, p->nice_inferior);
902 /* If that returned, we were unable to exec the subprocess.
903 Print an error message, if desired.
905 if (! p->ignore_uninstalled_p)
906 print_path_error (command);
908 exit (1); /* exits child fork */
911 default: /* parent */
912 (void) make_job (forked, ssi->number, command);
921 spawn_screenhack (saver_screen_info *ssi)
923 saver_info *si = ssi->global;
924 saver_preferences *p = &si->prefs;
927 if (!monitor_powered_on_p (si))
929 if (si->prefs.verbose_p)
931 "%s: %d: X says monitor has powered down; "
932 "not launching a hack.\n", blurb(), ssi->number);
936 if (p->screenhacks_count)
947 if (p->screenhacks_count < 1)
949 /* No hacks at all */
952 else if (p->screenhacks_count == 1)
954 /* Exactly one hack in the list */
957 else if (si->selection_mode == -1)
959 /* Select the next hack, wrapping. */
960 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
962 else if (si->selection_mode == -2)
964 /* Select the previous hack, wrapping. */
965 if (ssi->current_hack < 0)
966 new_hack = p->screenhacks_count - 1;
968 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
969 % p->screenhacks_count);
971 else if (si->selection_mode > 0)
973 /* Select a specific hack, by number (via the ACTIVATE command.) */
974 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
977 else if (p->mode == ONE_HACK &&
978 p->selected_hack >= 0)
980 /* Select a specific hack, by number (via "One Saver" mode.) */
981 new_hack = p->selected_hack;
984 else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
988 else if (p->mode == RANDOM_HACKS_SAME &&
991 /* Use the same hack that's running on screen 0.
992 (Assumes this function was called on screen 0 first.)
994 new_hack = si->screens[0].current_hack;
996 else /* (p->mode == RANDOM_HACKS) */
998 /* Select a random hack (but not the one we just ran.) */
999 while ((new_hack = random () % p->screenhacks_count)
1000 == ssi->current_hack)
1004 if (new_hack < 0) /* don't run a hack */
1006 ssi->current_hack = -1;
1007 if (si->selection_mode < 0)
1008 si->selection_mode = 0;
1012 ssi->current_hack = new_hack;
1013 hack = p->screenhacks[ssi->current_hack];
1015 /* If the hack is disabled, or there is no visual for this hack,
1016 then try again (move forward, or backward, or re-randomize.)
1017 Unless this hack was specified explicitly, in which case,
1021 select_visual_of_hack (ssi, hack);
1024 (!hack->enabled_p ||
1025 !on_path_p (hack->command) ||
1026 !select_visual_of_hack (ssi, hack)))
1028 if (++retry_count > (p->screenhacks_count*4))
1030 /* Uh, oops. Odds are, there are no suitable visuals,
1031 and we're looping. Give up. (This is totally lame,
1032 what we should do is make a list of suitable hacks at
1033 the beginning, then only loop over them.)
1037 "%s: %d: no programs enabled, or no suitable visuals.\n",
1038 blurb(), ssi->number);
1045 /* Turn off "next" and "prev" modes now, but "demo" mode is only
1046 turned off by explicit action.
1048 if (si->selection_mode < 0)
1049 si->selection_mode = 0;
1051 forked = fork_and_exec (ssi, hack->command);
1052 switch ((int) forked)
1054 case -1: /* fork failed */
1055 case 0: /* child fork (can't happen) */
1056 sprintf (buf, "%s: couldn't fork", blurb());
1058 restore_real_vroot (si);
1059 saver_exit (si, 1, "couldn't fork");
1068 store_saver_status (si); /* store current hack number */
1073 kill_screenhack (saver_screen_info *ssi)
1075 saver_info *si = ssi->global;
1077 kill_job (si, ssi->pid, SIGTERM);
1083 suspend_screenhack (saver_screen_info *ssi, Bool suspend_p)
1085 #ifdef SIGSTOP /* older VMS doesn't have it... */
1086 saver_info *si = ssi->global;
1088 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1089 #endif /* SIGSTOP */
1093 /* Called when we're exiting abnormally, to kill off the subproc. */
1095 emergency_kill_subproc (saver_info *si)
1099 signal (SIGCHLD, SIG_IGN);
1100 #endif /* SIGCHLD */
1102 for (i = 0; i < si->nscreens; i++)
1104 saver_screen_info *ssi = &si->screens[i];
1107 kill_job (si, ssi->pid, SIGTERM);
1114 screenhack_running_p (saver_info *si)
1116 Bool any_running_p = False;
1118 for (i = 0; i < si->nscreens; i++)
1120 saver_screen_info *ssi = &si->screens[i];
1121 if (ssi->pid) any_running_p = True;
1123 return any_running_p;
1127 /* Environment variables. */
1130 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
1131 is defined, the xscreensaver daemon will search that directory for hacks.
1134 hack_environment (saver_info *si)
1136 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1137 static const char *def_path = DEFAULT_PATH_PREFIX;
1138 if (def_path && *def_path)
1140 const char *opath = getenv("PATH");
1142 if (! opath) opath = "/bin:/usr/bin"; /* WTF */
1143 npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1144 strcpy (npath, "PATH=");
1145 strcat (npath, def_path);
1146 strcat (npath, ":");
1147 strcat (npath, opath);
1152 /* don't free (npath) -- some implementations of putenv (BSD 4.4,
1153 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1154 do not. So we must leak it (and/or the previous setting). Yay.
1157 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1162 hack_subproc_environment (Screen *screen, Window saver_window)
1164 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1165 the spawned processes inherit is correct. First, it must be on the same
1166 host and display as the value of -display passed in on our command line
1167 (which is not necessarily the same as what our $DISPLAY variable is.)
1168 Second, the screen number in the $DISPLAY passed to the subprocess should
1169 be the screen on which this particular hack is running -- not the display
1170 specification which the driver itself is using, since the driver ignores
1171 its screen number and manages all existing screens.
1173 Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
1174 us to (eventually) run multiple hacks in Xinerama mode, where each hack
1175 has the same $DISPLAY but a different piece of glass.
1177 Display *dpy = DisplayOfScreen (screen);
1178 const char *odpy = DisplayString (dpy);
1179 char *ndpy = (char *) malloc (strlen(odpy) + 20);
1180 char *nssw = (char *) malloc (40);
1183 strcpy (ndpy, "DISPLAY=");
1184 s = ndpy + strlen(ndpy);
1187 /* We have to find the last colon since it is the boundary between
1188 hostname & screen - IPv6 numeric format addresses may have many
1189 colons before that point, and DECnet addresses always have two colons */
1190 c = strrchr(s,':'); /* skip to last colon */
1191 if (c != NULL) s = c+1;
1192 while (isdigit(*s)) s++; /* skip over dpy number */
1193 while (*s == '.') s++; /* skip over dot */
1194 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1195 sprintf(s, "%d", screen_number (screen)); /* put on screen number */
1197 sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", (unsigned long) saver_window);
1199 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1200 any more, right? It's not Posix, but everyone seems to have it. */
1207 /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
1208 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1209 do not. So we must leak it (and/or the previous setting). Yay.
1211 #endif /* HAVE_PUTENV */
1218 get_best_gl_visual (saver_info *si, Screen *screen)
1224 int errin = -1, errout = -1;
1230 av[ac++] = "xscreensaver-gl-helper";
1235 perror ("error creating pipe:");
1242 if (!si->prefs.verbose_p)
1246 perror ("error creating pipe:");
1251 errout = errfds [1];
1254 block_sigchld(); /* This blocks it in the parent and child, to avoid
1255 racing. It is never unblocked in the child before
1256 the child exits, but that doesn't matter.
1259 switch ((int) (forked = fork ()))
1263 sprintf (buf, "%s: couldn't fork", blurb());
1265 saver_exit (si, 1, 0);
1269 close (in); /* don't need this one */
1270 close (ConnectionNumber (si->dpy)); /* close display fd */
1272 if (dup2 (out, STDOUT_FILENO) < 0) /* pipe stdout */
1274 perror ("could not dup() a new stdout:");
1278 if (! si->prefs.verbose_p)
1281 if (dup2 (errout, STDERR_FILENO) < 0)
1283 perror ("could not dup() a new stderr:");
1288 hack_subproc_environment (screen, 0); /* set $DISPLAY */
1290 execvp (av[0], av); /* shouldn't return. */
1292 if (errno != ENOENT /* || si->prefs.verbose_p */ )
1294 /* Ignore "no such file or directory" errors.
1295 Issue all other exec errors, though. */
1296 sprintf (buf, "%s: running %s", blurb(), av[0]);
1299 exit (1); /* exits fork */
1305 int wait_status = 0;
1307 FILE *f = fdopen (in, "r");
1308 unsigned long v = 0;
1311 close (out); /* don't need this one */
1314 if (! fgets (buf, sizeof(buf)-1, f))
1318 if (! si->prefs.verbose_p)
1324 /* Wait for the child to die. */
1325 waitpid (-1, &wait_status, 0);
1327 unblock_sigchld(); /* child is dead and waited, unblock now. */
1329 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1334 if (si->prefs.verbose_p)
1336 int L = strlen(buf);
1337 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1340 if (L && buf[L-1] == '\n')
1343 fprintf (stderr, "%s: %s said: \"%s\"\n",
1344 blurb(), av[0], buf);
1350 Visual *v = id_to_visual (screen, result);
1351 if (si->prefs.verbose_p)
1352 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1353 blurb(), screen_number (screen),
1355 (v == DefaultVisualOfScreen (screen)
1356 ? " (default)" : ""));
1367 /* Restarting the xscreensaver process from scratch. */
1369 static char **saved_argv;
1372 save_argv (int argc, char **argv)
1374 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1375 saved_argv [argc] = 0;
1378 int i = strlen (argv [argc]) + 1;
1379 saved_argv [argc] = (char *) malloc (i);
1380 memcpy (saved_argv [argc], argv [argc], i);
1385 /* Re-execs the process with the arguments in saved_argv. Does not return.
1388 restart_process (saver_info *si)
1392 shutdown_stderr (si);
1393 if (si->prefs.verbose_p)
1396 fprintf (stderr, "%s: re-executing", blurb());
1397 for (i = 0; saved_argv[i]; i++)
1398 fprintf (stderr, " %s", saved_argv[i]);
1399 fprintf (stderr, "\n");
1401 describe_uids (si, stderr);
1402 fprintf (stderr, "\n");
1406 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1409 sprintf (buf, "%s: could not restart process", blurb());