ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-4.22.tar.gz
[xscreensaver] / driver / subprocs.c
1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2  * xscreensaver, Copyright (c) 1991-2005 Jamie Zawinski <jwz@jwz.org>
3  *
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 
10  * implied warranty.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #include <X11/Xlib.h>           /* not used for much... */
22
23 #ifndef ESRCH
24 # include <errno.h>
25 #endif
26
27 #include <sys/time.h>           /* sys/resource.h needs this for timeval */
28
29 #ifdef HAVE_SYS_WAIT_H
30 # include <sys/wait.h>          /* for waitpid() and associated macros */
31 #endif
32
33 #ifdef HAVE_SETRLIMIT
34 # include <sys/resource.h>      /* for setrlimit() and RLIMIT_AS */
35 #endif
36
37 #ifdef VMS
38 # include <processes.h>
39 # include <unixio.h>            /* for close */
40 # include <unixlib.h>           /* for getpid */
41 # define pid_t int
42 # define fork  vfork
43 #endif /* VMS */
44
45 #include <signal.h>             /* for the signal names */
46
47 #if !defined(SIGCHLD) && defined(SIGCLD)
48 # define SIGCHLD SIGCLD
49 #endif
50
51 #if 0 /* putenv() is declared in stdlib.h on modern linux systems. */
52 #ifdef HAVE_PUTENV
53 extern int putenv (/* const char * */); /* getenv() is in stdlib.h... */
54 #endif
55 #endif
56
57 extern int kill (pid_t, int);           /* signal() is in sys/signal.h... */
58
59 /* This file doesn't need the Xt headers, so stub these types out... */
60 #undef XtPointer
61 #define XtAppContext void*
62 #define XrmDatabase  void*
63 #define XtIntervalId void*
64 #define XtPointer    void*
65 #define Widget       void*
66
67 #include "xscreensaver.h"
68 #include "yarandom.h"
69 #include "visual.h"    /* for id_to_visual() */
70
71 extern saver_info *global_si_kludge;    /* I hate C so much... */
72
73
74 /* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size
75    of a process's address space, i.e., the maximal brk(2) and mmap(2) values.
76    Setting this lets you put a cap on how much memory a process can allocate.
77
78    Except the "and mmap()" part kinda makes this useless, since many GL
79    implementations end up using mmap() to pull the whole frame buffer into
80    memory (or something along those lines) making it appear processes are
81    using hundreds of megabytes when in fact they're using very little, and
82    we end up capping their mallocs prematurely.  YAY!
83  */
84 #if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
85 # define RLIMIT_AS RLIMIT_VMEM
86 #endif
87
88 static void
89 limit_subproc_memory (int address_space_limit, Bool verbose_p)
90 {
91
92 /* This has caused way more problems than it has solved...
93    Let's just completely ignore the "memoryLimit" option now.
94  */
95 #undef HAVE_SETRLIMIT
96
97 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS)
98   struct rlimit r;
99
100   if (address_space_limit < 10 * 1024)  /* let's not be crazy */
101     return;
102
103   if (getrlimit (RLIMIT_AS, &r) != 0)
104     {
105       char buf [512];
106       sprintf (buf, "%s: getrlimit(RLIMIT_AS) failed", blurb());
107       perror (buf);
108       return;
109     }
110
111   r.rlim_cur = address_space_limit;
112
113   if (setrlimit (RLIMIT_AS, &r) != 0)
114     {
115       char buf [512];
116       sprintf (buf, "%s: setrlimit(RLIMIT_AS, {%lu, %lu}) failed",
117                blurb(), r.rlim_cur, r.rlim_max);
118       perror (buf);
119       return;
120     }
121
122   if (verbose_p)
123     {
124       int i = address_space_limit;
125       char buf[100];
126       if      (i >= (1<<30) && i == ((i >> 30) << 30))
127         sprintf(buf, "%dG", i >> 30);
128       else if (i >= (1<<20) && i == ((i >> 20) << 20))
129         sprintf(buf, "%dM", i >> 20);
130       else if (i >= (1<<10) && i == ((i >> 10) << 10))
131         sprintf(buf, "%dK", i >> 10);
132       else
133         sprintf(buf, "%d bytes", i);
134
135       fprintf (stderr, "%s: limited pid %lu address space to %s.\n",
136                blurb(), (unsigned long) getpid (), buf);
137     }
138
139 #endif /* HAVE_SETRLIMIT && RLIMIT_AS */
140 }
141
142 \f
143 /* Management of child processes, and de-zombification.
144  */
145
146 enum job_status {
147   job_running,  /* the process is still alive */
148   job_stopped,  /* we have sent it a STOP signal */
149   job_killed,   /* we have sent it a TERM signal */
150   job_dead      /* we have wait()ed for it, and it's dead -- this state only
151                    occurs so that we can avoid calling free() from a signal
152                    handler.  Shortly after going into this state, the list
153                    element will be removed. */
154 };
155
156 struct screenhack_job {
157   char *name;
158   pid_t pid;
159   int screen;
160   enum job_status status;
161   struct screenhack_job *next;
162 };
163
164 static struct screenhack_job *jobs = 0;
165
166 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
167 void
168 show_job_list (void)
169 {
170   struct screenhack_job *job;
171   fprintf(stderr, "%s: job list:\n", blurb());
172   for (job = jobs; job; job = job->next)
173     fprintf (stderr, "  %5ld: %2d: (%s) %s\n",
174              (long) job->pid,
175              job->screen,
176              (job->status == job_running ? "running" :
177               job->status == job_stopped ? "stopped" :
178               job->status == job_killed  ? " killed" :
179               job->status == job_dead    ? "   dead" : "    ???"),
180              job->name);
181   fprintf (stderr, "\n");
182 }
183
184
185 static void clean_job_list (void);
186
187 static struct screenhack_job *
188 make_job (pid_t pid, int screen, const char *cmd)
189 {
190   struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
191
192   static char name [1024];
193   const char *in = cmd;
194   char *out = name;
195   int got_eq = 0;
196   int first = 1;
197
198   clean_job_list();
199
200  AGAIN:
201   while (isspace(*in)) in++;            /* skip whitespace */
202   while (!isspace(*in) && *in != ':') {
203     if (*in == '=') got_eq = 1;
204     *out++ = *in++;                     /* snarf first token */
205   }
206
207   if (got_eq)                           /* if the first token was FOO=bar */
208     {                                   /* then get the next token instead. */
209       got_eq = 0;
210       out = name;
211       first = 0;
212       goto AGAIN;
213     }
214
215   while (isspace(*in)) in++;            /* skip whitespace */
216   *out = 0;
217
218   job->name = strdup(name);
219   job->pid = pid;
220   job->screen = screen;
221   job->status = job_running;
222   job->next = jobs;
223   jobs = job;
224
225   return jobs;
226 }
227
228
229 static void
230 free_job (struct screenhack_job *job)
231 {
232   if (!job)
233     return;
234   else if (job == jobs)
235     jobs = jobs->next;
236   else
237     {
238       struct screenhack_job *job2, *prev;
239       for (prev = 0, job2 = jobs;
240            job2;
241            prev = job2, job2 = job2->next)
242         if (job2 == job)
243           {
244             prev->next = job->next;
245             break;
246           }
247     }
248   free(job->name);
249   free(job);
250 }
251
252
253 /* Cleans out dead jobs from the jobs list -- this must only be called
254    from the main thread, not from a signal handler. 
255  */
256 static void
257 clean_job_list (void)
258 {
259   struct screenhack_job *job, *prev, *next;
260   for (prev = 0, job = jobs, next = (job ? job->next : 0);
261        job;
262        prev = job, job = next, next = (job ? job->next : 0))
263     {
264       if (job->status == job_dead)
265         {
266           if (prev)
267             prev->next = next;
268           free_job (job);
269           job = prev;
270         }
271     }
272 }
273
274
275 static struct screenhack_job *
276 find_job (pid_t pid)
277 {
278   struct screenhack_job *job;
279   for (job = jobs; job; job = job->next)
280     if (job->pid == pid)
281       return job;
282   return 0;
283 }
284
285 static void await_dying_children (saver_info *si);
286 #ifndef VMS
287 static void describe_dead_child (saver_info *, pid_t, int wait_status);
288 #endif
289
290
291 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
292    Don't alter this directly -- use block_sigchld() / unblock_sigchld().
293  */
294 static int block_sigchld_handler = 0;
295
296
297 #ifdef HAVE_SIGACTION
298  sigset_t
299 #else  /* !HAVE_SIGACTION */
300  int
301 #endif /* !HAVE_SIGACTION */
302 block_sigchld (void)
303 {
304 #ifdef HAVE_SIGACTION
305   sigset_t child_set;
306   sigemptyset (&child_set);
307   sigaddset (&child_set, SIGCHLD);
308   sigaddset (&child_set, SIGPIPE);
309   sigprocmask (SIG_BLOCK, &child_set, 0);
310 #endif /* HAVE_SIGACTION */
311
312   block_sigchld_handler++;
313
314 #ifdef HAVE_SIGACTION
315   return child_set;
316 #else  /* !HAVE_SIGACTION */
317   return 0;
318 #endif /* !HAVE_SIGACTION */
319 }
320
321 void
322 unblock_sigchld (void)
323 {
324 #ifdef HAVE_SIGACTION
325   sigset_t child_set;
326   sigemptyset(&child_set);
327   sigaddset(&child_set, SIGCHLD);
328   sigaddset(&child_set, SIGPIPE);
329   sigprocmask(SIG_UNBLOCK, &child_set, 0);
330 #endif /* HAVE_SIGACTION */
331
332   block_sigchld_handler--;
333 }
334
335 static int
336 kill_job (saver_info *si, pid_t pid, int signal)
337 {
338   saver_preferences *p = &si->prefs;
339   struct screenhack_job *job;
340   int status = -1;
341
342   clean_job_list();
343
344   if (block_sigchld_handler)
345     /* This function should not be called from the signal handler. */
346     abort();
347
348   block_sigchld();                      /* we control the horizontal... */
349
350   job = find_job (pid);
351   if (!job ||
352       !job->pid ||
353       job->status == job_killed)
354     {
355       if (p->verbose_p)
356         fprintf (stderr, "%s: no child %ld to signal!\n",
357                  blurb(), (long) pid);
358       goto DONE;
359     }
360
361   switch (signal) {
362   case SIGTERM: job->status = job_killed;  break;
363 #ifdef SIGSTOP
364     /* #### there must be a way to do this on VMS... */
365   case SIGSTOP: job->status = job_stopped; break;
366   case SIGCONT: job->status = job_running; break;
367 #endif /* SIGSTOP */
368   default: abort();
369   }
370
371   if (p->verbose_p)
372     fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
373              blurb(), job->screen,
374              (job->status == job_killed  ? "killing" :
375               job->status == job_stopped ? "suspending" : "resuming"),
376              (unsigned long) job->pid,
377              job->name);
378
379   status = kill (job->pid, signal);
380
381   if (p->verbose_p && status < 0)
382     {
383       if (errno == ESRCH)
384         fprintf (stderr,
385                  "%s: %d: child process %lu (%s) was already dead.\n",
386                  blurb(), job->screen, (unsigned long) job->pid, job->name);
387       else
388         {
389           char buf [1024];
390           sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
391                    blurb(), job->screen, (unsigned long) job->pid, job->name);
392           perror (buf);
393         }
394     }
395
396   await_dying_children (si);
397
398  DONE:
399   unblock_sigchld();
400   if (block_sigchld_handler < 0)
401     abort();
402
403   clean_job_list();
404   return status;
405 }
406
407
408 #ifdef SIGCHLD
409 static RETSIGTYPE
410 sigchld_handler (int sig)
411 {
412   saver_info *si = global_si_kludge;    /* I hate C so much... */
413
414   if (si->prefs.debug_p)
415     fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
416             (block_sigchld_handler ? " (blocked)" : ""));
417
418   if (block_sigchld_handler < 0)
419     abort();
420   else if (block_sigchld_handler == 0)
421     {
422       block_sigchld();
423       await_dying_children (si);
424       unblock_sigchld();
425     }
426
427   init_sigchld();
428 }
429 #endif /* SIGCHLD */
430
431
432 #ifndef VMS
433 static void
434 await_dying_children (saver_info *si)
435 {
436   while (1)
437     {
438       int wait_status = 0;
439       pid_t kid;
440
441       errno = 0;
442       kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
443
444       if (si->prefs.debug_p)
445         {
446           if (kid < 0 && errno)
447             fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
448                      (long) kid, errno);
449           else
450             fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
451                      (long) kid);
452         }
453
454       /* 0 means no more children to reap.
455          -1 means error -- except "interrupted system call" isn't a "real"
456          error, so if we get that, we should just try again. */
457       if (kid == 0 ||
458           (kid < 0 && errno != EINTR))
459         break;
460
461       describe_dead_child (si, kid, wait_status);
462     }
463 }
464
465
466 static void
467 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
468 {
469   int i;
470   saver_preferences *p = &si->prefs;
471   struct screenhack_job *job = find_job (kid);
472   const char *name = job ? job->name : "<unknown>";
473   int screen_no = job ? job->screen : 0;
474
475   if (WIFEXITED (wait_status))
476     {
477       int exit_status = WEXITSTATUS (wait_status);
478
479       /* Treat exit code as a signed 8-bit quantity. */
480       if (exit_status & 0x80) exit_status |= ~0xFF;
481
482       /* One might assume that exiting with non-0 means something went wrong.
483          But that loser xswarm exits with the code that it was killed with, so
484          it *always* exits abnormally.  Treat abnormal exits as "normal" (don't
485          mention them) if we've just killed the subprocess.  But mention them
486          if they happen on their own.
487        */
488       if (!job ||
489           (exit_status != 0 &&
490            (p->verbose_p || job->status != job_killed)))
491         fprintf (stderr,
492                  "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
493                  blurb(), screen_no, (unsigned long) kid, name, exit_status);
494       else if (p->verbose_p)
495         fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
496                  blurb(), screen_no, (unsigned long) kid, name);
497
498       if (job)
499         job->status = job_dead;
500     }
501   else if (WIFSIGNALED (wait_status))
502     {
503       if (p->verbose_p ||
504           !job ||
505           job->status != job_killed ||
506           WTERMSIG (wait_status) != SIGTERM)
507         fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
508                  blurb(), screen_no, (unsigned long) kid, name,
509                  signal_name (WTERMSIG(wait_status)));
510
511       if (job)
512         job->status = job_dead;
513     }
514   else if (WIFSTOPPED (wait_status))
515     {
516       if (p->verbose_p)
517         fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
518                  blurb(), (unsigned long) kid, name,
519                  signal_name (WSTOPSIG (wait_status)));
520
521       if (job)
522         job->status = job_stopped;
523     }
524   else
525     {
526       fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
527                blurb(), (unsigned long) kid, name);
528       if (job)
529         job->status = job_dead;
530     }
531
532   /* Clear out the pid so that screenhack_running_p() knows it's dead.
533    */
534   if (!job || job->status == job_dead)
535     for (i = 0; i < si->nscreens; i++)
536       {
537         saver_screen_info *ssi = &si->screens[i];
538         if (kid == ssi->pid)
539           ssi->pid = 0;
540       }
541 }
542
543 #else  /* VMS */
544 static void await_dying_children (saver_info *si) { return; }
545 #endif /* VMS */
546
547
548 void
549 init_sigchld (void)
550 {
551 #ifdef SIGCHLD
552
553 # ifdef HAVE_SIGACTION  /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
554
555   static Bool sigchld_initialized_p = 0;
556   if (!sigchld_initialized_p)
557     {
558       struct sigaction action, old;
559
560       action.sa_handler = sigchld_handler;
561       sigemptyset(&action.sa_mask);
562       action.sa_flags = 0;
563
564       if (sigaction(SIGCHLD, &action, &old) < 0)
565         {
566           char buf [255];
567           sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
568           perror (buf);
569         }
570       sigchld_initialized_p = True;
571     }
572
573 # else  /* !HAVE_SIGACTION */
574
575   if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
576     {
577       char buf [255];
578       sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
579       perror (buf);
580     }
581 # endif /* !HAVE_SIGACTION */
582 #endif /* SIGCHLD */
583 }
584
585
586
587 \f
588
589 static Bool
590 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
591 {
592   saver_info *si = ssi->global;
593   saver_preferences *p = &si->prefs;
594   Bool selected;
595
596   if (hack->visual && *hack->visual)
597     selected = select_visual(ssi, hack->visual);
598   else
599     selected = select_visual(ssi, 0);
600
601   if (!selected && (p->verbose_p || si->demoing_p))
602     fprintf (stderr,
603              (si->demoing_p
604               ? "%s: warning, no \"%s\" visual for \"%s\".\n"
605               : "%s: no \"%s\" visual; skipping \"%s\".\n"),
606              blurb(),
607              (hack->visual && *hack->visual ? hack->visual : "???"),
608              hack->command);
609
610   return selected;
611 }
612
613
614 static void
615 print_path_error (const char *program)
616 {
617   char buf [512];
618   char *cmd = strdup (program);
619   char *token = strchr (cmd, ' ');
620
621   if (token) *token = 0;
622   sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
623   free (cmd);
624   perror (buf);
625
626   if (errno == ENOENT &&
627       (token = getenv("PATH")))
628     {
629 # ifndef PATH_MAX
630 #  ifdef MAXPATHLEN
631 #   define PATH_MAX MAXPATHLEN
632 #  else
633 #   define PATH_MAX 2048
634 #  endif
635 # endif
636       char path[PATH_MAX];
637       fprintf (stderr, "\n");
638       *path = 0;
639 # if defined(HAVE_GETCWD)
640       getcwd (path, sizeof(path));
641 # elif defined(HAVE_GETWD)
642       getwd (path);
643 # endif
644       if (*path)
645         fprintf (stderr, "    Current directory is: %s\n", path);
646       fprintf (stderr, "    PATH is:\n");
647       token = strtok (strdup(token), ":");
648       while (token)
649         {
650           fprintf (stderr, "        %s\n", token);
651           token = strtok(0, ":");
652         }
653       fprintf (stderr, "\n");
654     }
655 }
656
657
658 /* Executes the command in another process.
659    Command may be any single command acceptable to /bin/sh.
660    It may include wildcards, but no semicolons.
661    If successful, the pid of the other process is returned.
662    Otherwise, -1 is returned and an error may have been
663    printed to stderr.
664  */
665 pid_t
666 fork_and_exec (saver_screen_info *ssi, const char *command)
667 {
668   saver_info *si = ssi->global;
669   saver_preferences *p = &si->prefs;
670   pid_t forked;
671
672   switch ((int) (forked = fork ()))
673     {
674     case -1:
675       {
676         char buf [255];
677         sprintf (buf, "%s: couldn't fork", blurb());
678         perror (buf);
679         break;
680       }
681
682     case 0:
683       close (ConnectionNumber (si->dpy));       /* close display fd */
684       limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
685       hack_subproc_environment (ssi);           /* set $DISPLAY */
686
687       if (p->verbose_p)
688         fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
689                  blurb(), ssi->number, command,
690                  (unsigned long) getpid ());
691
692       exec_command (p->shell, command, p->nice_inferior);
693
694       /* If that returned, we were unable to exec the subprocess.
695          Print an error message, if desired.
696        */
697       if (! p->ignore_uninstalled_p)
698         print_path_error (command);
699
700       exit (1);  /* exits child fork */
701       break;
702
703     default:    /* parent */
704       (void) make_job (forked, ssi->number, command);
705       break;
706     }
707
708   return forked;
709 }
710
711
712 static void
713 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
714 {
715   saver_info *si = ssi->global;
716   saver_preferences *p = &si->prefs;
717   raise_window (si, first_time_p, True, False);
718   XFlush (si->dpy);
719
720   if (p->screenhacks_count)
721     {
722       screenhack *hack;
723       pid_t forked;
724       char buf [255];
725       int new_hack = -1;
726       int retry_count = 0;
727       Bool force = False;
728
729     AGAIN:
730
731       if (p->screenhacks_count < 1)
732         {
733           /* No hacks at all */
734           new_hack = -1;
735         }
736       else if (p->screenhacks_count == 1)
737         {
738           /* Exactly one hack in the list */
739           new_hack = 0;
740         }
741       else if (si->selection_mode == -1)
742         {
743           /* Select the next hack, wrapping. */
744           new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
745         }
746       else if (si->selection_mode == -2)
747         {
748           /* Select the previous hack, wrapping. */
749           if (ssi->current_hack < 0)
750             new_hack = p->screenhacks_count - 1;
751           else
752             new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
753                         % p->screenhacks_count);
754         }
755       else if (si->selection_mode > 0)
756         {
757           /* Select a specific hack, by number (via the ACTIVATE command.) */
758           new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
759           force = True;
760         }
761       else if (p->mode == ONE_HACK &&
762                p->selected_hack >= 0)
763         {
764           /* Select a specific hack, by number (via "One Saver" mode.) */
765           new_hack = p->selected_hack;
766           force = True;
767         }
768       else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
769         {
770           new_hack = -1;
771         }
772       else if (p->mode == RANDOM_HACKS_SAME &&
773                ssi->number != 0)
774         {
775           /* Use the same hack that's running on screen 0.
776              (Assumes this function was called on screen 0 first.)
777            */
778           new_hack = si->screens[0].current_hack;
779         }
780       else  /* (p->mode == RANDOM_HACKS) */
781         {
782           /* Select a random hack (but not the one we just ran.) */
783           while ((new_hack = random () % p->screenhacks_count)
784                  == ssi->current_hack)
785             ;
786         }
787
788       if (new_hack < 0)   /* don't run a hack */
789         {
790           ssi->current_hack = -1;
791           if (si->selection_mode < 0)
792             si->selection_mode = 0;
793           return;
794         }
795
796       ssi->current_hack = new_hack;
797       hack = p->screenhacks[ssi->current_hack];
798
799       /* If the hack is disabled, or there is no visual for this hack,
800          then try again (move forward, or backward, or re-randomize.)
801          Unless this hack was specified explicitly, in which case,
802          use it regardless.
803        */
804       if (force)
805         select_visual_of_hack (ssi, hack);
806         
807       if (!force &&
808           (!hack->enabled_p ||
809            !select_visual_of_hack (ssi, hack)))
810         {
811           if (++retry_count > (p->screenhacks_count*4))
812             {
813               /* Uh, oops.  Odds are, there are no suitable visuals,
814                  and we're looping.  Give up.  (This is totally lame,
815                  what we should do is make a list of suitable hacks at
816                  the beginning, then only loop over them.)
817               */
818               if (p->verbose_p)
819                 fprintf(stderr,
820                       "%s: %d: no programs enabled, or no suitable visuals.\n",
821                         blurb(), ssi->number);
822               return;
823             }
824           else
825             goto AGAIN;
826         }
827
828       /* Turn off "next" and "prev" modes now, but "demo" mode is only
829          turned off by explicit action.
830        */
831       if (si->selection_mode < 0)
832         si->selection_mode = 0;
833
834       forked = fork_and_exec (ssi, hack->command);
835       switch ((int) forked)
836         {
837         case -1: /* fork failed */
838         case 0:  /* child fork (can't happen) */
839           sprintf (buf, "%s: couldn't fork", blurb());
840           perror (buf);
841           restore_real_vroot (si);
842           saver_exit (si, 1, "couldn't fork");
843           break;
844
845         default:
846           ssi->pid = forked;
847           break;
848         }
849     }
850 }
851
852
853 void
854 spawn_screenhack (saver_info *si, Bool first_time_p)
855 {
856   if (monitor_powered_on_p (si))
857     {
858       int i;
859       for (i = 0; i < si->nscreens; i++)
860         {
861           saver_screen_info *ssi = &si->screens[i];
862           spawn_screenhack_1 (ssi, first_time_p);
863         }
864     }
865   else if (si->prefs.verbose_p)
866     fprintf (stderr,
867              "%s: X says monitor has powered down; "
868              "not launching a hack.\n", blurb());
869
870   store_saver_status (si);  /* store current hack numbers */
871 }
872
873
874 void
875 kill_screenhack (saver_info *si)
876 {
877   int i;
878   for (i = 0; i < si->nscreens; i++)
879     {
880       saver_screen_info *ssi = &si->screens[i];
881       if (ssi->pid)
882         kill_job (si, ssi->pid, SIGTERM);
883       ssi->pid = 0;
884     }
885 }
886
887
888 void
889 suspend_screenhack (saver_info *si, Bool suspend_p)
890 {
891 #ifdef SIGSTOP  /* older VMS doesn't have it... */
892   int i;
893   for (i = 0; i < si->nscreens; i++)
894     {
895       saver_screen_info *ssi = &si->screens[i];
896       if (ssi->pid)
897         kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
898     }
899 #endif /* SIGSTOP */
900 }
901
902
903 /* Called when we're exiting abnormally, to kill off the subproc. */
904 void
905 emergency_kill_subproc (saver_info *si)
906 {
907   int i;
908 #ifdef SIGCHLD
909   signal (SIGCHLD, SIG_IGN);
910 #endif /* SIGCHLD */
911
912   for (i = 0; i < si->nscreens; i++)
913     {
914       saver_screen_info *ssi = &si->screens[i];
915       if (ssi->pid)
916         {
917           kill_job (si, ssi->pid, SIGTERM);
918           ssi->pid = 0;
919         }
920     }
921 }
922
923 Bool
924 screenhack_running_p (saver_info *si)
925 {
926   Bool any_running_p = False;
927   int i;
928   for (i = 0; i < si->nscreens; i++)
929     {
930       saver_screen_info *ssi = &si->screens[i];
931       if (ssi->pid) any_running_p = True;
932     }
933   return any_running_p;
934 }
935
936 \f
937 /* Environment variables. */
938
939
940 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
941    is defined, the xscreensaver daemon will search that directory for hacks.
942  */
943 void
944 hack_environment (saver_info *si)
945 {
946 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
947   static const char *def_path = DEFAULT_PATH_PREFIX;
948   if (def_path && *def_path)
949     {
950       const char *opath = getenv("PATH");
951       char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
952       strcpy (npath, "PATH=");
953       strcat (npath, def_path);
954       strcat (npath, ":");
955       strcat (npath, opath);
956
957       if (putenv (npath))
958         abort ();
959
960       /* don't free (npath) -- some implementations of putenv (BSD 4.4,
961          glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
962          do not.  So we must leak it (and/or the previous setting). Yay.
963        */
964     }
965 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
966 }
967
968
969 void
970 hack_subproc_environment (saver_screen_info *ssi)
971 {
972   /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
973      the spawned processes inherit is correct.  First, it must be on the same
974      host and display as the value of -display passed in on our command line
975      (which is not necessarily the same as what our $DISPLAY variable is.)
976      Second, the screen number in the $DISPLAY passed to the subprocess should
977      be the screen on which this particular hack is running -- not the display
978      specification which the driver itself is using, since the driver ignores
979      its screen number and manages all existing screens.
980
981      Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
982      us to (eventually) run multiple hacks in Xinerama mode, where each hack
983      has the same $DISPLAY but a different piece of glass.
984    */
985   saver_info *si = ssi->global;
986   const char *odpy = DisplayString (si->dpy);
987   char *ndpy = (char *) malloc (strlen(odpy) + 20);
988   char *nssw = (char *) malloc (40);
989   char *s;
990
991   strcpy (ndpy, "DISPLAY=");
992   s = ndpy + strlen(ndpy);
993   strcpy (s, odpy);
994
995   while (*s && *s != ':') s++;                  /* skip to colon */
996   while (*s == ':') s++;                        /* skip over colons */
997   while (isdigit(*s)) s++;                      /* skip over dpy number */
998   while (*s == '.') s++;                        /* skip over dot */
999   if (s[-1] != '.') *s++ = '.';                 /* put on a dot */
1000   sprintf(s, "%d", ssi->real_screen_number);    /* put on screen number */
1001
1002   sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
1003            (unsigned long) ssi->screensaver_window);
1004
1005   /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1006      any more, right?  It's not Posix, but everyone seems to have it. */
1007 #ifdef HAVE_PUTENV
1008   if (putenv (ndpy))
1009     abort ();
1010   if (putenv (nssw))
1011     abort ();
1012
1013   /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
1014      glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1015      do not.  So we must leak it (and/or the previous setting). Yay.
1016    */
1017 #endif /* HAVE_PUTENV */
1018 }
1019
1020 \f
1021 /* GL crap */
1022
1023 Visual *
1024 get_best_gl_visual (saver_screen_info *ssi)
1025 {
1026   saver_info *si = ssi->global;
1027   pid_t forked;
1028   int fds [2];
1029   int in, out;
1030   char buf[1024];
1031
1032   char *av[10];
1033   int ac = 0;
1034
1035   av[ac++] = "xscreensaver-gl-helper";
1036   av[ac] = 0;
1037
1038   if (pipe (fds))
1039     {
1040       perror ("error creating pipe:");
1041       return 0;
1042     }
1043
1044   in = fds [0];
1045   out = fds [1];
1046
1047   switch ((int) (forked = fork ()))
1048     {
1049     case -1:
1050       {
1051         sprintf (buf, "%s: couldn't fork", blurb());
1052         perror (buf);
1053         saver_exit (si, 1, 0);
1054       }
1055     case 0:
1056       {
1057         int stdout_fd = 1;
1058
1059         close (in);  /* don't need this one */
1060         close (ConnectionNumber (si->dpy));     /* close display fd */
1061
1062         if (dup2 (out, stdout_fd) < 0)          /* pipe stdout */
1063           {
1064             perror ("could not dup() a new stdout:");
1065             return 0;
1066           }
1067         hack_subproc_environment (ssi);         /* set $DISPLAY */
1068
1069         execvp (av[0], av);                     /* shouldn't return. */
1070
1071         if (errno != ENOENT || si->prefs.verbose_p)
1072           {
1073             /* Ignore "no such file or directory" errors, unless verbose.
1074                Issue all other exec errors, though. */
1075             sprintf (buf, "%s: running %s", blurb(), av[0]);
1076             perror (buf);
1077           }
1078         exit (1);                               /* exits fork */
1079         break;
1080       }
1081     default:
1082       {
1083         int result = 0;
1084         int wait_status = 0;
1085
1086         FILE *f = fdopen (in, "r");
1087         unsigned long v = 0;
1088         char c;
1089
1090         close (out);  /* don't need this one */
1091
1092         *buf = 0;
1093         fgets (buf, sizeof(buf)-1, f);
1094         fclose (f);
1095
1096         /* Wait for the child to die. */
1097         waitpid (-1, &wait_status, 0);
1098
1099         if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1100           result = (int) v;
1101
1102         if (result == 0)
1103           {
1104             if (si->prefs.verbose_p)
1105               {
1106                 int L = strlen(buf);
1107                 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1108                          blurb(), av[0]);
1109
1110                 if (L && buf[L-1] == '\n')
1111                   buf[--L] = 0;
1112                 if (*buf)
1113                   fprintf (stderr, "%s: %s said: \"%s\"\n",
1114                            blurb(), av[0], buf);
1115               }
1116             return 0;
1117           }
1118         else
1119           {
1120             Visual *v = id_to_visual (ssi->screen, result);
1121             if (si->prefs.verbose_p)
1122               fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1123                        blurb(), ssi->number,
1124                        av[0], result,
1125                        (v == ssi->default_visual ? " (default)" : ""));
1126             return v;
1127           }
1128       }
1129     }
1130
1131   abort();
1132 }
1133
1134
1135 \f
1136 /* Restarting the xscreensaver process from scratch. */
1137
1138 static char **saved_argv;
1139
1140 void
1141 save_argv (int argc, char **argv)
1142 {
1143   saved_argv = (char **) calloc (argc+2, sizeof (char *));
1144   saved_argv [argc] = 0;
1145   while (argc--)
1146     {
1147       int i = strlen (argv [argc]) + 1;
1148       saved_argv [argc] = (char *) malloc (i);
1149       memcpy (saved_argv [argc], argv [argc], i);
1150     }
1151 }
1152
1153
1154 /* Re-execs the process with the arguments in saved_argv.  Does not return.
1155  */
1156 void
1157 restart_process (saver_info *si)
1158 {
1159   fflush (stdout);
1160   fflush (stderr);
1161   shutdown_stderr (si);
1162   if (si->prefs.verbose_p)
1163     {
1164       int i;
1165       fprintf (stderr, "%s: re-executing", blurb());
1166       for (i = 0; saved_argv[i]; i++)
1167         fprintf (stderr, " %s", saved_argv[i]);
1168       fprintf (stderr, "\n");
1169     }
1170   describe_uids (si, stderr);
1171   fprintf (stderr, "\n");
1172
1173   fflush (stdout);
1174   fflush (stderr);
1175   execvp (saved_argv [0], saved_argv);  /* shouldn't return */
1176   {
1177     char buf [512];
1178     sprintf (buf, "%s: could not restart process", blurb());
1179     perror(buf);
1180     fflush(stderr);
1181     abort();
1182   }
1183 }