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 = 0; 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 percent = strtonum(argv[0], 0, 100, &percent_error); 148 if (percent_error) 149 errx(1, "Cannot parse brightness level %s: %s", 150 argv[0], 151 percent_error); 152 } 153 } 154 155 if ((fd = open(device_name, O_RDWR)) == -1) 156 errx(1, "cannot open %s: %s", 157 device_name, strerror(errno)); 158 159 if (caph_limit_stdio() < 0) 160 errx(1, "can't limit stdio rights"); 161 caph_cache_catpages(); 162 cap_rights_init(&right_ioctl, CAP_IOCTL); 163 if (caph_rights_limit(fd, &right_ioctl) < 0) 164 errx(1, "cap_right_limit() failed"); 165 if (caph_ioctls_limit(fd, backlight_ioctls, nitems(backlight_ioctls)) < 0) 166 errx(1, "caph_ioctls_limit() failed"); 167 if (caph_enter() < 0) 168 errx(1, "failed to enter capability mode"); 169 170 switch (action) { 171 case BACKLIGHT_QUERY: 172 if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 173 errx(1, "Cannot query the backlight device"); 174 if (quiet) 175 printf("%u\n", props.brightness); 176 else { 177 printf("brightness: %d\n", props.brightness); 178 if (props.nlevels != 0) { 179 printf("levels:"); 180 for (i = 0; i < props.nlevels; i++) 181 printf(" %d", props.levels[i]); 182 printf("\n"); 183 } 184 } 185 break; 186 case BACKLIGHT_SET_BRIGHTNESS: 187 props.brightness = percent; 188 if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 189 errx(1, "Cannot update the backlight device"); 190 break; 191 case BACKLIGHT_INCR: 192 case BACKLIGHT_DECR: 193 if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 194 errx(1, "Cannot query the backlight device"); 195 percent = percent == 0 ? 10 : percent; 196 percent = action == BACKLIGHT_INCR ? percent : -percent; 197 props.brightness += percent; 198 if ((int)props.brightness < 0) 199 props.brightness = 0; 200 if (props.brightness > 100) 201 props.brightness = 100; 202 if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 203 errx(1, "Cannot update the backlight device"); 204 break; 205 case BACKLIGHT_INFO: 206 if (ioctl(fd, BACKLIGHTGETINFO, &info) == -1) 207 errx(1, "Cannot query the backlight device"); 208 if (quiet == false) { 209 printf("Backlight name: %s\n", info.name); 210 printf("Backlight hardware type: %s\n", backlight_type_to_string(info.type)); 211 } else { 212 printf("%s\n", info.name); 213 printf("%s\n", backlight_type_to_string(info.type)); 214 } 215 break; 216 } 217 218 close(fd); 219 return (0); 220 } 221