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