diff --git a/brightnessctl.c b/brightnessctl.c index 1917212..4493552 100644 --- a/brightnessctl.c +++ b/brightnessctl.c @@ -60,8 +60,8 @@ static unsigned long percent_to_val(float, struct device *); static bool find_devices(struct device **, char *); static bool save_device_data(struct device *); static bool restore_device_data(struct device *); -static bool ensure_dir(char *); -static bool ensure_dev_dir(struct device *); +static bool mkdir_parent(const char *); +static bool ensure_dir(const char *); #ifdef ENABLE_LOGIND static bool logind_set_brightness(struct device *); @@ -266,9 +266,16 @@ int process_device(struct device *dev) { } free(file_path); } + mode_t old = umask(0); + char *sys_run_dir = getenv("XDG_RUNTIME_DIR"); + if (sys_run_dir) { + umask(0077); + run_dir = dir_child(sys_run_dir, "brightnessctl"); + } if (p.save) if (!save_device_data(dev)) fprintf(stderr, "Could not save data for device '%s'.\n", dev->id); + umask(old); if (p.restore) { if (restore_device_data(dev)) p.operation = RESTORE; @@ -557,104 +564,79 @@ int read_devices(struct device **devs) { } bool save_device_data(struct device *dev) { - char c[16]; - size_t s = sprintf(c, "%u", dev->curr_brightness); - char *d_path = cat_with('/', run_dir, dev->class, dev->id); - FILE *fp; - mode_t old = 0; - int error = 0; - errno = 0; - if (s <= 0) { - fprintf(stderr, "Error converting device data."); - error++; - goto fail; - } - if (!ensure_dev_dir(dev)) - goto fail; - old = umask(0); - fp = fopen(d_path, "w"); - umask(old); - if (!fp) - goto fail; - if (fwrite(c, 1, s, fp) < s) { - fprintf(stderr, "Error writing to '%s'.\n", d_path); - error++; + char *c_path = dir_child(run_dir, dev->class); + char *d_path = dir_child(c_path, dev->id); + bool ret = true; + if (ensure_dir(c_path)) { + FILE *fp = fopen(d_path, "wb"); + if (fp) { + fwrite(&dev->curr_brightness, sizeof(dev->curr_brightness), 1, fp); + if (ferror(fp)) { + ret = false; + fprintf(stderr, "Error writing to '%s'.\n", d_path); + } + fclose(fp); + } else { + ret = false; + fprintf(stderr, "Error opening '%s': %s\n", d_path, strerror(errno)); + } + } else { + fprintf(stderr, "Failed to access or create '%s': %s\n", path, strerror(errno)); } - fclose(fp); -fail: + free(c_path); free(d_path); - if (errno) { - perror("Error saving device data"); - error++; - } - return !error; + return ret; } bool restore_device_data(struct device *dev) { - char buf[16]; char *filename = cat_with('/', run_dir, dev->class, dev->id); - char *end; - FILE *fp; - memset(buf, 0, 16); - errno = 0; - if (!(fp = fopen(filename, "r"))) - goto fail; - if (!fread(buf, 1, 15, fp)) - goto rfail; - dev->curr_brightness = strtol(buf, &end, 10); - if (end == buf) - errno = EINVAL; -rfail: - fclose(fp); -fail: - free(filename); - if (errno) { + bool ret = true; + FILE *fp = fopen(filename, "rb"); + if (fp) { + unsigned int val; + fread(&val, sizeof(val), 1, fp); + if (!ferror(fp)) { + dev->curr_brightness = val; + } else { + ret = false; + fprintf(stderr, "Error reading file '%s'\n", filename); + } + fclose(fp); + } else { + ret = false; perror("Error restoring device data"); - return false; } - return true; + free(filename); + return ret; } - -bool ensure_dir(char *dir) { - struct stat sb; - if (stat(dir, &sb)) { - if (errno != ENOENT) - return false; - errno = 0; - if (mkdir(dir, 0777)) { - return false; - } - if (stat(dir, &sb)) - return false; - } - if (!S_ISDIR(sb.st_mode)) { - errno = ENOTDIR; +bool mkdir_parent(const char *path) { + if (!path) return false; + bool ret = true; + size_t size = strlen(path) + 1; + char *tmp = calloc(1, size); + if (!tmp) + return false; + for (const char *p = path; (p - path) < (long)size; p++) { + if ((*p == '/' || *p == '\0') && (p != path && *(p - 1) != '/')) { + memcpy(tmp, path, p - path); + tmp[p - path] = 0; + if (mkdir(tmp, 0777) && errno != EEXIST) { + ret = false; + perror(tmp); + break; + } + } } - return true; -} - -static bool ensure_run_dir() { - static bool set; - if (!set) { - char *sys_run_dir = getenv("XDG_RUNTIME_DIR"); - if (sys_run_dir) - run_dir = dir_child(sys_run_dir, "brightnessctl"); - set = true; - } - return ensure_dir(run_dir); + free(tmp); + return ret; } -bool ensure_dev_dir(struct device *dev) { - char *cpath; - bool ret; - if (!ensure_run_dir()) - return false; - cpath = dir_child(run_dir, dev->class); - ret = ensure_dir(cpath); - free(cpath); - return ret; +static bool ensure_dir(const char * path) { + if (!access(path, W_OK)) + return true; + return errno == ENOENT ? mkdir_parent(path) : false; } char *_cat_with(char c, ...) {