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_info *si, 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_preferences *p = &si->prefs;
347 Bool hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"=");
348 /* note: = is in the above because of the sh syntax "FOO=bar cmd". */
350 if (getuid() == (uid_t) 0 || geteuid() == (uid_t) 0)
352 /* If you're thinking of commenting this out, think again.
353 If you do so, you will open a security hole. Mail jwz
354 so that he may enlighten you as to the error of your ways.
356 fprintf (stderr, "%s: we're still running as root! Disaster!\n",
358 saver_exit (si, 1, 0);
362 fprintf (stderr, "%s: spawning \"%s\" in pid %lu%s.\n",
363 blurb(), command, (unsigned long) getpid (),
364 (hairy_p ? " (via shell)" : ""));
367 /* If it contains any shell metacharacters, do it the hard way,
368 and fork a shell to parse the arguments for us. */
369 exec_complex_command (p->shell, command);
371 /* Otherwise, we can just exec the program directly. */
372 exec_simple_command (command);
376 fprintf (stderr, "%s: spawning \"%s\" in pid %lu.\n",
377 blurb(), command, getpid());
378 exec_vms_command (command);
381 abort(); /* that shouldn't have returned. */
386 /* Management of child processes, and de-zombification.
390 job_running, /* the process is still alive */
391 job_stopped, /* we have sent it a STOP signal */
392 job_killed, /* we have sent it a TERM signal */
393 job_dead /* we have wait()ed for it, and it's dead -- this state only
394 occurs so that we can avoid calling free() from a signal
395 handler. Shortly after going into this state, the list
396 element will be removed. */
399 struct screenhack_job {
402 enum job_status status;
403 struct screenhack_job *next;
406 static struct screenhack_job *jobs = 0;
408 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
412 struct screenhack_job *job;
413 fprintf(stderr, "%s: job list:\n", blurb());
414 for (job = jobs; job; job = job->next)
415 fprintf (stderr, " %5ld: (%s) %s\n",
417 (job->status == job_running ? "running" :
418 job->status == job_stopped ? "stopped" :
419 job->status == job_killed ? " killed" :
420 job->status == job_dead ? " dead" : " ???"),
422 fprintf (stderr, "\n");
426 static void clean_job_list (void);
428 static struct screenhack_job *
429 make_job (pid_t pid, const char *cmd)
431 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
433 static char name [1024];
434 const char *in = cmd;
442 while (isspace(*in)) in++; /* skip whitespace */
443 while (!isspace(*in) && *in != ':') {
444 if (*in == '=') got_eq = 1;
445 *out++ = *in++; /* snarf first token */
448 if (got_eq) /* if the first token was FOO=bar */
449 { /* then get the next token instead. */
456 while (isspace(*in)) in++; /* skip whitespace */
459 job->name = strdup(name);
461 job->status = job_running;
470 free_job (struct screenhack_job *job)
474 else if (job == jobs)
478 struct screenhack_job *job2, *prev;
479 for (prev = 0, job2 = jobs;
481 prev = job2, job2 = job2->next)
484 prev->next = job->next;
493 /* Cleans out dead jobs from the jobs list -- this must only be called
494 from the main thread, not from a signal handler.
497 clean_job_list (void)
499 struct screenhack_job *job, *prev, *next;
500 for (prev = 0, job = jobs, next = (job ? job->next : 0);
502 prev = job, job = next, next = (job ? job->next : 0))
504 if (job->status == job_dead)
515 static struct screenhack_job *
518 struct screenhack_job *job;
519 for (job = jobs; job; job = job->next)
525 static void await_dying_children (saver_info *si);
527 static void describe_dead_child (saver_info *, pid_t, int wait_status);
531 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
532 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
534 static int block_sigchld_handler = 0;
540 #ifdef HAVE_SIGACTION
542 sigemptyset (&child_set);
543 sigaddset (&child_set, SIGCHLD);
544 sigprocmask (SIG_BLOCK, &child_set, 0);
545 #endif /* HAVE_SIGACTION */
547 block_sigchld_handler++;
551 unblock_sigchld (void)
553 #ifdef HAVE_SIGACTION
555 sigemptyset(&child_set);
556 sigaddset(&child_set, SIGCHLD);
557 sigprocmask(SIG_UNBLOCK, &child_set, 0);
558 #endif /* HAVE_SIGACTION */
560 block_sigchld_handler--;
564 kill_job (saver_info *si, pid_t pid, int signal)
566 saver_preferences *p = &si->prefs;
567 struct screenhack_job *job;
572 if (block_sigchld_handler)
573 /* This function should not be called from the signal handler. */
576 block_sigchld(); /* we control the horizontal... */
578 job = find_job (pid);
581 job->status == job_killed)
584 fprintf (stderr, "%s: no child %ld to signal!\n",
585 blurb(), (long) pid);
590 case SIGTERM: job->status = job_killed; break;
592 /* #### there must be a way to do this on VMS... */
593 case SIGSTOP: job->status = job_stopped; break;
594 case SIGCONT: job->status = job_running; break;
601 fprintf (stderr, "%s: %s pid %lu.\n", blurb(),
602 (signal == SIGTERM ? "killing" :
603 signal == SIGSTOP ? "suspending" :
604 signal == SIGCONT ? "resuming" : "signalling"),
605 (unsigned long) job->pid);
608 fprintf (stderr, "%s: %s pid %lu.\n", blurb(), "killing",
609 (unsigned long) job->pid);
610 #endif /* !SIGSTOP */
612 status = kill (job->pid, signal);
614 if (p->verbose_p && status < 0)
617 fprintf (stderr, "%s: child process %lu (%s) was already dead.\n",
618 blurb(), job->pid, job->name);
622 sprintf (buf, "%s: couldn't kill child process %lu (%s)",
623 blurb(), job->pid, job->name);
628 await_dying_children (si);
632 if (block_sigchld_handler < 0)
642 sigchld_handler (int sig)
644 saver_info *si = global_si_kludge; /* I hate C so much... */
646 if (si->prefs.debug_p)
647 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
648 (block_sigchld_handler ? " (blocked)" : ""));
650 if (block_sigchld_handler < 0)
652 else if (block_sigchld_handler == 0)
655 await_dying_children (si);
666 await_dying_children (saver_info *si)
674 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
676 if (si->prefs.debug_p)
678 if (kid < 0 && errno)
679 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
682 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
686 /* 0 means no more children to reap.
687 -1 means error -- except "interrupted system call" isn't a "real"
688 error, so if we get that, we should just try again. */
690 (kid < 0 && errno != EINTR))
693 describe_dead_child (si, kid, wait_status);
699 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
702 saver_preferences *p = &si->prefs;
703 struct screenhack_job *job = find_job (kid);
704 const char *name = job ? job->name : "<unknown>";
706 if (WIFEXITED (wait_status))
708 int exit_status = WEXITSTATUS (wait_status);
710 /* Treat exit code as a signed 8-bit quantity. */
711 if (exit_status & 0x80) exit_status |= ~0xFF;
713 /* One might assume that exiting with non-0 means something went wrong.
714 But that loser xswarm exits with the code that it was killed with, so
715 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
716 mention them) if we've just killed the subprocess. But mention them
717 if they happen on their own.
721 (p->verbose_p || job->status != job_killed)))
723 "%s: child pid %lu (%s) exited abnormally (code %d).\n",
724 blurb(), (unsigned long) kid, name, exit_status);
725 else if (p->verbose_p)
726 fprintf (stderr, "%s: child pid %lu (%s) exited normally.\n",
727 blurb(), (unsigned long) kid, name);
730 job->status = job_dead;
732 else if (WIFSIGNALED (wait_status))
736 job->status != job_killed ||
737 WTERMSIG (wait_status) != SIGTERM)
738 fprintf (stderr, "%s: child pid %lu (%s) terminated with %s.\n",
739 blurb(), (unsigned long) kid, name,
740 signal_name (WTERMSIG(wait_status)));
743 job->status = job_dead;
745 else if (WIFSTOPPED (wait_status))
748 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
749 blurb(), (unsigned long) kid, name,
750 signal_name (WSTOPSIG (wait_status)));
753 job->status = job_stopped;
757 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
758 blurb(), (unsigned long) kid, name);
760 job->status = job_dead;
763 /* Clear out the pid so that screenhack_running_p() knows it's dead.
765 if (!job || job->status == job_dead)
766 for (i = 0; i < si->nscreens; i++)
768 saver_screen_info *ssi = &si->screens[i];
775 static void await_dying_children (saver_info *si) { return; }
784 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
786 static Bool sigchld_initialized_p = 0;
787 if (!sigchld_initialized_p)
789 struct sigaction action, old;
791 action.sa_handler = sigchld_handler;
792 sigemptyset(&action.sa_mask);
795 if (sigaction(SIGCHLD, &action, &old) < 0)
798 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
801 sigchld_initialized_p = True;
804 # else /* !HAVE_SIGACTION */
806 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
809 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
812 # endif /* !HAVE_SIGACTION */
821 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
823 saver_info *si = ssi->global;
824 saver_preferences *p = &si->prefs;
827 if (hack->visual && *hack->visual)
828 selected = select_visual(ssi, hack->visual);
830 selected = select_visual(ssi, 0);
832 if (!selected && (p->verbose_p || si->demoing_p))
835 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
836 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
838 (hack->visual && *hack->visual ? hack->visual : "???"),
846 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
848 saver_info *si = ssi->global;
849 saver_preferences *p = &si->prefs;
850 raise_window (si, first_time_p, True, False);
853 if (p->screenhacks_count)
864 if (p->screenhacks_count == 1)
865 /* If there is only one hack in the list, there is no choice. */
868 else if (si->selection_mode == -1)
869 /* Select the next hack, wrapping. */
870 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
872 else if (si->selection_mode == -2)
873 /* Select the previous hack, wrapping. */
874 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
875 % p->screenhacks_count);
877 else if (si->selection_mode > 0)
878 /* Select a specific hack, by number. No negotiation. */
880 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
885 /* Select a random hack (but not the one we just ran.) */
886 while ((new_hack = random () % p->screenhacks_count)
887 == ssi->current_hack)
891 ssi->current_hack = new_hack;
892 hack = p->screenhacks[ssi->current_hack];
894 /* If the hack is disabled, or there is no visual for this hack,
895 then try again (move forward, or backward, or re-randomize.)
896 Unless this hack was specified explicitly, in which case,
900 select_visual_of_hack (ssi, hack);
904 !select_visual_of_hack (ssi, hack)))
906 if (++retry_count > (p->screenhacks_count*4))
908 /* Uh, oops. Odds are, there are no suitable visuals,
909 and we're looping. Give up. (This is totally lame,
910 what we should do is make a list of suitable hacks at
911 the beginning, then only loop over them.)
915 "%s: no suitable visuals for these programs.\n",
923 /* Turn off "next" and "prev" modes now, but "demo" mode is only
924 turned off by explicit action.
926 if (si->selection_mode < 0)
927 si->selection_mode = 0;
929 switch ((int) (forked = fork ()))
932 sprintf (buf, "%s: couldn't fork", blurb());
934 restore_real_vroot (si);
935 saver_exit (si, 1, 0);
938 close (ConnectionNumber (si->dpy)); /* close display fd */
939 nice_subproc (p->nice_inferior); /* change process priority */
940 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
941 hack_subproc_environment (ssi); /* set $DISPLAY */
942 exec_screenhack (si, hack->command); /* this does not return */
948 (void) make_job (forked, hack->command);
956 spawn_screenhack (saver_info *si, Bool first_time_p)
958 if (monitor_powered_on_p (si))
961 for (i = 0; i < si->nscreens; i++)
963 saver_screen_info *ssi = &si->screens[i];
964 spawn_screenhack_1 (ssi, first_time_p);
967 else if (si->prefs.verbose_p)
969 "%s: X says monitor has powered down; "
970 "not launching a hack.\n", blurb());
972 store_saver_status (si); /* store current hack numbers */
977 kill_screenhack (saver_info *si)
980 for (i = 0; i < si->nscreens; i++)
982 saver_screen_info *ssi = &si->screens[i];
984 kill_job (si, ssi->pid, SIGTERM);
991 suspend_screenhack (saver_info *si, Bool suspend_p)
993 #ifdef SIGSTOP /* older VMS doesn't have it... */
995 for (i = 0; i < si->nscreens; i++)
997 saver_screen_info *ssi = &si->screens[i];
999 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
1001 #endif /* SIGSTOP */
1005 /* Called when we're exiting abnormally, to kill off the subproc. */
1007 emergency_kill_subproc (saver_info *si)
1011 signal (SIGCHLD, SIG_IGN);
1012 #endif /* SIGCHLD */
1014 for (i = 0; i < si->nscreens; i++)
1016 saver_screen_info *ssi = &si->screens[i];
1019 kill_job (si, ssi->pid, SIGTERM);
1026 screenhack_running_p (saver_info *si)
1028 Bool any_running_p = False;
1030 for (i = 0; i < si->nscreens; i++)
1032 saver_screen_info *ssi = &si->screens[i];
1033 if (ssi->pid) any_running_p = True;
1035 return any_running_p;
1039 /* Environment variables. */
1042 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
1043 is defined, the xscreensaver daemon will search that directory for hacks.
1046 hack_environment (saver_info *si)
1048 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
1049 static const char *def_path = DEFAULT_PATH_PREFIX;
1050 if (def_path && *def_path)
1052 const char *opath = getenv("PATH");
1053 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
1054 strcpy (npath, "PATH=");
1055 strcat (npath, def_path);
1056 strcat (npath, ":");
1057 strcat (npath, opath);
1062 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1067 hack_subproc_environment (saver_screen_info *ssi)
1069 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
1070 the spawned processes inherit is correct. First, it must be on the same
1071 host and display as the value of -display passed in on our command line
1072 (which is not necessarily the same as what our $DISPLAY variable is.)
1073 Second, the screen number in the $DISPLAY passed to the subprocess should
1074 be the screen on which this particular hack is running -- not the display
1075 specification which the driver itself is using, since the driver ignores
1076 its screen number and manages all existing screens.
1078 saver_info *si = ssi->global;
1079 const char *odpy = DisplayString (si->dpy);
1080 char *ndpy = (char *) malloc(strlen(odpy) + 20);
1084 for (screen_number = 0; screen_number < si->nscreens; screen_number++)
1085 if (ssi == &si->screens[screen_number])
1088 strcpy (ndpy, "DISPLAY=");
1089 s = ndpy + strlen(ndpy);
1092 while (*s && *s != ':') s++; /* skip to colon */
1093 while (*s == ':') s++; /* skip over colons */
1094 while (isdigit(*s)) s++; /* skip over dpy number */
1095 while (*s == '.') s++; /* skip over dot */
1096 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1097 sprintf(s, "%d", screen_number); /* put on screen number */
1099 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1100 any more, right? It's not Posix, but everyone seems to have it. */
1104 #endif /* HAVE_PUTENV */
1111 get_best_gl_visual (saver_screen_info *ssi)
1113 saver_info *si = ssi->global;
1122 av[ac++] = "xscreensaver-gl-helper";
1127 perror ("error creating pipe:");
1134 switch ((int) (forked = fork ()))
1138 sprintf (buf, "%s: couldn't fork", blurb());
1140 saver_exit (si, 1, 0);
1146 close (in); /* don't need this one */
1147 close (ConnectionNumber (si->dpy)); /* close display fd */
1149 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1151 perror ("could not dup() a new stdout:");
1154 hack_subproc_environment (ssi); /* set $DISPLAY */
1156 execvp (av[0], av); /* shouldn't return. */
1158 if (errno != ENOENT || si->prefs.verbose_p)
1160 /* Ignore "no such file or directory" errors, unless verbose.
1161 Issue all other exec errors, though. */
1162 sprintf (buf, "%s: running %s", blurb(), av[0]);
1165 exit (1); /* exits fork */
1171 int wait_status = 0;
1173 FILE *f = fdopen (in, "r");
1174 unsigned long v = 0;
1177 close (out); /* don't need this one */
1180 fgets (buf, sizeof(buf)-1, f);
1183 /* Wait for the child to die. */
1184 waitpid (-1, &wait_status, 0);
1186 if (1 == sscanf (buf, "0x%x %c", &v, &c))
1191 if (si->prefs.verbose_p)
1192 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1198 Visual *v = id_to_visual (ssi->screen, result);
1199 if (si->prefs.verbose_p)
1200 fprintf (stderr, "%s: %s says the GL visual is 0x%X%s.\n",
1201 blurb(), av[0], result,
1202 (v == ssi->default_visual ? " (the default)" : ""));
1213 /* Restarting the xscreensaver process from scratch. */
1215 static char **saved_argv;
1218 save_argv (int argc, char **argv)
1220 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1221 saved_argv [argc] = 0;
1224 int i = strlen (argv [argc]) + 1;
1225 saved_argv [argc] = (char *) malloc (i);
1226 memcpy (saved_argv [argc], argv [argc], i);
1231 /* Re-execs the process with the arguments in saved_argv.
1232 Does not return unless there was an error.
1235 restart_process (saver_info *si)
1237 if (si->prefs.verbose_p)
1240 fprintf (real_stderr, "%s: re-executing", blurb());
1241 for (i = 0; saved_argv[i]; i++)
1242 fprintf (real_stderr, " %s", saved_argv[i]);
1243 fprintf (real_stderr, "\n");
1245 describe_uids (si, real_stderr);
1246 fprintf (real_stderr, "\n");
1248 fflush (real_stdout);
1249 fflush (real_stderr);
1250 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1253 sprintf (buf, "%s: could not restart process", blurb());