/*- * redshift-ng - Automatically adjust display colour temperature according the Sun * * Copyright (c) 2009-2018 Jon Lund Steffensen * Copyright (c) 2014-2016, 2025 Mattias Andrée * * redshift-ng is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * redshift-ng is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with redshift-ng. If not, see . */ #include "common.h" char * rtrim(char *s, char *end) { end = end ? end : strchr(s, '\0'); while (end != s && (end[-1] == ' ' || end[-1] == '\t')) end--; *end = '\0'; return s; } char * ltrim(char *s) { while (*s == ' ' || *s == '\t') s++; return s; } const char * get_home(void) { #ifdef WINDOWS return NULL; #else static const char *home = NULL; struct passwd *pw; if (!home) { pw = getpwuid(getuid()); if (pw) { home = pw->pw_dir; if (home && *home) return home; weprintf(_("Cannot determine your home directory, " "it is from the system's user table.")); } else if (errno) { weprintf("getpwuid:"); } else { weprintf(_("Cannot determine your home directory, your" " user ID is missing from the system's user table.")); /* `errno` can either be set to any number of error codes, * or be zero if the user does not have a passwd entry */ } home = ""; } return home; #endif } /** * Search for a file and open it in some manner * * @param path_spec Specification for the path to try * @param path_out Output parameter for the found file * @param pathbuf_out Output parameter for the memory allocation for `*path_out`; * shall be free(3)d by the caller * @param open_cb Pointer to function used to open the file, unless it * returns `NULL` it's return value is returned by the * function (`try_path`); `NULL` shall be returned if the * file `path` does not exist * @return File access object to the found file; `NULL` if not found */ static void * try_path(const struct env_path *path_spec, const char **path_out, char **pathbuf_out, void *(*open_cb)(const char *path)) { const char *prefix, *p, *q; char *path; size_t len; void *f = NULL; *path_out = NULL; *pathbuf_out = NULL; if (!path_spec->prefix_env) { prefix = get_home(); } else if (*path_spec->prefix_env) { prefix = getenv(path_spec->prefix_env); } else { f = (*open_cb)(path_spec->suffix); if (f) *path_out = path_spec->suffix; return f; } if (!prefix || !*prefix) return NULL; path = emalloc(strlen(prefix) + strlen(path_spec->suffix) + 1U); if (path_spec->multidir_env) { for (p = prefix; !f && *p; p = &q[!!*q]) { #ifdef strchrnul q = strchrnul(p, PATH_DELIMITER); #else q = strchr(p, PATH_DELIMITER); q = q ? q : strchr(p, '\0'); #endif len = (size_t)(q - p); if (!len) continue; memcpy(path, p, len); stpcpy(&path[len], path_spec->suffix); f = (*open_cb)(path); } } else { stpcpy(stpcpy(path, prefix), path_spec->suffix); f = (*open_cb)(path); } if (f) *path_out = *pathbuf_out = path; else free(path); return f; } /** * Open a file for reading, if it exists * * @param path The path to the file * @return `FILE` object for reading the file, * `NULL` if it doesn't exist */ static void * open_file(const char *path) { FILE *f = fopen(path, "r"); if (!f && errno != ENOENT) eprintf("fopen %s \"r\":", path); return f; } FILE * try_path_fopen(const struct env_path *path_spec, const char **path_out, char **pathbuf_out) { return try_path(path_spec, path_out, pathbuf_out, &open_file); } /** * Open a directory for reading, if it exists * * @param path The path to the directory * @return `DIR` object for reading the directory, * `NULL` if it doesn't exist */ static void * open_dir(const char *path) { DIR *f = opendir(path); if (!f && errno != ENOENT) eprintf("opendir %s:", path); return f; } DIR * try_path_opendir(const struct env_path *path_spec, const char **path_out, char **pathbuf_out) { return try_path(path_spec, path_out, pathbuf_out, &open_dir); } #ifndef WINDOWS void pipe_rdnonblock(int pipefds[2]) { int i, flags; /* Try to use pipe2(2) create O_CLOEXEC pipe */ # if defined(__linux__) && !defined(MISSING_PIPE2) if (!pipe2(pipefds, O_CLOEXEC)) goto apply_nonblock; else if (errno != ENOSYS) eprintf("pipe2 O_CLOEXEC:"); # endif /* Fallback for when pipe2(2) is not available */ if (pipe(pipefds)) eprintf("pipe:"); for (i = 0; i < 2; i++) { flags = fcntl(pipefds[i], F_GETFD); if (flags == -1) eprintf("fcntl F_GETFD:"); if (fcntl(pipefds[i], F_SETFD, flags | O_CLOEXEC)) eprintf("fcntl F_SETFD +O_CLOEXEC:"); } /* Make the read-end non-blocking */ # if defined(__linux__) && !defined(MISSING_PIPE2) apply_nonblock: # endif flags = fcntl(pipefds[0], F_GETFL); if (flags == -1) eprintf("fcntl F_GETFL:"); if (fcntl(pipefds[0], F_SETFL, flags | O_NONBLOCK)) eprintf("fcntl F_SETFL +O_NONBLOCK:"); } #endif void * ecalloc(size_t n, size_t m) { char *ret = calloc(n, m); if (!ret) eprintf("calloc:"); return ret; } void * emalloc(size_t n) { char *ret = malloc(n); if (!ret) eprintf("malloc:"); return ret; } void * erealloc(void *ptr, size_t n) { char *ret = realloc(ptr, n); if (!ret) eprintf("realloc:"); return ret; } char * estrdup(const char *s) { char *ret = strdup(s); if (!ret) eprintf("strdup:"); return ret; } void vweprintf(const char *fmt, va_list args) { int saved_errno; const char *errstrprefix, *errstr; saved_errno = errno; if (!*fmt) { errstrprefix = ""; errstr = strerror(saved_errno); } else if (strchr(fmt, '\0')[-1] == '\n') { errstrprefix = ""; errstr = NULL; } else if (strchr(fmt, '\0')[-1] == ':') { errstrprefix = " "; errstr = strerror(saved_errno); } else { errstrprefix = ""; errstr = ""; } fprintf(stderr, "%s: ", argv0); vfprintf(stderr, fmt, args); if (errstr) fprintf(stderr, "%s%s\n", errstrprefix, errstr); errno = saved_errno; } void weprintf(const char *fmt, ...) { va_list args; va_start(args, fmt); vweprintf(fmt, args); va_end(args); } void eprintf(const char *fmt, ...) { va_list args; va_start(args, fmt); vweprintf(fmt, args); va_end(args); exit(1); }