diff options
author | Mattias Andrée <m@maandree.se> | 2025-03-21 23:46:04 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-03-21 23:46:04 +0100 |
commit | a091370e612b79452ac882e299d0e85154a64b59 (patch) | |
tree | e3af7375e90955609424ebe19442ddb3d53d6e09 /src | |
parent | Remove dependency on libsimple since it's not portable (diff) | |
download | redshift-ng-a091370e612b79452ac882e299d0e85154a64b59.tar.gz redshift-ng-a091370e612b79452ac882e299d0e85154a64b59.tar.bz2 redshift-ng-a091370e612b79452ac882e299d0e85154a64b59.tar.xz |
misc stuff
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'src')
-rw-r--r-- | src/common.h | 23 | ||||
-rw-r--r-- | src/config.c | 114 | ||||
-rw-r--r-- | src/gamma-coopgamma.c | 1 | ||||
-rw-r--r-- | src/location-geoclue2.c | 3 | ||||
-rw-r--r-- | src/location.c | 5 | ||||
-rw-r--r-- | src/redshift.c | 36 | ||||
-rw-r--r-- | src/signals.c | 51 | ||||
-rw-r--r-- | src/util.c | 10 |
8 files changed, 196 insertions, 47 deletions
diff --git a/src/common.h b/src/common.h index aa9af94..b50bb6a 100644 --- a/src/common.h +++ b/src/common.h @@ -368,6 +368,11 @@ enum program_mode { PROGRAM_MODE_ONE_SHOT, /** + * Update temperature once and reset when killed + */ + PROGRAM_MODE_UNTIL_DEATH, + + /** * Print setting and exit */ PROGRAM_MODE_PRINT, @@ -632,8 +637,8 @@ struct setting_time { }; struct settings { - /* Path to config file */ const char *config_file; + int until_death; struct config_ini_state config; @@ -1103,6 +1108,22 @@ void run_period_change_hooks(enum period prev_period, enum period period); */ void install_signal_handlers(void); +/** + * Install signal handlers for forcefully terminating + * the process + * + * This is useful if slave thread is blocked + * + * SIGINT, SIGTERM, and SIGQUIT are set to at the + * first arrival arm a SIGARLM timer with a short + * expiration time, and on the second arrival + * immediately terminate the process. SIGARLM is + * set to immediately terminate the process. + */ +#ifndef WINDOWS +void install_forceful_exit_signal_handlers(void); +#endif + /* util.c */ diff --git a/src/config.c b/src/config.c index 03d0e74..ed61486 100644 --- a/src/config.c +++ b/src/config.c @@ -26,9 +26,10 @@ static void usage(void) { - fprintf(stderr, _("usage: %s %s"), argv0, - _("[-b day:night] [-c file] [-g r:g:b] [-l latitude:longitude | -l provider[:options]]" - " [-m method[:options]] [-o | -O temperature | -t day:night | -x] [-pPrv] | -h | -V")); + fprintf(stderr, _("usage: %s %s\n"), argv0, + _("[-b brightness] [-c file] [-g gamma] [-l latitude:longitude | -l provider[:options]] " + "[-m method[:options]] [-O temperature | -o | -p | -t temperature | -x] [-P | +P] " + "[-r | +r] [-dv] | -h | -V")); exit(1); } @@ -46,7 +47,7 @@ int verbose = 0; * Print general help text */ static void -print_help(void) /* TODO clean up */ +print_help(void) /* TODO clean up; add new options */ { /* TRANSLATORS: help output 1 LAT is latitude, LON is longitude, @@ -108,6 +109,49 @@ print_help(void) /* TODO clean up */ /** + * Parse a boolean string + * + * @param s The string to parse + * @param key The name of the configuration assigned the value `s` + * @return 1 if `s` represents true, 0 if `s` represents false + */ +GCC_ONLY(__attribute__((__pure__))) +static int +get_boolean(const char *s, const char *key) +{ + int ret; + if (s[0] == '0' || s[0] == '1') { + ret = s[0] - '0'; + if (s[1]) + goto bad; + } else { + bad: + eprintf(_("Value of configuration `%s' must be either `1' or `0'."), key); + } + return ret; +} + + +/** + * atof(3)-like wrapper for strtod(3) that checks that the string is valid + * + * @param s The string to parse + * @param key The name of the configuration assigned the value `s` + * @return The encoded value + */ +static double +checked_atof(const char *s, const char *key) +{ + double ret; + errno = 0; + ret = strtod(s, (void *)&s); + if (errno || *s) + eprintf(_("Value of configuration `%s' is not a value decimal value."), key); + return ret; +} + + +/** * Split a list of values, and remove leading and trailing whitespace * from each value * @@ -460,7 +504,10 @@ set_transition_time(char *str, struct setting_time *start, struct setting_time * if (!strs[i] || settings[i]->source > source) continue; if (settings[i]->source & SETTING_CONFIGFILE) { - /* TODO */ + if (i == 0) + weprintf(_("Start value for `%s' specified multiple times in configuration file."), key); + else + weprintf(_("End value for `%s' specified multiple times in configuration file."), key); } settings[i]->source |= source; settings[i]->value = parse_time(strs[i]); @@ -504,7 +551,7 @@ print_provider_list(void) printf(" %s\n", location_providers[i]->name); printf("\n"); - printf(_("Specify colon-separated options with`-l PROVIDER:OPTIONS'.\n")); + printf(_("Specify colon-separated options with `-l PROVIDER:OPTIONS'.\n")); /* TRANSLATORS: `help' must not be translated. */ printf(_("Try `-l PROVIDER:help' for help.\n")); } @@ -558,6 +605,7 @@ load_defaults(struct settings *settings) memset(settings, 0, sizeof(*settings)); /* set each `.source` to `SETTING_DEFAULT` and booleans to 0 */ settings->config_file = NULL; + settings->until_death = 0; settings->day.temperature.value = DEFAULT_DAY_TEMPERATURE; settings->day.brightness.value = DEFAULT_DAY_BRIGHTNESS; @@ -608,6 +656,10 @@ load_from_cmdline(struct settings *settings, int argc, char *argv[]) settings->config_file = ARG(); break; + case 'd': + settings->until_death = 1; + break; + case 'g': set_gamma(ARG(), &settings->day.gamma, &settings->night.gamma, NULL); break; @@ -723,6 +775,20 @@ load_from_cmdline(struct settings *settings, int argc, char *argv[]) default: usage(); + + } ARGALT('+') { + case 'P': + settings->preserve_gamma.source |= SETTING_CMDLINE; + settings->preserve_gamma.value = 1; + break; + + case 'r': + settings->use_fade.source |= SETTING_CMDLINE; + settings->use_fade.value = 1; + break; + + default: + usage(); } ARGEND; if (argc) @@ -740,13 +806,11 @@ load_from_cmdline(struct settings *settings, int argc, char *argv[]) static void load_from_config_ini(struct settings *settings, const char *key, char *value) { - /* TODO add "temperature" as alias to "temp" (with {,-day,-night} suffix) */ - - if (!strcasecmp(key, "temp")) { /* TODO new entry */ + if (!strcasecmp(key, "temp") || !strcasecmp(key, "temperature")) { set_temperature(value, &settings->day.temperature, &settings->night.temperature, key); - } else if (!strcasecmp(key, "temp-day")) { + } else if (!strcasecmp(key, "temp-day") || !strcasecmp(key, "temperature-day")) { set_temperature(value, &settings->day.temperature, NULL, key); - } else if (!strcasecmp(key, "temp-night")) { + } else if (!strcasecmp(key, "temp-night") || !strcasecmp(key, "temperature-night")) { set_temperature(value, NULL, &settings->night.temperature, key); } else if (!strcasecmp(key, "brightness")) { @@ -772,28 +836,28 @@ load_from_config_ini(struct settings *settings, const char *key, char *value) weprintf(_("`fade' setting specified multiple times in configuration file.")); settings->use_fade.source |= SETTING_CONFIGFILE; if (settings->use_fade.source <= SETTING_CONFIGFILE) - settings->use_fade.value = !!atoi(value); /* TODO */ + settings->use_fade.value = get_boolean(value, key); } else if (!strcasecmp(key, "preserve-gamma")) { if (settings->preserve_gamma.source & SETTING_CONFIGFILE) weprintf(_("`preserve-gamma' setting specified multiple times in configuration file.")); settings->preserve_gamma.source |= SETTING_CONFIGFILE; if (settings->preserve_gamma.source <= SETTING_CONFIGFILE) - settings->preserve_gamma.value = !!atoi(value); /* TODO */ + settings->preserve_gamma.value = get_boolean(value, key); } else if (!strcasecmp(key, "elevation-high")) { if (settings->elevation_high.source & SETTING_CONFIGFILE) weprintf(_("`elevation-high' setting specified multiple times in configuration file.")); settings->elevation_high.source |= SETTING_CONFIGFILE; if (settings->elevation_high.source <= SETTING_CONFIGFILE) - settings->elevation_high.value = atof(value); /* TODO */ + settings->elevation_high.value = checked_atof(value, key); } else if (!strcasecmp(key, "elevation-low")) { if (settings->elevation_low.source & SETTING_CONFIGFILE) weprintf(_("`elevation-low' setting specified multiple times in configuration file.")); settings->elevation_low.source |= SETTING_CONFIGFILE; if (settings->elevation_low.source <= SETTING_CONFIGFILE) - settings->elevation_low.value = atof(value); /* TODO */ + settings->elevation_low.value = checked_atof(value, key); } else if (!strcasecmp(key, "dawn-time")) { if (!set_transition_time(value, &settings->dawn.start, &settings->dawn.end, key)) @@ -822,6 +886,7 @@ load_settings(struct settings *settings, int argc, char *argv[]) { struct config_ini_section *section; struct config_ini_setting *setting; + const struct time_period *first, *current; int i, j, n; time_t duration; @@ -866,7 +931,7 @@ load_settings(struct settings *settings, int argc, char *argv[]) if (settings->elevation_high.value < settings->elevation_low.value) eprintf(_("High transition elevation cannot be lower than the low transition elevation.")); - /* If reseting effects, use neutral colour settings (static scheme) and do not preserve gamma */ + /* If resetting effects, use neutral colour settings (static scheme) and do not preserve gamma */ if (mode == PROGRAM_MODE_RESET) { scheme.type = STATIC_SCHEME; settings->preserve_gamma.value = 0; @@ -876,6 +941,8 @@ load_settings(struct settings *settings, int argc, char *argv[]) } /* Publish loaded settings */ + if (mode == PROGRAM_MODE_ONE_SHOT && settings->until_death) + mode = PROGRAM_MODE_UNTIL_DEATH; preserve_gamma = settings->preserve_gamma.value; use_fade = settings->use_fade.value; day_settings.temperature = settings->day.temperature.value; @@ -924,11 +991,18 @@ settings_published: /* TRANSLATORS: Append degree symbols if possible. */ printf(_("Solar elevations: day above %.1f, night below %.1f\n"), scheme.elevation.high, scheme.elevation.low); + } else if (scheme.type == CLOCK_SCHEME) {/ + printf(_("Schedule:\n")); + current = first = scheme.time.periods; + do { + printf(_(" %.2f%% day at %02u:%02u:%02u\n"), + current->day_level * 100, current->start / 60 / 60 % 24, + current->start / 60 % 60, current->start % 60); + } while ((current = current->next) != first); + printf(_("(End of schedule)\n")); } - if (scheme.type != STATIC_SCHEME) { - printf(_("Temperatures: %luK at day, %luK at night\n"), - day_settings.temperature, night_settings.temperature); - } + printf(_("Temperatures: %luK at day, %luK at night\n"), + day_settings.temperature, night_settings.temperature); printf(_("Brightness: %.2f:%.2f\n"), settings->day.brightness.value, settings->night.brightness.value); /* TRANSLATORS: The string in parenthesis is either Daytime or Night (translated). */ printf(_("Gamma (%s): %.3f, %.3f, %.3f\n"), _("Daytime"), diff --git a/src/gamma-coopgamma.c b/src/gamma-coopgamma.c index 0dfb9c2..6f9edb7 100644 --- a/src/gamma-coopgamma.c +++ b/src/gamma-coopgamma.c @@ -172,6 +172,7 @@ coopgamma_start(struct gamma_state *state) lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; break; case PROGRAM_MODE_CONTINUAL: + case PROGRAM_MODE_UNTIL_DEATH: lifespan = LIBCOOPGAMMA_UNTIL_DEATH; break; default: diff --git a/src/location-geoclue2.c b/src/location-geoclue2.c index 69323c2..ced6eb8 100644 --- a/src/location-geoclue2.c +++ b/src/location-geoclue2.c @@ -386,7 +386,8 @@ geoclue2_free(struct location_state *state) if (state->pipe_fd_read >= 0) close(state->pipe_fd_read); - /* Closing the pipe should cause the thread to exit */ + /* Closing the pipe should cause the thread to exit, but it may be blocked by I/O */ + install_forceful_exit_signal_handlers(); g_thread_join(state->thread); state->thread = NULL; diff --git a/src/location.c b/src/location.c index a70be8c..bd852a1 100644 --- a/src/location.c +++ b/src/location.c @@ -168,7 +168,10 @@ get_location(const struct location_provider *provider, LOCATION_STATE *state, in if (provider->fetch(state, location_out, &available) < 0) return -1; - } while (!available); + } while (!available && !exiting); + + if (exiting) + eprintf(_("Terminated by user.")); return 1; #endif diff --git a/src/redshift.c b/src/redshift.c index 4f2304c..ddab891 100644 --- a/src/redshift.c +++ b/src/redshift.c @@ -304,11 +304,11 @@ run_continual_mode(void) disable = 0; } if (exiting) { - if (done) /* TODO also if already disabled (fade complete) */ - break; /* On second signal stop the ongoing fade */ - done = 1; disabled = 1; exiting = 0; + if (done || (disabled && !fade_length)) + break; /* On second signal stop the ongoing fade */ + done = 1; } if (verbose && disabled != prev_disabled) printf(_("Status: %s\n"), disabled ? _("Disabled") : _("Enabled")); @@ -358,7 +358,7 @@ run_continual_mode(void) prev_target_colour = target_colour; /* Break loop when done and final fade is over */ - if (done && fade_length == 0) + if (done && !fade_length) break; /* Adjust temperature and sleep */ @@ -386,6 +386,9 @@ main(int argc, char *argv[]) double day_level; enum period period; struct colour_setting colour; +#ifndef WINDOWS + int fd; +#endif argv0 = argv[0]; @@ -397,6 +400,21 @@ main(int argc, char *argv[]) textdomain(PACKAGE); #endif + /* Ensure standard file descriptors exist */ +#ifndef WINDOWS + fd = open("/dev/null", O_RDWR); + while (fd < 2) { + if (fd < 0) + eprintf("open /dev/null O_RDWR:"); + fd = dup(fd); + } + if (fd > 2) + close(fd); +#endif + + /* Set up interprocess communication */ + install_signal_handlers(); + /* Get configurations and configure */ load_settings(&settings, argc, argv); if (scheme.type == SOLAR_SCHEME) { @@ -409,9 +427,6 @@ main(int argc, char *argv[]) } config_ini_free(&settings.config); - /* Set up interprocess communication */ - install_signal_handlers(); - /* Get location if required */ if (scheme.type == SOLAR_SCHEME) { if (provider->get_fd(provider_state) >= 0) @@ -441,10 +456,11 @@ main(int argc, char *argv[]) break; case PROGRAM_MODE_ONE_SHOT: + case PROGRAM_MODE_UNTIL_DEATH: case PROGRAM_MODE_RESET: if (method->apply(method_state, &colour, preserve_gamma) < 0) eprintf(_("Temperature adjustment failed.")); - if (method->autoreset) { + if (mode == PROGRAM_MODE_UNTIL_DEATH || method->autoreset) { weprintf(_("Press ctrl-c to stop...")); while (!exiting) pause(); @@ -461,9 +477,9 @@ main(int argc, char *argv[]) #endif } - if (method_state) - method->free(method_state); if (provider_state) provider->free(provider_state); + if (method_state) + method->free(method_state); return 0; } diff --git a/src/signals.c b/src/signals.c index 3487d23..390d684 100644 --- a/src/signals.c +++ b/src/signals.c @@ -25,8 +25,8 @@ volatile sig_atomic_t disable = 0; /** - * Signal handlar for exit signals (SIGINT, SIGTERM, SIGQUIT) - * + * Signal handler for exit signals (SIGINT, SIGTERM, SIGQUIT) + * * @param signo The received signal */ static void @@ -41,8 +41,8 @@ sigexit(int signo) /** - * Signal handlar for disable signal (SIGUSR1) - * + * Signal handler for disable signal (SIGUSR1) + * * @param signo The received signal */ #ifndef WINDOWS @@ -55,6 +55,24 @@ sigdisable(int signo) #endif +/** + * Signal handler for forceful exiting; installed by + * `install_forceful_exit_signal_handlers` + * + * @param signo The received signal + */ +#ifndef WINDOWS +static void +sigalrm(int signo) +{ + if (exiting || signo == SIGALRM) + exit(0); + exiting = 1; + alarm(1U); +} +#endif + + void install_signal_handlers(void) { @@ -90,3 +108,28 @@ install_signal_handlers(void) eprintf("sigaction SIGCHLD &{.sa_handler=SIG_IGN, .sa_mask={}, .sa_flags=0} NULL:"); #endif } + + +#ifndef WINDOWS +void +install_forceful_exit_signal_handlers(void) +{ + struct sigaction sigact; + sigset_t sigset; + + exiting = 0; + memset(&sigact, 0, sizeof(sigact)); + sigemptyset(&sigset); + sigact.sa_mask = sigset; + sigact.sa_flags = 0; + sigact.sa_handler = &sigalrm; + if (sigaction(SIGINT, &sigact, NULL)) + eprintf("sigaction SIGINT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); + if (sigaction(SIGTERM, &sigact, NULL)) + eprintf("sigaction SIGTERM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); + if (sigaction(SIGQUIT, &sigact, NULL)) + eprintf("sigaction SIGQUIT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); + if (sigaction(SIGALRM, &sigact, NULL)) + eprintf("sigaction SIGALRM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); +} +#endif @@ -271,9 +271,6 @@ vweprintf(const char *fmt, va_list args) { int saved_errno; const char *errstrprefix, *errstr; -#if !defined(WINDOWS) - int locked; -#endif saved_errno = errno; if (!*fmt) { @@ -289,19 +286,12 @@ vweprintf(const char *fmt, va_list args) errstrprefix = ""; errstr = ""; } -#if !defined(WINDOWS) - locked = !flock(STDERR_FILENO, LOCK_EX); -#endif fprintf(stderr, "%s: ", argv0); vfprintf(stderr, fmt, args); if (errstr) fprintf(stderr, "%s%s\n", errstrprefix, errstr); -#if !defined(WINDOWS) - if (locked) - flock(STDERR_FILENO, LOCK_UN); -#endif errno = saved_errno; } |