http://packetstorm.tacticalflex.com/UNIX/admin/xscreensaver-3.27.tar.gz
[xscreensaver] / driver / prefs.c
index e006e5778050259893f6aa65eb0ff3df81d36248..392394d1251f2e5fb293311c2f63a23568250f2e 100644 (file)
@@ -73,6 +73,41 @@ extern const char *blurb (void);
 
 
 static void get_screenhacks (saver_preferences *p);
+static char *format_command (const char *cmd, Bool wrap_p);
+
+
+static char *
+chase_symlinks (const char *file)
+{
+# ifdef HAVE_REALPATH
+  if (file)
+    {
+      char buf [2048];
+      if (realpath (file, buf))
+        return strdup (buf);
+
+      sprintf (buf, "%s: realpath", blurb());
+      perror(buf);
+    }
+# endif /* HAVE_REALPATH */
+  return 0;
+}
+
+
+static Bool
+i_am_a_nobody (uid_t uid)
+{
+  struct passwd *p;
+
+  p = getpwnam ("nobody");
+  if (! p) p = getpwnam ("noaccess");
+  if (! p) p = getpwnam ("daemon");
+
+  if (! p) /* There is no nobody? */
+    return False;
+
+  return (uid == p->pw_uid);
+}
 
 
 const char *
@@ -82,7 +117,18 @@ init_file_name (void)
 
   if (!file)
     {
-      struct passwd *p = getpwuid (getuid ());
+      uid_t uid = getuid ();
+      struct passwd *p = getpwuid (uid);
+
+      if (i_am_a_nobody (uid))
+        /* If we're running as nobody, then use root's .xscreensaver file
+           (since ~root/.xscreensaver and ~nobody/.xscreensaver are likely
+           to be different -- if we didn't do this, then xscreensaver-demo
+           would appear to have no effect when the luser is running as root.)
+         */
+        uid = 0;
+
+      p = getpwuid (uid);
 
       if (!p || !p->pw_name || !*p->pw_name)
        {
@@ -123,6 +169,10 @@ init_file_tmp_name (void)
     {
       const char *name = init_file_name();
       const char *suffix = ".tmp";
+
+      char *n2 = chase_symlinks (name);
+      if (n2) name = n2;
+
       if (!name || !*name)
        file = "";
       else
@@ -131,6 +181,8 @@ init_file_tmp_name (void)
          strcpy(file, name);
          strcat(file, suffix);
        }
+
+      if (n2) free (n2);
     }
 
   if (file && *file)
@@ -339,6 +391,7 @@ parse_init_file (saver_preferences *p)
       if (!p->db) abort();
       handle_entry (&p->db, key, value, name, line);
     }
+  fclose (in);
   free(buf);
 
   p->init_file_date = write_date;
@@ -385,6 +438,44 @@ tab_to (FILE *out, int from, int to)
   return from;
 }
 
