http://ftp.x.org/contrib/applications/xscreensaver-2.17.tar.gz
[xscreensaver] / driver / subprocs.c
index 50dd82b8a521459493a18f7506347a8be6aa9927..4126960b0bc177a0c8a48a349c6c499e569de782 100644 (file)
@@ -1,5 +1,5 @@
 /* subprocs.c --- choosing, spawning, and killing screenhacks.
- * xscreensaver, Copyright (c) 1991, 1992, 1993, 1995, 1997
+ * xscreensaver, Copyright (c) 1991, 1992, 1993, 1995, 1997, 1998
  *  Jamie Zawinski <jwz@netscape.com>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
@@ -301,8 +301,8 @@ struct screenhack_job {
 
 static struct screenhack_job *jobs = 0;
 
-#ifdef DEBUG
-static void
+/* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
+void
 show_job_list (void)
 {
   struct screenhack_job *job;
@@ -317,7 +317,6 @@ show_job_list (void)
             job->name);
   fprintf (stderr, "\n");
 }
-#endif
 
 
 static void clean_job_list (void);
@@ -418,9 +417,38 @@ static void describe_dead_child (saver_info *, pid_t, int wait_status);
 #endif
 
 
-/* Semaphore to temporarily turn the SIGCHLD handler into a no-op. */
+/* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
+   Don't alter this directly -- use block_sigchld() / unblock_sigchld().
+ */
 static int block_sigchld_handler = 0;
 
+
+static void
+block_sigchld (void)
+{
+#ifdef HAVE_SIGACTION
+  sigset_t child_set;
+  sigemptyset (&child_set);
+  sigaddset (&child_set, SIGCHLD);
+  sigprocmask (SIG_BLOCK, &child_set, 0);
+#endif /* HAVE_SIGACTION */
+
+  block_sigchld_handler++;
+}
+
+static void
+unblock_sigchld (void)
+{
+#ifdef HAVE_SIGACTION
+  sigset_t child_set;
+  sigemptyset(&child_set);
+  sigaddset(&child_set, SIGCHLD);
+  sigprocmask(SIG_UNBLOCK, &child_set, 0);
+#endif /* HAVE_SIGACTION */
+
+  block_sigchld_handler--;
+}
+
 static int
 kill_job (saver_info *si, pid_t pid, int signal)
 {
@@ -434,7 +462,7 @@ kill_job (saver_info *si, pid_t pid, int signal)
     /* This function should not be called from the signal handler. */
     abort();
 
-  block_sigchld_handler++;             /* we control the horizontal... */
+  block_sigchld();                     /* we control the horizontal... */
 
   job = find_job (pid);
   if (!job ||
@@ -489,7 +517,7 @@ kill_job (saver_info *si, pid_t pid, int signal)
   await_dying_children (si);
 
  DONE:
-  block_sigchld_handler--;
+  unblock_sigchld();
   if (block_sigchld_handler < 0)
     abort();
 
@@ -504,24 +532,22 @@ sigchld_handler (int sig)
 {
   saver_info *si = global_si_kludge;   /* I hate C so much... */
 
-#ifdef DEBUG
   if (si->prefs.debug_p)
     fprintf(stderr, "%s: got SIGCHLD%s\n", progname,
            (block_sigchld_handler ? " (blocked)" : ""));
-#endif
 
   if (block_sigchld_handler < 0)
     abort();
   else if (block_sigchld_handler == 0)
     {
-      block_sigchld_handler++;
+      block_sigchld();
       await_dying_children (si);
-      block_sigchld_handler--;
+      unblock_sigchld();
     }
 
   init_sigchld();
 }
-#endif
+#endif /* SIGCHLD */
 
 
 #ifndef VMS
@@ -535,14 +561,16 @@ await_dying_children (saver_info *si)
 
       errno = 0;
       kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);
-#ifdef DEBUG
+
       if (si->prefs.debug_p)
-       if (kid < 0 && errno)
-         fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", progname,
-                  (long) kid, errno);
-      else
-         fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", progname, (long) kid);
-#endif
+       {
+         if (kid < 0 && errno)
+           fprintf (stderr, "%s: waitpid(-1) ==> %ld (%d)\n", progname,
+                    (long) kid, errno);
+         else
+           fprintf (stderr, "%s: waitpid(-1) ==> %ld\n", progname,
+                    (long) kid);
+       }
 
       /* 0 means no more children to reap.
         -1 means error -- except "interrupted system call" isn't a "real"
@@ -641,13 +669,37 @@ void
 init_sigchld (void)
 {
 #ifdef SIGCHLD
+
+# ifdef HAVE_SIGACTION /* Thanks to Tom Kelly <tom@ancilla.toronto.on.ca> */
+
+  static Bool sigchld_initialized_p = 0;
+  if (!sigchld_initialized_p)
+    {
+      struct sigaction action, old;
+
+      action.sa_handler = sigchld_handler;
+      sigemptyset(&action.sa_mask);
+      action.sa_flags = 0;
+
+      if (sigaction(SIGCHLD, &action, &old) < 0)
+       {
+         char buf [255];
+         sprintf (buf, "%s: couldn't catch SIGCHLD", progname);
+         perror (buf);
+       }
+      sigchld_initialized_p = True;
+    }
+
+# else  /* !HAVE_SIGACTION */
+
   if (((long) signal (SIGCHLD, sigchld_handler)) == -1L)
     {
       char buf [255];
       sprintf (buf, "%s: couldn't catch SIGCHLD", progname);
       perror (buf);
     }
-#endif
+# endif /* !HAVE_SIGACTION */
+#endif /* SIGCHLD */
 }
 
 
@@ -841,7 +893,7 @@ emergency_kill_subproc (saver_info *si)
   int i;
 #ifdef SIGCHLD
   signal (SIGCHLD, SIG_IGN);
-#endif
+#endif /* SIGCHLD */
 
   for (i = 0; i < si->nscreens; i++)
     {
@@ -1001,6 +1053,7 @@ hack_uid (saver_info *si)
       si->locking_disabled_p = True;
       si->nolock_reason = "running as root";
       p = getpwnam ("nobody");
+      if (! p) p = getpwnam ("noaccess");
       if (! p) p = getpwnam ("daemon");
       if (! p) p = getpwnam ("bin");
       if (! p) p = getpwnam ("sys");
@@ -1036,13 +1089,14 @@ hack_uid (saver_info *si)
            }
        }
     }
-#ifndef NO_LOCKING
+# ifndef NO_LOCKING
  else  /* disable locking if already being run as "someone else" */
    {
      struct passwd *p = getpwuid (getuid ());
      if (!p ||
         !strcmp (p->pw_name, "root") ||
         !strcmp (p->pw_name, "nobody") ||
+        !strcmp (p->pw_name, "noaccess") ||
         !strcmp (p->pw_name, "daemon") ||
         !strcmp (p->pw_name, "bin") ||
         !strcmp (p->pw_name, "sys"))
@@ -1052,7 +1106,7 @@ hack_uid (saver_info *si)
         sprintf (si->nolock_reason, "running as %s", p->pw_name);
        }
    }
-#endif /* NO_LOCKING */
+# endif /* !NO_LOCKING */
 }
 
 void