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