1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 28 */ 29 30 #include <sys/types.h> 31 #include <sys/ioctl.h> 32 #include <stdbool.h> 33 #include <sys/capsicum.h> 34 #include <sys/backlight.h> 35 36 #include <err.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <capsicum_helpers.h> 45 46 #define BACKLIGHT_QUERY 0x0001 47 #define BACKLIGHT_SET_BRIGHTNESS 0x0002 48 #define BACKLIGHT_INCR 0x0004 49 #define BACKLIGHT_DECR 0x0008 50 #define BACKLIGHT_INFO 0x0010 51 52 static char device_name[PATH_MAX] = "/dev/backlight/backlight0"; 53 54 static void 55 set_device_name(const char *name) 56 { 57 58 if (name[0] == '/') 59 strlcpy(device_name, name, sizeof(device_name)); 60 else 61 snprintf(device_name, sizeof(device_name), "/dev/backlight/%s", name); 62 } 63 64 static void 65 usage(void) 66 { 67 fprintf(stderr, "Usage:\n"); 68 fprintf(stderr, "\tbacklight [-f dev]\n"); 69 fprintf(stderr, "\tbacklight [-f dev] -i\n"); 70 fprintf(stderr, "\tbacklight [-f dev] <percent>\n"); 71 fprintf(stderr, "\tbacklight [-f dev] incr|+ <percent>\n"); 72 fprintf(stderr, "\tbacklight [-f dev] decr|- <percent>\n"); 73 exit(1); 74 } 75 76 static const char * 77 backlight_type_to_string(enum backlight_info_type type) 78 { 79 switch (type) { 80 case BACKLIGHT_TYPE_PANEL: 81 return ("Panel"); 82 case BACKLIGHT_TYPE_KEYBOARD: 83 return ("Keyboard"); 84 } 85 86 return ("Unknown"); 87 } 88 89 int 90 main(int argc, char *argv[]) 91 { 92 struct backlight_props props; 93 struct backlight_info info; 94 int fd; 95 int action, ch; 96 cap_rights_t right_ioctl; 97 const unsigned long backlight_ioctls[] = { 98 BACKLIGHTGETSTATUS, 99 BACKLIGHTUPDATESTATUS, 100 BACKLIGHTGETINFO}; 101 long percent = -1; 102 const char *percent_error; 103 uint32_t i; 104 bool quiet = false; 105 106 action = BACKLIGHT_QUERY; 107 fd = -1; 108 109 while ((ch = getopt(argc, argv, "f:qhi")) != -1) { 110 switch (ch) { 111 case 'q': 112 quiet = true; 113 break; 114 case 'f': 115 set_device_name(optarg); 116 break; 117 case 'i': 118 action = BACKLIGHT_INFO; 119 break; 120 case 'h': 121 usage(); 122 break; 123 } 124 } 125 126 argc -= optind; 127 argv += optind; 128 if (argc != 0) { 129 if (strcmp("incr", argv[0]) == 0 || 130 strcmp("+", argv[0]) == 0) { 131 action = BACKLIGHT_INCR; 132 argc -= 1; 133 argv += 1; 134 } 135 else if (strcmp("decr", argv[0]) == 0 || 136 strcmp("-", argv[0]) == 0) { 137 action = BACKLIGHT_DECR; 138 argc -= 1; 139 argv += 1; 140 } else 141 action = BACKLIGHT_SET_BRIGHTNESS; 142 143 if (argc == 1) { 144 /* ignore a trailing % for user friendlyness */ 145 if (strlen(argv[0]) > 0 && 146 argv[0][strlen(argv[0]) - 1] == '%') 147 argv[0][strlen(argv[0]) - 1] = '\0'; 148 percent = strtonum(argv[0], 0, 100, &percent_error); 149 if (percent_error) 150 errx(1, "Cannot parse brightness level %s: %s", 151 argv[0], 152 percent_error); 153 } 154 } 155 156 if ((fd = open(device_name, O_RDWR)) == -1) 157 errx(1, "cannot open %s: %s", 158 device_name, strerror(errno)); 159 160 if (caph_limit_stdio() < 0) 161 errx(1, "can't limit stdio rights"); 162 caph_cache_catpages(); 163 cap_rights_init(&right_ioctl, CAP_IOCTL); 164 if (caph_rights_limit(fd, &right_ioctl) < 0) 165 errx(1, "cap_right_limit() failed"); 166 if (caph_ioctls_limit(fd, backlight_ioctls, nitems(backlight_ioctls)) < 0) 167 errx(1, "caph_ioctls_limit() failed"); 168 if (caph_enter() < 0) 169 errx(1, "failed to enter capability mode"); 170 171 switch (action) { 172 case BACKLIGHT_QUERY: 173 if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 174 errx(1, "Cannot query the backlight device"); 175 if (quiet) 176 printf("%u\n", props.brightness); 177 else { 178 printf("brightness: %d\n", props.brightness); 179 if (props.nlevels != 0) { 180 printf("levels:"); 181 for (i = 0; i < props.nlevels; i++) 182 printf(" %d", props.levels[i]); 183 printf("\n"); 184 } 185 } 186 break; 187 case BACKLIGHT_SET_BRIGHTNESS: 188 if (percent == -1) 189 usage(); 190 props.brightness = percent; 191 if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 192 errx(1, "Cannot update the backlight device"); 193 break; 194 case BACKLIGHT_INCR: 195 case BACKLIGHT_DECR: 196 if (percent == 0) 197 /* Avoid any ioctl if we don't have anything to do */ 198 break; 199 if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 200 errx(1, "Cannot query the backlight device"); 201 percent = percent == -1 ? 10 : percent; 202 percent = action == BACKLIGHT_INCR ? percent : -percent; 203 props.brightness += percent; 204 if ((int)props.brightness < 0) 205 props.brightness = 0; 206 if (props.brightness > 100) 207 props.brightness = 100; 208 if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 209 errx(1, "Cannot update the backlight device"); 210 break; 211 case BACKLIGHT_INFO: 212 if (ioctl(fd, BACKLIGHTGETINFO, &info) == -1) 213 errx(1, "Cannot query the backlight device"); 214 if (quiet == false) { 215 printf("Backlight name: %s\n", info.name); 216 printf("Backlight hardware type: %s\n", backlight_type_to_string(info.type)); 217 } else { 218 printf("%s\n", info.name); 219 printf("%s\n", backlight_type_to_string(info.type)); 220 } 221 break; 222 } 223 224 close(fd); 225 return (0); 226 } 227