+static char *
+stab_to (char *out, int from, int to)
+{
+  int tab_width = 8;
+  int to_mod = (to / tab_width) * tab_width;
+  while (from < to_mod)
+    {
+      *out++ = '\t';
+      from = (((from / tab_width) + 1) * tab_width);
+    }
+  while (from < to)
+    {
+      *out++ = ' ';
+      from++;
+    }
+  return out;
+}
+
+static int
+string_columns (const char *string, int length, int start)
+{
+  int tab_width = 8;
+  int col = start;
+  const char *end = string + length;
+  while (string < end)
+    {
+      if (*string == '\n')
+        col = 0;
+      else if (*string == '\t')
+        col = (((col / tab_width) + 1) * tab_width);
+      else
+        col++;
+      string++;
+    }
+  return col;
+}
+
+
 static void
 write_entry (FILE *out, const char *key, const char *value)
 {
@@ -392,10 +483,8 @@ write_entry (FILE *out, const char *key, const char *value)
   char *v2 = v;
   char *nl = 0;
   int col;
-  Bool do_visual_kludge = (!strcmp(key, "programs"));
-  Bool do_wrap = do_visual_kludge;
-  int tab = (do_visual_kludge ? 16 : 23);
-  int tab2 = 3;
+  Bool programs_p = (!strcmp(key, "programs"));
+  int tab = (programs_p ? 32 : 16);
   Bool first = True;
 
   fprintf(out, "%s:", key);
@@ -403,49 +492,35 @@ write_entry (FILE *out, const char *key, const char *value)
 
   while (1)
     {
-      char *s;
-      Bool disabled_p = False;
-
-      v2 = strip(v2);
+      if (!programs_p)
+        v2 = strip(v2);
       nl = strchr(v2, '\n');
       if (nl)
        *nl = 0;
 
-      if (do_visual_kludge && *v2 == '-')
-       {
-         disabled_p = True;
-         v2++;
-         v2 = strip(v2);
-       }
-
-      if (first && disabled_p)
-       first = False;
+      if (first && programs_p)
+        {
+         col = tab_to (out, col, 77);
+         fprintf (out, " \\\n");
+         col = 0;
+        }
 
       if (first)
        first = False;
       else
        {
-         col = tab_to(out, col, 75);
-         fprintf(out, " \\n\\\n");
+         col = tab_to (out, col, 75);
+         fprintf (out, " \\n\\\n");
          col = 0;
        }
 
-      if (disabled_p)
-       {
-         fprintf(out, "-");
-         col++;
-       }
+      if (!programs_p)
+        col = tab_to (out, col, tab);
 
-      s = (do_visual_kludge ? strpbrk(v2, " \t\n:") : 0);
-      if (s && *s == ':')
-       col = tab_to (out, col, tab2);
-      else
-       col = tab_to (out, col, tab);
-
-      if (do_wrap &&
-         strlen(v2) + col > 75)
+      if (programs_p &&
+         string_columns(v2, strlen (v2), col) + col > 75)
        {
-         int L = strlen(v2);
+         int L = strlen (v2);
          int start = 0;
          int end = start;
          while (start < L)
@@ -455,7 +530,7 @@ write_entry (FILE *out, const char *key, const char *value)
              while (v2[end] != ' ' && v2[end] != '\t' &&
                     v2[end] != '\n' && v2[end] != 0)
                end++;
-             if (col + (end - start) >= 74)
+             if (string_columns (v2 + start, (end - start), col) >= 74)
                {
                  col = tab_to (out, col, 75);
                  fprintf(out, "   \\\n");
@@ -464,17 +539,15 @@ write_entry (FILE *out, const char *key, const char *value)
                    start++;
                }
 
+              col = string_columns (v2 + start, (end - start), col);
              while (start < end)
-               {
-                 fputc(v2[start++], out);
-                 col++;
-               }
+                fputc(v2[start++], out);
            }
        }
       else
        {
          fprintf (out, "%s", v2);
-         col += strlen(v2);
+         col += string_columns(v2, strlen (v2), col);
        }
 
       if (nl)
@@ -487,11 +560,14 @@ write_entry (FILE *out, const char *key, const char *value)
   free(v);
 }
 
-void
-write_init_file (saver_preferences *p, const char *version_string)
+int
+write_init_file (saver_preferences *p, const char *version_string,
+                 Bool verbose_p)
 {
+  int status = -1;
   const char *name = init_file_name();
   const char *tmp_name = init_file_tmp_name();
+  char *n2 = chase_symlinks (name);
   struct stat st;
   int i, j;
 
@@ -504,9 +580,11 @@ write_init_file (saver_preferences *p, const char *version_string)
   char *stderr_font;
   FILE *out;
 
-  if (!name) return;
+  if (!name) goto END;
 
-  if (p->verbose_p)
+  if (n2) name = n2;
+
+  if (verbose_p)
     fprintf (stderr, "%s: writing \"%s\".\n", blurb(), name);
 
   unlink (tmp_name);
@@ -517,18 +595,24 @@ write_init_file (saver_preferences *p, const char *version_string)
       sprintf(buf, "%s: error writing \"%s\"", blurb(), name);
       perror(buf);
       free(buf);
-      return;
+      goto END;
     }
 
   /* Give the new .xscreensaver file the same permissions as the old one;
      except ensure that it is readable and writable by owner, and not
-     executable.
+     executable.  Extra hack: if we're running as root, make the file
+     be world-readable (so that the daemon, running as "nobody", will
+     still be able to read it.)
    */
   if (stat(name, &st) == 0)
     {
       mode_t mode = st.st_mode;
-      mode |= S_IRUSR | S_IWUSR;
-      mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+      mode |= S_IRUSR | S_IWUSR;               /* read/write by user */
+      mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);  /* executable by none */
+
+      if (getuid() == (uid_t) 0)               /* read by group/other */
+        mode |= S_IRGRP | S_IROTH;
+
       if (fchmod (fileno(out), mode) != 0)
        {
          char *buf = (char *) malloc(1024 + strlen(name));
@@ -536,7 +620,7 @@ write_init_file (saver_preferences *p, const char *version_string)
                   tmp_name, (unsigned int) mode);
          perror(buf);
          free(buf);
