1 /* subprocs.c --- choosing, spawning, and killing screenhacks.
2 * xscreensaver, Copyright (c) 1991, 1992, 1993, 1995, 1997, 1998
3 * Jamie Zawinski <jwz@netscape.com>
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
22 #include <X11/Xlib.h> /* not used for much... */
28 #include <sys/time.h> /* sys/resource.h needs this for timeval */
32 # include <sys/resource.h> /* for setpriority() and PRIO_PROCESS */
33 # include <sys/wait.h> /* for waitpid() and associated macros */
37 # if __DECC_VER >= 50200000
38 # include <sys/wait.h>
41 # include <processes.h>
42 # include <unixio.h> /* for close */
43 # include <unixlib.h> /* for getpid */
49 #include <signal.h> /* for the signal names */
52 #include <pwd.h> /* for getpwnam() and struct passwd */
53 #include <grp.h> /* for getgrgid() and struct group */
54 #endif /* NO_SETUID */
56 #if !defined(SIGCHLD) && defined(SIGCLD)
57 #define SIGCHLD SIGCLD
61 extern int putenv (/* const char * */); /* getenv() is in stdlib.h... */
63 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
65 /* This file doesn't need the Xt headers, so stub these types out... */
67 #define XtAppContext void*
68 #define XrmDatabase void*
69 #define XtIntervalId void*
70 #define XtPointer void*
73 #include "xscreensaver.h"
77 extern saver_info *global_si_kludge; /* I hate C so much... */
79 static void hack_environment (saver_screen_info *ssi);
83 nice_subproc (int nice_level)
88 #if defined(HAVE_NICE)
90 int old_nice = nice (0);
91 int n = nice_level - old_nice;
93 if (nice (n) == -1 && errno != 0)
96 sprintf (buf, "%s: nice(%d) failed", progname, n);
100 #elif defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
101 if (setpriority (PRIO_PROCESS, getpid(), nice_level) != 0)
104 sprintf (buf, "%s: setpriority(PRIO_PROCESS, %lu, %d) failed",
105 progname, (unsigned long) getpid(), nice_level);
110 "%s: don't know how to change process priority on this system.\n",
120 exec_simple_command (const char *command)
124 char *token = strtok (strdup(command), " \t");
128 token = strtok(0, " \t");
132 execvp (av[0], av); /* shouldn't return. */
136 sprintf (buf, "%s: could not execute \"%s\"", progname, av[0]);
139 if (errno == ENOENT &&
140 (token = getenv("PATH")))
144 # define PATH_MAX MAXPATHLEN
146 # define PATH_MAX 2048
150 fprintf (stderr, "\n");
152 # if defined(HAVE_GETCWD)
153 getcwd (path, sizeof(path));
154 # elif defined(HAVE_GETWD)
158 fprintf (stderr, " Current directory is: %s\n", path);
159 fprintf (stderr, " PATH is:\n");
160 token = strtok (strdup(token), ":");
163 fprintf (stderr, " %s\n", token);
164 token = strtok(0, ":");
166 fprintf (stderr, "\n");
171 exit (1); /* Note that this only exits a child fork. */
176 exec_complex_command (const char *shell, const char *command)
180 char *command2 = (char *) malloc (strlen (command) + 6);
181 memcpy (command2, "exec ", 5);
182 memcpy (command2 + 5, command, strlen (command) + 1);
184 /* Invoke the shell as "/bin/sh -c 'exec prog -arg -arg ...'" */
185 av [ac++] = (char *) shell;
187 av [ac++] = command2;
190 execvp (av[0], av); /* shouldn't return. */
194 sprintf (buf, "%s: execvp(\"%s\") failed", progname, av[0]);
198 exit (1); /* Note that this only exits a child fork. */
205 exec_vms_command (const char *command)
210 exit (1); /* Note that this only exits a child fork. */
217 exec_screenhack (saver_info *si, const char *command)
219 /* I don't believe what a sorry excuse for an operating system UNIX is!
221 - I want to spawn a process.
222 - I want to know it's pid so that I can kill it.
223 - I would like to receive a message when it dies of natural causes.
224 - I want the spawned process to have user-specified arguments.
226 If shell metacharacters are present (wildcards, backquotes, etc), the
227 only way to parse those arguments is to run a shell to do the parsing
230 And the only way to know the pid of the process is to fork() and exec()
231 it in the spawned side of the fork.
233 But if you're running a shell to parse your arguments, this gives you
234 the pid of the *shell*, not the pid of the *process* that you're
235 actually interested in, which is an *inferior* of the shell. This also
236 means that the SIGCHLD you get applies to the shell, not its inferior.
237 (Why isn't that sufficient? I don't remember any more, but it turns
240 So, the only solution, when metacharacters are present, is to force the
241 shell to exec() its inferior. What a fucking hack! We prepend "exec "
242 to the command string, and hope it doesn't contain unquoted semicolons
243 or ampersands (we don't search for them, because we don't want to
244 prohibit their use in quoted strings (messages, for example) and parsing
245 out the various quote characters is too much of a pain.)
247 (Actually, Clint Wong <clint@jts.com> points out that process groups
248 might be used to take care of this problem; this may be worth considering
249 some day, except that, 1: this code works now, so why fix it, and 2: from
250 what I've seen in Emacs, dealing with process groups isn't especially
253 saver_preferences *p = &si->prefs;
256 Bool hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"");
259 printf ("%s: spawning \"%s\" in pid %lu%s.\n",
260 progname, command, (unsigned long) getpid (),
261 (hairy_p ? " (via shell)" : ""));
264 /* If it contains any shell metacharacters, do it the hard way,
265 and fork a shell to parse the arguments for us. */
266 exec_complex_command (p->shell, command);
268 /* Otherwise, we can just exec the program directly. */
269 exec_simple_command (command);
273 printf ("%s: spawning \"%s\" in pid %lu.\n", progname, command, getpid());
274 exec_vms_command (command);
277 abort(); /* that shouldn't have returned. */
282 /* Management of child processes, and de-zombification.
286 job_running, /* the process is still alive */
287 job_stopped, /* we have sent it a STOP signal */
288 job_killed, /* we have sent it a TERM signal */
289 job_dead /* we have wait()ed for it, and it's dead -- this state only
290 occurs so that we can avoid calling free() from a signal
291 handler. Shortly after going into this state, the list
292 element will be removed. */
295 struct screenhack_job {
298 enum job_status status;
299 struct screenhack_job *next;
302 static struct screenhack_job *jobs = 0;
308 struct screenhack_job *job;
309 fprintf(stderr, "%s: job list:\n", progname);
310 for (job = jobs; job; job = job->next)
311 fprintf (stderr, " %5ld: (%s) %s\n",
313 (job->status == job_running ? "running" :
314 job->status == job_stopped ? "stopped" :
315 job->status == job_killed ? " killed" :
316 job->status == job_dead ? " dead" : " ???"),
318 fprintf (stderr, "\n");
323 static void clean_job_list (void);
325 static struct screenhack_job *
326 make_job (pid_t pid, const char *cmd)
328 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
330 static char name [1024];
331 const char *in = cmd;
336 while (isspace(*in)) in++; /* skip whitespace */
337 while (!isspace(*in) && *in != ':')
338 *out++ = *in++; /* snarf first token */
339 while (isspace(*in)) in++; /* skip whitespace */
340 if (*in == ':') /* token was a visual name; skip it. */
344 while (isspace(*in)) in++; /* skip whitespace */
345 while (!isspace(*in)) *out++ = *in++; /* snarf first token */
349 job->name = strdup(name);
351 job->status = job_running;
360 free_job (struct screenhack_job *job)
364 else if (job == jobs)
368 struct screenhack_job *job2, *prev;
369 for (prev = 0, job2 = jobs;
371 prev = job2, job2 = job2->next)
374 prev->next = job->next;
383 /* Cleans out dead jobs from the jobs list -- this must only be called
384 from the main thread, not from a signal handler.
387 clean_job_list (void)
389 struct screenhack_job *job, *prev, *next;
390 for (prev = 0, job = jobs, next = (job ? job->next : 0);
392 prev = job, job = next, next = (job ? job->next : 0))
394 if (job->status == job_dead)
405 static struct screenhack_job *
408 struct screenhack_job *job;
409 for (job = jobs; job; job = job->next)
415 static void await_dying_children (saver_info *si);
417 static void describe_dead_child (saver_info *, pid_t, int wait_status);
421 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
422 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
424 static int block_sigchld_handler = 0;
430 #ifdef HAVE_SIGACTION
432 sigemptyset (&child_set);
433 sigaddset (&child_set, SIGCHLD);
434 sigprocmask (SIG_BLOCK, &child_set, 0);
435 #endif /* HAVE_SIGACTION */
437 block_sigchld_handler++;
441 unblock_sigchld (void)
443 #ifdef HAVE_SIGACTION
445 sigemptyset(&child_set);
446 sigaddset(&child_set, SIGCHLD);
447 sigprocmask(SIG_UNBLOCK, &child_set, 0);
448 #endif /* HAVE_SIGACTION */
450 block_sigchld_handler--;
454 kill_job (saver_info *si, pid_t pid, int signal)
456 saver_preferences *p = &si->prefs;
457 struct screenhack_job *job;
462 if (block_sigchld_handler)
463 /* This function should not be called from the signal handler. */
466 block_sigchld(); /* we control the horizontal... */
468 job = find_job (pid);
471 job->status == job_killed)
474 fprintf (stderr, "%s: no child %ld to signal!\n",
475 progname, (long) pid);
480 case SIGTERM: job->status = job_killed; break;
482 /* #### there must be a way to do this on VMS... */
483 case SIGSTOP: job->status = job_stopped; break;
484 case SIGCONT: job->status = job_running; break;
491 fprintf (stderr, "%s: %s pid %lu.\n", progname,
492 (signal == SIGTERM ? "killing" :
493 signal == SIGSTOP ? "suspending" :
494 signal == SIGCONT ? "resuming" : "signalling"),
495 (unsigned long) job->pid);
498 fprintf (stderr, "%s: %s pid %lu.\n", progname, "killing",
499 (unsigned long) job->pid);
500 #endif /* !SIGSTOP */
502 status = kill (job->pid, signal);
504 if (p->verbose_p && status < 0)
507 fprintf (stderr, "%s: child process %lu (%s) was already dead.\n",
508 progname, job->pid, job->name);
512 sprintf (buf, "%s: couldn't kill child process %lu (%s)",
513 progname, job->pid, job->name);
518 await_dying_children (si);
522 if (block_sigchld_handler < 0)
532 sigchld_handler (int sig)
534 saver_info *si = global_si_kludge; /* I hate C so much... */
537 if (si->prefs.debug_p)
538 fprintf(stderr, "%s: got SIGCHLD%s\n", progname,
539 (block_sigchld_handler ? " (blocked)" : ""));
542 if (block_sigchld_handler < 0)
544 else if (block_sigchld_handler == 0)
547 await_dying_children (si);
558 await_dying_children (saver_info *si)
566 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
568 if (si->prefs.debug_p)
569 if (kid < 0 && errno)
570 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", progname,
573 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", progname, (long) kid);
576 /* 0 means no more children to reap.
577 -1 means error -- except "interrupted system call" isn't a "real"
578 error, so if we get that, we should just try again. */
580 (kid < 0 && errno != EINTR))
583 describe_dead_child (si, kid, wait_status);
589 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
592 saver_preferences *p = &si->prefs;
593 struct screenhack_job *job = find_job (kid);
594 const char *name = job ? job->name : "<unknown>";
596 if (WIFEXITED (wait_status))
598 int exit_status = WEXITSTATUS (wait_status);
600 /* Treat exit code as a signed 8-bit quantity. */
601 if (exit_status & 0x80) exit_status |= ~0xFF;
603 /* One might assume that exiting with non-0 means something went wrong.
604 But that loser xswarm exits with the code that it was killed with, so
605 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
606 mention them) if we've just killed the subprocess. But mention them
607 if they happen on their own.
611 (p->verbose_p || job->status != job_killed)))
613 "%s: child pid %lu (%s) exited abnormally (code %d).\n",
614 progname, (unsigned long) kid, name, exit_status);
615 else if (p->verbose_p)
616 printf ("%s: child pid %lu (%s) exited normally.\n",
617 progname, (unsigned long) kid, name);
620 job->status = job_dead;
622 else if (WIFSIGNALED (wait_status))
626 job->status != job_killed ||
627 WTERMSIG (wait_status) != SIGTERM)
628 fprintf (stderr, "%s: child pid %lu (%s) terminated with %s.\n",
629 progname, (unsigned long) kid, name,
630 signal_name (WTERMSIG(wait_status)));
633 job->status = job_dead;
635 else if (WIFSTOPPED (wait_status))
638 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
639 progname, (unsigned long) kid, name,
640 signal_name (WSTOPSIG (wait_status)));
643 job->status = job_stopped;
647 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
648 progname, (unsigned long) kid, name);
650 job->status = job_dead;
653 /* Clear out the pid so that screenhack_running_p() knows it's dead.
655 if (!job || job->status == job_dead)
656 for (i = 0; i < si->nscreens; i++)
658 saver_screen_info *ssi = &si->screens[i];
665 static void await_dying_children (saver_info *si) { return; }
674 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
676 static Bool sigchld_initialized_p = 0;
677 if (!sigchld_initialized_p)
679 struct sigaction action, old;
681 action.sa_handler = sigchld_handler;
682 sigemptyset(&action.sa_mask);
685 if (sigaction(SIGCHLD, &action, &old) < 0)
688 sprintf (buf, "%s: couldn't catch SIGCHLD", progname);
691 sigchld_initialized_p = True;
694 # else /* !HAVE_SIGACTION */
696 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
699 sprintf (buf, "%s: couldn't catch SIGCHLD", progname);
702 # endif /* !HAVE_SIGACTION */
711 select_visual_of_hack (saver_screen_info *ssi, const char *hack)
713 saver_info *si = ssi->global;
714 saver_preferences *p = &si->prefs;
716 static char vis [1024];
717 const char *in = hack;
719 while (isspace(*in)) in++; /* skip whitespace */
720 while (!isspace(*in) && *in != ':')
721 *out++ = *in++; /* snarf first token */
722 while (isspace(*in)) in++; /* skip whitespace */
726 selected = select_visual(ssi, vis);
728 selected = select_visual(ssi, 0);
730 if (!selected && (p->verbose_p || si->demo_mode_p))
732 if (*in == ':') in++;
733 while (isspace(*in)) in++;
736 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
737 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
738 progname, (vis ? vis : "???"), in);
746 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
748 saver_info *si = ssi->global;
749 saver_preferences *p = &si->prefs;
750 raise_window (si, first_time_p, True, False);
753 if (p->screenhacks_count || si->demo_mode_p)
762 hack = si->demo_hack;
764 /* Ignore visual-selection failure if in demo mode. */
765 (void) select_visual_of_hack (ssi, hack);
772 if (p->screenhacks_count == 1)
774 else if (si->next_mode_p == 1)
775 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
776 else if (si->next_mode_p == 2)
777 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
778 % p->screenhacks_count);
780 while ((new_hack = random () % p->screenhacks_count)
781 == ssi->current_hack)
783 ssi->current_hack = new_hack;
784 hack = p->screenhacks[ssi->current_hack];
786 if (!select_visual_of_hack (ssi, hack))
788 if (++retry_count > (p->screenhacks_count*4))
790 /* Uh, oops. Odds are, there are no suitable visuals,
791 and we're looping. Give up. (This is totally lame,
792 what we should do is make a list of suitable hacks at
793 the beginning, then only loop over them.)
797 "%s: no suitable visuals for these programs.\n",
808 /* If there's a visual description on the front of the command, nuke it.
812 while (isspace(*in)) in++; /* skip whitespace */
814 while (!isspace(*in) && *in != ':') in++; /* snarf first token */
815 while (isspace(*in)) in++; /* skip whitespace */
819 while (isspace(*in)) in++;
824 switch ((int) (forked = fork ()))
827 sprintf (buf, "%s: couldn't fork", progname);
829 restore_real_vroot (si);
833 close (ConnectionNumber (si->dpy)); /* close display fd */
834 nice_subproc (p->nice_inferior); /* change process priority */
835 hack_environment (ssi); /* set $DISPLAY */
836 exec_screenhack (si, hack); /* this does not return */
842 (void) make_job (forked, hack);
850 spawn_screenhack (saver_info *si, Bool first_time_p)
853 for (i = 0; i < si->nscreens; i++)
855 saver_screen_info *ssi = &si->screens[i];
856 spawn_screenhack_1 (ssi, first_time_p);
862 kill_screenhack (saver_info *si)
865 for (i = 0; i < si->nscreens; i++)
867 saver_screen_info *ssi = &si->screens[i];
869 kill_job (si, ssi->pid, SIGTERM);
876 suspend_screenhack (saver_info *si, Bool suspend_p)
878 #ifdef SIGSTOP /* older VMS doesn't have it... */
880 for (i = 0; i < si->nscreens; i++)
882 saver_screen_info *ssi = &si->screens[i];
884 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
890 /* Called when we're exiting abnormally, to kill off the subproc. */
892 emergency_kill_subproc (saver_info *si)
896 signal (SIGCHLD, SIG_IGN);
899 for (i = 0; i < si->nscreens; i++)
901 saver_screen_info *ssi = &si->screens[i];
904 kill_job (si, ssi->pid, SIGTERM);
911 screenhack_running_p (saver_info *si)
915 for (i = 0; i < si->nscreens; i++)
917 saver_screen_info *ssi = &si->screens[i];
925 /* Restarting the xscreensaver process from scratch. */
927 static char **saved_argv;
930 save_argv (int argc, char **argv)
932 saved_argv = (char **) malloc ((argc + 2) * sizeof (char *));
933 saved_argv [argc] = 0;
936 int i = strlen (argv [argc]) + 1;
937 saved_argv [argc] = (char *) malloc (i);
938 memcpy (saved_argv [argc], argv [argc], i);
943 restart_process (saver_info *si)
945 fflush (real_stdout);
946 fflush (real_stderr);
947 execvp (saved_argv [0], saved_argv); /* shouldn't return */
950 sprintf (buf, "%s: could not restart process", progname);
956 /* Like restart_process(), but ensures that when it restarts,
957 it comes up in demo-mode. */
959 demo_mode_restart_process (saver_info *si)
962 for (i = 0; saved_argv [i]; i++);
963 /* add the -demo switch; save_argv() left room for this. */
964 saved_argv [i] = "-demo";
965 saved_argv [i+1] = 0;
966 restart_process (si); /* shouldn't return */
972 hack_environment (saver_screen_info *ssi)
974 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
975 the spawned processes inherit is correct. First, it must be on the same
976 host and display as the value of -display passed in on our command line
977 (which is not necessarily the same as what our $DISPLAY variable is.)
978 Second, the screen number in the $DISPLAY passed to the subprocess should
979 be the screen on which this particular hack is running -- not the display
980 specification which the driver itself is using, since the driver ignores
981 its screen number and manages all existing screens.
983 saver_info *si = ssi->global;
984 const char *odpy = DisplayString (si->dpy);
985 char *ndpy = (char *) malloc(strlen(odpy) + 20);
989 for (screen_number = 0; screen_number < si->nscreens; screen_number++)
990 if (ssi == &si->screens[screen_number])
992 if (screen_number >= si->nscreens) abort();
994 strcpy (ndpy, "DISPLAY=");
995 s = ndpy + strlen(ndpy);
998 while (*s && *s != ':') s++; /* skip to colon */
999 while (*s == ':') s++; /* skip over colons */
1000 while (isdigit(*s)) s++; /* skip over dpy number */
1001 while (*s == '.') s++; /* skip over dot */
1002 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1003 sprintf(s, "%d", screen_number); /* put on screen number */
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. */
1010 #endif /* HAVE_PUTENV */
1014 /* Change the uid/gid of the screensaver process, so that it is safe for it
1015 to run setuid root (which it needs to do on some systems to read the
1016 encrypted passwords from the passwd file.)
1018 hack_uid() is run before opening the X connection, so that XAuth works.
1019 hack_uid_warn() is called after the connection is opened and the command
1020 line arguments are parsed, so that the messages from hack_uid() get
1021 printed after we know whether we're in `verbose' mode.
1026 static int hack_uid_errno;
1027 static char hack_uid_buf [255], *hack_uid_error;
1030 hack_uid (saver_info *si)
1033 /* If we've been run as setuid or setgid to someone else (most likely root)
1034 turn off the extra permissions so that random user-specified programs
1035 don't get special privileges. (On some systems it might be necessary
1036 to install this as setuid root in order to read the passwd file to
1037 implement lock-mode...)
1045 /* If we're being run as root (as from xdm) then switch the user id
1046 to something safe. */
1050 /* Locking can't work when running as root, because we have no way of
1051 knowing what the user id of the logged in user is (so we don't know
1052 whose password to prompt for.)
1054 si->locking_disabled_p = True;
1055 si->nolock_reason = "running as root";
1056 p = getpwnam ("nobody");
1057 if (! p) p = getpwnam ("noaccess");
1058 if (! p) p = getpwnam ("daemon");
1059 if (! p) p = getpwnam ("bin");
1060 if (! p) p = getpwnam ("sys");
1063 hack_uid_error = "couldn't find safe uid; running as root.";
1064 hack_uid_errno = -1;
1068 struct group *g = getgrgid (p->pw_gid);
1069 hack_uid_error = hack_uid_buf;
1070 sprintf (hack_uid_error, "changing uid/gid to %s/%s (%ld/%ld).",
1071 p->pw_name, (g ? g->gr_name : "???"),
1072 (long) p->pw_uid, (long) p->pw_gid);
1074 /* Change the gid to be a safe one. If we can't do that, then
1075 print a warning. We change the gid before the uid so that we
1076 change the gid while still root. */
1077 if (setgid (p->pw_gid) != 0)
1079 hack_uid_errno = errno;
1080 sprintf (hack_uid_error, "couldn't set gid to %s (%ld)",
1081 (g ? g->gr_name : "???"), (long) p->pw_gid);
1084 /* Now change the uid to be a safe one. */
1085 if (setuid (p->pw_uid) != 0)
1087 hack_uid_errno = errno;
1088 sprintf (hack_uid_error, "couldn't set uid to %s (%ld)",
1089 p->pw_name, (long) p->pw_uid);
1094 else /* disable locking if already being run as "someone else" */
1096 struct passwd *p = getpwuid (getuid ());
1098 !strcmp (p->pw_name, "root") ||
1099 !strcmp (p->pw_name, "nobody") ||
1100 !strcmp (p->pw_name, "noaccess") ||
1101 !strcmp (p->pw_name, "daemon") ||
1102 !strcmp (p->pw_name, "bin") ||
1103 !strcmp (p->pw_name, "sys"))
1105 si->locking_disabled_p = True;
1106 si->nolock_reason = hack_uid_buf;
1107 sprintf (si->nolock_reason, "running as %s", p->pw_name);
1110 # endif /* !NO_LOCKING */
1114 hack_uid_warn (saver_info *si)
1116 saver_preferences *p = &si->prefs;
1118 if (! hack_uid_error)
1120 else if (hack_uid_errno == 0)
1123 printf ("%s: %s\n", progname, hack_uid_error);
1128 sprintf (buf, "%s: %s", progname, hack_uid_error);
1129 if (hack_uid_errno == -1)
1130 fprintf (stderr, "%s\n", buf);
1133 errno = hack_uid_errno;
1139 #endif /* !NO_SETUID */