From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / driver / subprocs.c
1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2  * xscreensaver, Copyright (c) 1991-2016 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 #include <sys/param.h>          /* for PATH_MAX */
29
30 #ifdef HAVE_SYS_WAIT_H
31 # include <sys/wait.h>          /* for waitpid() and associated macros */
32 #endif
33
34 #ifdef HAVE_SETRLIMIT
35 # include <sys/resource.h>      /* for setrlimit() and RLIMIT_AS */
36 #endif
37
38 #ifdef VMS
39 # include <processes.h>
40 # include <unixio.h>            /* for close */
41 # include <unixlib.h>           /* for getpid */
42 # define pid_t int
43 # define fork  vfork
44 #endif /* VMS */
45
46 #include <signal.h>             /* for the signal names */
47
48 #if !defined(SIGCHLD) && defined(SIGCLD)
49 # define SIGCHLD SIGCLD
50 #endif
51
52 #if 0 /* putenv() is declared in stdlib.h on modern linux systems. */
53 #ifdef HAVE_PUTENV
54 extern int putenv (/* const char * */); /* getenv() is in stdlib.h... */
55 #endif
56 #endif
57
58 extern int kill (pid_t, int);           /* signal() is in sys/signal.h... */
59
60 /* This file doesn't need the Xt headers, so stub these types out... */
61 #undef XtPointer
62 #define XtAppContext void*
63 #define XrmDatabase  void*
64 #define XtIntervalId void*
65 #define XtPointer    void*
66 #define Widget       void*
67
68 #include "xscreensaver.h"
69 #include "exec.h"
70 #include "yarandom.h"
71 #include "visual.h"    /* for id_to_visual() */
72
73 extern saver_info *global_si_kludge;    /* I hate C so much... */
74
75
76 /* Used when printing error/debugging messages from signal handlers.
77  */
78 static const char *
79 no_malloc_number_to_string (long num)
80 {
81   static char string[128] = "";
82   int num_digits;
83   Bool negative_p = False;
84
85   num_digits = 0;
86
87   if (num == 0)
88     return "0";
89
90   if (num < 0)
91     {
92       negative_p = True;
93       num = -num;
94     }
95
96   while ((num > 0) && (num_digits < sizeof(string) - 1))
97     {
98       int digit;
99       digit = (int) num % 10;
100       num_digits++;
101       string[sizeof(string) - 1 - num_digits] = digit + '0';
102       num /= 10;
103     }
104
105   if (negative_p)
106     {
107       num_digits++;
108       string[sizeof(string) - 1 - num_digits] = '-';
109     }
110
111   return string + sizeof(string) - 1 - num_digits;
112 }
113
114 /* Like write(), but runs strlen() on the arg to get the length. */
115 static int
116 write_string (int fd, const char *str)
117 {
118   return write (fd, str, strlen (str));
119 }
120
121 static int
122 write_long (int fd, long n)
123 {
124   const char *str = no_malloc_number_to_string (n);
125   return write_string (fd, str);
126 }
127
128
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.
132
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!
138  */
139 #if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
140 # define RLIMIT_AS RLIMIT_VMEM
141 #endif
142
143 static void
144 limit_subproc_memory (int address_space_limit, Bool verbose_p)
145 {
146
147 /* This has caused way more problems than it has solved...
148    Let's just completely ignore the "memoryLimit" option now.
149  */
150 #undef HAVE_SETRLIMIT
151
152 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS)
153   struct rlimit r;
154
155   if (address_space_limit < 10 * 1024)  /* let's not be crazy */
156     return;
157
158   if (getrlimit (RLIMIT_AS, &r) != 0)
159     {
160       char buf [512];
161       sprintf (buf, "%s: getrlimit(RLIMIT_AS) failed", blurb());
162       perror (buf);
163       return;
164     }
165
166   r.rlim_cur = address_space_limit;
167
168   if (setrlimit (RLIMIT_AS, &r) != 0)
169     {
170       char buf [512];
171       sprintf (buf, "%s: setrlimit(RLIMIT_AS, {%lu, %lu}) failed",
172                blurb(), r.rlim_cur, r.rlim_max);
173       perror (buf);
174       return;
175     }
176
177   if (verbose_p)
178     {
179       int i = address_space_limit;
180       char buf[100];
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);
187       else
188         sprintf(buf, "%d bytes", i);
189
190       fprintf (stderr, "%s: limited pid %lu address space to %s.\n",
191                blurb(), (unsigned long) getpid (), buf);
192     }
193
194 #endif /* HAVE_SETRLIMIT && RLIMIT_AS */
195 }
196
197 \f
198 /* Management of child processes, and de-zombification.
199  */
200
201 enum job_status {
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. */
209 };
210
211 struct screenhack_job {
212   char *name;
213   pid_t pid;
214   int screen;
215   enum job_status status;
216   time_t launched, killed;
217   struct screenhack_job *next;
218 };
219
220 static struct screenhack_job *jobs = 0;
221
222 /* for debugging -- nothing calls this, but it's useful to invoke from gdb.
223  */
224 void show_job_list (void);
225
226 void
227 show_job_list (void)
228 {
229   struct screenhack_job *job;
230   fprintf(stderr, "%s: job list:\n", blurb());
231   for (job = jobs; job; job = job->next)
232     {
233       char b[] = "           ??:??:??     ";
234       char *t = (job->killed   ? timestring (job->killed) :
235                  job->launched ? timestring (job->launched) : b);
236       t += 11;
237       t[8] = 0;
238         fprintf (stderr, "  %5ld: %2d: (%s) %s %s\n",
239                  (long) job->pid,
240                  job->screen,
241                  (job->status == job_running ? "running" :
242                   job->status == job_stopped ? "stopped" :
243                   job->status == job_killed  ? " killed" :
244                   job->status == job_dead    ? "   dead" : "    ???"),
245                  t, job->name);
246     }
247   fprintf (stderr, "\n");
248 }
249
250
251 static void clean_job_list (void);
252
253 static struct screenhack_job *
254 make_job (pid_t pid, int screen, const char *cmd)
255 {
256   struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
257
258   static char name [1024];
259   const char *in = cmd;
260   char *out = name;
261   int got_eq = 0;
262   int first = 1;
263
264   clean_job_list();
265
266  AGAIN:
267   while (isspace(*in)) in++;            /* skip whitespace */
268   while (!isspace(*in) && *in != ':') {
269     if (*in == '=') got_eq = 1;
270     *out++ = *in++;                     /* snarf first token */
271   }
272
273   if (got_eq)                           /* if the first token was FOO=bar */
274     {                                   /* then get the next token instead. */
275       got_eq = 0;
276       out = name;
277       first = 0;
278       goto AGAIN;
279     }
280
281   while (isspace(*in)) in++;            /* skip whitespace */
282   *out = 0;
283
284   job->name = strdup(name);
285   job->pid = pid;
286   job->screen = screen;
287   job->status = job_running;
288   job->launched = time ((time_t *) 0);
289   job->killed = 0;
290   job->next = jobs;
291   jobs = job;
292
293   return jobs;
294 }
295
296
297 static void
298 free_job (struct screenhack_job *job)
299 {
300   if (!job)
301     return;
302   else if (job == jobs)
303     jobs = jobs->next;
304   else
305     {
306       struct screenhack_job *job2, *prev;
307       for (prev = 0, job2 = jobs;
308            job2;
309            prev = job2, job2 = job2->next)
310         if (job2 == job)
311           {
312             prev->next = job->next;
313             break;
314           }
315     }
316   free(job->name);
317   free(job);
318 }
319
320
321 /* Cleans out dead jobs from the jobs list -- this must only be called
322    from the main thread, not from a signal handler. 
323  */
324 static void
325 clean_job_list (void)
326 {
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;
331
332   for (prev = 0, job = jobs, next = (job ? job->next : 0);
333        job;
334        prev = job, job = next, next = (job ? job->next : 0))
335     {
336       if (job->status == job_dead)
337         {
338           if (prev)
339             prev->next = next;
340           free_job (job);
341           job = prev;
342         }
343       else if (job->status == job_killed &&
344                now - job->killed > 10 &&
345                now - last_warn   > 10)
346         {
347           fprintf (stderr,
348                    "%s: WARNING: pid %ld (%s) sent SIGTERM %ld seconds ago"
349                    " and did not die!\n",
350                    blurb(),
351                    (long) job->pid,
352                    job->name,
353                    (long) (now - job->killed));
354           warnedp = True;
355         }
356     }
357   if (warnedp) last_warn = now;
358 }
359
360
361 static struct screenhack_job *
362 find_job (pid_t pid)
363 {
364   struct screenhack_job *job;
365   for (job = jobs; job; job = job->next)
366     if (job->pid == pid)
367       return job;
368   return 0;
369 }
370
371 static void await_dying_children (saver_info *si);
372 #ifndef VMS
373 static void describe_dead_child (saver_info *, pid_t, int wait_status);
374 #endif
375
376
377 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
378    Don't alter this directly -- use block_sigchld() / unblock_sigchld().
379  */
380 static int block_sigchld_handler = 0;
381
382
383 #ifdef HAVE_SIGACTION
384  sigset_t
385 #else  /* !HAVE_SIGACTION */
386  int
387 #endif /* !HAVE_SIGACTION */
388 block_sigchld (void)
389 {
390 #ifdef HAVE_SIGACTION
391   struct sigaction sa;
392   sigset_t child_set;
393
394   memset (&sa, 0, sizeof (sa));
395   sa.sa_handler = SIG_IGN;
396   sigaction (SIGPIPE, &sa, NULL);
397
398   sigemptyset (&child_set);
399   sigaddset (&child_set, SIGCHLD);
400   sigprocmask (SIG_BLOCK, &child_set, 0);
401
402 #else  /* !HAVE_SIGACTION */
403   signal (SIGPIPE, SIG_IGN);
404 #endif /* !HAVE_SIGACTION */
405
406   block_sigchld_handler++;
407
408 #ifdef HAVE_SIGACTION
409   return child_set;
410 #else  /* !HAVE_SIGACTION */
411   return 0;
412 #endif /* !HAVE_SIGACTION */
413 }
414
415 void
416 unblock_sigchld (void)
417 {
418   if (block_sigchld_handler <= 0)
419     abort();
420
421   if (block_sigchld_handler <= 1)  /* only unblock if count going to 0 */
422     {
423 #ifdef HAVE_SIGACTION
424   struct sigaction sa;
425   sigset_t child_set;
426
427   memset(&sa, 0, sizeof (sa));
428   sa.sa_handler = SIG_DFL;
429   sigaction(SIGPIPE, &sa, NULL);
430
431   sigemptyset(&child_set);
432   sigaddset(&child_set, SIGCHLD);
433   sigprocmask(SIG_UNBLOCK, &child_set, 0);
434
435 #else /* !HAVE_SIGACTION */
436   signal(SIGPIPE, SIG_DFL);
437 #endif /* !HAVE_SIGACTION */
438     }
439
440   block_sigchld_handler--;
441 }
442
443 static int
444 kill_job (saver_info *si, pid_t pid, int signal)
445 {
446   saver_preferences *p = &si->prefs;
447   struct screenhack_job *job;
448   int status = -1;
449
450   clean_job_list();
451
452   if (in_signal_handler_p)
453     /* This function should not be called from the signal handler. */
454     abort();
455
456   block_sigchld();                      /* we control the horizontal... */
457
458   job = find_job (pid);
459   if (!job ||
460       !job->pid ||
461       job->status == job_killed)
462     {
463       if (p->verbose_p)
464         fprintf (stderr, "%s: no child %ld to signal!\n",
465                  blurb(), (long) pid);
466       goto DONE;
467     }
468
469   switch (signal) {
470   case SIGTERM:
471     job->status = job_killed;
472     job->killed = time ((time_t *) 0);
473     break;
474 #ifdef SIGSTOP
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;
478 #endif /* SIGSTOP */
479   default: abort();
480   }
481
482   if (p->verbose_p)
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,
488              job->name);
489
490   status = kill (job->pid, signal);
491
492   if (p->verbose_p && status < 0)
493     {
494       if (errno == ESRCH)
495         fprintf (stderr,
496                  "%s: %d: child process %lu (%s) was already dead.\n",
497                  blurb(), job->screen, (unsigned long) job->pid, job->name);
498       else
499         {
500           char buf [1024];
501           sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
502                    blurb(), job->screen, (unsigned long) job->pid, job->name);
503           perror (buf);
504         }
505     }
506
507   await_dying_children (si);
508
509  DONE:
510   unblock_sigchld();
511   if (block_sigchld_handler < 0)
512     abort();
513
514   clean_job_list();
515   return status;
516 }
517
518
519 #ifdef SIGCHLD
520 static RETSIGTYPE
521 sigchld_handler (int sig)
522 {
523   saver_info *si = global_si_kludge;    /* I hate C so much... */
524   in_signal_handler_p++;
525
526   if (si->prefs.debug_p)
527     {
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)" : ""));
531       */
532       write_string (STDERR_FILENO, blurb());
533       write_string (STDERR_FILENO, ": got SIGCHLD");
534
535       if (block_sigchld_handler)
536         write_string (STDERR_FILENO, " (blocked)\n");
537       else
538         write_string (STDERR_FILENO, "\n");
539     }
540
541   if (block_sigchld_handler < 0)
542     abort();
543   else if (block_sigchld_handler == 0)
544     {
545       block_sigchld();
546       await_dying_children (si);
547       unblock_sigchld();
548     }
549
550   init_sigchld();
551   in_signal_handler_p--;
552 }
553 #endif /* SIGCHLD */
554
555
556 #ifndef VMS
557
558 static void
559 await_dying_children (saver_info *si)
560 {
561   while (1)
562     {
563       int wait_status = 0;
564       pid_t kid;
565
566       errno = 0;
567       kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
568
569       if (si->prefs.debug_p)
570         {
571           if (kid < 0 && errno)
572             {
573               /* Don't call fprintf() from signal handlers, as it might malloc.
574               fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
575                        (long) kid, errno);
576                */
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");
583             }
584           else
585             {
586               /* Don't call fprintf() from signal handlers, as it might malloc.
587               fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
588                        (long) kid);
589                */
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");
594             }
595         }
596
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. */
600       if (kid == 0 ||
601           (kid < 0 && errno != EINTR))
602         break;
603
604       describe_dead_child (si, kid, wait_status);
605     }
606 }
607
608
609 static void
610 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
611 {
612   int i;
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;
617
618   if (WIFEXITED (wait_status))
619     {
620       int exit_status = WEXITSTATUS (wait_status);
621
622       /* Treat exit code as a signed 8-bit quantity. */
623       if (exit_status & 0x80) exit_status |= ~0xFF;
624
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.
630        */
631       if (!job ||
632           (exit_status != 0 &&
633            (p->verbose_p || job->status != job_killed)))
634         {
635           /* Don't call fprintf() from signal handlers, as it might malloc.
636           fprintf (stderr,
637                    "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
638                    blurb(), screen_no, (unsigned long) kid, name, exit_status);
639            */
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"); 
650         }
651       else if (p->verbose_p)
652         {
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);
656            */
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");
665         }
666
667       if (job)
668         job->status = job_dead;
669     }
670   else if (WIFSIGNALED (wait_status))
671     {
672       if (p->verbose_p ||
673           !job ||
674           job->status != job_killed ||
675           WTERMSIG (wait_status) != SIGTERM)
676         {
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)));
681            */
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");
692         }
693
694       if (job)
695         job->status = job_dead;
696     }
697   else if (WIFSTOPPED (wait_status))
698     {
699       if (p->verbose_p)
700         {
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)));
705            */
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");
716         }
717
718       if (job)
719         job->status = job_stopped;
720     }
721   else
722     {
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);
726        */
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!");
735       if (job)
736         job->status = job_dead;
737     }
738
739   /* Clear out the pid so that screenhack_running_p() knows it's dead.
740    */
741   if (!job || job->status == job_dead)
742     for (i = 0; i < si->nscreens; i++)
743       {
744         saver_screen_info *ssi = &si->screens[i];
745         if (kid == ssi->pid)
746           ssi->pid = 0;
747       }
748 }
749
750 #else  /* VMS */
751 static void await_dying_children (saver_info *si) { return; }
752 #endif /* VMS */
753
754
755 void
756 init_sigchld (void)
757 {
758 #ifdef SIGCHLD
759
760 # ifdef HAVE_SIGACTION  /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
761
762   static Bool sigchld_initialized_p = 0;
763   if (!sigchld_initialized_p)
764     {
765       struct sigaction action, old;
766
767       action.sa_handler = sigchld_handler;
768       sigemptyset(&action.sa_mask);
769       action.sa_flags = 0;
770
771       if (sigaction(SIGCHLD, &action, &old) < 0)
772         {
773           char buf [255];
774           sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
775           perror (buf);
776         }
777       sigchld_initialized_p = True;
778     }
779
780 # else  /* !HAVE_SIGACTION */
781
782   if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
783     {
784       char buf [255];
785       sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
786       perror (buf);
787     }
788 # endif /* !HAVE_SIGACTION */
789 #endif /* SIGCHLD */
790 }
791
792
793
794 \f
795
796 static Bool
797 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
798 {
799   saver_info *si = ssi->global;
800   saver_preferences *p = &si->prefs;
801   Bool selected;
802
803   if (hack->visual && *hack->visual)
804     selected = select_visual(ssi, hack->visual);
805   else
806     selected = select_visual(ssi, 0);
807
808   if (!selected && (p->verbose_p || si->demoing_p))
809     fprintf (stderr,
810              (si->demoing_p
811               ? "%s: warning, no \"%s\" visual for \"%s\".\n"
812               : "%s: no \"%s\" visual; skipping \"%s\".\n"),
813              blurb(),
814              (hack->visual && *hack->visual ? hack->visual : "???"),
815              hack->command);
816
817   return selected;
818 }
819
820
821 static void
822 print_path_error (const char *program)
823 {
824   char buf [512];
825   char *cmd = strdup (program);
826   char *token = strchr (cmd, ' ');
827
828   if (token) *token = 0;
829   sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
830   free (cmd);
831   perror (buf);
832
833   if (errno == ENOENT &&
834       (token = getenv("PATH")))
835     {
836 # ifndef PATH_MAX
837 #  ifdef MAXPATHLEN
838 #   define PATH_MAX MAXPATHLEN
839 #  else
840 #   define PATH_MAX 2048
841 #  endif
842 # endif
843       char path[PATH_MAX];
844       fprintf (stderr, "\n");
845       *path = 0;
846 # if defined(HAVE_GETCWD)
847       if (! getcwd (path, sizeof(path)))
848         *path = 0;
849 # elif defined(HAVE_GETWD)
850       getwd (path);
851 # endif
852       if (*path)
853         fprintf (stderr, "    Current directory is: %s\n", path);
854       fprintf (stderr, "    PATH is:\n");
855       token = strtok (strdup(token), ":");
856       while (token)
857         {
858           fprintf (stderr, "        %s\n", token);
859           token = strtok(0, ":");
860         }
861       fprintf (stderr, "\n");
862     }
863 }
864
865
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
871    printed to stderr.
872  */
873 pid_t
874 fork_and_exec (saver_screen_info *ssi, const char *command)
875 {
876   saver_info *si = ssi->global;
877   saver_preferences *p = &si->prefs;
878   pid_t forked;
879
880   switch ((int) (forked = fork ()))
881     {
882     case -1:
883       {
884         char buf [255];
885         sprintf (buf, "%s: couldn't fork", blurb());
886         perror (buf);
887         break;
888       }
889
890     case 0:
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);
894
895       if (p->verbose_p)
896         fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
897                  blurb(), ssi->number, command,
898                  (unsigned long) getpid ());
899
900       exec_command (p->shell, command, p->nice_inferior);
901
902       /* If that returned, we were unable to exec the subprocess.
903          Print an error message, if desired.
904        */
905       if (! p->ignore_uninstalled_p)
906         print_path_error (command);
907
908       exit (1);  /* exits child fork */
909       break;
910
911     default:    /* parent */
912       (void) make_job (forked, ssi->number, command);
913       break;
914     }
915
916   return forked;
917 }
918
919
920 void
921 spawn_screenhack (saver_screen_info *ssi)
922 {
923   saver_info *si = ssi->global;
924   saver_preferences *p = &si->prefs;
925   XFlush (si->dpy);
926
927   if (!monitor_powered_on_p (si))
928     {
929       if (si->prefs.verbose_p)
930         fprintf (stderr,
931                  "%s: %d: X says monitor has powered down; "
932                  "not launching a hack.\n", blurb(), ssi->number);
933       return;
934     }
935
936   if (p->screenhacks_count)
937     {
938       screenhack *hack;
939       pid_t forked;
940       char buf [255];
941       int new_hack = -1;
942       int retry_count = 0;
943       Bool force = False;
944
945     AGAIN:
946
947       if (p->screenhacks_count < 1)
948         {
949           /* No hacks at all */
950           new_hack = -1;
951         }
952       else if (p->screenhacks_count == 1)
953         {
954           /* Exactly one hack in the list */
955           new_hack = 0;
956         }
957       else if (si->selection_mode == -1)
958         {
959           /* Select the next hack, wrapping. */
960           new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
961         }
962       else if (si->selection_mode == -2)
963         {
964           /* Select the previous hack, wrapping. */
965           if (ssi->current_hack < 0)
966             new_hack = p->screenhacks_count - 1;
967           else
968             new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
969                         % p->screenhacks_count);
970         }
971       else if (si->selection_mode > 0)
972         {
973           /* Select a specific hack, by number (via the ACTIVATE command.) */
974           new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
975           force = True;
976         }
977       else if (p->mode == ONE_HACK &&
978                p->selected_hack >= 0)
979         {
980           /* Select a specific hack, by number (via "One Saver" mode.) */
981           new_hack = p->selected_hack;
982           force = True;
983         }
984       else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
985         {
986           new_hack = -1;
987         }
988       else if (p->mode == RANDOM_HACKS_SAME &&
989                ssi->number != 0)
990         {
991           /* Use the same hack that's running on screen 0.
992              (Assumes this function was called on screen 0 first.)
993            */
994           new_hack = si->screens[0].current_hack;
995         }
996       else  /* (p->mode == RANDOM_HACKS) */
997         {
998           /* Select a random hack (but not the one we just ran.) */
999           while ((new_hack = random () % p->screenhacks_count)
1000                  == ssi->current_hack)
1001             ;
1002         }
1003
1004       if (new_hack < 0)   /* don't run a hack */
1005         {
1006           ssi->current_hack = -1;
1007           if (si->selection_mode < 0)
1008             si->selection_mode = 0;
1009           return;
1010         }
1011
1012       ssi->current_hack = new_hack;
1013       hack = p->screenhacks[ssi->current_hack];
1014
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,
1018          use it regardless.
1019        */
1020       if (force)
1021         select_visual_of_hack (ssi, hack);
1022         
1023       if (!force &&
1024           (!hack->enabled_p ||
1025            !on_path_p (hack->command) ||
1026            !select_visual_of_hack (ssi, hack)))
1027         {
1028           if (++retry_count > (p->screenhacks_count*4))
1029             {
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.)
1034               */
1035               if (p->verbose_p)
1036                 fprintf(stderr,
1037                       "%s: %d: no programs enabled, or no suitable visuals.\n",
1038                         blurb(), ssi->number);
1039               return;
1040             }
1041           else
1042             goto AGAIN;
1043         }
1044
1045       /* Turn off "next" and "prev" modes now, but "demo" mode is only
1046          turned off by explicit action.
1047        */
1048       if (si->selection_mode < 0)
1049         si->selection_mode = 0;
1050
1051       forked = fork_and_exec (ssi, hack->command);
1052       switch ((int) forked)
1053         {
1054         case -1: /* fork failed */
1055         case 0:  /* child fork (can't happen) */
1056           sprintf (buf, "%s: couldn't fork", blurb());
1057           perror (buf);
1058           restore_real_vroot (si);
1059           saver_exit (si, 1, "couldn't fork");
1060           break;
1061
1062         default:
1063           ssi->pid = forked;
1064           break;
1065         }
1066     }
1067
1068   store_saver_status (si);  /* store current hack number */
1069 }
1070
1071
1072 void
1073 kill_screenhack (saver_screen_info *ssi)
1074 {
1075   saver_info *si = ssi->global;
1076   if (ssi->pid)
1077     kill_job (si, ssi->pid, SIGTERM);
1078   ssi->pid = 0;
1079 }
1080
1081
1082 void
1083 suspend_screenhack (saver_screen_info *ssi, Bool suspend_p)
1084 {
1085 #ifdef SIGSTOP  /* older VMS doesn't have it... */
1086   saver_info *si = ssi->global;
1087   if (ssi->pid)
1088     kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1089 #endif /* SIGSTOP */
1090 }
1091
1092
1093 /* Called when we're exiting abnormally, to kill off the subproc. */
1094 void
1095 emergency_kill_subproc (saver_info *si)
1096 {
1097   int i;
1098 #ifdef SIGCHLD
1099   signal (SIGCHLD, SIG_IGN);
1100 #endif /* SIGCHLD */
1101
1102   for (i = 0; i < si->nscreens; i++)
1103     {
1104       saver_screen_info *ssi = &si->screens[i];
1105       if (ssi->pid)
1106         {
1107           kill_job (si, ssi->pid, SIGTERM);
1108           ssi->pid = 0;
1109         }
1110     }
1111 }
1112
1113 Bool
1114 screenhack_running_p (saver_info *si)
1115 {
1116   Bool any_running_p = False;
1117   int i;
1118   for (i = 0; i < si->nscreens; i++)
1119     {
1120       saver_screen_info *ssi = &si->screens[i];
1121       if (ssi->pid) any_running_p = True;
1122     }
1123   return any_running_p;
1124 }
1125
1126 \f
1127 /* Environment variables. */
1128
1129
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.
1132  */
1133 void
1134 hack_environment (saver_info *si)
1135 {
1136 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1137   static const char *def_path = DEFAULT_PATH_PREFIX;
1138   if (def_path && *def_path)
1139     {
1140       const char *opath = getenv("PATH");
1141       char *npath;
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);
1148
1149       if (putenv (npath))
1150         abort ();
1151
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.
1155        */
1156     }
1157 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1158 }
1159
1160
1161 void
1162 hack_subproc_environment (Screen *screen, Window saver_window)
1163 {
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.
1172
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.
1176    */
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);
1181   char *s, *c;
1182
1183   strcpy (ndpy, "DISPLAY=");
1184   s = ndpy + strlen(ndpy);
1185   strcpy (s, odpy);
1186
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 */
1196
1197   sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", (unsigned long) saver_window);
1198
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. */
1201 #ifdef HAVE_PUTENV
1202   if (putenv (ndpy))
1203     abort ();
1204   if (putenv (nssw))
1205     abort ();
1206
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.
1210    */
1211 #endif /* HAVE_PUTENV */
1212 }
1213
1214 \f
1215 /* GL crap */
1216
1217 Visual *
1218 get_best_gl_visual (saver_info *si, Screen *screen)
1219 {
1220   pid_t forked;
1221   int fds [2];
1222   int in, out;
1223   int errfds[2];
1224   int errin = -1, errout = -1;
1225   char buf[1024];
1226
1227   char *av[10];
1228   int ac = 0;
1229
1230   av[ac++] = "xscreensaver-gl-helper";
1231   av[ac] = 0;
1232
1233   if (pipe (fds))
1234     {
1235       perror ("error creating pipe:");
1236       return 0;
1237     }
1238
1239   in = fds [0];
1240   out = fds [1];
1241
1242   if (!si->prefs.verbose_p)
1243     {
1244       if (pipe (errfds))
1245         {
1246           perror ("error creating pipe:");
1247           return 0;
1248         }
1249
1250       errin = errfds [0];
1251       errout = errfds [1];
1252     }
1253
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.
1257                       */
1258
1259   switch ((int) (forked = fork ()))
1260     {
1261     case -1:
1262       {
1263         sprintf (buf, "%s: couldn't fork", blurb());
1264         perror (buf);
1265         saver_exit (si, 1, 0);
1266       }
1267     case 0:
1268       {
1269         close (in);  /* don't need this one */
1270         close (ConnectionNumber (si->dpy));     /* close display fd */
1271
1272         if (dup2 (out, STDOUT_FILENO) < 0)      /* pipe stdout */
1273           {
1274             perror ("could not dup() a new stdout:");
1275             return 0;
1276           }
1277
1278         if (! si->prefs.verbose_p)
1279           {
1280             close(errin);
1281             if (dup2 (errout, STDERR_FILENO) < 0)
1282               {
1283                 perror ("could not dup() a new stderr:");
1284                 return 0;
1285               }
1286           }
1287
1288         hack_subproc_environment (screen, 0);   /* set $DISPLAY */
1289
1290         execvp (av[0], av);                     /* shouldn't return. */
1291
1292         if (errno != ENOENT /* || si->prefs.verbose_p */ )
1293           {
1294             /* Ignore "no such file or directory" errors.
1295                Issue all other exec errors, though. */
1296             sprintf (buf, "%s: running %s", blurb(), av[0]);
1297             perror (buf);
1298           }
1299         exit (1);                               /* exits fork */
1300         break;
1301       }
1302     default:
1303       {
1304         int result = 0;
1305         int wait_status = 0;
1306
1307         FILE *f = fdopen (in, "r");
1308         unsigned long v = 0;
1309         char c;
1310
1311         close (out);  /* don't need this one */
1312
1313         *buf = 0;
1314         if (! fgets (buf, sizeof(buf)-1, f))
1315           *buf = 0;
1316         fclose (f);
1317
1318         if (! si->prefs.verbose_p)
1319           {
1320             close (errout);
1321             close (errin);
1322           }
1323
1324         /* Wait for the child to die. */
1325         waitpid (-1, &wait_status, 0);
1326
1327         unblock_sigchld();   /* child is dead and waited, unblock now. */
1328
1329         if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1330           result = (int) v;
1331
1332         if (result == 0)
1333           {
1334             if (si->prefs.verbose_p)
1335               {
1336                 int L = strlen(buf);
1337                 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1338                          blurb(), av[0]);
1339
1340                 if (L && buf[L-1] == '\n')
1341                   buf[--L] = 0;
1342                 if (*buf)
1343                   fprintf (stderr, "%s: %s said: \"%s\"\n",
1344                            blurb(), av[0], buf);
1345               }
1346             return 0;
1347           }
1348         else
1349           {
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),
1354                        av[0], result,
1355                        (v == DefaultVisualOfScreen (screen)
1356                         ? " (default)" : ""));
1357             return v;
1358           }
1359       }
1360     }
1361
1362   abort();
1363 }
1364
1365
1366 \f
1367 /* Restarting the xscreensaver process from scratch. */
1368
1369 static char **saved_argv;
1370
1371 void
1372 save_argv (int argc, char **argv)
1373 {
1374   saved_argv = (char **) calloc (argc+2, sizeof (char *));
1375   saved_argv [argc] = 0;
1376   while (argc--)
1377     {
1378       int i = strlen (argv [argc]) + 1;
1379       saved_argv [argc] = (char *) malloc (i);
1380       memcpy (saved_argv [argc], argv [argc], i);
1381     }
1382 }
1383
1384
1385 /* Re-execs the process with the arguments in saved_argv.  Does not return.
1386  */
1387 void
1388 restart_process (saver_info *si)
1389 {
1390   fflush (stdout);
1391   fflush (stderr);
1392   shutdown_stderr (si);
1393   if (si->prefs.verbose_p)
1394     {
1395       int i;
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");
1400     }
1401   describe_uids (si, stderr);
1402   fprintf (stderr, "\n");
1403
1404   fflush (stdout);
1405   fflush (stderr);
1406   execvp (saved_argv [0], saved_argv);  /* shouldn't return */
1407   {
1408     char buf [512];
1409     sprintf (buf, "%s: could not restart process", blurb());
1410     perror(buf);
1411     fflush(stderr);
1412     abort();
1413   }
1414 }