-         return;
+         goto END;
        }
     }
 
@@ -548,14 +632,24 @@ write_init_file (saver_preferences *p, const char *version_string)
   stderr_font = get_string_resource ("font", "Font");
 
   i = 0;
-  for (j = 0; j < p->screenhacks_count; j++)
-    i += strlen(p->screenhacks[j]) + 2;
   {
-    char *ss = programs = (char *) malloc(i + 10);
+    char *ss;
+    char **hack_strings = (char **)
+      calloc (p->screenhacks_count, sizeof(char *));
+
+    for (j = 0; j < p->screenhacks_count; j++)
+      {
+        hack_strings[j] = format_hack (p->screenhacks[j], True);
+        i += strlen (hack_strings[j]);
+        i += 2;
+      }
+
+    ss = programs = (char *) malloc(i + 10);
     *ss = 0;
     for (j = 0; j < p->screenhacks_count; j++)
       {
-       strcat(ss, p->screenhacks[j]);
+        strcat (ss, hack_strings[j]);
+        free (hack_strings[j]);
        ss += strlen(ss);
        *ss++ = '\n';
        *ss = 0;
@@ -698,7 +792,7 @@ write_init_file (saver_preferences *p, const char *version_string)
          perror(buf);
          unlink (tmp_name);
          free(buf);
-         return;
+         goto END;
        }
 
       if (rename (tmp_name, name) != 0)
@@ -709,7 +803,7 @@ write_init_file (saver_preferences *p, const char *version_string)
          perror(buf);
          unlink (tmp_name);
          free(buf);
-         return;
+         goto END;
        }
       else
        {
@@ -718,6 +812,8 @@ write_init_file (saver_preferences *p, const char *version_string)
          /* Since the .xscreensaver file is used for IPC, let's try and make
             sure that the bits actually land on the disk right away. */
          sync ();
+
+          status = 0;    /* wrote and renamed successfully! */
        }
     }
   else
@@ -727,8 +823,12 @@ write_init_file (saver_preferences *p, const char *version_string)
       perror(buf);
       free(buf);
       unlink (tmp_name);
-      return;
+      goto END;
     }
+
+ END:
+  if (n2) free (n2);
+  return status;
 }
 
 \f
@@ -800,7 +900,6 @@ load_init_file (saver_preferences *p)
    */
   if (p->passwd_timeout <= 0) p->passwd_timeout = 30000;        /* 30 secs */
   if (p->timeout < 10000) p->timeout = 10000;                   /* 10 secs */
-  if (p->cycle < 0) p->cycle = 0;
   if (p->cycle != 0 && p->cycle < 2000) p->cycle = 2000;        /*  2 secs */
   if (p->pointer_timeout <= 0) p->pointer_timeout = 5000;       /*  5 secs */
   if (p->notice_events_timeout <= 0)
@@ -809,15 +908,7 @@ load_init_file (saver_preferences *p)
     p->fade_p = False;
   if (! p->fade_p) p->unfade_p = False;
 
