diff options
author | Aiden Gall <aiden@aidengall.xyz> | 2023-12-11 18:41:43 +0000 |
---|---|---|
committer | Aiden Gall <aiden@aidengall.xyz> | 2023-12-11 18:41:43 +0000 |
commit | ac18fcd10eff325973211b894ba4236cc1c3818c (patch) | |
tree | 5c49b9977fee854d258d257cec2462bb126743d6 /simplebl.c |
initial commit
Diffstat (limited to 'simplebl.c')
-rw-r--r-- | simplebl.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/simplebl.c b/simplebl.c new file mode 100644 index 0000000..b1fd622 --- /dev/null +++ b/simplebl.c @@ -0,0 +1,206 @@ +/* Copyright (C) 2023 Aiden Gall + +This program 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. + +This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <grp.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static const char VIDEO_GROUP[] = "video"; + +static const char BRIGHTNESS[] = + "/sys/class/backlight/intel_backlight/brightness"; +static const char MAX_BRIGHTNESS[] = + "/sys/class/backlight/intel_backlight/max_brightness"; + +static void die(const char *fmt, ...); +static long strtonum(const char *arg, long minval, long maxval); + +static int check_group(void); + +static long read_sys_file_num(const char *path); +static void write_sys_file_num(const char *path, long val); + +static void +die(const char *const fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + exit(EXIT_FAILURE); +} + +static long +strtonum(const char *const arg, const long minval, const long maxval) +{ + long ret; + char *endptr; + + if (minval > maxval) + die("strtonum: Invalid range\n"); + if (!arg) + die("strtonum: Missing argument\n"); + + errno = 0; + ret = strtol(arg, &endptr, 10); + if (errno) + die("strtol: %s\n", strerror(errno)); + if (arg == endptr || *endptr) + die("strtol: Invalid integer\n"); + + if (ret < minval || ret > maxval) + die("strtonum: Argument out of range\n"); + + return ret; +} + +static int +check_group(void) +{ + uid_t uid, euid; + gid_t video_gid; + + gid_t *glist; + int glist_size; + + struct group *grp; + + int i; + + uid = getuid(); + euid = geteuid(); + if (uid == 0) + return 1; + if (euid != 0) + die("check_group: setuid is not set\n"); + + errno = 0; + grp = getgrnam(VIDEO_GROUP); + if (errno) + die("getgrnam: %s\n", strerror(errno)); + if (!grp) + die("getgrnam: Group '%s' not found\n", VIDEO_GROUP); + video_gid = grp->gr_gid; + + errno = 0; + glist_size = getgroups(0, NULL); + if (errno) + die("getgroups: %s\n", strerror(errno)); + glist = calloc(glist_size, sizeof(*glist)); + if (!glist) + die("check_group: Out of memory\n"); + + errno = 0; + if (getgroups(glist_size, glist) != glist_size) + die("getgroups: Inconsistent number of groups\n"); + if (errno) + die("getgroups: %s\n", strerror(errno)); + + for (i = 0; i < glist_size; i++) { + if (glist[i] == video_gid) { + free(glist); + return 1; + } + } + + free(glist); + return 0; +} + +static long +read_sys_file_num(const char *const path) +{ + FILE *fd; + char buf[64]; + + errno = 0; + fd = fopen(path, "r"); + if (errno) + die("fopen: %s\n", strerror(errno)); + if (!fd) + die("fopen: Returned NULL\n"); + + if (!fgets(buf, sizeof(buf), fd)) + die("fgets: Returned NULL\n"); + fclose(fd); + buf[strcspn(buf, "\n")] = '\0'; + + return strtonum(buf, 0, LONG_MAX/2); +} + +static void +write_sys_file_num(const char *const path, const long val) +{ + FILE *fd; + + errno = 0; + fd = fopen(path, "w"); + if (errno) + die("fopen: %s\n", strerror(errno)); + if (!fd) + die("fopen: Returned NULL\n"); + + if (!fprintf(fd, "%ld\n", val)) + die("fprintf: Failed to write\n"); + fclose(fd); +} + +int +main(int argc, char *argv[]) +{ + long brightness, max_brightness; + long val; + + if (!check_group()) + die("%s: User not in '%s' group\n", argv[0], VIDEO_GROUP); + + if (argc != 3) + die("%s: Invalid number of arguments\n", argv[0]); + + val = strtonum(argv[2], 0, LONG_MAX/2); + + if (argv[1][1]) + goto invalid_mode; + switch (argv[1][0]) { + case '-': + val = -val; + /* FALLTHROUGH */ + case '+': + brightness = read_sys_file_num(BRIGHTNESS); + val += brightness; + /* FALLTHROUGH */ + case '=': + max_brightness = read_sys_file_num(MAX_BRIGHTNESS); + if (val < 0) + val = 0; + if (val > max_brightness) + val = max_brightness; + + write_sys_file_num(BRIGHTNESS, val); + break; + default: + invalid_mode: + die("%s: Invalid mode\n", argv[0]); + } + + return 0; +} |