1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991-2008 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 struct screenhack_job *next;
219 static struct screenhack_job *jobs = 0;
221 /* for debugging -- nothing calls this, but it's useful to invoke from gdb.
223 void show_job_list (void);
228 struct screenhack_job *job;
229 fprintf(stderr, "%s: job list:\n", blurb());
230 for (job = jobs; job; job = job->next)
231 fprintf (stderr, " %5ld: %2d: (%s) %s\n",
234 (job->status == job_running ? "running" :
235 job->status == job_stopped ? "stopped" :
236 job->status == job_killed ? " killed" :
237 job->status == job_dead ? " dead" : " ???"),
239 fprintf (stderr, "\n");
243 static void clean_job_list (void);
245 static struct screenhack_job *
246 make_job (pid_t pid, int screen, const char *cmd)
248 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
250 static char name [1024];
251 const char *in = cmd;
259 while (isspace(*in)) in++; /* skip whitespace */
260 while (!isspace(*in) && *in != ':') {
261 if (*in == '=') got_eq = 1;
262 *out++ = *in++; /* snarf first token */
265 if (got_eq) /* if the first token was FOO=bar */
266 { /* then get the next token instead. */
273 while (isspace(*in)) in++; /* skip whitespace */
276 job->name = strdup(name);
278 job->screen = screen;
279 job->status = job_running;
288 free_job (struct screenhack_job *job)
292 else if (job == jobs)
296 struct screenhack_job *job2, *prev;
297 for (prev = 0, job2 = jobs;
299 prev = job2, job2 = job2->next)
302 prev->next = job->next;
311 /* Cleans out dead jobs from the jobs list -- this must only be called
312 from the main thread, not from a signal handler.
315 clean_job_list (void)
317 struct screenhack_job *job, *prev, *next;
318 for (prev = 0, job = jobs, next = (job ? job->next : 0);
320 prev = job, job = next, next = (job ? job->next : 0))
322 if (job->status == job_dead)
333 static struct screenhack_job *
336 struct screenhack_job *job;
337 for (job = jobs; job; job = job->next)
343 static void await_dying_children (saver_info *si);
345 static void describe_dead_child (saver_info *, pid_t, int wait_status);
349 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
350 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
352 static int block_sigchld_handler = 0;
355 #ifdef HAVE_SIGACTION
357 #else /* !HAVE_SIGACTION */
359 #endif /* !HAVE_SIGACTION */
362 #ifdef HAVE_SIGACTION
366 memset (&sa, 0, sizeof (sa));
367 sa.sa_handler = SIG_IGN;
368 sigaction (SIGPIPE, &sa, NULL);
370 sigemptyset (&child_set);
371 sigaddset (&child_set, SIGCHLD);
372 sigprocmask (SIG_BLOCK, &child_set, 0);
374 #else /* !HAVE_SIGACTION */
375 signal (SIGPIPE, SIG_IGN);
376 #endif /* !HAVE_SIGACTION */
378 block_sigchld_handler++;
380 #ifdef HAVE_SIGACTION
382 #else /* !HAVE_SIGACTION */
384 #endif /* !HAVE_SIGACTION */
388 unblock_sigchld (void)
390 #ifdef HAVE_SIGACTION
394 memset(&sa, 0, sizeof (sa));
395 sa.sa_handler = SIG_DFL;
396 sigaction(SIGPIPE, &sa, NULL);
398 sigemptyset(&child_set);
399 sigaddset(&child_set, SIGCHLD);
400 sigprocmask(SIG_UNBLOCK, &child_set, 0);
402 #else /* !HAVE_SIGACTION */
403 signal(SIGPIPE, SIG_DFL);
404 #endif /* !HAVE_SIGACTION */
406 block_sigchld_handler--;
410 kill_job (saver_info *si, pid_t pid, int signal)
412 saver_preferences *p = &si->prefs;
413 struct screenhack_job *job;
418 if (block_sigchld_handler)
419 /* This function should not be called from the signal handler. */
422 block_sigchld(); /* we control the horizontal... */
424 job = find_job (pid);
427 job->status == job_killed)
430 fprintf (stderr, "%s: no child %ld to signal!\n",
431 blurb(), (long) pid);
436 case SIGTERM: job->status = job_killed; break;
438 /* #### there must be a way to do this on VMS... */
439 case SIGSTOP: job->status = job_stopped; break;
440 case SIGCONT: job->status = job_running; break;
446 fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
447 blurb(), job->screen,
448 (job->status == job_killed ? "killing" :
449 job->status == job_stopped ? "suspending" : "resuming"),
450 (unsigned long) job->pid,
453 status = kill (job->pid, signal);
455 if (p->verbose_p && status < 0)
459 "%s: %d: child process %lu (%s) was already dead.\n",
460 blurb(), job->screen, (unsigned long) job->pid, job->name);
464 sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
465 blurb(), job->screen, (unsigned long) job->pid, job->name);
470 await_dying_children (si);
474 if (block_sigchld_handler < 0)
484 sigchld_handler (int sig)
486 saver_info *si = global_si_kludge; /* I hate C so much... */
488 if (si->prefs.debug_p)
490 /* Don't call fprintf() from signal handlers, as it might malloc.
491 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
492 (block_sigchld_handler ? " (blocked)" : ""));
494 write_string (STDERR_FILENO, blurb());
495 write_string (STDERR_FILENO, ": got SIGCHLD");
497 if (block_sigchld_handler)
498 write_string (STDERR_FILENO, " (blocked)\n");
500 write_string (STDERR_FILENO, "\n");
503 if (block_sigchld_handler < 0)
505 else if (block_sigchld_handler == 0)
508 await_dying_children (si);
520 await_dying_children (saver_info *si)
528 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
530 if (si->prefs.debug_p)
532 if (kid < 0 && errno)
534 /* Don't call fprintf() from signal handlers, as it might malloc.
535 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
538 write_string (STDERR_FILENO, blurb());
539 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
540 write_long (STDERR_FILENO, (long) kid);
541 write_string (STDERR_FILENO, " (");
542 write_long (STDERR_FILENO, (long) errno);
543 write_string (STDERR_FILENO, ")\n");
547 /* Don't call fprintf() from signal handlers, as it might malloc.
548 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
551 write_string (STDERR_FILENO, blurb());
552 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
553 write_long (STDERR_FILENO, (long) kid);
554 write_string (STDERR_FILENO, "\n");
558 /* 0 means no more children to reap.
559 -1 means error -- except "interrupted system call" isn't a "real"
560 error, so if we get that, we should just try again. */
562 (kid < 0 && errno != EINTR))
565 describe_dead_child (si, kid, wait_status);
571 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
574 saver_preferences *p = &si->prefs;
575 struct screenhack_job *job = find_job (kid);
576 const char *name = job ? job->name : "<unknown>";
577 int screen_no = job ? job->screen : 0;
579 if (WIFEXITED (wait_status))
581 int exit_status = WEXITSTATUS (wait_status);
583 /* Treat exit code as a signed 8-bit quantity. */
584 if (exit_status & 0x80) exit_status |= ~0xFF;
586 /* One might assume that exiting with non-0 means something went wrong.
587 But that loser xswarm exits with the code that it was killed with, so
588 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
589 mention them) if we've just killed the subprocess. But mention them
590 if they happen on their own.
594 (p->verbose_p || job->status != job_killed)))
596 /* Don't call fprintf() from signal handlers, as it might malloc.
598 "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
599 blurb(), screen_no, (unsigned long) kid, name, exit_status);
601 write_string (STDERR_FILENO, blurb());
602 write_string (STDERR_FILENO, ": ");
603 write_long (STDERR_FILENO, (long) screen_no);
604 write_string (STDERR_FILENO, ": child pid ");
605 write_long (STDERR_FILENO, (long) kid);
606 write_string (STDERR_FILENO, " (");
607 write_string (STDERR_FILENO, name);
608 write_string (STDERR_FILENO, ") exited abnormally (code ");
609 write_long (STDERR_FILENO, (long) exit_status);
610 write_string (STDERR_FILENO, ").\n");
612 else if (p->verbose_p)
614 /* Don't call fprintf() from signal handlers, as it might malloc.
615 fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
616 blurb(), screen_no, (unsigned long) kid, name);
618 write_string (STDERR_FILENO, blurb());
619 write_string (STDERR_FILENO, ": ");
620 write_long (STDERR_FILENO, (long) screen_no);
621 write_string (STDERR_FILENO, ": child pid ");
622 write_long (STDERR_FILENO, (long) kid);
623 write_string (STDERR_FILENO, " (");
624 write_string (STDERR_FILENO, name);
625 write_string (STDERR_FILENO, ") exited normally.\n");
629 job->status = job_dead;
631 else if (WIFSIGNALED (wait_status))
635 job->status != job_killed ||
636 WTERMSIG (wait_status) != SIGTERM)
638 /* Don't call fprintf() from signal handlers, as it might malloc.
639 fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
640 blurb(), screen_no, (unsigned long) kid, name,
641 signal_name (WTERMSIG(wait_status)));
643 write_string (STDERR_FILENO, blurb());
644 write_string (STDERR_FILENO, ": ");
645 write_long (STDERR_FILENO, (long) screen_no);
646 write_string (STDERR_FILENO, ": child pid ");
647 write_long (STDERR_FILENO, (long) kid);
648 write_string (STDERR_FILENO, " (");
649 write_string (STDERR_FILENO, name);
650 write_string (STDERR_FILENO, ") terminated with signal ");
651 write_long (STDERR_FILENO, WTERMSIG(wait_status));
652 write_string (STDERR_FILENO, ".\n");
656 job->status = job_dead;
658 else if (WIFSTOPPED (wait_status))
662 /* Don't call fprintf() from signal handlers, as it might malloc.
663 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
664 blurb(), (unsigned long) kid, name,
665 signal_name (WSTOPSIG (wait_status)));
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, ") stopped with signal ");
675 write_long (STDERR_FILENO, WSTOPSIG(wait_status));
676 write_string (STDERR_FILENO, ".\n");
680 job->status = job_stopped;
684 /* Don't call fprintf() from signal handlers, as it might malloc.
685 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
686 blurb(), (unsigned long) kid, name);
688 write_string (STDERR_FILENO, blurb());
689 write_string (STDERR_FILENO, ": ");
690 write_long (STDERR_FILENO, (long) screen_no);
691 write_string (STDERR_FILENO, ": child pid ");
692 write_long (STDERR_FILENO, (long) kid);
693 write_string (STDERR_FILENO, " (");
694 write_string (STDERR_FILENO, name);
695 write_string (STDERR_FILENO, ") died in a mysterious way!");
697 job->status = job_dead;
700 /* Clear out the pid so that screenhack_running_p() knows it's dead.
702 if (!job || job->status == job_dead)
703 for (i = 0; i < si->nscreens; i++)
705 saver_screen_info *ssi = &si->screens[i];
712 static void await_dying_children (saver_info *si) { return; }
721 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
723 static Bool sigchld_initialized_p = 0;
724 if (!sigchld_initialized_p)
726 struct sigaction action, old;
728 action.sa_handler = sigchld_handler;
729 sigemptyset(&action.sa_mask);
732 if (sigaction(SIGCHLD, &action, &old) < 0)
735 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
738 sigchld_initialized_p = True;
741 # else /* !HAVE_SIGACTION */
743 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
746 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
749 # endif /* !HAVE_SIGACTION */
758 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
760 saver_info *si = ssi->global;
761 saver_preferences *p = &si->prefs;
764 if (hack->visual && *hack->visual)
765 selected = select_visual(ssi, hack->visual);
767 selected = select_visual(ssi, 0);
769 if (!selected && (p->verbose_p || si->demoing_p))
772 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
773 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
775 (hack->visual && *hack->visual ? hack->visual : "???"),
783 print_path_error (const char *program)
786 char *cmd = strdup (program);
787 char *token = strchr (cmd, ' ');
789 if (token) *token = 0;
790 sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
794 if (errno == ENOENT &&
795 (token = getenv("PATH")))
799 # define PATH_MAX MAXPATHLEN
801 # define PATH_MAX 2048
805 fprintf (stderr, "\n");
807 # if defined(HAVE_GETCWD)
808 if (! getcwd (path, sizeof(path)))
810 # elif defined(HAVE_GETWD)
814 fprintf (stderr, " Current directory is: %s\n", path);
815 fprintf (stderr, " PATH is:\n");
816 token = strtok (strdup(token), ":");
819 fprintf (stderr, " %s\n", token);
820 token = strtok(0, ":");
822 fprintf (stderr, "\n");
827 /* Executes the command in another process.
828 Command may be any single command acceptable to /bin/sh.
829 It may include wildcards, but no semicolons.
830 If successful, the pid of the other process is returned.
831 Otherwise, -1 is returned and an error may have been
835 fork_and_exec (saver_screen_info *ssi, const char *command)
837 saver_info *si = ssi->global;
838 saver_preferences *p = &si->prefs;
841 switch ((int) (forked = fork ()))
846 sprintf (buf, "%s: couldn't fork", blurb());
852 close (ConnectionNumber (si->dpy)); /* close display fd */
853 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
854 hack_subproc_environment (ssi->screen, ssi->screensaver_window);
857 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
858 blurb(), ssi->number, command,
859 (unsigned long) getpid ());
861 exec_command (p->shell, command, p->nice_inferior);
863 /* If that returned, we were unable to exec the subprocess.
864 Print an error message, if desired.
866 if (! p->ignore_uninstalled_p)
867 print_path_error (command);
869 exit (1); /* exits child fork */
872 default: /* parent */
873 (void) make_job (forked, ssi->number, command);
882 spawn_screenhack (saver_screen_info *ssi)
884 saver_info *si = ssi->global;
885 saver_preferences *p = &si->prefs;
888 if (!monitor_powered_on_p (si))
890 if (si->prefs.verbose_p)
892 "%s: %d: X says monitor has powered down; "
893 "not launching a hack.\n", blurb(), ssi->number);
897 if (p->screenhacks_count)
908 if (p->screenhacks_count < 1)
910 /* No hacks at all */
913 else if (p->screenhacks_count == 1)
915 /* Exactly one hack in the list */
918 else if (si->selection_mode == -1)
920 /* Select the next hack, wrapping. */
921 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
923 else if (si->selection_mode == -2)
925 /* Select the previous hack, wrapping. */
926 if (ssi->current_hack < 0)
927 new_hack = p->screenhacks_count - 1;
929 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
930 % p->screenhacks_count);
932 else if (si->selection_mode > 0)
934 /* Select a specific hack, by number (via the ACTIVATE command.) */
935 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
938 else if (p->mode == ONE_HACK &&
939 p->selected_hack >= 0)
941 /* Select a specific hack, by number (via "One Saver" mode.) */
942 new_hack = p->selected_hack;
945 else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
949 else if (p->mode == RANDOM_HACKS_SAME &&
952 /* Use the same hack that's running on screen 0.
953 (Assumes this function was called on screen 0 first.)
955 new_hack = si->screens[0].current_hack;
957 else /* (p->mode == RANDOM_HACKS) */
959 /* Select a random hack (but not the one we just ran.) */
960 while ((new_hack = random () % p->screenhacks_count)
961 == ssi->current_hack)
965 if (new_hack < 0) /* don't run a hack */
967 ssi->current_hack = -1;
968 if (si->selection_mode < 0)
969 si->selection_mode = 0;
973 ssi->current_hack = new_hack;
974 hack = p->screenhacks[ssi->current_hack];
976 /* If the hack is disabled, or there is no visual for this hack,
977 then try again (move forward, or backward, or re-randomize.)
978 Unless this hack was specified explicitly, in which case,
982 select_visual_of_hack (ssi, hack);
986 !on_path_p (hack->command) ||
987 !select_visual_of_hack (ssi, hack)))
989 if (++retry_count > (p->screenhacks_count*4))
991 /* Uh, oops. Odds are, there are no suitable visuals,
992 and we're looping. Give up. (This is totally lame,
993 what we should do is make a list of suitable hacks at
994 the beginning, then only loop over them.)
998 "%s: %d: no programs enabled, or no suitable visuals.\n",
999 blurb(), ssi->number);
1006 /* Turn off "next" and "prev" modes now, but "demo" mode is only
1007 turned off by explicit action.
1009 if (si->selection_mode < 0)
1010 si->selection_mode = 0;
1012 forked = fork_and_exec (ssi, hack->command);
1013 switch ((int) forked)
1015 case -1: /* fork failed */
1016 case 0: /* child fork (can't happen) */
1017 sprintf (buf, "%s: couldn't fork", blurb());
1019 restore_real_vroot (si);
1020 saver_exit (si, 1, "couldn't fork");
1029 store_saver_status (si); /* store current hack number */
1034 kill_screenhack (saver_screen_info *ssi)
1036 saver_info *si = ssi->global;
1038 kill_job (si, ssi->pid, SIGTERM);
1044 suspend_screenhack (saver_screen_info *ssi, Bool suspend_p)
1046 #ifdef SIGSTOP /* older VMS doesn't have it... */
1047 saver_info *si = ssi->global;
1049 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1050 #endif /* SIGSTOP */
1054 /* Called when we're exiting abnormally, to kill off the subproc. */
1056 emergency_kill_subproc (saver_info *si)
1060 signal (SIGCHLD, SIG_IGN);
1061 #endif /* SIGCHLD */
1063 for (i = 0; i < si->nscreens; i++)
1065 saver_screen_info *ssi = &si->screens[i];
1068 kill_job (si, ssi->pid, SIGTERM);
1075 screenhack_running_p (saver_info *si)
1077 Bool any_running_p = False;
1079 for (i = 0; i < si->nscreens; i++)
1081 saver_screen_info *ssi = &si->screens[i];
1082 if (ssi->pid) any_running_p = True;
1084 return any_running_p;
1088 /* Environment variables. */
1091 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
1092 is defined, the xscreensaver daemon will search that directory for hacks.
1095 hack_environment (saver_info *si)
1097 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1098 static const char *def_path = DEFAULT_PATH_PREFIX;
1099 if (def_path && *def_path)
1101 const char *opath = getenv("PATH");
1102 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1103 strcpy (npath, "PATH=");
1104 strcat (npath, def_path);
1105 strcat (npath, ":");
1106 strcat (npath, opath);
1111 /* don't free (npath) -- some implementations of putenv (BSD 4.4,
1112 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1113 do not. So we must leak it (and/or the previous setting). Yay.
1116 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1121 hack_subproc_environment (Screen *screen, Window saver_window)
1123 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1124 the spawned processes inherit is correct. First, it must be on the same
1125 host and display as the value of -display passed in on our command line
1126 (which is not necessarily the same as what our $DISPLAY variable is.)
1127 Second, the screen number in the $DISPLAY passed to the subprocess should
1128 be the screen on which this particular hack is running -- not the display
1129 specification which the driver itself is using, since the driver ignores
1130 its screen number and manages all existing screens.
1132 Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
1133 us to (eventually) run multiple hacks in Xinerama mode, where each hack
1134 has the same $DISPLAY but a different piece of glass.
1136 Display *dpy = DisplayOfScreen (screen);
1137 const char *odpy = DisplayString (dpy);
1138 char *ndpy = (char *) malloc (strlen(odpy) + 20);
1139 char *nssw = (char *) malloc (40);
1142 strcpy (ndpy, "DISPLAY=");
1143 s = ndpy + strlen(ndpy);
1146 /* We have to find the last colon since it is the boundary between
1147 hostname & screen - IPv6 numeric format addresses may have many
1148 colons before that point, and DECnet addresses always have two colons */
1149 c = strrchr(s,':'); /* skip to last colon */
1150 if (c != NULL) s = c+1;
1151 while (isdigit(*s)) s++; /* skip over dpy number */
1152 while (*s == '.') s++; /* skip over dot */
1153 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1154 sprintf(s, "%d", screen_number (screen)); /* put on screen number */
1156 sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", (unsigned long) saver_window);
1158 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1159 any more, right? It's not Posix, but everyone seems to have it. */
1166 /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
1167 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1168 do not. So we must leak it (and/or the previous setting). Yay.
1170 #endif /* HAVE_PUTENV */
1177 get_best_gl_visual (saver_info *si, Screen *screen)
1183 int errin = -1, errout = -1;
1189 av[ac++] = "xscreensaver-gl-helper";
1194 perror ("error creating pipe:");
1201 if (!si->prefs.verbose_p)
1205 perror ("error creating pipe:");
1210 errout = errfds [1];
1213 block_sigchld(); /* This blocks it in the parent and child, to avoid
1214 racing. It is never unblocked in the child before
1215 the child exits, but that doesn't matter.
1218 switch ((int) (forked = fork ()))
1222 sprintf (buf, "%s: couldn't fork", blurb());
1224 saver_exit (si, 1, 0);
1228 close (in); /* don't need this one */
1229 close (ConnectionNumber (si->dpy)); /* close display fd */
1231 if (dup2 (out, STDOUT_FILENO) < 0) /* pipe stdout */
1233 perror ("could not dup() a new stdout:");
1237 if (! si->prefs.verbose_p)
1240 if (dup2 (errout, STDERR_FILENO) < 0)
1242 perror ("could not dup() a new stderr:");
1247 hack_subproc_environment (screen, 0); /* set $DISPLAY */
1249 execvp (av[0], av); /* shouldn't return. */
1251 if (errno != ENOENT /* || si->prefs.verbose_p */ )
1253 /* Ignore "no such file or directory" errors.
1254 Issue all other exec errors, though. */
1255 sprintf (buf, "%s: running %s", blurb(), av[0]);
1258 exit (1); /* exits fork */
1264 int wait_status = 0;
1266 FILE *f = fdopen (in, "r");
1267 unsigned long v = 0;
1270 close (out); /* don't need this one */
1273 if (! fgets (buf, sizeof(buf)-1, f))
1277 if (! si->prefs.verbose_p)
1283 /* Wait for the child to die. */
1284 waitpid (-1, &wait_status, 0);
1286 unblock_sigchld(); /* child is dead and waited, unblock now. */
1288 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1293 if (si->prefs.verbose_p)
1295 int L = strlen(buf);
1296 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1299 if (L && buf[L-1] == '\n')
1302 fprintf (stderr, "%s: %s said: \"%s\"\n",
1303 blurb(), av[0], buf);
1309 Visual *v = id_to_visual (screen, result);
1310 if (si->prefs.verbose_p)
1311 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1312 blurb(), screen_number (screen),
1314 (v == DefaultVisualOfScreen (screen)
1315 ? " (default)" : ""));
1326 /* Restarting the xscreensaver process from scratch. */
1328 static char **saved_argv;
1331 save_argv (int argc, char **argv)
1333 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1334 saved_argv [argc] = 0;
1337 int i = strlen (argv [argc]) + 1;
1338 saved_argv [argc] = (char *) malloc (i);
1339 memcpy (saved_argv [argc], argv [argc], i);
1344 /* Re-execs the process with the arguments in saved_argv. Does not return.
1347 restart_process (saver_info *si)
1351 shutdown_stderr (si);
1352 if (si->prefs.verbose_p)
1355 fprintf (stderr, "%s: re-executing", blurb());
1356 for (i = 0; saved_argv[i]; i++)
1357 fprintf (stderr, " %s", saved_argv[i]);
1358 fprintf (stderr, "\n");
1360 describe_uids (si, stderr);
1361 fprintf (stderr, "\n");
1365 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1368 sprintf (buf, "%s: could not restart process", blurb());