X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fprefs.c;h=c074d1f4c2cb509bc043f80a0a1ee41ba1c4bba2;hb=a1d41b2aa6e18bf9a49b914a99dda8232c5d7762;hp=2b8be46d05b5a3a6b8dff8c7315beda2d2b08157;hpb=72c1f4c1dc6ab07fe121a327ff1c30bf51ef74c1;p=xscreensaver diff --git a/driver/prefs.c b/driver/prefs.c index 2b8be46d..c074d1f4 100644 --- a/driver/prefs.c +++ b/driver/prefs.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -74,7 +75,8 @@ extern const char *blurb (void); static void get_screenhacks (saver_preferences *p); static char *format_command (const char *cmd, Bool wrap_p); - +static void merge_system_screenhacks (saver_preferences *p, + screenhack **system_list, int count); static char * chase_symlinks (const char *file) @@ -94,6 +96,22 @@ chase_symlinks (const char *file) } +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 * init_file_name (void) { @@ -101,7 +119,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) { @@ -164,6 +193,39 @@ init_file_tmp_name (void) return 0; } +static int +get_byte_resource (char *name, char *class) +{ + char *s = get_string_resource (name, class); + char *s2 = s; + int n = 0; + if (!s) return 0; + + while (isspace(*s2)) s2++; + while (*s2 >= '0' && *s2 <= '9') + { + n = (n * 10) + (*s2 - '0'); + s2++; + } + while (isspace(*s2)) s2++; + if (*s2 == 'k' || *s2 == 'K') n <<= 10; + else if (*s2 == 'm' || *s2 == 'M') n <<= 20; + else if (*s2 == 'g' || *s2 == 'G') n <<= 30; + else if (*s2) + { + LOSE: + fprintf (stderr, "%s: %s must be a number of bytes, not \"%s\".\n", + progname, name, s); + return 0; + } + s2++; + if (*s2 == 'b' || *s2 == 'B') s2++; + while (isspace(*s2)) s2++; + if (*s2) goto LOSE; + + return n; +} + static const char * const prefs[] = { "timeout", @@ -176,13 +238,14 @@ static const char * const prefs[] = { "installColormap", "verbose", "timestamp", - "splash", /* not saved -- same as "splashDuration: 0" */ + "splash", "splashDuration", "demoCommand", "prefsCommand", "helpURL", "loadURL", "nice", + "memoryLimit", "fade", "unfade", "fadeSeconds", @@ -190,6 +253,14 @@ static const char * const prefs[] = { "captureStderr", "captureStdout", /* not saved -- obsolete */ "font", + "dpmsEnabled", + "dpmsStandby", + "dpmsSuspend", + "dpmsOff", + "grabDesktopImages", + "grabVideoFrames", + "chooseRandomImages", + "imageDirectory", "", "programs", "", @@ -463,6 +534,9 @@ write_entry (FILE *out, const char *key, const char *value) fprintf(out, "%s:", key); col = strlen(key) + 1; + if (strlen(key) > 14) + col = tab_to (out, col, 20); + while (1) { if (!programs_p) @@ -533,9 +607,11 @@ 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); @@ -546,7 +622,6 @@ write_init_file (saver_preferences *p, const char *version_string) */ char *visual_name; char *programs; - Bool capture_stderr_p; Bool overlay_stderr_p; char *stderr_font; FILE *out; @@ -555,7 +630,7 @@ write_init_file (saver_preferences *p, const char *version_string) if (n2) name = n2; - if (p->verbose_p) + if (verbose_p) fprintf (stderr, "%s: writing \"%s\".\n", blurb(), name); unlink (tmp_name); @@ -571,13 +646,19 @@ write_init_file (saver_preferences *p, const char *version_string) /* 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)); @@ -592,7 +673,6 @@ write_init_file (saver_preferences *p, const char *version_string) /* Kludge, since these aren't in the saver_preferences struct... */ visual_name = get_string_resource ("visualID", "VisualID"); programs = 0; - capture_stderr_p = get_boolean_resource ("captureStderr", "Boolean"); overlay_stderr_p = get_boolean_resource ("overlayStderr", "Boolean"); stderr_font = get_string_resource ("font", "Font"); @@ -642,7 +722,7 @@ write_init_file (saver_preferences *p, const char *version_string) { char buf[255]; const char *pr = prefs[j]; - enum pref_type { pref_str, pref_int, pref_bool, pref_time + enum pref_type { pref_str, pref_int, pref_bool, pref_byte, pref_time } type = pref_str; const char *s = 0; int i = 0; @@ -672,20 +752,32 @@ write_init_file (saver_preferences *p, const char *version_string) CHECK("installColormap") type = pref_bool, b = p->install_cmap_p; CHECK("verbose") type = pref_bool, b = p->verbose_p; CHECK("timestamp") type = pref_bool, b = p->timestamp_p; - CHECK("splash") continue; /* don't save */ + CHECK("splash") type = pref_bool, b = p->splash_p; CHECK("splashDuration") type = pref_time, t = p->splash_duration; CHECK("demoCommand") type = pref_str, s = p->demo_command; CHECK("prefsCommand") type = pref_str, s = p->prefs_command; CHECK("helpURL") type = pref_str, s = p->help_url; CHECK("loadURL") type = pref_str, s = p->load_url_command; CHECK("nice") type = pref_int, i = p->nice_inferior; + CHECK("memoryLimit") type = pref_byte, i = p->inferior_memory_limit; CHECK("fade") type = pref_bool, b = p->fade_p; CHECK("unfade") type = pref_bool, b = p->unfade_p; CHECK("fadeSeconds") type = pref_time, t = p->fade_seconds; CHECK("fadeTicks") type = pref_int, i = p->fade_ticks; - CHECK("captureStderr") type = pref_bool, b = capture_stderr_p; + CHECK("captureStderr") type = pref_bool, b = p->capture_stderr_p; CHECK("captureStdout") continue; /* don't save */ CHECK("font") type = pref_str, s = stderr_font; + + CHECK("dpmsEnabled") type = pref_bool, b = p->dpms_enabled_p; + CHECK("dpmsStandby") type = pref_time, t = p->dpms_standby; + CHECK("dpmsSuspend") type = pref_time, t = p->dpms_suspend; + CHECK("dpmsOff") type = pref_time, t = p->dpms_off; + + CHECK("grabDesktopImages") type =pref_bool, b = p->grab_desktop_p; + CHECK("grabVideoFrames") type =pref_bool, b = p->grab_video_p; + CHECK("chooseRandomImages")type =pref_bool, b = p->random_image_p; + CHECK("imageDirectory") type =pref_str, s = p->image_directory; + CHECK("programs") type = pref_str, s = programs; CHECK("pointerPollTime") type = pref_time, t = p->pointer_timeout; CHECK("windowCreationTimeout")type=pref_time,t= p->notice_events_timeout; @@ -729,6 +821,19 @@ write_init_file (saver_preferences *p, const char *version_string) s = buf; } break; + case pref_byte: + { + if (i >= (1<<30) && i == ((i >> 30) << 30)) + sprintf(buf, "%dG", i >> 30); + else if (i >= (1<<20) && i == ((i >> 20) << 20)) + sprintf(buf, "%dM", i >> 20); + else if (i >= (1<<10) && i == ((i >> 10) << 10)) + sprintf(buf, "%dK", i >> 10); + else + sprintf(buf, "%d", i); + s = buf; + } + break; default: abort(); break; @@ -777,6 +882,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 @@ -791,12 +898,34 @@ write_init_file (saver_preferences *p, const char *version_string) END: if (n2) free (n2); + return status; } /* Parsing the resource database */ +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 void +free_screenhack_list (screenhack **list, int count) +{ + int i; + if (!list) return; + for (i = 0; i < count; i++) + if (list[i]) + free_screenhack (list[i]); + free (list); +} + /* Populate `saver_preferences' with the contents of the resource database. Note that this may be called multiple times -- it is re-run each time @@ -810,6 +939,24 @@ load_init_file (saver_preferences *p) { static Bool first_time = True; + screenhack **system_default_screenhacks = 0; + int system_default_screenhack_count = 0; + + if (first_time) + { + /* Get the programs resource before the .xscreensaver file has been + parsed and merged into the resource database for the first time: + this is the value of *programs from the app-defaults file. + Then clear it out so that it will be parsed again later, after + the init file has been read. + */ + get_screenhacks (p); + system_default_screenhacks = p->screenhacks; + system_default_screenhack_count = p->screenhacks_count; + p->screenhacks = 0; + p->screenhacks_count = 0; + } + if (parse_init_file (p) != 0) /* file might have gone away */ if (!first_time) return; @@ -826,6 +973,9 @@ load_init_file (saver_preferences *p) p->fade_ticks = get_integer_resource ("fadeTicks", "Integer"); p->install_cmap_p = get_boolean_resource ("installColormap", "Boolean"); p->nice_inferior = get_integer_resource ("nice", "Nice"); + p->inferior_memory_limit = get_byte_resource ("memoryLimit", "MemoryLimit"); + p->splash_p = get_boolean_resource ("splash", "Boolean"); + p->capture_stderr_p = get_boolean_resource ("captureStderr", "Boolean"); p->initial_delay = 1000 * get_seconds_resource ("initialDelay", "Time"); p->splash_duration = 1000 * get_seconds_resource ("splashDuration", "Time"); @@ -836,6 +986,18 @@ load_init_file (saver_preferences *p) p->pointer_timeout = 1000 * get_seconds_resource ("pointerPollTime", "Time"); p->notice_events_timeout = 1000*get_seconds_resource("windowCreationTimeout", "Time"); + + p->dpms_enabled_p = get_boolean_resource ("dpmsEnabled", "Boolean"); + p->dpms_standby = 1000 * get_minutes_resource ("dpmsStandby", "Time"); + p->dpms_suspend = 1000 * get_minutes_resource ("dpmsSuspend", "Time"); + p->dpms_off = 1000 * get_minutes_resource ("dpmsOff", "Time"); + + p->grab_desktop_p = get_boolean_resource ("grabDesktopImages", "Boolean"); + p->grab_video_p = get_boolean_resource ("grabVideoFrames", "Boolean"); + p->random_image_p = get_boolean_resource ("chooseRandomImages", "Boolean"); + p->image_directory = get_string_resource ("imageDirectory", + "ImageDirectory"); + p->shell = get_string_resource ("bourneShell", "BourneShell"); p->demo_command = get_string_resource("demoCommand", "URL"); @@ -843,12 +1005,23 @@ load_init_file (saver_preferences *p) p->help_url = get_string_resource("helpURL", "URL"); p->load_url_command = get_string_resource("loadURL", "LoadURL"); + + /* If "*splash" is unset, default to true. */ { - char *s; - if ((s = get_string_resource ("splash", "Boolean"))) - if (!get_boolean_resource("splash", "Boolean")) - p->splash_duration = 0; - if (s) free (s); + char *s = get_string_resource ("splash", "Boolean"); + if (s) + free (s); + else + p->splash_p = True; + } + + /* If "*grabDesktopImages" is unset, default to true. */ + { + char *s = get_string_resource ("grabDesktopImages", "Boolean"); + if (s) + free (s); + else + p->grab_desktop_p = True; } p->use_xidle_extension = get_boolean_resource ("xidleExtension","Boolean"); @@ -870,12 +1043,42 @@ load_init_file (saver_preferences *p) p->fade_p = False; if (! p->fade_p) p->unfade_p = False; + /* The DPMS settings may have the value 0. + But if they are negative, or are a range less than 10 seconds, + reset them to sensible defaults. (Since that must be a mistake.) + */ + if (p->dpms_standby != 0 && + p->dpms_standby < 10 * 1000) + p->dpms_standby = 2 * 60 * 60 * 1000; /* 2 hours */ + if (p->dpms_suspend != 0 && + p->dpms_suspend < 10 * 1000) + p->dpms_suspend = 2 * 60 * 60 * 1000; /* 2 hours */ + if (p->dpms_off != 0 && + p->dpms_off < 10 * 1000) + p->dpms_off = 4 * 60 * 60 * 1000; /* 4 hours */ + + if (p->dpms_standby == 0 && /* if *all* are 0, then DPMS is disabled */ + p->dpms_suspend == 0 && + p->dpms_off == 0) + p->dpms_enabled_p = False; + + 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 */ get_screenhacks (p); + if (system_default_screenhack_count) /* note: first_time is also true */ + { + merge_system_screenhacks (p, system_default_screenhacks, + system_default_screenhack_count); + free_screenhack_list (system_default_screenhacks, + system_default_screenhack_count); + system_default_screenhacks = 0; + system_default_screenhack_count = 0; + } + if (p->debug_p) { p->xsync_p = True; @@ -885,6 +1088,82 @@ load_init_file (saver_preferences *p) } } + +/* If there are any hacks in the system-wide defaults that are not in + the ~/.xscreensaver file, add the new ones to the end of the list. + This does *not* actually save the file. + */ +static void +merge_system_screenhacks (saver_preferences *p, + screenhack **system_list, int system_count) +{ + /* Yeah yeah, this is an N^2 operation, but I don't have hashtables handy, + so fuck it. */ + + int made_space = 0; + int i; + for (i = 0; i < system_count; i++) + { + int j; + Bool matched_p = False; + + for (j = 0; j < p->screenhacks_count; j++) + { + char *name; + if (!system_list[i]->name) + system_list[i]->name = make_hack_name (system_list[i]->command); + + name = p->screenhacks[j]->name; + if (!name) + name = make_hack_name (p->screenhacks[j]->command); + + matched_p = !strcasecmp (name, system_list[i]->name); + + if (name != p->screenhacks[j]->name) + free (name); + + if (matched_p) + break; + } + + if (!matched_p) + { + /* We have an entry in the system-wide list that is not in the + user's .xscreensaver file. Add it to the end. + Note that p->screenhacks is a single malloc block, not a + linked list, so we have to realloc it. + */ + screenhack *oh = system_list[i]; + screenhack *nh = (screenhack *) malloc (sizeof(screenhack)); + + if (made_space == 0) + { + made_space = 10; + p->screenhacks = (screenhack **) + realloc (p->screenhacks, + (p->screenhacks_count + made_space + 1) + * sizeof(screenhack)); + if (!p->screenhacks) abort(); + } + + nh->enabled_p = oh->enabled_p; + nh->visual = oh->visual ? strdup(oh->visual) : 0; + nh->name = oh->name ? strdup(oh->name) : 0; + nh->command = oh->command ? strdup(oh->command) : 0; + + p->screenhacks[p->screenhacks_count++] = nh; + p->screenhacks[p->screenhacks_count] = 0; + made_space--; + +#if 0 + fprintf (stderr, "%s: noticed new hack: %s\n", blurb(), + (nh->name ? nh->name : make_hack_name (nh->command))); +#endif + } + } +} + + /* Parsing the programs resource. */ @@ -937,17 +1216,6 @@ parse_screenhack (const char *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) { @@ -994,6 +1262,53 @@ format_command (const char *cmd, Bool wrap_p) } +/* Returns a new string describing the shell command. + This may be just the name of the program, capitalized. + It also may be something from the resource database (gotten + by looking for "hacks.XYZ.name", where XYZ is the program.) + */ +char * +make_hack_name (const char *shell_command) +{ + char *s = strdup (shell_command); + char *s2; + char res_name[255]; + + for (s2 = s; *s2; s2++) /* truncate at first whitespace */ + if (isspace (*s2)) + { + *s2 = 0; + break; + } + + s2 = strrchr (s, '/'); /* if pathname, take last component */ + if (s2) + { + s2 = strdup (s2+1); + free (s); + s = s2; + } + + if (strlen (s) > 50) /* 51 is hereby defined as "unreasonable" */ + s[50] = 0; + + sprintf (res_name, "hacks.%s.name", s); /* resource? */ + s2 = get_string_resource (res_name, res_name); + if (s2) + return s2; + + for (s2 = s; *s2; s2++) /* if it has any capitals, return it */ + if (*s2 >= 'A' && *s2 <= 'Z') + return s; + + if (s[0] >= 'a' && s[0] <= 'z') /* else cap it */ + s[0] -= 'a'-'A'; + if (s[0] == 'X' && s[1] >= 'a' && s[1] <= 'z') /* (magic leading X) */ + s[1] -= 'a'-'A'; + return s; +} + + char * format_hack (screenhack *hack, Bool wrap_p) { @@ -1037,10 +1352,7 @@ format_hack (screenhack *hack, Bool wrap_p) col = string_columns (h2, strlen (h2), 0); if (wrap_p && col >= tab) - { - out = stab_to (out, col, 77); - *out += strlen(out); - } + out = stab_to (out, col, 77); else *out++ = ' '; @@ -1065,7 +1377,7 @@ format_hack (screenhack *hack, Bool wrap_p) static void get_screenhacks (saver_preferences *p) { - int i = 0; + int i, j; int start = 0; int end = 0; int size; @@ -1087,35 +1399,25 @@ get_screenhacks (saver_preferences *p) d = get_string_resource ("programs", "Programs"); - if (p->screenhacks) - { - for (i = 0; i < p->screenhacks_count; i++) - if (p->screenhacks[i]) - free_screenhack (p->screenhacks[i]); - free(p->screenhacks); - p->screenhacks = 0; - } + free_screenhack_list (p->screenhacks, p->screenhacks_count); + p->screenhacks = 0; + p->screenhacks_count = 0; if (!d || !*d) - { - p->screenhacks_count = 0; - p->screenhacks = 0; - return; - } + return; size = strlen (d); /* Count up the number of newlines (which will be equal to or larger than - the number of hacks.) + one less than the number of hacks.) */ - i = 0; - for (i = 0; d[i]; i++) + for (i = j = 0; d[i]; i++) if (d[i] == '\n') - i++; - i++; + j++; + j++; - p->screenhacks = (screenhack **) calloc (sizeof (screenhack *), i+1); + p->screenhacks = (screenhack **) calloc (j + 1, sizeof (screenhack *)); /* Iterate over the lines in `d' (the string with newlines) and make new strings to stuff into the `screenhacks' array.