1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991-2001 Jamie Zawinski <jwz@jwz.org>
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
21 #include <X11/Xlib.h> /* not used for much... */
27 #include <sys/time.h> /* sys/resource.h needs this for timeval */
29 #ifdef HAVE_SYS_WAIT_H
30 # include <sys/wait.h> /* for waitpid() and associated macros */
33 #if (defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)) || \
34 defined(HAVE_SETRLIMIT)
35 # include <sys/resource.h> /* for setpriority() and PRIO_PROCESS */
36 /* and also setrlimit() and RLIMIT_AS */
40 # include <processes.h>
41 # include <unixio.h> /* for close */
42 # include <unixlib.h> /* for getpid */
47 #include <signal.h> /* for the signal names */
49 #if !defined(SIGCHLD) && defined(SIGCLD)
50 # define SIGCHLD SIGCLD
53 #if 0 /* putenv() is declared in stdlib.h on modern linux systems. */
55 extern int putenv (/* const char * */); /* getenv() is in stdlib.h... */
59 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
61 /* This file doesn't need the Xt headers, so stub these types out... */
63 #define XtAppContext void*
64 #define XrmDatabase void*
65 #define XtIntervalId void*
66 #define XtPointer void*
69 #include "xscreensaver.h"
71 #include "visual.h" /* for id_to_visual() */
73 extern saver_info *global_si_kludge; /* I hate C so much... */
76 nice_subproc (int nice_level)
81 #if defined(HAVE_NICE)
83 int old_nice = nice (0);
84 int n = nice_level - old_nice;
86 if (nice (n) == -1 && errno != 0)
89 sprintf (buf, "%s: nice(%d) failed", blurb(), n);
93 #elif defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
94 if (setpriority (PRIO_PROCESS, getpid(), nice_level) != 0)
97 sprintf (buf, "%s: setpriority(PRIO_PROCESS, %lu, %d) failed",
98 blurb(), (unsigned long) getpid(), nice_level);
103 "%s: don't know how to change process priority on this system.\n",
110 /* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size
111 of a process's address space, i.e., the maximal brk(2) and mmap(2) values.
112 Setting this lets you put a cap on how much memory a process can allocate.
114 #if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
115 # define RLIMIT_AS RLIMIT_VMEM
119 limit_subproc_memory (int address_space_limit, Bool verbose_p)
121 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS)
124 if (address_space_limit < 10 * 1024) /* let's not be crazy */
127 if (getrlimit (RLIMIT_AS, &r) != 0)
130 sprintf (buf, "%s: getrlimit(RLIMIT_AS) failed", blurb());
135 r.rlim_cur = address_space_limit;
137 if (setrlimit (RLIMIT_AS, &r) != 0)
140 sprintf (buf, "%s: setrlimit(RLIMIT_AS, {%lu, %lu}) failed",
141 blurb(), r.rlim_cur, r.rlim_max);
148 int i = address_space_limit;
150 if (i >= (1<<30) && i == ((i >> 30) << 30))
151 sprintf(buf, "%dG", i >> 30);
152 else if (i >= (1<<20) && i == ((i >> 20) << 20))
153 sprintf(buf, "%dM", i >> 20);
154 else if (i >= (1<<10) && i == ((i >> 10) << 10))
155 sprintf(buf, "%dK", i >> 10);
157 sprintf(buf, "%d bytes", i);
159 fprintf (stderr, "%s: limited pid %lu address space to %s.\n",
160 blurb(), (unsigned long) getpid (), buf);
163 #endif /* HAVE_SETRLIMIT && RLIMIT_AS */
171 exec_simple_command (const char *command)
175 char *token = strtok (strdup(command), " \t");
179 token = strtok(0, " \t");
183 execvp (av[0], av); /* shouldn't return. */
187 sprintf (buf, "%s: could not execute \"%s\"", blurb(), av[0]);
190 if (errno == ENOENT &&
191 (token = getenv("PATH")))
195 # define PATH_MAX MAXPATHLEN
197 # define PATH_MAX 2048
201 fprintf (stderr, "\n");
203 # if defined(HAVE_GETCWD)
204 getcwd (path, sizeof(path));
205 # elif defined(HAVE_GETWD)
209 fprintf (stderr, " Current directory is: %s\n", path);
210 fprintf (stderr, " PATH is:\n");
211 token = strtok (strdup(token), ":");
214 fprintf (stderr, " %s\n", token);
215 token = strtok(0, ":");
217 fprintf (stderr, "\n");
222 exit (1); /* Note that this only exits a child fork. */
227 exec_complex_command (const char *shell, const char *command)
231 char *command2 = (char *) malloc (strlen (command) + 10);
234 const char *after_vars;
236 /* Skip leading whitespace.
238 while (*command == ' ' || *command == '\t')
241 /* If the string has a series of tokens with "=" in them at them, set
242 `after_vars' to point into the string after those tokens and any
243 trailing whitespace. Otherwise, after_vars == command.
245 after_vars = command;
246 for (s = command; *s; s++)
248 if (*s == '=') got_eq = 1;
253 while (*s == ' ' || *s == '\t')
264 strncat (command2, command, after_vars - command);
265 strcat (command2, "exec ");
266 strcat (command2, after_vars);
268 /* We have now done these transformations:
269 "foo -x -y" ==> "exec foo -x -y"
270 "BLAT=foop foo -x" ==> "BLAT=foop exec foo -x"
271 "BLAT=foop A=b foo -x" ==> "BLAT=foop A=b exec foo -x"
275 /* Invoke the shell as "/bin/sh -c 'exec prog -arg -arg ...'" */
276 av [ac++] = (char *) shell;
278 av [ac++] = command2;
281 execvp (av[0], av); /* shouldn't return. */
285 sprintf (buf, "%s: execvp(\"%s\") failed", blurb(), av[0]);
289 exit (1); /* Note that this only exits a child fork. */
296 exec_vms_command (const char *command)
301 exit (1); /* Note that this only exits a child fork. */
308 exec_screenhack (saver_screen_info *ssi, const char *command)
310 /* I don't believe what a sorry excuse for an operating system UNIX is!
312 - I want to spawn a process.
313 - I want to know it's pid so that I can kill it.
314 - I would like to receive a message when it dies of natural causes.
315 - I want the spawned process to have user-specified arguments.
317 If shell metacharacters are present (wildcards, backquotes, etc), the
318 only way to parse those arguments is to run a shell to do the parsing
321 And the only way to know the pid of the process is to fork() and exec()
322 it in the spawned side of the fork.
324 But if you're running a shell to parse your arguments, this gives you
325 the pid of the *shell*, not the pid of the *process* that you're
326 actually interested in, which is an *inferior* of the shell. This also
327 means that the SIGCHLD you get applies to the shell, not its inferior.
328 (Why isn't that sufficient? I don't remember any more, but it turns
331 So, the only solution, when metacharacters are present, is to force the
332 shell to exec() its inferior. What a fucking hack! We prepend "exec "
333 to the command string, and hope it doesn't contain unquoted semicolons
334 or ampersands (we don't search for them, because we don't want to
335 prohibit their use in quoted strings (messages, for example) and parsing
336 out the various quote characters is too much of a pain.)
338 (Actually, Clint Wong <clint@jts.com> points out that process groups
339 might be used to take care of this problem; this may be worth considering
340 some day, except that, 1: this code works now, so why fix it, and 2: from
341 what I've seen in Emacs, dealing with process groups isn't especially
344 saver_info *si = ssi->global;
345 saver_preferences *p = &si->prefs;
348 Bool hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"=");
349 /* note: = is in the above because of the sh syntax "FOO=bar cmd". */
351 if (getuid() == (uid_t) 0 || geteuid() == (uid_t) 0)
353 /* If you're thinking of commenting this out, think again.
354 If you do so, you will open a security hole. Mail jwz
355 so that he may enlighten you as to the error of your ways.
357 fprintf (stderr, "%s: we're still running as root! Disaster!\n",
359 saver_exit (si, 1, 0);
363 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu%s.\n",
364 blurb(), ssi->number, command,
365 (unsigned long) getpid (),
366 (hairy_p ? " (via shell)" : ""));
369 /* If it contains any shell metacharacters, do it the hard way,
370 and fork a shell to parse the arguments for us. */
371 exec_complex_command (p->shell, command);
373 /* Otherwise, we can just exec the program directly. */
374 exec_simple_command (command);
378 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
379 blurb(), ssi->number, command, getpid());
380 exec_vms_command (command);
383 abort(); /* that shouldn't have returned. */
388 /* Management of child processes, and de-zombification.
392 job_running, /* the process is still alive */
393 job_stopped, /* we have sent it a STOP signal */
394 job_killed, /* we have sent it a TERM signal */
395 job_dead /* we have wait()ed for it, and it's dead -- this state only
396 occurs so that we can avoid calling free() from a signal
397 handler. Shortly after going into this state, the list
398 element will be removed. */
401 struct screenhack_job {
405 enum job_status status;
406 struct screenhack_job *next;
409 static struct screenhack_job *jobs = 0;
411 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
415 struct screenhack_job *job;
416 fprintf(stderr, "%s: job list:\n", blurb());
417 for (job = jobs; job; job = job->next)
418 fprintf (stderr, " %5ld: %2d: (%s) %s\n",
421 (job->status == job_running ? "running" :
422 job->status == job_stopped ? "stopped" :
423 job->status == job_killed ? " killed" :
424 job->status == job_dead ? " dead" : " ???"),
426 fprintf (stderr, "\n");
430 static void clean_job_list (void);
432 static struct screenhack_job *
433 make_job (pid_t pid, int screen, const char *cmd)
435 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
437 static char name [1024];
438 const char *in = cmd;
446 while (isspace(*in)) in++; /* skip whitespace */
447 while (!isspace(*in) && *in != ':') {
448 if (*in == '=') got_eq = 1;
449 *out++ = *in++; /* snarf first token */
452 if (got_eq) /* if the first token was FOO=bar */
453 { /* then get the next token instead. */
460 while (isspace(*in)) in++; /* skip whitespace */
463 job->name = strdup(name);
465 job->screen = screen;
466 job->status = job_running;
475 free_job (struct screenhack_job *job)
479 else if (job == jobs)
483 struct screenhack_job *job2, *prev;
484 for (prev = 0, job2 = jobs;
486 prev = job2, job2 = job2->next)
489 prev->next = job->next;
498 /* Cleans out dead jobs from the jobs list -- this must only be called
499 from the main thread, not from a signal handler.
502 clean_job_list (void)
504 struct screenhack_job *job, *prev, *next;
505 for (prev = 0, job = jobs, next = (job ? job->next : 0);
507 prev = job, job = next, next = (job ? job->next : 0))
509 if (job->status == job_dead)
520 static struct screenhack_job *
523 struct screenhack_job *job;
524 for (job = jobs; job; job = job->next)
530 static void await_dying_children (saver_info *si);
532 static void describe_dead_child (saver_info *, pid_t, int wait_status);
536 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
537 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
539 static int block_sigchld_handler = 0;
545 #ifdef HAVE_SIGACTION
547 sigemptyset (&child_set);
548 sigaddset (&child_set, SIGCHLD);
549 sigprocmask (SIG_BLOCK, &child_set, 0);
550 #endif /* HAVE_SIGACTION */
552 block_sigchld_handler++;
556 unblock_sigchld (void)
558 #ifdef HAVE_SIGACTION
560 sigemptyset(&child_set);
561 sigaddset(&child_set, SIGCHLD);
562 sigprocmask(SIG_UNBLOCK, &child_set, 0);
563 #endif /* HAVE_SIGACTION */
565 block_sigchld_handler--;
569 kill_job (saver_info *si, pid_t pid, int signal)
571 saver_preferences *p = &si->prefs;
572 struct screenhack_job *job;
577 if (block_sigchld_handler)
578 /* This function should not be called from the signal handler. */
581 block_sigchld(); /* we control the horizontal... */
583 job = find_job (pid);
586 job->status == job_killed)
589 fprintf (stderr, "%s: no child %ld to signal!\n",
590 blurb(), (long) pid);
595 case SIGTERM: job->status = job_killed; break;
597 /* #### there must be a way to do this on VMS... */
598 case SIGSTOP: job->status = job_stopped; break;
599 case SIGCONT: job->status = job_running; break;
605 fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
606 blurb(), job->screen,
607 (job->status == job_killed ? "killing" :
608 job->status == job_stopped ? "suspending" : "resuming"),
609 (unsigned long) job->pid,
612 status = kill (job->pid, signal);
614 if (p->verbose_p && status < 0)
618 "%s: %d: child process %lu (%s) was already dead.\n",
619 blurb(), job->screen, job->pid, job->name);
623 sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
624 blurb(), job->screen, job->pid, job->name);
629 await_dying_children (si);
633 if (block_sigchld_handler < 0)
643 sigchld_handler (int sig)
645 saver_info *si = global_si_kludge; /* I hate C so much... */
647 if (si->prefs.debug_p)
648 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
649 (block_sigchld_handler ? " (blocked)" : ""));
651 if (block_sigchld_handler < 0)
653 else if (block_sigchld_handler == 0)
656 await_dying_children (si);
667 await_dying_children (saver_info *si)
675 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
677 if (si->prefs.debug_p)
679 if (kid < 0 && errno)
680 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
683 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
687 /* 0 means no more children to reap.
688 -1 means error -- except "interrupted system call" isn't a "real"
689 error, so if we get that, we should just try again. */
691 (kid < 0 && errno != EINTR))
694 describe_dead_child (si, kid, wait_status);
700 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
703 saver_preferences *p = &si->prefs;
704 struct screenhack_job *job = find_job (kid);
705 const char *name = job ? job->name : "<unknown>";
706 int screen_no = job ? job->screen : 0;
708 if (WIFEXITED (wait_status))
710 int exit_status = WEXITSTATUS (wait_status);
712 /* Treat exit code as a signed 8-bit quantity. */
713 if (exit_status & 0x80) exit_status |= ~0xFF;
715 /* One might assume that exiting with non-0 means something went wrong.
716 But that loser xswarm exits with the code that it was killed with, so
717 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
718 mention them) if we've just killed the subprocess. But mention them
719 if they happen on their own.
723 (p->verbose_p || job->status != job_killed)))
725 "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
726 blurb(), screen_no, (unsigned long) kid, name, exit_status);
727 else if (p->verbose_p)
728 fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
729 blurb(), screen_no, (unsigned long) kid, name);
732 job->status = job_dead;
734 else if (WIFSIGNALED (wait_status))
738 job->status != job_killed ||
739 WTERMSIG (wait_status) != SIGTERM)
740 fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
741 blurb(), screen_no, (unsigned long) kid, name,
742 signal_name (WTERMSIG(wait_status)));
745 job->status = job_dead;
747 else if (WIFSTOPPED (wait_status))
750 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
751 blurb(), (unsigned long) kid, name,
752 signal_name (WSTOPSIG (wait_status)));
755 job->status = job_stopped;
759 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
760 blurb(), (unsigned long) kid, name);
762 job->status = job_dead;
765 /* Clear out the pid so that screenhack_running_p() knows it's dead.
767 if (!job || job->status == job_dead)
768 for (i = 0; i < si->nscreens; i++)
770 saver_screen_info *ssi = &si->screens[i];
777 static void await_dying_children (saver_info *si) { return; }
786 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
788 static Bool sigchld_initialized_p = 0;
789 if (!sigchld_initialized_p)
791 struct sigaction action, old;
793 action.sa_handler = sigchld_handler;
794 sigemptyset(&action.sa_mask);
797 if (sigaction(SIGCHLD, &action, &old) < 0)
800 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
803 sigchld_initialized_p = True;
806 # else /* !HAVE_SIGACTION */
808 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
811 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
814 # endif /* !HAVE_SIGACTION */
823 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
825 saver_info *si = ssi->global;
826 saver_preferences *p = &si->prefs;
829 if (hack->visual && *hack->visual)
830 selected = select_visual(ssi, hack->visual);
832 selected = select_visual(ssi, 0);
834 if (!selected && (p->verbose_p || si->demoing_p))
837 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
838 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
840 (hack->visual && *hack->visual ? hack->visual : "???"),
848 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
850 saver_info *si = ssi->global;
851 saver_preferences *p = &si->prefs;
852 raise_window (si, first_time_p, True, False);
855 if (p->screenhacks_count)
866 if (p->screenhacks_count < 1)
868 /* No hacks at all */
871 else if (si->selection_mode == -1)
873 /* Select the next hack, wrapping. */
874 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
876 else if (si->selection_mode == -2)
878 /* Select the previous hack, wrapping. */
879 if (ssi->current_hack < 0)
880 new_hack = p->screenhacks_count - 1;
882 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
883 % p->screenhacks_count);
885 else if (si->selection_mode > 0)
887 /* Select a specific hack, by number (via the ACTIVATE command.) */
888 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
891 else if (p->mode == ONE_HACK &&
892 p->selected_hack >= 0)
894 /* Select a specific hack, by number (via "One Saver" mode.) */
895 new_hack = p->selected_hack;
898 else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
902 else /* (p->mode == RANDOM_HACKS) */
904 /* Select a random hack (but not the one we just ran.) */
905 while ((new_hack = random () % p->screenhacks_count)
906 == ssi->current_hack)
910 if (new_hack < 0) /* don't run a hack */
912 ssi->current_hack = -1;
913 if (si->selection_mode < 0)
914 si->selection_mode = 0;
918 ssi->current_hack = new_hack;
919 hack = p->screenhacks[ssi->current_hack];
921 /* If the hack is disabled, or there is no visual for this hack,
922 then try again (move forward, or backward, or re-randomize.)
923 Unless this hack was specified explicitly, in which case,
927 select_visual_of_hack (ssi, hack);
931 !select_visual_of_hack (ssi, hack)))
933 if (++retry_count > (p->screenhacks_count*4))
935 /* Uh, oops. Odds are, there are no suitable visuals,
936 and we're looping. Give up. (This is totally lame,
937 what we should do is make a list of suitable hacks at
938 the beginning, then only loop over them.)
942 "%s: no suitable visuals for these programs.\n",
950 /* Turn off "next" and "prev" modes now, but "demo" mode is only
951 turned off by explicit action.
953 if (si->selection_mode < 0)
954 si->selection_mode = 0;
956 switch ((int) (forked = fork ()))
959 sprintf (buf, "%s: couldn't fork", blurb());
961 restore_real_vroot (si);
962 saver_exit (si, 1, 0);
965 close (ConnectionNumber (si->dpy)); /* close display fd */
966 nice_subproc (p->nice_inferior); /* change process priority */
967 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
968 hack_subproc_environment (ssi); /* set $DISPLAY */
969 exec_screenhack (ssi, hack->command); /* this does not return */
975 (void) make_job (forked, ssi->number, hack->command);
983 spawn_screenhack (saver_info *si, Bool first_time_p)
985 if (monitor_powered_on_p (si))
988 for (i = 0; i < si->nscreens; i++)
990 saver_screen_info *ssi = &si->screens[i];
991 spawn_screenhack_1 (ssi, first_time_p);
994 else if (si->prefs.verbose_p)
996 "%s: X says monitor has powered down; "
997 "not launching a hack.\n", blurb());
999 store_saver_status (si); /* store current hack numbers */
1004 kill_screenhack (saver_info *si)
1007 for (i = 0; i < si->nscreens; i++)
1009 saver_screen_info *ssi = &si->screens[i];
1011 kill_job (si, ssi->pid, SIGTERM);
1018 suspend_screenhack (saver_info *si, Bool suspend_p)
1020 #ifdef SIGSTOP /* older VMS doesn't have it... */
1022 for (i = 0; i < si->nscreens; i++)
1024 saver_screen_info *ssi = &si->screens[i];
1026 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1028 #endif /* SIGSTOP */
1032 /* Called when we're exiting abnormally, to kill off the subproc. */
1034 emergency_kill_subproc (saver_info *si)
1038 signal (SIGCHLD, SIG_IGN);
1039 #endif /* SIGCHLD */
1041 for (i = 0; i < si->nscreens; i++)
1043 saver_screen_info *ssi = &si->screens[i];
1046 kill_job (si, ssi->pid, SIGTERM);
1053 screenhack_running_p (saver_info *si)
1055 Bool any_running_p = False;
1057 for (i = 0; i < si->nscreens; i++)
1059 saver_screen_info *ssi = &si->screens[i];
1060 if (ssi->pid) any_running_p = True;
1062 return any_running_p;
1066 /* Environment variables. */
1069 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
1070 is defined, the xscreensaver daemon will search that directory for hacks.
1073 hack_environment (saver_info *si)
1075 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1076 static const char *def_path = DEFAULT_PATH_PREFIX;
1077 if (def_path && *def_path)
1079 const char *opath = getenv("PATH");
1080 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1081 strcpy (npath, "PATH=");
1082 strcat (npath, def_path);
1083 strcat (npath, ":");
1084 strcat (npath, opath);
1089 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1094 hack_subproc_environment (saver_screen_info *ssi)
1096 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1097 the spawned processes inherit is correct. First, it must be on the same
1098 host and display as the value of -display passed in on our command line
1099 (which is not necessarily the same as what our $DISPLAY variable is.)
1100 Second, the screen number in the $DISPLAY passed to the subprocess should
1101 be the screen on which this particular hack is running -- not the display
1102 specification which the driver itself is using, since the driver ignores
1103 its screen number and manages all existing screens.
1105 saver_info *si = ssi->global;
1106 const char *odpy = DisplayString (si->dpy);
1107 char *ndpy = (char *) malloc(strlen(odpy) + 20);
1110 strcpy (ndpy, "DISPLAY=");
1111 s = ndpy + strlen(ndpy);
1114 while (*s && *s != ':') s++; /* skip to colon */
1115 while (*s == ':') s++; /* skip over colons */
1116 while (isdigit(*s)) s++; /* skip over dpy number */
1117 while (*s == '.') s++; /* skip over dot */
1118 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1119 sprintf(s, "%d", ssi->number); /* put on screen number */
1121 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1122 any more, right? It's not Posix, but everyone seems to have it. */
1126 #endif /* HAVE_PUTENV */
1133 get_best_gl_visual (saver_screen_info *ssi)
1135 saver_info *si = ssi->global;
1144 av[ac++] = "xscreensaver-gl-helper";
1149 perror ("error creating pipe:");
1156 switch ((int) (forked = fork ()))
1160 sprintf (buf, "%s: couldn't fork", blurb());
1162 saver_exit (si, 1, 0);
1168 close (in); /* don't need this one */
1169 close (ConnectionNumber (si->dpy)); /* close display fd */
1171 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1173 perror ("could not dup() a new stdout:");
1176 hack_subproc_environment (ssi); /* set $DISPLAY */
1178 execvp (av[0], av); /* shouldn't return. */
1180 if (errno != ENOENT || si->prefs.verbose_p)
1182 /* Ignore "no such file or directory" errors, unless verbose.
1183 Issue all other exec errors, though. */
1184 sprintf (buf, "%s: running %s", blurb(), av[0]);
1187 exit (1); /* exits fork */
1193 int wait_status = 0;
1195 FILE *f = fdopen (in, "r");
1196 unsigned long v = 0;
1199 close (out); /* don't need this one */
1202 fgets (buf, sizeof(buf)-1, f);
1205 /* Wait for the child to die. */
1206 waitpid (-1, &wait_status, 0);
1208 if (1 == sscanf (buf, "0x%x %c", &v, &c))
1213 if (si->prefs.verbose_p)
1214 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1220 Visual *v = id_to_visual (ssi->screen, result);
1221 if (si->prefs.verbose_p)
1222 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1223 blurb(), ssi->number,
1225 (v == ssi->default_visual ? " (default)" : ""));
1236 /* Restarting the xscreensaver process from scratch. */
1238 static char **saved_argv;
1241 save_argv (int argc, char **argv)
1243 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1244 saved_argv [argc] = 0;
1247 int i = strlen (argv [argc]) + 1;
1248 saved_argv [argc] = (char *) malloc (i);
1249 memcpy (saved_argv [argc], argv [argc], i);
1254 /* Re-execs the process with the arguments in saved_argv.
1255 Does not return unless there was an error.
1258 restart_process (saver_info *si)
1260 if (si->prefs.verbose_p)
1263 fprintf (real_stderr, "%s: re-executing", blurb());
1264 for (i = 0; saved_argv[i]; i++)
1265 fprintf (real_stderr, " %s", saved_argv[i]);
1266 fprintf (real_stderr, "\n");
1268 describe_uids (si, real_stderr);
1269 fprintf (real_stderr, "\n");
1271 fflush (real_stdout);
1272 fflush (real_stderr);
1273 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1276 sprintf (buf, "%s: could not restart process", blurb());