a9fec53c0bf5d512d0d35d0359951417fb0c9ad5
[xscreensaver] / driver / subprocs.c
1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2  * xscreensaver, Copyright (c) 1991, 1992, 1993, 1995, 1997, 1998
3  *  Jamie Zawinski <jwz@jwz.org>
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation.  No representations are made about the suitability of this
10  * software for any purpose.  It is provided "as is" without express or 
11  * implied warranty.
12  */
13
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <string.h>
21
22 #include <X11/Xlib.h>           /* not used for much... */
23
24 #ifndef ESRCH
25 # include <errno.h>
26 #endif
27
28 #include <sys/time.h>           /* sys/resource.h needs this for timeval */
29
30 #ifdef HAVE_SYS_WAIT_H
31 # include <sys/wait.h>          /* for waitpid() and associated macros */
32 #endif
33
34 #if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
35 # include <sys/resource.h>      /* for setpriority() and PRIO_PROCESS */
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 "yarandom.h"
70
71
72 extern saver_info *global_si_kludge;    /* I hate C so much... */
73
74 static void
75 nice_subproc (int nice_level)
76 {
77   if (nice_level == 0)
78     return;
79
80 #if defined(HAVE_NICE)
81   {
82     int old_nice = nice (0);
83     int n = nice_level - old_nice;
84     errno = 0;
85     if (nice (n) == -1 && errno != 0)
86       {
87         char buf [512];
88         sprintf (buf, "%s: nice(%d) failed", blurb(), n);
89         perror (buf);
90     }
91   }
92 #elif defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
93   if (setpriority (PRIO_PROCESS, getpid(), nice_level) != 0)
94     {
95       char buf [512];
96       sprintf (buf, "%s: setpriority(PRIO_PROCESS, %lu, %d) failed",
97                blurb(), (unsigned long) getpid(), nice_level);
98       perror (buf);
99     }
100 #else
101   fprintf (stderr,
102            "%s: don't know how to change process priority on this system.\n",
103            blurb());
104
105 #endif
106 }
107
108
109 #ifndef VMS
110
111 static void
112 exec_simple_command (const char *command)
113 {
114   char *av[1024];
115   int ac = 0;
116   char *token = strtok (strdup(command), " \t");
117   while (token)
118     {
119       av[ac++] = token;
120       token = strtok(0, " \t");
121     }
122   av[ac] = 0;
123
124   execvp (av[0], av);                   /* shouldn't return. */
125
126   {
127     char buf [512];
128     sprintf (buf, "%s: could not execute \"%s\"", blurb(), av[0]);
129     perror (buf);
130
131     if (errno == ENOENT &&
132         (token = getenv("PATH")))
133       {
134 # ifndef PATH_MAX
135 #  ifdef MAXPATHLEN
136 #   define PATH_MAX MAXPATHLEN
137 #  else
138 #   define PATH_MAX 2048
139 #  endif
140 # endif
141         char path[PATH_MAX];
142         fprintf (stderr, "\n");
143         *path = 0;
144 # if defined(HAVE_GETCWD)
145         getcwd (path, sizeof(path));
146 # elif defined(HAVE_GETWD)
147         getwd (path);
148 # endif
149         if (*path)
150           fprintf (stderr, "    Current directory is: %s\n", path);
151         fprintf (stderr, "    PATH is:\n");
152         token = strtok (strdup(token), ":");
153         while (token)
154           {
155             fprintf (stderr, "        %s\n", token);
156             token = strtok(0, ":");
157           }
158         fprintf (stderr, "\n");
159       }
160   }
161   fflush(stderr);
162   fflush(stdout);
163   exit (1);     /* Note that this only exits a child fork.  */
164 }
165
166
167 static void
168 exec_complex_command (const char *shell, const char *command)
169 {
170   char *av[5];
171   int ac = 0;
172   char *command2 = (char *) malloc (strlen (command) + 6);
173   memcpy (command2, "exec ", 5);
174   memcpy (command2 + 5, command, strlen (command) + 1);
175
176   /* Invoke the shell as "/bin/sh -c 'exec prog -arg -arg ...'" */
177   av [ac++] = (char *) shell;
178   av [ac++] = "-c";
179   av [ac++] = command2;
180   av [ac]   = 0;
181
182   execvp (av[0], av);                   /* shouldn't return. */
183
184   {
185     char buf [512];
186     sprintf (buf, "%s: execvp(\"%s\") failed", blurb(), av[0]);
187     perror (buf);
188     fflush(stderr);
189     fflush(stdout);
190     exit (1);   /* Note that this only exits a child fork.  */
191   }
192 }
193
194 #else  /* VMS */
195
196 static void
197 exec_vms_command (const char *command)
198 {
199   system (command);
200   fflush (stderr);
201   fflush (stdout);
202   exit (1);     /* Note that this only exits a child fork.  */
203 }
204
205 #endif /* !VMS */
206
207
208 static void
209 exec_screenhack (saver_info *si, const char *command)
210 {
211   /* I don't believe what a sorry excuse for an operating system UNIX is!
212
213      - I want to spawn a process.
214      - I want to know it's pid so that I can kill it.
215      - I would like to receive a message when it dies of natural causes.
216      - I want the spawned process to have user-specified arguments.
217
218      If shell metacharacters are present (wildcards, backquotes, etc), the
219      only way to parse those arguments is to run a shell to do the parsing
220      for you.
221
222      And the only way to know the pid of the process is to fork() and exec()
223      it in the spawned side of the fork.
224
225      But if you're running a shell to parse your arguments, this gives you
226      the pid of the *shell*, not the pid of the *process* that you're
227      actually interested in, which is an *inferior* of the shell.  This also
228      means that the SIGCHLD you get applies to the shell, not its inferior.
229      (Why isn't that sufficient?  I don't remember any more, but it turns
230      out that it isn't.)
231
232      So, the only solution, when metacharacters are present, is to force the
233      shell to exec() its inferior.  What a fucking hack!  We prepend "exec "
234      to the command string, and hope it doesn't contain unquoted semicolons
235      or ampersands (we don't search for them, because we don't want to
236      prohibit their use in quoted strings (messages, for example) and parsing
237      out the various quote characters is too much of a pain.)
238
239      (Actually, Clint Wong <clint@jts.com> points out that process groups
240      might be used to take care of this problem; this may be worth considering
241      some day, except that, 1: this code works now, so why fix it, and 2: from
242      what I've seen in Emacs, dealing with process groups isn't especially
243      portable.)
244    */
245   saver_preferences *p = &si->prefs;
246
247 #ifndef VMS
248   Bool hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"=");
249   /* note: = is in the above because of the sh syntax "FOO=bar cmd". */
250
251   if (p->verbose_p)
252     fprintf (stderr, "%s: spawning \"%s\" in pid %lu%s.\n",
253              blurb(), command, (unsigned long) getpid (),
254              (hairy_p ? " (via shell)" : ""));
255
256   if (hairy_p)
257     /* If it contains any shell metacharacters, do it the hard way,
258        and fork a shell to parse the arguments for us. */
259     exec_complex_command (p->shell, command);
260   else
261     /* Otherwise, we can just exec the program directly. */
262     exec_simple_command (command);
263
264 #else /* VMS */
265   if (p->verbose_p)
266     fprintf (stderr, "%s: spawning \"%s\" in pid %lu.\n",
267              blurb(), command, getpid());
268   exec_vms_command (command);
269 #endif /* VMS */
270
271   abort();      /* that shouldn't have returned. */
272 }
273
274
275 \f
276 /* Management of child processes, and de-zombification.
277  */
278
279 enum job_status {
280   job_running,  /* the process is still alive */
281   job_stopped,  /* we have sent it a STOP signal */
282   job_killed,   /* we have sent it a TERM signal */
283   job_dead      /* we have wait()ed for it, and it's dead -- this state only
284                    occurs so that we can avoid calling free() from a signal
285                    handler.  Shortly after going into this state, the list
286                    element will be removed. */
287 };
288
289 struct screenhack_job {
290   char *name;
291   pid_t pid;
292   enum job_status status;
293   struct screenhack_job *next;
294 };
295
296 static struct screenhack_job *jobs = 0;
297
298 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
299 void
300 show_job_list (void)
301 {
302   struct screenhack_job *job;
303   fprintf(stderr, "%s: job list:\n", blurb());
304   for (job = jobs; job; job = job->next)
305     fprintf (stderr, "  %5ld: (%s) %s\n",
306              (long) job->pid,
307              (job->status == job_running ? "running" :
308               job->status == job_stopped ? "stopped" :
309               job->status == job_killed  ? " killed" :
310               job->status == job_dead    ? "   dead" : "    ???"),
311              job->name);
312   fprintf (stderr, "\n");
313 }
314
315
316 static void clean_job_list (void);
317
318 static struct screenhack_job *
319 make_job (pid_t pid, const char *cmd)
320 {
321   struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
322
323   static char name [1024];
324   const char *in = cmd;
325   char *out = name;
326
327   clean_job_list();
328
329   while (isspace(*in)) in++;            /* skip whitespace */
330   while (!isspace(*in) && *in != ':')
331     *out++ = *in++;                     /* snarf first token */
332   while (isspace(*in)) in++;            /* skip whitespace */
333   if (*in == ':')                       /* token was a visual name; skip it. */
334     {
335       in++;
336       out = name;
337       while (isspace(*in)) in++;                /* skip whitespace */
338       while (!isspace(*in)) *out++ = *in++;     /* snarf first token */
339     }
340   *out = 0;
341
342   job->name = strdup(name);
343   job->pid = pid;
344   job->status = job_running;
345   job->next = jobs;
346   jobs = job;
347
348   return jobs;
349 }
350
351
352 static void
353 free_job (struct screenhack_job *job)
354 {
355   if (!job)
356     return;
357   else if (job == jobs)
358     jobs = jobs->next;
359   else
360     {
361       struct screenhack_job *job2, *prev;
362       for (prev = 0, job2 = jobs;
363            job2;
364            prev = job2, job2 = job2->next)
365         if (job2 == job)
366           {
367             prev->next = job->next;
368             break;
369           }
370     }
371   free(job->name);
372   free(job);
373 }
374
375
376 /* Cleans out dead jobs from the jobs list -- this must only be called
377    from the main thread, not from a signal handler. 
378  */
379 static void
380 clean_job_list (void)
381 {
382   struct screenhack_job *job, *prev, *next;
383   for (prev = 0, job = jobs, next = (job ? job->next : 0);
384        job;
385        prev = job, job = next, next = (job ? job->next : 0))
386     {
387       if (job->status == job_dead)
388         {
389           if (prev)
390             prev->next = next;
391           free_job (job);
392           job = prev;
393         }
394     }
395 }
396
397
398 static struct screenhack_job *
399 find_job (pid_t pid)
400 {
401   struct screenhack_job *job;
402   for (job = jobs; job; job = job->next)
403     if (job->pid == pid)
404       return job;
405   return 0;
406 }
407
408 static void await_dying_children (saver_info *si);
409 #ifndef VMS
410 static void describe_dead_child (saver_info *, pid_t, int wait_status);
411 #endif
412
413
414 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
415    Don't alter this directly -- use block_sigchld() / unblock_sigchld().
416  */
417 static int block_sigchld_handler = 0;
418
419
420 static void
421 block_sigchld (void)
422 {
423 #ifdef HAVE_SIGACTION
424   sigset_t child_set;
425   sigemptyset (&child_set);
426   sigaddset (&child_set, SIGCHLD);
427   sigprocmask (SIG_BLOCK, &child_set, 0);
428 #endif /* HAVE_SIGACTION */
429
430   block_sigchld_handler++;
431 }
432
433 static void
434 unblock_sigchld (void)
435 {
436 #ifdef HAVE_SIGACTION
437   sigset_t child_set;
438   sigemptyset(&child_set);
439   sigaddset(&child_set, SIGCHLD);
440   sigprocmask(SIG_UNBLOCK, &child_set, 0);
441 #endif /* HAVE_SIGACTION */
442
443   block_sigchld_handler--;
444 }
445
446 static int
447 kill_job (saver_info *si, pid_t pid, int signal)
448 {
449   saver_preferences *p = &si->prefs;
450   struct screenhack_job *job;
451   int status = -1;
452
453   clean_job_list();
454
455   if (block_sigchld_handler)
456     /* This function should not be called from the signal handler. */
457     abort();
458
459   block_sigchld();                      /* we control the horizontal... */
460
461   job = find_job (pid);
462   if (!job ||
463       !job->pid ||
464       job->status == job_killed)
465     {
466       if (p->verbose_p)
467         fprintf (stderr, "%s: no child %ld to signal!\n",
468                  blurb(), (long) pid);
469       goto DONE;
470     }
471
472   switch (signal) {
473   case SIGTERM: job->status = job_killed;  break;
474 #ifdef SIGSTOP
475     /* #### there must be a way to do this on VMS... */
476   case SIGSTOP: job->status = job_stopped; break;
477   case SIGCONT: job->status = job_running; break;
478 #endif /* SIGSTOP */
479   default: abort();
480   }
481
482 #ifdef SIGSTOP
483   if (p->verbose_p)
484     fprintf (stderr, "%s: %s pid %lu.\n", blurb(),
485              (signal == SIGTERM ? "killing" :
486               signal == SIGSTOP ? "suspending" :
487               signal == SIGCONT ? "resuming" : "signalling"),
488              (unsigned long) job->pid);
489 #else  /* !SIGSTOP */
490   if (p->verbose_p)
491     fprintf (stderr, "%s: %s pid %lu.\n", blurb(), "killing",
492              (unsigned long) job->pid);
493 #endif /* !SIGSTOP */
494
495   status = kill (job->pid, signal);
496
497   if (p->verbose_p && status < 0)
498     {
499       if (errno == ESRCH)
500         fprintf (stderr, "%s: child process %lu (%s) was already dead.\n",
501                  blurb(), job->pid, job->name);
502       else
503         {
504           char buf [1024];
505           sprintf (buf, "%s: couldn't kill child process %lu (%s)",
506                    blurb(), job->pid, job->name);
507           perror (buf);
508         }
509     }
510
511   await_dying_children (si);
512
513  DONE:
514   unblock_sigchld();
515   if (block_sigchld_handler < 0)
516     abort();
517
518   clean_job_list();
519   return status;
520 }
521
522
523 #ifdef SIGCHLD
524 static RETSIGTYPE
525 sigchld_handler (int sig)
526 {
527   saver_info *si = global_si_kludge;    /* I hate C so much... */
528
529   if (si->prefs.debug_p)
530     fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
531             (block_sigchld_handler ? " (blocked)" : ""));
532
533   if (block_sigchld_handler < 0)
534     abort();
535   else if (block_sigchld_handler == 0)
536     {
537       block_sigchld();
538       await_dying_children (si);
539       unblock_sigchld();
540     }
541
542   init_sigchld();
543 }
544 #endif /* SIGCHLD */
545
546
547 #ifndef VMS
548 static void
549 await_dying_children (saver_info *si)
550 {
551   while (1)
552     {
553       int wait_status = 0;
554       pid_t kid;
555
556       errno = 0;
557       kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
558
559       if (si->prefs.debug_p)
560         {
561           if (kid < 0 && errno)
562             fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
563                      (long) kid, errno);
564           else
565             fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
566                      (long) kid);
567         }
568
569       /* 0 means no more children to reap.
570          -1 means error -- except "interrupted system call" isn't a "real"
571          error, so if we get that, we should just try again. */
572       if (kid == 0 ||
573           (kid < 0 && errno != EINTR))
574         break;
575
576       describe_dead_child (si, kid, wait_status);
577     }
578 }
579
580
581 static void
582 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
583 {
584   int i;
585   saver_preferences *p = &si->prefs;
586   struct screenhack_job *job = find_job (kid);
587   const char *name = job ? job->name : "<unknown>";
588
589   if (WIFEXITED (wait_status))
590     {
591       int exit_status = WEXITSTATUS (wait_status);
592
593       /* Treat exit code as a signed 8-bit quantity. */
594       if (exit_status & 0x80) exit_status |= ~0xFF;
595
596       /* One might assume that exiting with non-0 means something went wrong.
597          But that loser xswarm exits with the code that it was killed with, so
598          it *always* exits abnormally.  Treat abnormal exits as "normal" (don't
599          mention them) if we've just killed the subprocess.  But mention them
600          if they happen on their own.
601        */
602       if (!job ||
603           (exit_status != 0 &&
604            (p->verbose_p || job->status != job_killed)))
605         fprintf (stderr,
606                  "%s: child pid %lu (%s) exited abnormally (code %d).\n",
607                  blurb(), (unsigned long) kid, name, exit_status);
608       else if (p->verbose_p)
609         fprintf (stderr, "%s: child pid %lu (%s) exited normally.\n",
610                  blurb(), (unsigned long) kid, name);
611
612       if (job)
613         job->status = job_dead;
614     }
615   else if (WIFSIGNALED (wait_status))
616     {
617       if (p->verbose_p ||
618           !job ||
619           job->status != job_killed ||
620           WTERMSIG (wait_status) != SIGTERM)
621         fprintf (stderr, "%s: child pid %lu (%s) terminated with %s.\n",
622                  blurb(), (unsigned long) kid, name,
623                  signal_name (WTERMSIG(wait_status)));
624
625       if (job)
626         job->status = job_dead;
627     }
628   else if (WIFSTOPPED (wait_status))
629     {
630       if (p->verbose_p)
631         fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
632                  blurb(), (unsigned long) kid, name,
633                  signal_name (WSTOPSIG (wait_status)));
634
635       if (job)
636         job->status = job_stopped;
637     }
638   else
639     {
640       fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
641                blurb(), (unsigned long) kid, name);
642       if (job)
643         job->status = job_dead;
644     }
645
646   /* Clear out the pid so that screenhack_running_p() knows it's dead.
647    */
648   if (!job || job->status == job_dead)
649     for (i = 0; i < si->nscreens; i++)
650       {
651         saver_screen_info *ssi = &si->screens[i];
652         if (kid == ssi->pid)
653           ssi->pid = 0;
654       }
655 }
656
657 #else  /* VMS */
658 static void await_dying_children (saver_info *si) { return; }
659 #endif /* VMS */
660
661
662 void
663 init_sigchld (void)
664 {
665 #ifdef SIGCHLD
666
667 # ifdef HAVE_SIGACTION  /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
668
669   static Bool sigchld_initialized_p = 0;
670   if (!sigchld_initialized_p)
671     {
672       struct sigaction action, old;
673
674       action.sa_handler = sigchld_handler;
675       sigemptyset(&action.sa_mask);
676       action.sa_flags = 0;
677
678       if (sigaction(SIGCHLD, &action, &old) < 0)
679         {
680           char buf [255];
681           sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
682           perror (buf);
683         }
684       sigchld_initialized_p = True;
685     }
686
687 # else  /* !HAVE_SIGACTION */
688
689   if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
690     {
691       char buf [255];
692       sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
693       perror (buf);
694     }
695 # endif /* !HAVE_SIGACTION */
696 #endif /* SIGCHLD */
697 }
698
699
700
701 \f
702
703 static Bool
704 hack_enabled_p (const char *hack)
705 {
706   const char *s = hack;
707   while (isspace(*s)) s++;
708   return (*s != '-');
709 }
710
711 static Bool
712 select_visual_of_hack (saver_screen_info *ssi, const char *hack)
713 {
714   saver_info *si = ssi->global;
715   saver_preferences *p = &si->prefs;
716   Bool selected;
717   static char vis [1024];
718   const char *in = hack;
719   char *out = vis;
720   while (isspace(*in)) in++;            /* skip whitespace */
721   if (*in == '-') in++;                 /* skip optional "-" */
722   while (isspace(*in)) in++;            /* skip whitespace */
723
724   while (!isspace(*in) && *in != ':')
725     *out++ = *in++;                     /* snarf first token */
726   while (isspace(*in)) in++;            /* skip whitespace */
727   *out = 0;
728
729   if (*in == ':')
730     selected = select_visual(ssi, vis);
731   else
732     selected = select_visual(ssi, 0);
733
734   if (!selected && (p->verbose_p || si->demoing_p))
735     {
736       if (*in == ':') in++;
737       while (isspace(*in)) in++;
738       fprintf (stderr,
739                (si->demoing_p
740                 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
741                 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
742                blurb(), (vis ? vis : "???"), in);
743     }
744
745   return selected;
746 }
747
748
749 static void
750 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
751 {
752   saver_info *si = ssi->global;
753   saver_preferences *p = &si->prefs;
754   raise_window (si, first_time_p, True, False);
755   XFlush (si->dpy);
756
757   if (p->screenhacks_count)
758     {
759       char *hack;
760       pid_t forked;
761       char buf [255];
762       int new_hack;
763       int retry_count = 0;
764       Bool force = False;
765
766     AGAIN:
767
768       if (p->screenhacks_count == 1)
769         /* If there is only one hack in the list, there is no choice. */
770         new_hack = 0;
771
772       else if (si->selection_mode == -1)
773         /* Select the next hack, wrapping. */
774         new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
775
776       else if (si->selection_mode == -2)
777         /* Select the previous hack, wrapping. */
778         new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
779                     % p->screenhacks_count);
780
781       else if (si->selection_mode > 0)
782         /* Select a specific hack, by number.  No negotiation. */
783         {
784           new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
785           force = True;
786         }
787       else
788         {
789           /* Select a random hack (but not the one we just ran.) */
790           while ((new_hack = random () % p->screenhacks_count)
791                  == ssi->current_hack)
792             ;
793         }
794
795       ssi->current_hack = new_hack;
796       hack = p->screenhacks[ssi->current_hack];
797
798       /* If the hack is disabled, or there is no visual for this hack,
799          then try again (move forward, or backward, or re-randomize.)
800          Unless this hack was specified explicitly, in which case,
801          use it regardless.
802        */
803       if (!force &&
804           (!hack_enabled_p (hack) ||
805            !select_visual_of_hack (ssi, hack)))
806         {
807           if (++retry_count > (p->screenhacks_count*4))
808             {
809               /* Uh, oops.  Odds are, there are no suitable visuals,
810                  and we're looping.  Give up.  (This is totally lame,
811                  what we should do is make a list of suitable hacks at
812                  the beginning, then only loop over them.)
813               */
814               if (p->verbose_p)
815                 fprintf(stderr,
816                         "%s: no suitable visuals for these programs.\n",
817                         blurb());
818               return;
819             }
820           else
821             goto AGAIN;
822         }
823
824       /* Turn off "next" and "prev" modes now, but "demo" mode is only
825          turned off by explicit action.
826        */
827       if (si->selection_mode < 0)
828         si->selection_mode = 0;
829
830
831       /* If there's a visual description on the front of the command, nuke it.
832        */
833       {
834         char *in = hack;
835         while (isspace(*in)) in++;                      /* skip whitespace */
836         if (*in == '-') in++;                           /* skip optional "-" */
837         while (isspace(*in)) in++;                      /* skip whitespace */
838         hack = in;
839         while (!isspace(*in) && *in != ':') in++;       /* snarf first token */
840         while (isspace(*in)) in++;                      /* skip whitespace */
841         if (*in == ':')
842           {
843             in++;
844             while (isspace(*in)) in++;
845             hack = in;
846           }
847       }
848
849       switch ((int) (forked = fork ()))
850         {
851         case -1:
852           sprintf (buf, "%s: couldn't fork", blurb());
853           perror (buf);
854           restore_real_vroot (si);
855           saver_exit (si, 1, 0);
856
857         case 0:
858           close (ConnectionNumber (si->dpy));   /* close display fd */
859           nice_subproc (p->nice_inferior);      /* change process priority */
860           hack_subproc_environment (ssi);       /* set $DISPLAY */
861           exec_screenhack (si, hack);           /* this does not return */
862           abort();
863           break;
864
865         default:
866           ssi->pid = forked;
867           (void) make_job (forked, hack);
868           break;
869         }
870     }
871 }
872
873
874 void
875 spawn_screenhack (saver_info *si, Bool first_time_p)
876 {
877   int i;
878
879   if (!monitor_powered_on_p (si))
880     {
881       if (si->prefs.verbose_p)
882         fprintf (stderr,
883                  "%s: server reports that monitor has powered down; "
884                  "not launching a new hack.\n", blurb());
885       return;
886     }
887
888   for (i = 0; i < si->nscreens; i++)
889     {
890       saver_screen_info *ssi = &si->screens[i];
891       spawn_screenhack_1 (ssi, first_time_p);
892     }
893 }
894
895
896 void
897 kill_screenhack (saver_info *si)
898 {
899   int i;
900   for (i = 0; i < si->nscreens; i++)
901     {
902       saver_screen_info *ssi = &si->screens[i];
903       if (ssi->pid)
904         kill_job (si, ssi->pid, SIGTERM);
905       ssi->pid = 0;
906     }
907 }
908
909
910 void
911 suspend_screenhack (saver_info *si, Bool suspend_p)
912 {
913 #ifdef SIGSTOP  /* older VMS doesn't have it... */
914   int i;
915   for (i = 0; i < si->nscreens; i++)
916     {
917       saver_screen_info *ssi = &si->screens[i];
918       if (ssi->pid)
919         kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
920     }
921 #endif /* SIGSTOP */
922 }
923
924
925 /* Called when we're exiting abnormally, to kill off the subproc. */
926 void
927 emergency_kill_subproc (saver_info *si)
928 {
929   int i;
930 #ifdef SIGCHLD
931   signal (SIGCHLD, SIG_IGN);
932 #endif /* SIGCHLD */
933
934   for (i = 0; i < si->nscreens; i++)
935     {
936       saver_screen_info *ssi = &si->screens[i];
937       if (ssi->pid)
938         {
939           kill_job (si, ssi->pid, SIGTERM);
940           ssi->pid = 0;
941         }
942     }
943 }
944
945 Bool
946 screenhack_running_p (saver_info *si)
947 {
948   Bool result = True;
949   int i;
950   for (i = 0; i < si->nscreens; i++)
951     {
952       saver_screen_info *ssi = &si->screens[i];
953       if (!ssi->pid)
954         result = False;
955     }
956   return result;
957 }
958
959 \f
960 /* Environment variables. */
961
962
963 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
964    is defined, the xscreensaver daemon will search that directory for hacks.
965  */
966 void
967 hack_environment (saver_info *si)
968 {
969 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
970   static const char *def_path = DEFAULT_PATH_PREFIX;
971   if (def_path && *def_path)
972     {
973       const char *opath = getenv("PATH");
974       char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
975       strcpy (npath, "PATH=");
976       strcat (npath, def_path);
977       strcat (npath, ":");
978       strcat (npath, opath);
979
980       if (putenv (npath))
981         abort ();
982     }
983 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
984 }
985
986
987 void
988 hack_subproc_environment (saver_screen_info *ssi)
989 {
990   /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
991      the spawned processes inherit is correct.  First, it must be on the same
992      host and display as the value of -display passed in on our command line
993      (which is not necessarily the same as what our $DISPLAY variable is.)
994      Second, the screen number in the $DISPLAY passed to the subprocess should
995      be the screen on which this particular hack is running -- not the display
996      specification which the driver itself is using, since the driver ignores
997      its screen number and manages all existing screens.
998    */
999   saver_info *si = ssi->global;
1000   const char *odpy = DisplayString (si->dpy);
1001   char *ndpy = (char *) malloc(strlen(odpy) + 20);
1002   int screen_number;
1003   char *s;
1004
1005   for (screen_number = 0; screen_number < si->nscreens; screen_number++)
1006     if (ssi == &si->screens[screen_number])
1007       break;
1008
1009   strcpy (ndpy, "DISPLAY=");
1010   s = ndpy + strlen(ndpy);
1011   strcpy (s, odpy);
1012
1013   while (*s && *s != ':') s++;                  /* skip to colon */
1014   while (*s == ':') s++;                        /* skip over colons */
1015   while (isdigit(*s)) s++;                      /* skip over dpy number */
1016   while (*s == '.') s++;                        /* skip over dot */
1017   if (s[-1] != '.') *s++ = '.';                 /* put on a dot */
1018   sprintf(s, "%d", screen_number);              /* put on screen number */
1019
1020   /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1021      any more, right?  It's not Posix, but everyone seems to have it. */
1022 #ifdef HAVE_PUTENV
1023   if (putenv (ndpy))
1024     abort ();
1025 #endif /* HAVE_PUTENV */
1026 }
1027
1028 \f
1029 /* Restarting the xscreensaver process from scratch. */
1030
1031 static char **saved_argv;
1032
1033 void
1034 save_argv (int argc, char **argv)
1035 {
1036   saved_argv = (char **) calloc (argc+2, sizeof (char *));
1037   saved_argv [argc] = 0;
1038   while (argc--)
1039     {
1040       int i = strlen (argv [argc]) + 1;
1041       saved_argv [argc] = (char *) malloc (i);
1042       memcpy (saved_argv [argc], argv [argc], i);
1043     }
1044 }
1045
1046
1047 /* Re-execs the process with the arguments in saved_argv.
1048    Does not return unless there was an error.
1049  */
1050 void
1051 restart_process (saver_info *si)
1052 {
1053   if (si->prefs.verbose_p)
1054     {
1055       int i;
1056       fprintf (real_stderr, "%s: re-executing", blurb());
1057       for (i = 0; saved_argv[i]; i++)
1058         fprintf (real_stderr, " %s", saved_argv[i]);
1059       fprintf (real_stderr, "\n");
1060     }
1061   describe_uids (si, real_stderr);
1062   fprintf (real_stderr, "\n");
1063
1064   fflush (real_stdout);
1065   fflush (real_stderr);
1066   execvp (saved_argv [0], saved_argv);  /* shouldn't return */
1067   {
1068     char buf [512];
1069     sprintf (buf, "%s: could not restart process", blurb());
1070     perror(buf);
1071     fflush(stderr);
1072   }
1073   XBell(si->dpy, 0);
1074 }