1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991-2005 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 */
34 # include <sys/resource.h> /* for setrlimit() and RLIMIT_AS */
38 # include <processes.h>
39 # include <unixio.h> /* for close */
40 # include <unixlib.h> /* for getpid */
45 #include <signal.h> /* for the signal names */
47 #if !defined(SIGCHLD) && defined(SIGCLD)
48 # define SIGCHLD SIGCLD
51 #if 0 /* putenv() is declared in stdlib.h on modern linux systems. */
53 extern int putenv (/* const char * */); /* getenv() is in stdlib.h... */
57 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
59 /* This file doesn't need the Xt headers, so stub these types out... */
61 #define XtAppContext void*
62 #define XrmDatabase void*
63 #define XtIntervalId void*
64 #define XtPointer void*
67 #include "xscreensaver.h"
69 #include "visual.h" /* for id_to_visual() */
71 extern saver_info *global_si_kludge; /* I hate C so much... */
74 /* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size
75 of a process's address space, i.e., the maximal brk(2) and mmap(2) values.
76 Setting this lets you put a cap on how much memory a process can allocate.
78 Except the "and mmap()" part kinda makes this useless, since many GL
79 implementations end up using mmap() to pull the whole frame buffer into
80 memory (or something along those lines) making it appear processes are
81 using hundreds of megabytes when in fact they're using very little, and
82 we end up capping their mallocs prematurely. YAY!
84 #if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
85 # define RLIMIT_AS RLIMIT_VMEM
89 limit_subproc_memory (int address_space_limit, Bool verbose_p)
92 /* This has caused way more problems than it has solved...
93 Let's just completely ignore the "memoryLimit" option now.
97 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS)
100 if (address_space_limit < 10 * 1024) /* let's not be crazy */
103 if (getrlimit (RLIMIT_AS, &r) != 0)
106 sprintf (buf, "%s: getrlimit(RLIMIT_AS) failed", blurb());
111 r.rlim_cur = address_space_limit;
113 if (setrlimit (RLIMIT_AS, &r) != 0)
116 sprintf (buf, "%s: setrlimit(RLIMIT_AS, {%lu, %lu}) failed",
117 blurb(), r.rlim_cur, r.rlim_max);
124 int i = address_space_limit;
126 if (i >= (1<<30) && i == ((i >> 30) << 30))
127 sprintf(buf, "%dG", i >> 30);
128 else if (i >= (1<<20) && i == ((i >> 20) << 20))
129 sprintf(buf, "%dM", i >> 20);
130 else if (i >= (1<<10) && i == ((i >> 10) << 10))
131 sprintf(buf, "%dK", i >> 10);
133 sprintf(buf, "%d bytes", i);
135 fprintf (stderr, "%s: limited pid %lu address space to %s.\n",
136 blurb(), (unsigned long) getpid (), buf);
139 #endif /* HAVE_SETRLIMIT && RLIMIT_AS */
143 /* Management of child processes, and de-zombification.
147 job_running, /* the process is still alive */
148 job_stopped, /* we have sent it a STOP signal */
149 job_killed, /* we have sent it a TERM signal */
150 job_dead /* we have wait()ed for it, and it's dead -- this state only
151 occurs so that we can avoid calling free() from a signal
152 handler. Shortly after going into this state, the list
153 element will be removed. */
156 struct screenhack_job {
160 enum job_status status;
161 struct screenhack_job *next;
164 static struct screenhack_job *jobs = 0;
166 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
170 struct screenhack_job *job;
171 fprintf(stderr, "%s: job list:\n", blurb());
172 for (job = jobs; job; job = job->next)
173 fprintf (stderr, " %5ld: %2d: (%s) %s\n",
176 (job->status == job_running ? "running" :
177 job->status == job_stopped ? "stopped" :
178 job->status == job_killed ? " killed" :
179 job->status == job_dead ? " dead" : " ???"),
181 fprintf (stderr, "\n");
185 static void clean_job_list (void);
187 static struct screenhack_job *
188 make_job (pid_t pid, int screen, const char *cmd)
190 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
192 static char name [1024];
193 const char *in = cmd;
201 while (isspace(*in)) in++; /* skip whitespace */
202 while (!isspace(*in) && *in != ':') {
203 if (*in == '=') got_eq = 1;
204 *out++ = *in++; /* snarf first token */
207 if (got_eq) /* if the first token was FOO=bar */
208 { /* then get the next token instead. */
215 while (isspace(*in)) in++; /* skip whitespace */
218 job->name = strdup(name);
220 job->screen = screen;
221 job->status = job_running;
230 free_job (struct screenhack_job *job)
234 else if (job == jobs)
238 struct screenhack_job *job2, *prev;
239 for (prev = 0, job2 = jobs;
241 prev = job2, job2 = job2->next)
244 prev->next = job->next;
253 /* Cleans out dead jobs from the jobs list -- this must only be called
254 from the main thread, not from a signal handler.
257 clean_job_list (void)
259 struct screenhack_job *job, *prev, *next;
260 for (prev = 0, job = jobs, next = (job ? job->next : 0);
262 prev = job, job = next, next = (job ? job->next : 0))
264 if (job->status == job_dead)
275 static struct screenhack_job *
278 struct screenhack_job *job;
279 for (job = jobs; job; job = job->next)
285 static void await_dying_children (saver_info *si);
287 static void describe_dead_child (saver_info *, pid_t, int wait_status);
291 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
292 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
294 static int block_sigchld_handler = 0;
297 #ifdef HAVE_SIGACTION
299 #else /* !HAVE_SIGACTION */
301 #endif /* !HAVE_SIGACTION */
304 #ifdef HAVE_SIGACTION
306 sigemptyset (&child_set);
307 sigaddset (&child_set, SIGCHLD);
308 sigaddset (&child_set, SIGPIPE);
309 sigprocmask (SIG_BLOCK, &child_set, 0);
310 #endif /* HAVE_SIGACTION */
312 block_sigchld_handler++;
314 #ifdef HAVE_SIGACTION
316 #else /* !HAVE_SIGACTION */
318 #endif /* !HAVE_SIGACTION */
322 unblock_sigchld (void)
324 #ifdef HAVE_SIGACTION
326 sigemptyset(&child_set);
327 sigaddset(&child_set, SIGCHLD);
328 sigaddset(&child_set, SIGPIPE);
329 sigprocmask(SIG_UNBLOCK, &child_set, 0);
330 #endif /* HAVE_SIGACTION */
332 block_sigchld_handler--;
336 kill_job (saver_info *si, pid_t pid, int signal)
338 saver_preferences *p = &si->prefs;
339 struct screenhack_job *job;
344 if (block_sigchld_handler)
345 /* This function should not be called from the signal handler. */
348 block_sigchld(); /* we control the horizontal... */
350 job = find_job (pid);
353 job->status == job_killed)
356 fprintf (stderr, "%s: no child %ld to signal!\n",
357 blurb(), (long) pid);
362 case SIGTERM: job->status = job_killed; break;
364 /* #### there must be a way to do this on VMS... */
365 case SIGSTOP: job->status = job_stopped; break;
366 case SIGCONT: job->status = job_running; break;
372 fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
373 blurb(), job->screen,
374 (job->status == job_killed ? "killing" :
375 job->status == job_stopped ? "suspending" : "resuming"),
376 (unsigned long) job->pid,
379 status = kill (job->pid, signal);
381 if (p->verbose_p && status < 0)
385 "%s: %d: child process %lu (%s) was already dead.\n",
386 blurb(), job->screen, (unsigned long) job->pid, job->name);
390 sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
391 blurb(), job->screen, (unsigned long) job->pid, job->name);
396 await_dying_children (si);
400 if (block_sigchld_handler < 0)
410 sigchld_handler (int sig)
412 saver_info *si = global_si_kludge; /* I hate C so much... */
414 if (si->prefs.debug_p)
415 fprintf(stderr, "%s: got SIGCHLD%s\n", blurb(),
416 (block_sigchld_handler ? " (blocked)" : ""));
418 if (block_sigchld_handler < 0)
420 else if (block_sigchld_handler == 0)
423 await_dying_children (si);
434 await_dying_children (saver_info *si)
442 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
444 if (si->prefs.debug_p)
446 if (kid < 0 && errno)
447 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", blurb(),
450 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", blurb(),
454 /* 0 means no more children to reap.
455 -1 means error -- except "interrupted system call" isn't a "real"
456 error, so if we get that, we should just try again. */
458 (kid < 0 && errno != EINTR))
461 describe_dead_child (si, kid, wait_status);
467 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
470 saver_preferences *p = &si->prefs;
471 struct screenhack_job *job = find_job (kid);
472 const char *name = job ? job->name : "<unknown>";
473 int screen_no = job ? job->screen : 0;
475 if (WIFEXITED (wait_status))
477 int exit_status = WEXITSTATUS (wait_status);
479 /* Treat exit code as a signed 8-bit quantity. */
480 if (exit_status & 0x80) exit_status |= ~0xFF;
482 /* One might assume that exiting with non-0 means something went wrong.
483 But that loser xswarm exits with the code that it was killed with, so
484 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
485 mention them) if we've just killed the subprocess. But mention them
486 if they happen on their own.
490 (p->verbose_p || job->status != job_killed)))
492 "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
493 blurb(), screen_no, (unsigned long) kid, name, exit_status);
494 else if (p->verbose_p)
495 fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
496 blurb(), screen_no, (unsigned long) kid, name);
499 job->status = job_dead;
501 else if (WIFSIGNALED (wait_status))
505 job->status != job_killed ||
506 WTERMSIG (wait_status) != SIGTERM)
507 fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
508 blurb(), screen_no, (unsigned long) kid, name,
509 signal_name (WTERMSIG(wait_status)));
512 job->status = job_dead;
514 else if (WIFSTOPPED (wait_status))
517 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
518 blurb(), (unsigned long) kid, name,
519 signal_name (WSTOPSIG (wait_status)));
522 job->status = job_stopped;
526 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
527 blurb(), (unsigned long) kid, name);
529 job->status = job_dead;
532 /* Clear out the pid so that screenhack_running_p() knows it's dead.
534 if (!job || job->status == job_dead)
535 for (i = 0; i < si->nscreens; i++)
537 saver_screen_info *ssi = &si->screens[i];
544 static void await_dying_children (saver_info *si) { return; }
553 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
555 static Bool sigchld_initialized_p = 0;
556 if (!sigchld_initialized_p)
558 struct sigaction action, old;
560 action.sa_handler = sigchld_handler;
561 sigemptyset(&action.sa_mask);
564 if (sigaction(SIGCHLD, &action, &old) < 0)
567 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
570 sigchld_initialized_p = True;
573 # else /* !HAVE_SIGACTION */
575 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
578 sprintf (buf, "%s: couldn't catch SIGCHLD", blurb());
581 # endif /* !HAVE_SIGACTION */
590 select_visual_of_hack (saver_screen_info *ssi, screenhack *hack)
592 saver_info *si = ssi->global;
593 saver_preferences *p = &si->prefs;
596 if (hack->visual && *hack->visual)
597 selected = select_visual(ssi, hack->visual);
599 selected = select_visual(ssi, 0);
601 if (!selected && (p->verbose_p || si->demoing_p))
604 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
605 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
607 (hack->visual && *hack->visual ? hack->visual : "???"),
615 print_path_error (const char *program)
618 char *cmd = strdup (program);
619 char *token = strchr (cmd, ' ');
621 if (token) *token = 0;
622 sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
626 if (errno == ENOENT &&
627 (token = getenv("PATH")))
631 # define PATH_MAX MAXPATHLEN
633 # define PATH_MAX 2048
637 fprintf (stderr, "\n");
639 # if defined(HAVE_GETCWD)
640 getcwd (path, sizeof(path));
641 # elif defined(HAVE_GETWD)
645 fprintf (stderr, " Current directory is: %s\n", path);
646 fprintf (stderr, " PATH is:\n");
647 token = strtok (strdup(token), ":");
650 fprintf (stderr, " %s\n", token);
651 token = strtok(0, ":");
653 fprintf (stderr, "\n");
658 /* Executes the command in another process.
659 Command may be any single command acceptable to /bin/sh.
660 It may include wildcards, but no semicolons.
661 If successful, the pid of the other process is returned.
662 Otherwise, -1 is returned and an error may have been
666 fork_and_exec (saver_screen_info *ssi, const char *command)
668 saver_info *si = ssi->global;
669 saver_preferences *p = &si->prefs;
672 switch ((int) (forked = fork ()))
677 sprintf (buf, "%s: couldn't fork", blurb());
683 close (ConnectionNumber (si->dpy)); /* close display fd */
684 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
685 hack_subproc_environment (ssi); /* set $DISPLAY */
688 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
689 blurb(), ssi->number, command,
690 (unsigned long) getpid ());
692 exec_command (p->shell, command, p->nice_inferior);
694 /* If that returned, we were unable to exec the subprocess.
695 Print an error message, if desired.
697 if (! p->ignore_uninstalled_p)
698 print_path_error (command);
700 exit (1); /* exits child fork */
703 default: /* parent */
704 (void) make_job (forked, ssi->number, command);
713 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
715 saver_info *si = ssi->global;
716 saver_preferences *p = &si->prefs;
717 raise_window (si, first_time_p, True, False);
720 if (p->screenhacks_count)
731 if (p->screenhacks_count < 1)
733 /* No hacks at all */
736 else if (p->screenhacks_count == 1)
738 /* Exactly one hack in the list */
741 else if (si->selection_mode == -1)
743 /* Select the next hack, wrapping. */
744 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
746 else if (si->selection_mode == -2)
748 /* Select the previous hack, wrapping. */
749 if (ssi->current_hack < 0)
750 new_hack = p->screenhacks_count - 1;
752 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
753 % p->screenhacks_count);
755 else if (si->selection_mode > 0)
757 /* Select a specific hack, by number (via the ACTIVATE command.) */
758 new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
761 else if (p->mode == ONE_HACK &&
762 p->selected_hack >= 0)
764 /* Select a specific hack, by number (via "One Saver" mode.) */
765 new_hack = p->selected_hack;
768 else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
772 else if (p->mode == RANDOM_HACKS_SAME &&
775 /* Use the same hack that's running on screen 0.
776 (Assumes this function was called on screen 0 first.)
778 new_hack = si->screens[0].current_hack;
780 else /* (p->mode == RANDOM_HACKS) */
782 /* Select a random hack (but not the one we just ran.) */
783 while ((new_hack = random () % p->screenhacks_count)
784 == ssi->current_hack)
788 if (new_hack < 0) /* don't run a hack */
790 ssi->current_hack = -1;
791 if (si->selection_mode < 0)
792 si->selection_mode = 0;
796 ssi->current_hack = new_hack;
797 hack = p->screenhacks[ssi->current_hack];
799 /* If the hack is disabled, or there is no visual for this hack,
800 then try again (move forward, or backward, or re-randomize.)
801 Unless this hack was specified explicitly, in which case,
805 select_visual_of_hack (ssi, hack);
809 !select_visual_of_hack (ssi, hack)))
811 if (++retry_count > (p->screenhacks_count*4))
813 /* Uh, oops. Odds are, there are no suitable visuals,
814 and we're looping. Give up. (This is totally lame,
815 what we should do is make a list of suitable hacks at
816 the beginning, then only loop over them.)
820 "%s: %d: no programs enabled, or no suitable visuals.\n",
821 blurb(), ssi->number);
828 /* Turn off "next" and "prev" modes now, but "demo" mode is only
829 turned off by explicit action.
831 if (si->selection_mode < 0)
832 si->selection_mode = 0;
834 forked = fork_and_exec (ssi, hack->command);
835 switch ((int) forked)
837 case -1: /* fork failed */
838 case 0: /* child fork (can't happen) */
839 sprintf (buf, "%s: couldn't fork", blurb());
841 restore_real_vroot (si);
842 saver_exit (si, 1, "couldn't fork");
854 spawn_screenhack (saver_info *si, Bool first_time_p)
856 if (monitor_powered_on_p (si))
859 for (i = 0; i < si->nscreens; i++)
861 saver_screen_info *ssi = &si->screens[i];
862 spawn_screenhack_1 (ssi, first_time_p);
865 else if (si->prefs.verbose_p)
867 "%s: X says monitor has powered down; "
868 "not launching a hack.\n", blurb());
870 store_saver_status (si); /* store current hack numbers */
875 kill_screenhack (saver_info *si)
878 for (i = 0; i < si->nscreens; i++)
880 saver_screen_info *ssi = &si->screens[i];
882 kill_job (si, ssi->pid, SIGTERM);
889 suspend_screenhack (saver_info *si, Bool suspend_p)
891 #ifdef SIGSTOP /* older VMS doesn't have it... */
893 for (i = 0; i < si->nscreens; i++)
895 saver_screen_info *ssi = &si->screens[i];
897 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
903 /* Called when we're exiting abnormally, to kill off the subproc. */
905 emergency_kill_subproc (saver_info *si)
909 signal (SIGCHLD, SIG_IGN);
912 for (i = 0; i < si->nscreens; i++)
914 saver_screen_info *ssi = &si->screens[i];
917 kill_job (si, ssi->pid, SIGTERM);
924 screenhack_running_p (saver_info *si)
926 Bool any_running_p = False;
928 for (i = 0; i < si->nscreens; i++)
930 saver_screen_info *ssi = &si->screens[i];
931 if (ssi->pid) any_running_p = True;
933 return any_running_p;
937 /* Environment variables. */
940 /* Modifies $PATH in the current environment, so that if DEFAULT_PATH_PREFIX
941 is defined, the xscreensaver daemon will search that directory for hacks.
944 hack_environment (saver_info *si)
946 #if defined(HAVE_PUTENV) && defined(DEFAULT_PATH_PREFIX)
947 static const char *def_path = DEFAULT_PATH_PREFIX;
948 if (def_path && *def_path)
950 const char *opath = getenv("PATH");
951 char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
952 strcpy (npath, "PATH=");
953 strcat (npath, def_path);
955 strcat (npath, opath);
960 /* don't free (npath) -- some implementations of putenv (BSD 4.4,
961 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
962 do not. So we must leak it (and/or the previous setting). Yay.
965 #endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
970 hack_subproc_environment (saver_screen_info *ssi)
972 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
973 the spawned processes inherit is correct. First, it must be on the same
974 host and display as the value of -display passed in on our command line
975 (which is not necessarily the same as what our $DISPLAY variable is.)
976 Second, the screen number in the $DISPLAY passed to the subprocess should
977 be the screen on which this particular hack is running -- not the display
978 specification which the driver itself is using, since the driver ignores
979 its screen number and manages all existing screens.
981 Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
982 us to (eventually) run multiple hacks in Xinerama mode, where each hack
983 has the same $DISPLAY but a different piece of glass.
985 saver_info *si = ssi->global;
986 const char *odpy = DisplayString (si->dpy);
987 char *ndpy = (char *) malloc (strlen(odpy) + 20);
988 char *nssw = (char *) malloc (40);
991 strcpy (ndpy, "DISPLAY=");
992 s = ndpy + strlen(ndpy);
995 while (*s && *s != ':') s++; /* skip to colon */
996 while (*s == ':') s++; /* skip over colons */
997 while (isdigit(*s)) s++; /* skip over dpy number */
998 while (*s == '.') s++; /* skip over dot */
999 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1000 sprintf(s, "%d", ssi->real_screen_number); /* put on screen number */
1002 sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
1003 (unsigned long) ssi->screensaver_window);
1005 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1006 any more, right? It's not Posix, but everyone seems to have it. */
1013 /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
1014 glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
1015 do not. So we must leak it (and/or the previous setting). Yay.
1017 #endif /* HAVE_PUTENV */
1024 get_best_gl_visual (saver_screen_info *ssi)
1026 saver_info *si = ssi->global;
1035 av[ac++] = "xscreensaver-gl-helper";
1040 perror ("error creating pipe:");
1047 switch ((int) (forked = fork ()))
1051 sprintf (buf, "%s: couldn't fork", blurb());
1053 saver_exit (si, 1, 0);
1059 close (in); /* don't need this one */
1060 close (ConnectionNumber (si->dpy)); /* close display fd */
1062 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1064 perror ("could not dup() a new stdout:");
1067 hack_subproc_environment (ssi); /* set $DISPLAY */
1069 execvp (av[0], av); /* shouldn't return. */
1071 if (errno != ENOENT || si->prefs.verbose_p)
1073 /* Ignore "no such file or directory" errors, unless verbose.
1074 Issue all other exec errors, though. */
1075 sprintf (buf, "%s: running %s", blurb(), av[0]);
1078 exit (1); /* exits fork */
1084 int wait_status = 0;
1086 FILE *f = fdopen (in, "r");
1087 unsigned long v = 0;
1090 close (out); /* don't need this one */
1093 fgets (buf, sizeof(buf)-1, f);
1096 /* Wait for the child to die. */
1097 waitpid (-1, &wait_status, 0);
1099 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1104 if (si->prefs.verbose_p)
1106 int L = strlen(buf);
1107 fprintf (stderr, "%s: %s did not report a GL visual!\n",
1110 if (L && buf[L-1] == '\n')
1113 fprintf (stderr, "%s: %s said: \"%s\"\n",
1114 blurb(), av[0], buf);
1120 Visual *v = id_to_visual (ssi->screen, result);
1121 if (si->prefs.verbose_p)
1122 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
1123 blurb(), ssi->number,
1125 (v == ssi->default_visual ? " (default)" : ""));
1136 /* Restarting the xscreensaver process from scratch. */
1138 static char **saved_argv;
1141 save_argv (int argc, char **argv)
1143 saved_argv = (char **) calloc (argc+2, sizeof (char *));
1144 saved_argv [argc] = 0;
1147 int i = strlen (argv [argc]) + 1;
1148 saved_argv [argc] = (char *) malloc (i);
1149 memcpy (saved_argv [argc], argv [argc], i);
1154 /* Re-execs the process with the arguments in saved_argv. Does not return.
1157 restart_process (saver_info *si)
1161 shutdown_stderr (si);
1162 if (si->prefs.verbose_p)
1165 fprintf (stderr, "%s: re-executing", blurb());
1166 for (i = 0; saved_argv[i]; i++)
1167 fprintf (stderr, " %s", saved_argv[i]);
1168 fprintf (stderr, "\n");
1170 describe_uids (si, stderr);
1171 fprintf (stderr, "\n");
1175 execvp (saved_argv [0], saved_argv); /* shouldn't return */
1178 sprintf (buf, "%s: could not restart process", blurb());