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 setname; 105 bool quiet = false; 106 107 action = BACKLIGHT_QUERY; 108 setname = false; 109 fd = -1; 110 111 while ((ch = getopt(argc, argv, "f:qhi")) != -1) { 112 switch (ch) { 113 case 'q': 114 quiet = true; 115 break; 116 case 'f': 117 setname = true; 118 set_device_name(optarg); 119 break; 120 case 'i': 121 action = BACKLIGHT_INFO; 122 break; 123 case 'h': 124 usage(); 125 break; 126 } 127 } 128 129 argc -= optind; 130 argv += optind; 131 if (argc != 0) { 132 if (strcmp("incr", argv[0]) == 0 || 133 strcmp("+", argv[0]) == 0) { 134 action = BACKLIGHT_INCR; 135 argc -= 1; 136 argv += 1; 137 } 138 else if (strcmp("decr", argv[0]) == 0 || 139 strcmp("-", argv[0]) == 0) { 140 action = BACKLIGHT_DECR; 141 argc -= 1; 142 argv += 1; 143 } else 144 action = BACKLIGHT_SET_BRIGHTNESS; 145 146 if (argc == 1) { 147 /* ignore a trailing % for user friendlyness */ 148 if (strlen(argv[0]) > 0 && 149 argv[0][strlen(argv[0]) - 1] == '%') 150 argv[0][strlen(argv[0]) - 1] = '\0'; 151 percent = strtonum(argv[0], 0, 100, &percent_error); 152 if (percent_error) 153 errx(1, "Cannot parse brightness level %s: %s", 154 argv[0], 155 percent_error); 156 } 157 } 158 159 if ((fd = open(device_name, O_RDWR)) == -1) 160 errx(1, "cannot open %s: %s", 161 device_name, strerror(errno)); 162 163 if (caph_limit_stdio() < 0) 164 errx(1, "can't limit stdio rights"); 165 caph_cache_catpages(); 166 cap_rights_init(&right_ioctl, CAP_IOCTL); 167 if (caph_rights_limit(fd, &right_ioctl) < 0) 168 errx(1, "cap_right_limit() failed"); 169 if (caph_ioctls_limit(fd, backlight_ioctls, nitems(backlight_ioctls)) < 0) 170 errx(1, "caph_ioctls_limit() failed"); 171 if (caph_enter() < 0) 172 errx(1, "failed to enter capability mode"); 173 174 switch (action) { 175 case BACKLIGHT_QUERY: 176 if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 177 errx(1, "Cannot query the backlight device"); 178 if (quiet) 179 printf("%u\n", props.brightness); 180 else { 181 printf("brightness: %d\n", props.brightness); 182 if (props.nlevels != 0) { 183 printf("levels:"); 184 for (i = 0; i < props.nlevels; i++) 185 printf(" %d", props.levels[i]); 186 printf("\n"); 187 } 188 } 189 break; 190 case BACKLIGHT_SET_BRIGHTNESS: 191 if (percent == -1) 192 usage(); 193 props.brightness = percent; 194 if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 195 errx(1, "Cannot update the backlight device"); 196 break; 197 case BACKLIGHT_INCR: 198 case BACKLIGHT_DECR: 199 if (percent == 0) 200 /* Avoid any ioctl if we don't have anything to do */ 201 break; 202 if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 203 errx(1, "Cannot query the backlight device"); 204 percent = percent == -1 ? 10 : percent; 205 percent = action == BACKLIGHT_INCR ? percent : -percent; 206 props.brightness += percent; 207 if ((int)props.brightness < 0) 208 props.brightness = 0; 209 if (props.brightness > 100) 210 props.brightness = 100; 211 if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 212 errx(1, "Cannot update the backlight device"); 213 break; 214 case BACKLIGHT_INFO: 215 if (ioctl(fd, BACKLIGHTGETINFO, &info) == -1) 216 errx(1, "Cannot query the backlight device"); 217 if (quiet == false) { 218 printf("Backlight name: %s\n", info.name); 219 printf("Backlight hardware type: %s\n", backlight_type_to_string(info.type)); 220 } else { 221 printf("%s\n", info.name); 222 printf("%s\n", backlight_type_to_string(info.type)); 223 } 224 break; 225 } 226 227 close(fd); 228 return (0); 229 } 230