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