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