X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fprefs.c;h=392394d1251f2e5fb293311c2f63a23568250f2e;hb=de041722414a2e31c1c04caa10aaec9d6952e9b4;hp=e006e5778050259893f6aa65eb0ff3df81d36248;hpb=59ac4e9a0de290e4275a7bbb890ad16abd09d68f;p=xscreensaver diff --git a/driver/prefs.c b/driver/prefs.c index e006e577..392394d1 100644 --- a/driver/prefs.c +++ b/driver/prefs.c @@ -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; } @@ -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();