-  if (p->verbose_p && !p->fading_possible_p && (p->fade_p || p->unfade_p))
-    {
-      fprintf (stderr, "%s: there are no PseudoColor or GrayScale visuals.\n",
-              blurb());
-      fprintf (stderr, "%s: ignoring the request for fading/unfading.\n",
-              blurb());
-    }
-
-  p->watchdog_timeout = p->cycle;
+  p->watchdog_timeout = p->cycle * 0.6;
   if (p->watchdog_timeout < 30000) p->watchdog_timeout = 30000;          /* 30 secs */
   if (p->watchdog_timeout > 3600000) p->watchdog_timeout = 3600000; /*  1 hr */
 
@@ -836,52 +927,73 @@ load_init_file (saver_preferences *p)
 /* Parsing the programs resource.
  */
 
-static char *
-reformat_hack (const char *hack)
+screenhack *
+parse_screenhack (const char *line)
 {
-  int i;
-  const char *in = hack;
-  int indent = 15;
-  char *h2 = (char *) malloc(strlen(in) + indent + 2);
-  char *out = h2;
-  Bool disabled_p = False;
+  screenhack *h = (screenhack *) calloc (1, sizeof(*h));
+  const char *s;
 
-  while (isspace(*in)) in++;           /* skip whitespace */
+  h->enabled_p = True;
 
-  if (*in == '-')                      /* Handle a leading "-". */
+  while (isspace(*line)) line++;               /* skip whitespace */
+  if (*line == '-')                            /* handle "-" */
     {
-      in++;
-      hack = in;
-      *out++ = '-';
-      *out++ = ' ';
-      disabled_p = True;
-      while (isspace(*in)) in++;
+      h->enabled_p = False;
+      line++;
+      while (isspace(*line)) line++;           /* skip whitespace */
     }
+
+  s = line;                                    /* handle "visual:" */
+  while (*line && *line != ':' && *line != '"' && !isspace(*line))
+    line++;
+  if (*line != ':')
+    line = s;
   else
     {
-      *out++ = ' ';
-      *out++ = ' ';
+      h->visual = (char *) malloc (line-s+1);
+      strncpy (h->visual, s, line-s);
+      h->visual[line-s] = 0;
+      if (*line == ':') line++;                        /* skip ":" */
+      while (isspace(*line)) line++;           /* skip whitespace */
     }
 
-  while (*in && !isspace(*in) && *in != ':')
-    *out++ = *in++;                    /* snarf first token */
-  while (isspace(*in)) in++;           /* skip whitespace */
-
-  if (*in == ':')
-    *out++ = *in++;                    /* copy colon */
-  else
+  if (*line == '"')                            /* handle "name" */
     {
-      in = hack;
-      out = h2 + 2;                    /* reset to beginning */
+      line++;
+      s = line;
+      while (*line && *line != '"')
+        line++;
+      h->name = (char *) malloc (line-s+1);
+      strncpy (h->name, s, line-s);
+      h->name[line-s] = 0;
+      if (*line == '"') line++;                        /* skip "\"" */
+      while (isspace(*line)) line++;           /* skip whitespace */
     }
 
-  *out = 0;
+  h->command = format_command (line, False);   /* handle command */
+  return h;
+}
 
-  while (isspace(*in)) in++;           /* skip whitespace */
-  for (i = strlen(h2); i < indent; i++)        /* indent */
-    *out++ = ' ';
 
-  /* copy the rest of the line. */
+void
+free_screenhack (screenhack *hack)
+{
+  if (hack->visual) free (hack->visual);
+  if (hack->name) free (hack->name);
+  free (hack->command);
+  memset (hack, 0, sizeof(*hack));
+  free (hack);
+}
+
+
+static char *
+format_command (const char *cmd, Bool wrap_p)
+{
+  int tab = 30;
+  int col = tab;
+  char *cmd2 = (char *) calloc (1, 2 * (strlen (cmd) + 1));
+  const char *in = cmd;
+  char *out = cmd2;
   while (*in)
     {
       /* shrink all whitespace to one space, for the benefit of the "demo"
@@ -891,30 +1003,98 @@ reformat_hack (const char *hack)
       switch (*in)
        {
        case '\'': case '"': case '`': case '\\':
-         {
-           /* Metachars are scary.  Copy the rest of the line unchanged. */
-           while (*in)
-             *out++ = *in++;
-         }
+          /* Metachars are scary.  Copy the rest of the line unchanged. */
+          while (*in)
+            *out++ = *in++, col++;
          break;
+
        case ' ': case '\t':
-         {
-           while (*in == ' ' || *in == '\t')
-             in++;
-           *out++ = ' ';
-         }
+          /* Squeeze all other whitespace down to one space. */
+          while (*in == ' ' || *in == '\t')
+            in++;
+          *out++ = ' ', col++;
          break;
+
        default:
-         *out++ = *in++;
+          /* Copy other chars unchanged. */
+         *out++ = *in++, col++;
          break;
        }
     }
