1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991-2006 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
364 sigemptyset (&child_set);
365 sigaddset (&child_set, SIGCHLD);
366 sigaddset (&child_set, SIGPIPE);
367 sigprocmask (SIG_BLOCK, &child_set, 0);
368 #endif /* HAVE_SIGACTION */
370 block_sigchld_handler++;
372 #ifdef HAVE_SIGACTION
374 #else /* !HAVE_SIGACTION */
376 #endif /* !HAVE_SIGACTION */
380 unblock_sigchld (void)
382 #ifdef HAVE_SIGACTION
384 sigemptyset(&child_set);
385 sigaddset(&child_set, SIGCHLD);
386 sigaddset(&child_set, SIGPIPE);
387 sigprocmask(SIG_UNBLOCK, &child_set, 0);
388 #endif /* HAVE_SIGACTION */
390 block_sigchld_handler--;
394 kill_job (saver_info *si, pid_t pid, int signal)
396 saver_preferences *p = &si->prefs;
397 struct screenhack_job *job;
402 if (block_sigchld_handler)
403 /* This function should not be called from the signal handler. */
406 block_sigchld(); /* we control the horizontal... */
408 job = find_job (pid);
411 job->status == job_killed)
414 fprintf (stderr, "%s: no child %ld to signal!\n",
415 blurb(), (long) pid);
420 case SIGTERM: job->status = job_killed; break;
422 /* #### there must be a way to do this on VMS... */
423 case SIGSTOP: job->status = job_stopped; break;
424 case SIGCONT: job->status = job_running; break;
430 fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
431 blurb(), job->screen,
432 (job->status == job_killed ? "killing" :
433 job->status == job_stopped ? "suspending" : "resuming"),
434 (unsigned long) job->pid,
437 status = kill (job->pid, signal);
439 if (p->verbose_p && status < 0)
443 "%s: %d: child process %lu (%s) was already dead.\n",
444 blurb(), job->screen, (unsigned long) job->pid, job->name);
448 sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
449 blurb(), job->screen, (unsigned long) job->pid, job->name);
454 await_dying_children (si);
458 if (block_sigchld_handler < 0)
468 sigchld_handler (int sig)
470 saver_info *si = global_si_kludge; /* I hate C so much... */
472 if (si->prefs.debug_p)
474 /* Don't call fprintf() from signal handlers, as it might malloc.
475 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
476 (block_sigchld_handler ? " (blocked)" : ""));
478 write_string (STDERR_FILENO, blurb());
479 write_string (STDERR_FILENO, ": got SIGCHLD");
481 if (block_sigchld_handler)
482 write_string (STDERR_FILENO, " (blocked)\n");
484 write_string (STDERR_FILENO, "\n");
487 if (block_sigchld_handler < 0)
489 else if (block_sigchld_handler == 0)
492 await_dying_children (si);
504 await_dying_children (saver_info *si)
512 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
514 if (si->prefs.debug_p)
516 if (kid < 0 && errno)
518 /* Don't call fprintf() from signal handlers, as it might malloc.
519 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
522 write_string (STDERR_FILENO, blurb());
523 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
524 write_long (STDERR_FILENO, (long) kid);
525 write_string (STDERR_FILENO, " (");
526 write_long (STDERR_FILENO, (long) errno);
527 write_string (STDERR_FILENO, ")\n");
531 /* Don't call fprintf() from signal handlers, as it might malloc.
532 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
535 write_string (STDERR_FILENO, blurb());
536 write_string (STDERR_FILENO, ": waitpid(-1) ==> ");
537 write_long (STDERR_FILENO, (long) kid);
538 write_string (STDERR_FILENO, "\n");
542 /* 0 means no more children to reap.
543 -1 means error -- except "interrupted system call" isn't a "real"
544 error, so if we get that, we should just try again. */
546 (kid < 0 && errno != EINTR))
549 describe_dead_child (si, kid, wait_status);
555 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
558 saver_preferences *p = &si->prefs;
559 struct screenhack_job *job = find_job (kid);
560 const char *name = job ? job->name : "<unknown>";
561 int screen_no = job ? job->screen : 0;
563 if (WIFEXITED (wait_status))
565 int exit_status = WEXITSTATUS (wait_status);
567 /* Treat exit code as a signed 8-bit quantity. */
568 if (exit_status & 0x80) exit_status |= ~0xFF;
570 /* One might assume that exiting with non-0 means something went wrong.
571 But that loser xswarm exits with the code that it was killed with, so
572 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
573 mention them) if we've just killed the subprocess. But mention them
574 if they happen on their own.
578 (p->verbose_p || job->status != job_killed)))
580 /* Don't call fprintf() from signal handlers, as it might malloc.
582 "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
583 blurb(), screen_no, (unsigned long) kid, name, exit_status);
585 write_string (STDERR_FILENO, blurb());
586 write_string (STDERR_FILENO, ": ");
587 write_long (STDERR_FILENO, (long) screen_no);
588 write_string (STDERR_FILENO, ": child pid ");
589 write_long (STDERR_FILENO, (long) kid);
590 write_string (STDERR_FILENO, " (");
591 write_string (STDERR_FILENO, name);
592 write_string (STDERR_FILENO, ") exited abnormally (code ");
593 write_long (STDERR_FILENO, (long) exit_status);
594 write_string (STDERR_FILENO, ").\n");
596 else if (p->verbose_p)
598 /* Don't call fprintf() from signal handlers, as it might malloc.
599 fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
600 blurb(), screen_no, (unsigned long) kid, name);
602 write_string (STDERR_FILENO, blurb());
603 write_string (STDERR_FILENO, ": ");
604 write_long (STDERR_FILENO, (long) screen_no);
605 write_string (STDERR_FILENO, ": child pid ");
606 write_long (STDERR_FILENO, (long) kid);
607 write_string (STDERR_FILENO, " (");
608 write_string (STDERR_FILENO, name);
609 write_string (STDERR_FILENO, ") exited normally.\n");
613 job->status = job_dead;
615 else if (WIFSIGNALED (wait_status))
619 job->status != job_killed ||
620 WTERMSIG (wait_status) != SIGTERM)
622 /* Don't call fprintf() from signal handlers, as it might malloc.
623 fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
624 blurb(), screen_no, (unsigned long) kid, name,
625 signal_name (WTERMSIG(wait_status)));
627 write_string (STDERR_FILENO, blurb());
628 write_string (STDERR_FILENO, ": ");
629 write_long (STDERR_FILENO, (long) screen_no);
630 write_string (STDERR_FILENO, ": child pid ");
631 write_long (STDERR_FILENO, (long) kid);
632 write_string (STDERR_FILENO, " (");
633 write_string (STDERR_FILENO, name);
634 write_string (STDERR_FILENO, ") terminated with signal ");
635 write_long (STDERR_FILENO, WTERMSIG(wait_status));
636 write_string (STDERR_FILENO, ".\n");
640 job->status = job_dead;
642 else if (WIFSTOPPED (wait_status))
646 /* Don't call fprintf() from signal handlers, as it might malloc.
647 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
648 blurb(), (unsigned long) kid, name,
649 signal_name (WSTOPSIG (wait_status)));
651 write_string (STDERR_FILENO, blurb());
652 write_string (STDERR_FILENO, ": ");
653 write_long (STDERR_FILENO, (long) screen_no);
654 write_string (STDERR_FILENO, ": child pid ");
655 write_long (STDERR_FILENO, (long) kid);
656 write_string (STDERR_FILENO, " (");
657 write_string (STDERR_FILENO, name);
658 write_string (STDERR_FILENO, ") stopped with signal ");
659 write_long (STDERR_FILENO, WSTOPSIG(wait_status));
660 write_string (STDERR_FILENO, ".\n");
664 job->status = job_stopped;
668 /* Don't call fprintf() from signal handlers, as it might malloc.
669 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
670 blurb(), (unsigned long) kid, name);
672 write_string (STDERR_FILENO, blurb());
673 write_string (STDERR_FILENO, ": ");
674 write_long (STDERR_FILENO, (long) screen_no);
675 write_string (STDERR_FILENO, ": child pid ");
676 write_long (STDERR_FILENO, (long) kid);
677 write_string (STDERR_FILENO, " (");
678 write_string (STDERR_FILENO, name);
679 write_string (STDERR_FILENO, ") died in a mysterious way!");
681 job->status = job_dead;
684 /* Clear out the pid so that screenhack_running_p() knows it's dead.
686 if (!job || job->status == job_dead)
687 for (i = 0; i < si->nscreens; i++)
689 saver_screen_info *ssi = &si->screens[i];
696 static void await_dying_children (saver_info *si) { return; }
705 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
707 static Bool sigchld_initialized_p = 0;
708 if (!sigchld_initialized_p)
710 struct sigaction action, old;
712 action.sa_handler = sigchld_handler;
713 sigemptyset(&action.sa_mask);
716 if (sigaction(SIGCHLD, &action, &old) < 0)
719 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
722 sigchld_initialized_p = True;
725 # else /* !HAVE_SIGACTION */
727 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
730 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
733 # endif /* !HAVE_SIGACTION */
742 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
744 saver_info *si = ssi->global;
745 saver_preferences *p = &si->prefs;
748 if (hack->visual && *hack->visual)
749 selected = select_visual(ssi, hack->visual);
751 selected = select_visual(ssi, 0);
753 if (!selected && (p->verbose_p || si->demoing_p))
756 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
757 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
759 (hack->visual && *hack->visual ? hack->visual : "???"),
767 print_path_error (const char *program)
770 char *cmd = strdup (program);
771 char *token = strchr (cmd, ' ');
773 if (token) *token = 0;
774 sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
778 if (errno == ENOENT &&
779 (token = getenv("PATH")))
783 # define PATH_MAX MAXPATHLEN
785 # define PATH_MAX 2048
789 fprintf (stderr, "\n");
791 # if defined(HAVE_GETCWD)
792 if (! getcwd (path, sizeof(path)))
794 # elif defined(HAVE_GETWD)
798 fprintf (stderr, " Current directory is: %s\n", path);
799 fprintf (stderr, " PATH is:\n");
800 token = strtok (strdup(token), ":");
803 fprintf (stderr, " %s\n", token);
804 token = strtok(0, ":");
806 fprintf (stderr, "\n");
811 /* Executes the command in another process.
812 Command may be any single command acceptable to /bin/sh.
813 It may include wildcards, but no semicolons.
814 If successful, the pid of the other process is returned.
815 Otherwise, -1 is returned and an error may have been
819 fork_and_exec (saver_screen_info *ssi, const char *command)
821 saver_info *si = ssi->global;
822 saver_preferences *p = &si->prefs;
825 switch ((int) (forked = fork ()))
830 sprintf (buf, "%s: couldn't fork", blurb());
836 close (ConnectionNumber (si->dpy)); /* close display fd */
837 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
838 hack_subproc_environment (ssi); /* set $DISPLAY */
841 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
842 blurb(), ssi->number, command,
843 (unsigned long) getpid ());
845 exec_command (p->shell, command, p->nice_inferior);
847 /* If that returned, we were unable to exec the subprocess.
848 Print an error message, if desired.
850 if (! p->ignore_uninstalled_p)
851 print_path_error (command);
853 exit (1); /* exits child fork */
856 default: /* parent */
857 (void) make_job (forked, ssi->number, command);
866 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
868 saver_info *si = ssi->global;
869 saver_preferences *p = &si->prefs;
870 raise_window (si, first_time_p, True, False);
873 if (p->screenhacks_count)
884 if (p->screenhacks_count < 1)
886 /* No hacks at all */
889 else if (p->screenhacks_count == 1)
891 /* Exactly one hack in the list */
894 else if (si->selection_mode == -1)
896 /* Select the next hack, wrapping. */
897 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
899 else if (si->selection_mode == -2)
901 /* Select the previous hack, wrapping. */
902 if (ssi->current_hack < 0)
903 new_hack = p->screenhacks_count - 1;
905 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
906 % p->screenhacks_count);
908 else if (si->selection_mode > 0)
910 /* Select a specific hack, by number (via the ACTIVATE command.) */
911 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
914 else if (p->mode == ONE_HACK &&
915 p->selected_hack >= 0)
917 /* Select a specific hack, by number (via "One Saver" mode.) */
918 new_hack = p->selected_hack;
921 else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
925 else if (p->mode == RANDOM_HACKS_SAME &&
928 /* Use the same hack that's running on screen 0.
929 (Assumes this function was called on screen 0 first.)
931 new_hack = si->screens[0].current_hack;
933 else /* (p->mode == RANDOM_HACKS) */
935 /* Select a random hack (but not the one we just ran.) */
936 while ((new_hack = random () % p->screenhacks_count)
937 == ssi->current_hack)
941 if (new_hack < 0) /* don't run a hack */
943 ssi->current_hack = -1;
944 if (si->selection_mode < 0)
945 si->selection_mode = 0;
949 ssi->current_hack = new_hack;
950 hack = p->screenhacks[ssi->current_hack];
952 /* If the hack is disabled, or there is no visual for this hack,
953 then try again (move forward, or backward, or re-randomize.)
954 Unless this hack was specified explicitly, in which case,
958 select_visual_of_hack (ssi, hack);
962 !on_path_p (hack->command) ||
963 !select_visual_of_hack (ssi, hack)))
965 if (++retry_count > (p->screenhacks_count*4))
967 /* Uh, oops. Odds are, there are no suitable visuals,
968 and we're looping. Give up. (This is totally lame,
969 what we should do is make a list of suitable hacks at
970 the beginning, then only loop over them.)
974 "%s: %d: no programs enabled, or no suitable visuals.\n",
975 blurb(), ssi->number);
982 /* Turn off "next" and "prev" modes now, but "demo" mode is only
983 turned off by explicit action.
985 if (si->selection_mode < 0)
986 si->selection_mode = 0;
988 forked = fork_and_exec (ssi, hack->command);
989 switch ((int) forked)
991 case -1: /* fork failed */
992 case 0: /* child fork (can't happen) */
993 sprintf (buf, "%s: couldn't fork", blurb());
995 restore_real_vroot (si);
996 saver_exit (si, 1, "couldn't fork");
1008 spawn_screenhack (saver_info *si, Bool first_time_p)
1010 if (monitor_powered_on_p (si))
1013 for (i = 0; i < si->nscreens; i++)
1015 saver_screen_info *ssi = &si->screens[i];
1016 spawn_screenhack_1 (ssi, first_time_p);
1019 else if (si->prefs.verbose_p)
1021 "%s: X says monitor has powered down; "
1022 "not launching a hack.\n", blurb());
1024 store_saver_status (si); /* store current hack numbers */
1029 kill_screenhack (saver_info *si)
1032 for (i = 0; i < si->nscreens; i++)
1034 saver_screen_info *ssi = &si->screens[i];
1036 kill_job (si, ssi->pid, SIGTERM);
1043 suspend_screenhack (saver_info *si, Bool suspend_p)
1045 #ifdef SIGSTOP /* older VMS doesn't have it... */
1047 for (i = 0; i < si->nscreens; i++)
1049 saver_screen_info *ssi = &si->screens[i];
1051 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1053 #endif /* SIGSTOP */
1057 /* Called when we're exiting abnormally, to kill off the subproc. */
1059 emergency_kill_subproc (saver_info *si)
1063 signal (SIGCHLD, SIG_IGN);
1064 #endif /* SIGCHLD */
1066 for (i = 0; i < si->nscreens; i++)
1068 saver_screen_info *ssi = &si->screens[i];
1071 kill_job (si, ssi->pid, SIGTERM);
1078 screenhack_running_p (saver_info *si)
1080 Bool any_running_p = False;
1082 for (i = 0; i < si->nscreens; i++)
1084 saver_screen_info *ssi = &si->screens[i];
1085 if (ssi->pid) any_running_p = True;
1087 return any_running_p;
1091 /* Environment variables. */
1094 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
1095 is defined, the xscreensaver daemon will search that directory for hacks.
1098 hack_environment (saver_info *si)
1100 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1101 static const char *def_path = DEFAULT_PATH_PREFIX;
1102 if (def_path && *def_path)
1104 const char *opath = getenv("PATH");
1105 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1106 strcpy (npath, "PATH=");
1107 strcat (npath, def_path);
1108 strcat (npath, ":");
1109 strcat (npath, opath);
1114 /* don't free (npath) -- some implementations of putenv (BSD 4.4,
1115 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1116 do not. So we must leak it (and/or the previous setting). Yay.
1119 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1124 hack_subproc_environment (saver_screen_info *ssi)
1126 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1127 the spawned processes inherit is correct. First, it must be on the same
1128 host and display as the value of -display passed in on our command line
1129 (which is not necessarily the same as what our $DISPLAY variable is.)
1130 Second, the screen number in the $DISPLAY passed to the subprocess should
1131 be the screen on which this particular hack is running -- not the display
1132 specification which the driver itself is using, since the driver ignores
1133 its screen number and manages all existing screens.
1135 Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
1136 us to (eventually) run multiple hacks in Xinerama mode, where each hack
1137 has the same $DISPLAY but a different piece of glass.
1139 saver_info *si = ssi->global;
1140 const char *odpy = DisplayString (si->dpy);
1141 char *ndpy = (char *) malloc (strlen(odpy) + 20);
1142 char *nssw = (char *) malloc (40);
1145 strcpy (ndpy, "DISPLAY=");
1146 s = ndpy + strlen(ndpy);
1149 /* We have to find the last colon since it is the boundary between
1150 hostname & screen - IPv6 numeric format addresses may have many
1151 colons before that point, and DECnet addresses always have two colons */
1152 c = strrchr(s,':'); /* skip to last colon */
1153 if (c != NULL) s = c+1;
1154 while (isdigit(*s)) s++; /* skip over dpy number */
1155 while (*s == '.') s++; /* skip over dot */
1156 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1157 sprintf(s, "%d", ssi->real_screen_number); /* put on screen number */
1159 sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
1160 (unsigned long) ssi->screensaver_window);
1162 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1163 any more, right? It's not Posix, but everyone seems to have it. */
1170 /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
1171 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1172 do not. So we must leak it (and/or the previous setting). Yay.
1174 #endif /* HAVE_PUTENV */
1181 get_best_gl_visual (saver_screen_info *ssi)
1183 saver_info *si = ssi->global;
1192 av[ac++] = "xscreensaver-gl-helper";
1197 perror ("error creating pipe:");
1204 switch ((int) (forked = fork ()))
1208 sprintf (buf, "%s: couldn't fork", blurb());
1210 saver_exit (si, 1, 0);
1216 close (in); /* don't need this one */
1217 close (ConnectionNumber (si->dpy)); /* close display fd */
1219 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1221 perror ("could not dup() a new stdout:");
1224 hack_subproc_environment (ssi); /* set $DISPLAY */
1226 execvp (av[0], av); /* shouldn't return. */
1228 if (errno != ENOENT || si->prefs.verbose_p)
1230 /* Ignore "no such file or directory" errors, unless verbose.
1231 Issue all other exec errors, though. */
1232 sprintf (buf, "%s: running %s", blurb(), av[0]);
1235 exit (1); /* exits fork */
1241 int wait_status = 0;
1243 FILE *f = fdopen (in, "r");
1244 unsigned long v = 0;
1247 close (out); /* don't need this one */
1250 if (! fgets (buf, sizeof(buf)-1, f))
1254 /* Wait for the child to die. */
1255 waitpid (-1, &wait_status, 0);
1257 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1262 if (si->prefs.verbose_p)
1264 int L = strlen(buf);
1265 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1268 if (L && buf[L-1] == '\n')
1271 fprintf (stderr, "%s: %s said: \"%s\"\n",
1272 blurb(), av[0], buf);
1278 Visual *v = id_to_visual (ssi->screen, result);
1279 if (si->prefs.verbose_p)
1280 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1281 blurb(), ssi->number,
1283 (v == ssi->default_visual ? " (default)" : ""));
1294 /* Restarting the xscreensaver process from scratch. */
1296 static char **saved_argv;
1299 save_argv (int argc, char **argv)
1301 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1302 saved_argv [argc] = 0;
1305 int i = strlen (argv [argc]) + 1;
1306 saved_argv [argc] = (char *) malloc (i);
1307 memcpy (saved_argv [argc], argv [argc], i);
1312 /* Re-execs the process with the arguments in saved_argv. Does not return.
1315 restart_process (saver_info *si)
1319 shutdown_stderr (si);
1320 if (si->prefs.verbose_p)
1323 fprintf (stderr, "%s: re-executing", blurb());
1324 for (i = 0; saved_argv[i]; i++)
1325 fprintf (stderr, " %s", saved_argv[i]);
1326 fprintf (stderr, "\n");
1328 describe_uids (si, stderr);
1329 fprintf (stderr, "\n");
1333 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1336 sprintf (buf, "%s: could not restart process", blurb());