1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020 Emmanuel Vadot <manu@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/ioctl.h> 30 #include <stdbool.h> 31 #include <sys/capsicum.h> 32 #include <sys/backlight.h> 33 34 #include <err.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <limits.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <capsicum_helpers.h> 43 44 #define BACKLIGHT_QUERY 0x0001 45 #define BACKLIGHT_SET_BRIGHTNESS 0x0002 46 #define BACKLIGHT_INCR 0x0004 47 #define BACKLIGHT_DECR 0x0008 48 #define BACKLIGHT_INFO 0x0010 49 50 static char device_name[PATH_MAX] = "/dev/backlight/backlight0"; 51 52 static void 53 set_device_name(const char *name) 54 { 55 56 if (name[0] == '/') 57 strlcpy(device_name, name, sizeof(device_name)); 58 else 59 snprintf(device_name, sizeof(device_name), "/dev/backlight/%s", name); 60 } 61 62 static void 63 usage(void) 64 { 65 fprintf(stderr, "Usage:\n"); 66 fprintf(stderr, "\tbacklight [-q] [-f device]\n"); 67 fprintf(stderr, "\tbacklight [-q] [-f device] -i\n"); 68 fprintf(stderr, "\tbacklight [-f device] value\n"); 69 fprintf(stderr, "\tbacklight [-f device] incr|+ value\n"); 70 fprintf(stderr, "\tbacklight [-f device] decr|- value\n"); 71 exit(1); 72 } 73 74 static const char * 75 backlight_type_to_string(enum backlight_info_type type) 76 { 77 switch (type) { 78 case BACKLIGHT_TYPE_PANEL: 79 return ("Panel"); 80 case BACKLIGHT_TYPE_KEYBOARD: 81 return ("Keyboard"); 82 } 83 84 return ("Unknown"); 85 } 86 87 int 88 main(int argc, char *argv[]) 89 { 90 struct backlight_props props; 91 struct backlight_info info; 92 int fd; 93 int action, ch; 94 cap_rights_t right_ioctl; 95 const unsigned long backlight_ioctls[] = { 96 BACKLIGHTGETSTATUS, 97 BACKLIGHTUPDATESTATUS, 98 BACKLIGHTGETINFO}; 99 long percent = -1; 100 const char *percent_error; 101 uint32_t i; 102 bool quiet = false; 103 104 action = BACKLIGHT_QUERY; 105 fd = -1; 106 107 while ((ch = getopt(argc, argv, "f:qhi")) != -1) { 108 switch (ch) { 109 case 'q': 110 quiet = true; 111 break; 112 case 'f': 113 set_device_name(optarg); 114 break; 115 case 'i': 116 action = BACKLIGHT_INFO; 117 break; 118 case 'h': 119 usage(); 120 break; 121 } 122 } 123 124 argc -= optind; 125 argv += optind; 126 if (argc != 0) { 127 if (strcmp("incr", argv[0]) == 0 || 128 strcmp("+", argv[0]) == 0) { 129 action = BACKLIGHT_INCR; 130 argc -= 1; 131 argv += 1; 132 } 133 else if (strcmp("decr", argv[0]) == 0 || 134 strcmp("-", argv[0]) == 0) { 135 action = BACKLIGHT_DECR; 136 argc -= 1; 137 argv += 1; 138 } else 139 action = BACKLIGHT_SET_BRIGHTNESS; 140 141 if (argc == 1) { 142 /* ignore a trailing % for user friendlyness */ 143 if (strlen(argv[0]) > 0 && 144 argv[0][strlen(argv[0]) - 1] == '%') 145 argv[0][strlen(argv[0]) - 1] = '\0'; 146 percent = strtonum(argv[0], 0, 100, &percent_error); 147 if (percent_error) 148 errx(1, "Cannot parse brightness level %s: %s", 149 argv[0], 150 percent_error); 151 } 152 } 153 154 if ((fd = open(device_name, O_RDWR)) == -1) 155 errx(1, "cannot open %s: %s", 156 device_name, strerror(errno)); 157 158 if (caph_limit_stdio() < 0) 159 errx(1, "can't limit stdio rights"); 160 caph_cache_catpages(); 161 cap_rights_init(&right_ioctl, CAP_IOCTL); 162 if (caph_rights_limit(fd, &right_ioctl) < 0) 163 errx(1, "cap_right_limit() failed"); 164 if (caph_ioctls_limit(fd, backlight_ioctls, nitems(backlight_ioctls)) < 0) 165 errx(1, "caph_ioctls_limit() failed"); 166 if (caph_enter() < 0) 167 errx(1, "failed to enter capability mode"); 168 169 switch (action) { 170 case BACKLIGHT_QUERY: 171 if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 172 errx(1, "Cannot query the backlight device"); 173 if (quiet) 174 printf("%u\n", props.brightness); 175 else { 176 printf("brightness: %d\n", props.brightness); 177 if (props.nlevels != 0) { 178 printf("levels:"); 179 for (i = 0; i < props.nlevels; i++) 180 printf(" %d", props.levels[i]); 181 printf("\n"); 182 } 183 } 184 break; 185 case BACKLIGHT_SET_BRIGHTNESS: 186 if (percent == -1) 187 usage(); 188 props.brightness = percent; 189 if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 190 errx(1, "Cannot update the backlight device"); 191 break; 192 case BACKLIGHT_INCR: 193 case BACKLIGHT_DECR: 194 if (percent == 0) 195 /* Avoid any ioctl if we don't have anything to do */ 196 break; 197 if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 198 errx(1, "Cannot query the backlight device"); 199 percent = percent == -1 ? 10 : percent; 200 percent = action == BACKLIGHT_INCR ? percent : -percent; 201 props.brightness += percent; 202 if ((int)props.brightness < 0) 203 props.brightness = 0; 204 if (props.brightness > 100) 205 props.brightness = 100; 206 if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 207 errx(1, "Cannot update the backlight device"); 208 break; 209 case BACKLIGHT_INFO: 210 if (ioctl(fd, BACKLIGHTGETINFO, &info) == -1) 211 errx(1, "Cannot query the backlight device"); 212 if (quiet == false) { 213 printf("Backlight name: %s\n", info.name); 214 printf("Backlight hardware type: %s\n", backlight_type_to_string(info.type)); 215 } else { 216 printf("%s\n", info.name); 217 printf("%s\n", backlight_type_to_string(info.type)); 218 } 219 break; 220 } 221 222 close(fd); 223 return (0); 224 } 225