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