summaryrefslogtreecommitdiff
path: root/simplebl.c
diff options
context:
space:
mode:
Diffstat (limited to 'simplebl.c')
-rw-r--r--simplebl.c206
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;
+}