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