+
   *out = 0;
 
-  /* strip trailing whitespace. */
-  out = out-1;
-  while (out > h2 && (*out == ' ' || *out == '\t' || *out == '\n'))
-    *out-- = 0;
+  /* Strip trailing whitespace */
+  while (out > cmd2 && isspace (out[-1]))
+    *(--out) = 0;
+
+  return cmd2;
+}
+
+
+char *
+format_hack (screenhack *hack, Bool wrap_p)
+{
+  int tab = 32;
+  int size = (2 * (strlen(hack->command) +
+                   (hack->visual ? strlen(hack->visual) : 0) +
+                   (hack->name ? strlen(hack->name) : 0) +
+                   tab));
+  char *h2 = (char *) malloc (size);
+  char *out = h2;
+  char *s;
+  int col = 0;
+
+  if (!hack->enabled_p) *out++ = '-';          /* write disabled flag */
+
+  if (hack->visual && *hack->visual)           /* write visual name */
+    {
+      if (hack->enabled_p) *out++ = ' ';
+      *out++ = ' ';
+      strcpy (out, hack->visual);
+      out += strlen (hack->visual);
+      *out++ = ':';
+      *out++ = ' ';
+    }
+
+  *out = 0;
+  col = string_columns (h2, strlen (h2), 0);
+
+  if (hack->name && *hack->name)               /* write pretty name */
+    {
+      int L = (strlen (hack->name) + 2);
+      if (L + col < tab)
+        out = stab_to (out, col, tab - L - 2);
+      else
+        *out++ = ' ';
+      *out++ = '"';
+      strcpy (out, hack->name);
+      out += strlen (hack->name);
+      *out++ = '"';
+      *out = 0;
+
+      col = string_columns (h2, strlen (h2), 0);
+      if (wrap_p && col >= tab)
+        {
+          out = stab_to (out, col, 77);
+          *out += strlen(out);
+        }
+      else
+        *out++ = ' ';
+
+      if (out >= h2+size) abort();
+    }
+
+  *out = 0;
+  col = string_columns (h2, strlen (h2), 0);
+  out = stab_to (out, col, tab);               /* indent */
+
+  if (out >= h2+size) abort();
+  s = format_command (hack->command, wrap_p);
+  strcpy (out, s);
+  out += strlen (s);
+  free (s);
+  *out = 0;
 
   return h2;
 }
@@ -949,7 +1129,7 @@ get_screenhacks (saver_preferences *p)
     {
       for (i = 0; i < p->screenhacks_count; i++)
        if (p->screenhacks[i])
-         free (p->screenhacks[i]);
+         free_screenhack (p->screenhacks[i]);
       free(p->screenhacks);
       p->screenhacks = 0;
     }
@@ -973,7 +1153,7 @@ get_screenhacks (saver_preferences *p)
       i++;
   i++;
 
-  p->screenhacks = (char **) calloc (sizeof (char *), i+1);
+  p->screenhacks = (screenhack **) calloc (sizeof (screenhack *), i+1);
 
   /* Iterate over the lines in `d' (the string with newlines)
      and make new strings to stuff into the `screenhacks' array.
@@ -993,7 +1173,7 @@ get_screenhacks (saver_preferences *p)
       /* null terminate. */
       d[end] = 0;
 
-      p->screenhacks[p->screenhacks_count++] = reformat_hack (d + start);
+      p->screenhacks[p->screenhacks_count++] = parse_screenhack (d + start);
       if (p->screenhacks_count >= i)
        abort();