http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.23.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            !select_visual_of_hack (ssi, hack)))
958         {
959           if (++retry_count > (p->screenhacks_count*4))
960             {
961               /* Uh, oops.  Odds are, there are no suitable visuals,
962                  and we're looping.  Give up.  (This is totally lame,
963                  what we should do is make a list of suitable hacks at
964                  the beginning, then only loop over them.)
965               */
966               if (p->verbose_p)
967                 fprintf(stderr,
968                       "%s: %d: no programs enabled, or no suitable visuals.\n",
969                         blurb(), ssi->number);
970               return;
971             }
972           else
973             goto AGAIN;
974         }
975
976       /* Turn off "next" and "prev" modes now, but "demo" mode is only
977          turned off by explicit action.
978        */
979       if (si->selection_mode < 0)
980         si->selection_mode = 0;
981
982       forked = fork_and_exec (ssi, hack->command);
983       switch ((int) forked)
984         {
985         case -1: /* fork failed */
986         case 0:  /* child fork (can't happen) */
987           sprintf (buf, "%s: couldn't fork", blurb());
988           perror (buf);
989           restore_real_vroot (si);
990           saver_exit (si, 1, "couldn't fork");
991           break;
992
993         default:
994           ssi->pid = forked;
995           break;
996         }
997     }
998 }
999
1000
1001 void
1002 spawn_screenhack (saver_info *si, Bool first_time_p)
1003 {
1004   if (monitor_powered_on_p (si))
1005     {
1006       int i;
1007       for (i = 0; i < si->nscreens; i++)
1008         {
1009           saver_screen_info *ssi = &si->screens[i];
1010           spawn_screenhack_1 (ssi, first_time_p);
1011         }
1012     }
1013   else if (si->prefs.verbose_p)
1014     fprintf (stderr,
1015              "%s: X says monitor has powered down; "
1016              "not launching a hack.\n", blurb());
1017
1018   store_saver_status (si);  /* store current hack numbers */
1019 }
1020
1021
1022 void
1023 kill_screenhack (saver_info *si)
1024 {
1025   int i;
1026   for (i = 0; i < si->nscreens; i++)
1027     {
1028       saver_screen_info *ssi = &si->screens[i];
1029       if (ssi->pid)
1030         kill_job (si, ssi->pid, SIGTERM);
1031       ssi->pid = 0;
1032     }
1033 }
1034
1035
1036 void
1037 suspend_screenhack (saver_info *si, Bool suspend_p)
1038 {
1039 #ifdef SIGSTOP  /* older VMS doesn't have it... */
1040   int i;
1041   for (i = 0; i < si->nscreens; i++)
1042     {
1043       saver_screen_info *ssi = &si->screens[i];
1044       if (ssi->pid)
1045         kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1046     }
1047 #endif /* SIGSTOP */
1048 }
1049
1050
1051 /* Called when we're exiting abnormally, to kill off the subproc. */
1052 void
1053 emergency_kill_subproc (saver_info *si)
1054 {
1055   int i;
1056 #ifdef SIGCHLD
1057   signal (SIGCHLD, SIG_IGN);
1058 #endif /* SIGCHLD */
1059
1060   for (i = 0; i < si->nscreens; i++)
1061     {
1062       saver_screen_info *ssi = &si->screens[i];
1063       if (ssi->pid)
1064         {
1065           kill_job (si, ssi->pid, SIGTERM);
1066           ssi->pid = 0;
1067         }
1068     }
1069 }
1070
1071 Bool
1072 screenhack_running_p (saver_info *si)
1073 {
1074   Bool any_running_p = False;
1075   int i;
1076   for (i = 0; i < si->nscreens; i++)
1077     {
1078       saver_screen_info *ssi = &si->screens[i];
1079       if (ssi->pid) any_running_p = True;
1080     }
1081   return any_running_p;
1082 }
1083
1084 \f
1085 /* Environment variables. */
1086
1087
1088 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
1089    is defined, the xscreensaver daemon will search that directory for hacks.
1090  */
1091 void
1092 hack_environment (saver_info *si)
1093 {
1094 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1095   static const char *def_path = DEFAULT_PATH_PREFIX;
1096   if (def_path && *def_path)
1097     {
1098       const char *opath = getenv("PATH");
1099       char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1100       strcpy (npath, "PATH=");
1101       strcat (npath, def_path);
1102       strcat (npath, ":");
1103       strcat (npath, opath);
1104
1105       if (putenv (npath))
1106         abort ();
1107
1108       /* don't free (npath) -- some implementations of putenv (BSD 4.4,
1109          glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1110          do not.  So we must leak it (and/or the previous setting). Yay.
1111        */
1112     }
1113 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1114 }
1115
1116
1117 void
1118 hack_subproc_environment (saver_screen_info *ssi)
1119 {
1120   /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1121      the spawned processes inherit is correct.  First, it must be on the same
1122      host and display as the value of -display passed in on our command line
1123      (which is not necessarily the same as what our $DISPLAY variable is.)
1124      Second, the screen number in the $DISPLAY passed to the subprocess should
1125      be the screen on which this particular hack is running -- not the display
1126      specification which the driver itself is using, since the driver ignores
1127      its screen number and manages all existing screens.
1128
1129      Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
1130      us to (eventually) run multiple hacks in Xinerama mode, where each hack
1131      has the same $DISPLAY but a different piece of glass.
1132    */
1133   saver_info *si = ssi->global;
1134   const char *odpy = DisplayString (si->dpy);
1135   char *ndpy = (char *) malloc (strlen(odpy) + 20);
1136   char *nssw = (char *) malloc (40);
1137   char *s;
1138
1139   strcpy (ndpy, "DISPLAY=");
1140   s = ndpy + strlen(ndpy);
1141   strcpy (s, odpy);
1142
1143   while (*s && *s != ':') s++;                  /* skip to colon */
1144   while (*s == ':') s++;                        /* skip over colons */
1145   while (isdigit(*s)) s++;                      /* skip over dpy number */
1146   while (*s == '.') s++;                        /* skip over dot */
1147   if (s[-1] != '.') *s++ = '.';                 /* put on a dot */
1148   sprintf(s, "%d", ssi->real_screen_number);    /* put on screen number */
1149
1150   sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
1151            (unsigned long) ssi->screensaver_window);
1152
1153   /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1154      any more, right?  It's not Posix, but everyone seems to have it. */
1155 #ifdef HAVE_PUTENV
1156   if (putenv (ndpy))
1157     abort ();
1158   if (putenv (nssw))
1159     abort ();
1160
1161   /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
1162      glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1163      do not.  So we must leak it (and/or the previous setting). Yay.
1164    */
1165 #endif /* HAVE_PUTENV */
1166 }
1167
1168 \f
1169 /* GL crap */
1170
1171 Visual *
1172 get_best_gl_visual (saver_screen_info *ssi)
1173 {
1174   saver_info *si = ssi->global;
1175   pid_t forked;
1176   int fds [2];
1177   int in, out;
1178   char buf[1024];
1179
1180   char *av[10];
1181   int ac = 0;
1182
1183   av[ac++] = "xscreensaver-gl-helper";
1184   av[ac] = 0;
1185
1186   if (pipe (fds))
1187     {
1188       perror ("error creating pipe:");
1189       return 0;
1190     }
1191
1192   in = fds [0];
1193   out = fds [1];
1194
1195   switch ((int) (forked = fork ()))
1196     {
1197     case -1:
1198       {
1199         sprintf (buf, "%s: couldn't fork", blurb());
1200         perror (buf);
1201         saver_exit (si, 1, 0);
1202       }
1203     case 0:
1204       {
1205         int stdout_fd = 1;
1206
1207         close (in);  /* don't need this one */
1208         close (ConnectionNumber (si->dpy));     /* close display fd */
1209
1210         if (dup2 (out, stdout_fd) < 0)          /* pipe stdout */
1211           {
1212             perror ("could not dup() a new stdout:");
1213             return 0;
1214           }
1215         hack_subproc_environment (ssi);         /* set $DISPLAY */
1216
1217         execvp (av[0], av);                     /* shouldn't return. */
1218
1219         if (errno != ENOENT || si->prefs.verbose_p)
1220           {
1221             /* Ignore "no such file or directory" errors, unless verbose.
1222                Issue all other exec errors, though. */
1223             sprintf (buf, "%s: running %s", blurb(), av[0]);
1224             perror (buf);
1225           }
1226         exit (1);                               /* exits fork */
1227         break;
1228       }
1229     default:
1230       {
1231         int result = 0;
1232         int wait_status = 0;
1233
1234         FILE *f = fdopen (in, "r");
1235         unsigned long v = 0;
1236         char c;
1237
1238         close (out);  /* don't need this one */
1239
1240         *buf = 0;
1241         if (! fgets (buf, sizeof(buf)-1, f))
1242           *buf = 0;
1243         fclose (f);
1244
1245         /* Wait for the child to die. */
1246         waitpid (-1, &wait_status, 0);
1247
1248         if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1249           result = (int) v;
1250
1251         if (result == 0)
1252           {
1253             if (si->prefs.verbose_p)
1254               {
1255                 int L = strlen(buf);
1256                 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1257                          blurb(), av[0]);
1258
1259                 if (L && buf[L-1] == '\n')
1260                   buf[--L] = 0;
1261                 if (*buf)
1262                   fprintf (stderr, "%s: %s said: \"%s\"\n",
1263                            blurb(), av[0], buf);
1264               }
1265             return 0;
1266           }
1267         else
1268           {
1269             Visual *v = id_to_visual (ssi->screen, result);
1270             if (si->prefs.verbose_p)
1271               fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1272                        blurb(), ssi->number,
1273                        av[0], result,
1274                        (v == ssi->default_visual ? " (default)" : ""));
1275             return v;
1276           }
1277       }
1278     }
1279
1280   abort();
1281 }
1282
1283
1284 \f
1285 /* Restarting the xscreensaver process from scratch. */
1286
1287 static char **saved_argv;
1288
1289 void
1290 save_argv (int argc, char **argv)
1291 {
1292   saved_argv = (char **) calloc (argc+2, sizeof (char *));
1293   saved_argv [argc] = 0;
1294   while (argc--)
1295     {
1296       int i = strlen (argv [argc]) + 1;
1297       saved_argv [argc] = (char *) malloc (i);
1298       memcpy (saved_argv [argc], argv [argc], i);
1299     }
1300 }
1301
1302
1303 /* Re-execs the process with the arguments in saved_argv.  Does not return.
1304  */
1305 void
1306 restart_process (saver_info *si)
1307 {
1308   fflush (stdout);
1309   fflush (stderr);
1310   shutdown_stderr (si);
1311   if (si->prefs.verbose_p)
1312     {
1313       int i;
1314       fprintf (stderr, "%s: re-executing", blurb());
1315       for (i = 0; saved_argv[i]; i++)
1316         fprintf (stderr, " %s", saved_argv[i]);
1317       fprintf (stderr, "\n");
1318     }
1319   describe_uids (si, stderr);
1320   fprintf (stderr, "\n");
1321
1322   fflush (stdout);
1323   fflush (stderr);
1324   execvp (saved_argv [0], saved_argv);  /* shouldn't return */
1325   {
1326     char buf [512];
1327     sprintf (buf, "%s: could not restart process", blurb());
1328     perror(buf);
1329     fflush(stderr);
1330     abort();
1331   }
1332 }