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;
304 /* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
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");
322 static void clean_job_list (void);
324 static struct screenhack_job *
325 make_job (pid_t pid, const char *cmd)
327 struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
329 static char name [1024];
330 const char *in = cmd;
335 while (isspace(*in)) in++; /* skip whitespace */
336 while (!isspace(*in) && *in != ':')
337 *out++ = *in++; /* snarf first token */
338 while (isspace(*in)) in++; /* skip whitespace */
339 if (*in == ':') /* token was a visual name; skip it. */
343 while (isspace(*in)) in++; /* skip whitespace */
344 while (!isspace(*in)) *out++ = *in++; /* snarf first token */
348 job->name = strdup(name);
350 job->status = job_running;
359 free_job (struct screenhack_job *job)
363 else if (job == jobs)
367 struct screenhack_job *job2, *prev;
368 for (prev = 0, job2 = jobs;
370 prev = job2, job2 = job2->next)
373 prev->next = job->next;
382 /* Cleans out dead jobs from the jobs list -- this must only be called
383 from the main thread, not from a signal handler.
386 clean_job_list (void)
388 struct screenhack_job *job, *prev, *next;
389 for (prev = 0, job = jobs, next = (job ? job->next : 0);
391 prev = job, job = next, next = (job ? job->next : 0))
393 if (job->status == job_dead)
404 static struct screenhack_job *
407 struct screenhack_job *job;
408 for (job = jobs; job; job = job->next)
414 static void await_dying_children (saver_info *si);
416 static void describe_dead_child (saver_info *, pid_t, int wait_status);
420 /* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
421 Don't alter this directly -- use block_sigchld() / unblock_sigchld().
423 static int block_sigchld_handler = 0;
429 #ifdef HAVE_SIGACTION
431 sigemptyset (&child_set);
432 sigaddset (&child_set, SIGCHLD);
433 sigprocmask (SIG_BLOCK, &child_set, 0);
434 #endif /* HAVE_SIGACTION */
436 block_sigchld_handler++;
440 unblock_sigchld (void)
442 #ifdef HAVE_SIGACTION
444 sigemptyset(&child_set);
445 sigaddset(&child_set, SIGCHLD);
446 sigprocmask(SIG_UNBLOCK, &child_set, 0);
447 #endif /* HAVE_SIGACTION */
449 block_sigchld_handler--;
453 kill_job (saver_info *si, pid_t pid, int signal)
455 saver_preferences *p = &si->prefs;
456 struct screenhack_job *job;
461 if (block_sigchld_handler)
462 /* This function should not be called from the signal handler. */
465 block_sigchld(); /* we control the horizontal... */
467 job = find_job (pid);
470 job->status == job_killed)
473 fprintf (stderr, "%s: no child %ld to signal!\n",
474 progname, (long) pid);
479 case SIGTERM: job->status = job_killed; break;
481 /* #### there must be a way to do this on VMS... */
482 case SIGSTOP: job->status = job_stopped; break;
483 case SIGCONT: job->status = job_running; break;
490 fprintf (stderr, "%s: %s pid %lu.\n", progname,
491 (signal == SIGTERM ? "killing" :
492 signal == SIGSTOP ? "suspending" :
493 signal == SIGCONT ? "resuming" : "signalling"),
494 (unsigned long) job->pid);
497 fprintf (stderr, "%s: %s pid %lu.\n", progname, "killing",
498 (unsigned long) job->pid);
499 #endif /* !SIGSTOP */
501 status = kill (job->pid, signal);
503 if (p->verbose_p && status < 0)
506 fprintf (stderr, "%s: child process %lu (%s) was already dead.\n",
507 progname, job->pid, job->name);
511 sprintf (buf, "%s: couldn't kill child process %lu (%s)",
512 progname, job->pid, job->name);
517 await_dying_children (si);
521 if (block_sigchld_handler < 0)
531 sigchld_handler (int sig)
533 saver_info *si = global_si_kludge; /* I hate C so much... */
535 if (si->prefs.debug_p)
536 fprintf(stderr, "%s: got SIGCHLD%s\n", progname,
537 (block_sigchld_handler ? " (blocked)" : ""));
539 if (block_sigchld_handler < 0)
541 else if (block_sigchld_handler == 0)
544 await_dying_children (si);
555 await_dying_children (saver_info *si)
563 kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
565 if (si->prefs.debug_p)
567 if (kid < 0 && errno)
568 fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", progname,
571 fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", progname,
575 /* 0 means no more children to reap.
576 -1 means error -- except "interrupted system call" isn't a "real"
577 error, so if we get that, we should just try again. */
579 (kid < 0 && errno != EINTR))
582 describe_dead_child (si, kid, wait_status);
588 describe_dead_child (saver_info *si, pid_t kid, int wait_status)
591 saver_preferences *p = &si->prefs;
592 struct screenhack_job *job = find_job (kid);
593 const char *name = job ? job->name : "<unknown>";
595 if (WIFEXITED (wait_status))
597 int exit_status = WEXITSTATUS (wait_status);
599 /* Treat exit code as a signed 8-bit quantity. */
600 if (exit_status & 0x80) exit_status |= ~0xFF;
602 /* One might assume that exiting with non-0 means something went wrong.
603 But that loser xswarm exits with the code that it was killed with, so
604 it *always* exits abnormally. Treat abnormal exits as "normal" (don't
605 mention them) if we've just killed the subprocess. But mention them
606 if they happen on their own.
610 (p->verbose_p || job->status != job_killed)))
612 "%s: child pid %lu (%s) exited abnormally (code %d).\n",
613 progname, (unsigned long) kid, name, exit_status);
614 else if (p->verbose_p)
615 printf ("%s: child pid %lu (%s) exited normally.\n",
616 progname, (unsigned long) kid, name);
619 job->status = job_dead;
621 else if (WIFSIGNALED (wait_status))
625 job->status != job_killed ||
626 WTERMSIG (wait_status) != SIGTERM)
627 fprintf (stderr, "%s: child pid %lu (%s) terminated with %s.\n",
628 progname, (unsigned long) kid, name,
629 signal_name (WTERMSIG(wait_status)));
632 job->status = job_dead;
634 else if (WIFSTOPPED (wait_status))
637 fprintf (stderr, "%s: child pid %lu (%s) stopped with %s.\n",
638 progname, (unsigned long) kid, name,
639 signal_name (WSTOPSIG (wait_status)));
642 job->status = job_stopped;
646 fprintf (stderr, "%s: child pid %lu (%s) died in a mysterious way!",
647 progname, (unsigned long) kid, name);
649 job->status = job_dead;
652 /* Clear out the pid so that screenhack_running_p() knows it's dead.
654 if (!job || job->status == job_dead)
655 for (i = 0; i < si->nscreens; i++)
657 saver_screen_info *ssi = &si->screens[i];
664 static void await_dying_children (saver_info *si) { return; }
673 # ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
675 static Bool sigchld_initialized_p = 0;
676 if (!sigchld_initialized_p)
678 struct sigaction action, old;
680 action.sa_handler = sigchld_handler;
681 sigemptyset(&action.sa_mask);
684 if (sigaction(SIGCHLD, &action, &old) < 0)
687 sprintf (buf, "%s: couldn't catch SIGCHLD", progname);
690 sigchld_initialized_p = True;
693 # else /* !HAVE_SIGACTION */
695 if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
698 sprintf (buf, "%s: couldn't catch SIGCHLD", progname);
701 # endif /* !HAVE_SIGACTION */
710 select_visual_of_hack (saver_screen_info *ssi, const char *hack)
712 saver_info *si = ssi->global;
713 saver_preferences *p = &si->prefs;
715 static char vis [1024];
716 const char *in = hack;
718 while (isspace(*in)) in++; /* skip whitespace */
719 while (!isspace(*in) && *in != ':')
720 *out++ = *in++; /* snarf first token */
721 while (isspace(*in)) in++; /* skip whitespace */
725 selected = select_visual(ssi, vis);
727 selected = select_visual(ssi, 0);
729 if (!selected && (p->verbose_p || si->demo_mode_p))
731 if (*in == ':') in++;
732 while (isspace(*in)) in++;
735 ? "%s: warning, no \"%s\" visual for \"%s\".\n"
736 : "%s: no \"%s\" visual; skipping \"%s\".\n"),
737 progname, (vis ? vis : "???"), in);
745 spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
747 saver_info *si = ssi->global;
748 saver_preferences *p = &si->prefs;
749 raise_window (si, first_time_p, True, False);
752 if (p->screenhacks_count || si->demo_mode_p)
761 hack = si->demo_hack;
763 /* Ignore visual-selection failure if in demo mode. */
764 (void) select_visual_of_hack (ssi, hack);
771 if (p->screenhacks_count == 1)
773 else if (si->next_mode_p == 1)
774 new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
775 else if (si->next_mode_p == 2)
776 new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
777 % p->screenhacks_count);
779 while ((new_hack = random () % p->screenhacks_count)
780 == ssi->current_hack)
782 ssi->current_hack = new_hack;
783 hack = p->screenhacks[ssi->current_hack];
785 if (!select_visual_of_hack (ssi, hack))
787 if (++retry_count > (p->screenhacks_count*4))
789 /* Uh, oops. Odds are, there are no suitable visuals,
790 and we're looping. Give up. (This is totally lame,
791 what we should do is make a list of suitable hacks at
792 the beginning, then only loop over them.)
796 "%s: no suitable visuals for these programs.\n",
807 /* If there's a visual description on the front of the command, nuke it.
811 while (isspace(*in)) in++; /* skip whitespace */
813 while (!isspace(*in) && *in != ':') in++; /* snarf first token */
814 while (isspace(*in)) in++; /* skip whitespace */
818 while (isspace(*in)) in++;
823 switch ((int) (forked = fork ()))
826 sprintf (buf, "%s: couldn't fork", progname);
828 restore_real_vroot (si);
832 close (ConnectionNumber (si->dpy)); /* close display fd */
833 nice_subproc (p->nice_inferior); /* change process priority */
834 hack_environment (ssi); /* set $DISPLAY */
835 exec_screenhack (si, hack); /* this does not return */
841 (void) make_job (forked, hack);
849 spawn_screenhack (saver_info *si, Bool first_time_p)
852 for (i = 0; i < si->nscreens; i++)
854 saver_screen_info *ssi = &si->screens[i];
855 spawn_screenhack_1 (ssi, first_time_p);
861 kill_screenhack (saver_info *si)
864 for (i = 0; i < si->nscreens; i++)
866 saver_screen_info *ssi = &si->screens[i];
868 kill_job (si, ssi->pid, SIGTERM);
875 suspend_screenhack (saver_info *si, Bool suspend_p)
877 #ifdef SIGSTOP /* older VMS doesn't have it... */
879 for (i = 0; i < si->nscreens; i++)
881 saver_screen_info *ssi = &si->screens[i];
883 kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
889 /* Called when we're exiting abnormally, to kill off the subproc. */
891 emergency_kill_subproc (saver_info *si)
895 signal (SIGCHLD, SIG_IGN);
898 for (i = 0; i < si->nscreens; i++)
900 saver_screen_info *ssi = &si->screens[i];
903 kill_job (si, ssi->pid, SIGTERM);
910 screenhack_running_p (saver_info *si)
914 for (i = 0; i < si->nscreens; i++)
916 saver_screen_info *ssi = &si->screens[i];
924 /* Restarting the xscreensaver process from scratch. */
926 static char **saved_argv;
929 save_argv (int argc, char **argv)
931 saved_argv = (char **) malloc ((argc + 2) * sizeof (char *));
932 saved_argv [argc] = 0;
935 int i = strlen (argv [argc]) + 1;
936 saved_argv [argc] = (char *) malloc (i);
937 memcpy (saved_argv [argc], argv [argc], i);
942 restart_process (saver_info *si)
944 fflush (real_stdout);
945 fflush (real_stderr);
946 execvp (saved_argv [0], saved_argv); /* shouldn't return */
949 sprintf (buf, "%s: could not restart process", progname);
955 /* Like restart_process(), but ensures that when it restarts,
956 it comes up in demo-mode. */
958 demo_mode_restart_process (saver_info *si)
961 for (i = 0; saved_argv [i]; i++);
962 /* add the -initial-demo-mode switch; save_argv() left room for this. */
963 saved_argv [i] = "-initial-demo-mode";
964 saved_argv [i+1] = 0;
965 restart_process (si); /* shouldn't return */
971 hack_environment (saver_screen_info *ssi)
973 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
974 the spawned processes inherit is correct. First, it must be on the same
975 host and display as the value of -display passed in on our command line
976 (which is not necessarily the same as what our $DISPLAY variable is.)
977 Second, the screen number in the $DISPLAY passed to the subprocess should
978 be the screen on which this particular hack is running -- not the display
979 specification which the driver itself is using, since the driver ignores
980 its screen number and manages all existing screens.
982 saver_info *si = ssi->global;
983 const char *odpy = DisplayString (si->dpy);
984 char *ndpy = (char *) malloc(strlen(odpy) + 20);
988 for (screen_number = 0; screen_number < si->nscreens; screen_number++)
989 if (ssi == &si->screens[screen_number])
991 if (screen_number >= si->nscreens) abort();
993 strcpy (ndpy, "DISPLAY=");
994 s = ndpy + strlen(ndpy);
997 while (*s && *s != ':') s++; /* skip to colon */
998 while (*s == ':') s++; /* skip over colons */
999 while (isdigit(*s)) s++; /* skip over dpy number */
1000 while (*s == '.') s++; /* skip over dot */
1001 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
1002 sprintf(s, "%d", screen_number); /* put on screen number */
1004 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1005 any more, right? It's not Posix, but everyone seems to have it. */
1009 #endif /* HAVE_PUTENV */
1013 /* Change the uid/gid of the screensaver process, so that it is safe for it
1014 to run setuid root (which it needs to do on some systems to read the
1015 encrypted passwords from the passwd file.)
1017 hack_uid() is run before opening the X connection, so that XAuth works.
1018 hack_uid_warn() is called after the connection is opened and the command
1019 line arguments are parsed, so that the messages from hack_uid() get
1020 printed after we know whether we're in `verbose' mode.
1025 static int hack_uid_errno;
1026 static char hack_uid_buf [255], *hack_uid_error;
1029 hack_uid (saver_info *si)
1032 /* If we've been run as setuid or setgid to someone else (most likely root)
1033 turn off the extra permissions so that random user-specified programs
1034 don't get special privileges. (On some systems it might be necessary
1035 to install this as setuid root in order to read the passwd file to
1036 implement lock-mode...)
1044 /* If we're being run as root (as from xdm) then switch the user id
1045 to something safe. */
1049 /* Locking can't work when running as root, because we have no way of
1050 knowing what the user id of the logged in user is (so we don't know
1051 whose password to prompt for.)
1053 si->locking_disabled_p = True;
1054 si->nolock_reason = "running as root";
1055 p = getpwnam ("nobody");
1056 if (! p) p = getpwnam ("noaccess");
1057 if (! p) p = getpwnam ("daemon");
1058 if (! p) p = getpwnam ("bin");
1059 if (! p) p = getpwnam ("sys");
1062 hack_uid_error = "couldn't find safe uid; running as root.";
1063 hack_uid_errno = -1;
1067 struct group *g = getgrgid (p->pw_gid);
1068 hack_uid_error = hack_uid_buf;
1069 sprintf (hack_uid_error, "changing uid/gid to %s/%s (%ld/%ld).",
1070 p->pw_name, (g ? g->gr_name : "???"),
1071 (long) p->pw_uid, (long) p->pw_gid);
1073 /* Change the gid to be a safe one. If we can't do that, then
1074 print a warning. We change the gid before the uid so that we
1075 change the gid while still root. */
1076 if (setgid (p->pw_gid) != 0)
1078 hack_uid_errno = errno;
1079 sprintf (hack_uid_error, "couldn't set gid to %s (%ld)",
1080 (g ? g->gr_name : "???"), (long) p->pw_gid);
1083 /* Now change the uid to be a safe one. */
1084 if (setuid (p->pw_uid) != 0)
1086 hack_uid_errno = errno;
1087 sprintf (hack_uid_error, "couldn't set uid to %s (%ld)",
1088 p->pw_name, (long) p->pw_uid);
1093 else /* disable locking if already being run as "someone else" */
1095 struct passwd *p = getpwuid (getuid ());
1097 !strcmp (p->pw_name, "root") ||
1098 !strcmp (p->pw_name, "nobody") ||
1099 !strcmp (p->pw_name, "noaccess") ||
1100 !strcmp (p->pw_name, "daemon") ||
1101 !strcmp (p->pw_name, "bin") ||
1102 !strcmp (p->pw_name, "sys"))
1104 si->locking_disabled_p = True;
1105 si->nolock_reason = hack_uid_buf;
1106 sprintf (si->nolock_reason, "running as %s", p->pw_name);
1109 # endif /* !NO_LOCKING */
1113 hack_uid_warn (saver_info *si)
1115 saver_preferences *p = &si->prefs;
1117 if (! hack_uid_error)
1119 else if (hack_uid_errno == 0)
1122 printf ("%s: %s\n", progname, hack_uid_error);
1127 sprintf (buf, "%s: %s", progname, hack_uid_error);
1128 if (hack_uid_errno == -1)
1129 fprintf (stderr, "%s\n", buf);
1132 errno = hack_uid_errno;
1138 #endif /* !NO_SETUID */