1 /* $NetBSD: screenblank.c,v 1.4 1997/05/17 15:48:50 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Screensaver daemon for the Sun 3 and SPARC. 41 */ 42 43 #include <sys/types.h> 44 #include <sys/time.h> 45 #include <sys/stat.h> 46 #include <sys/ioctl.h> 47 #include <sys/queue.h> 48 #include <ctype.h> 49 #include <err.h> 50 #include <errno.h> 51 #include <fcntl.h> 52 #include <limits.h> 53 #include <math.h> 54 #include <paths.h> 55 #include <stdlib.h> 56 #include <stdio.h> 57 #include <string.h> 58 #include <signal.h> 59 #include <unistd.h> 60 61 #include <machine/fbio.h> 62 63 #include "pathnames.h" 64 65 struct dev_stat { 66 LIST_ENTRY(dev_stat) ds_link; /* linked list */ 67 char *ds_path; /* path to device */ 68 int ds_isfb; /* boolean; framebuffer? */ 69 time_t ds_atime; /* time device last accessed */ 70 time_t ds_mtime; /* time device last modified */ 71 }; 72 LIST_HEAD(ds_list, dev_stat) ds_list; 73 74 extern char *__progname; 75 76 static void add_dev __P((char *, int)); 77 static void change_state __P((int)); 78 static void cvt_arg __P((char *, struct timeval *)); 79 static void logpid __P((void)); 80 static void sighandler __P((int)); 81 static void usage __P((void)); 82 83 int 84 main(argc, argv) 85 int argc; 86 char **argv; 87 { 88 struct dev_stat *dsp; 89 struct timeval timo_on, timo_off, *tvp; 90 struct sigaction sa; 91 struct stat st; 92 int ch, change, fflag = 0, kflag = 0, mflag = 0, state; 93 94 LIST_INIT(&ds_list); 95 96 /* 97 * Set the default timeouts: 10 minutes on, .25 seconds off. 98 */ 99 timo_on.tv_sec = 600; 100 timo_on.tv_usec = 0; 101 timo_off.tv_sec = 0; 102 timo_off.tv_usec = 250000; 103 104 while ((ch = getopt(argc, argv, "d:e:f:km")) != -1) { 105 switch (ch) { 106 case 'd': 107 cvt_arg(optarg, &timo_on); 108 break; 109 110 case 'e': 111 cvt_arg(optarg, &timo_off); 112 break; 113 114 case 'f': 115 fflag = 1; 116 add_dev(optarg, 1); 117 break; 118 119 case 'k': 120 if (mflag || kflag) 121 usage(); 122 kflag = 1; 123 break; 124 125 case 'm': 126 if (kflag || mflag) 127 usage(); 128 mflag = 1; 129 break; 130 131 default: 132 usage(); 133 } 134 } 135 argc -= optind; 136 if (argc) 137 usage(); 138 139 /* 140 * Add the keyboard, mouse, and default framebuffer devices 141 * as necessary. We _always_ check the console device. 142 */ 143 add_dev(_PATH_CONSOLE, 0); 144 if (!kflag) 145 add_dev(_PATH_KEYBOARD, 0); 146 if (!mflag) 147 add_dev(_PATH_MOUSE, 0); 148 if (!fflag) 149 add_dev(_PATH_FB, 1); 150 151 /* Ensure that the framebuffer is on. */ 152 state = FBVIDEO_ON; 153 change_state(state); 154 tvp = &timo_on; 155 156 /* 157 * Make sure the framebuffer gets turned back on when we're 158 * killed. 159 */ 160 sa.sa_handler = sighandler; 161 sa.sa_flags = SA_NOCLDSTOP; 162 if (sigemptyset(&sa.sa_mask)) 163 err(1, "sigemptyset"); 164 if (sigaction(SIGINT, &sa, NULL) || sigaction(SIGTERM, &sa, NULL) || 165 sigaction(SIGHUP, &sa, NULL)) 166 err(1, "sigaction"); 167 168 /* Detach. */ 169 if (daemon(0, 0)) 170 err(1, "daemon"); 171 logpid(); 172 173 /* Start the state machine. */ 174 for (;;) { 175 change = 0; 176 for (dsp = ds_list.lh_first; dsp != NULL; 177 dsp = dsp->ds_link.le_next) { 178 /* Don't check framebuffers. */ 179 if (dsp->ds_isfb) 180 continue; 181 if (stat(dsp->ds_path, &st) < 0) 182 err(1, "stat: %s", dsp->ds_path); 183 if (st.st_atime > dsp->ds_atime) { 184 change = 1; 185 dsp->ds_atime = st.st_atime; 186 } 187 if (st.st_mtime > dsp->ds_mtime) { 188 change = 1; 189 dsp->ds_mtime = st.st_mtime; 190 } 191 } 192 193 switch (state) { 194 case FBVIDEO_ON: 195 if (!change) { 196 state = FBVIDEO_OFF; 197 change_state(state); 198 tvp = &timo_off; 199 } 200 break; 201 202 case FBVIDEO_OFF: 203 if (change) { 204 state = FBVIDEO_ON; 205 change_state(state); 206 tvp = &timo_on; 207 } 208 break; 209 } 210 211 if (select(0, NULL, NULL, NULL, tvp) < 0) 212 err(1, "select"); 213 } 214 /* NOTREACHED */ 215 } 216 217 static void 218 add_dev(path, isfb) 219 char *path; 220 int isfb; 221 { 222 struct dev_stat *dsp1, *dsp2; 223 224 /* Create the entry... */ 225 dsp1 = malloc(sizeof(struct dev_stat)); 226 if (dsp1 == NULL) 227 errx(1, "can't allocate memory for %s", path); 228 bzero(dsp1, sizeof(struct dev_stat)); 229 dsp1->ds_path = path; 230 dsp1->ds_isfb = isfb; 231 232 /* ...and put it in the list. */ 233 if (ds_list.lh_first == NULL) { 234 LIST_INSERT_HEAD(&ds_list, dsp1, ds_link); 235 } else { 236 for (dsp2 = ds_list.lh_first; dsp2->ds_link.le_next != NULL; 237 dsp2 = dsp2->ds_link.le_next) 238 /* Nothing. */ ; 239 LIST_INSERT_AFTER(dsp2, dsp1, ds_link); 240 } 241 } 242 243 /* ARGSUSED */ 244 static void 245 sighandler(sig) 246 int sig; 247 { 248 249 /* Kill the pid file and re-enable the framebuffer before exit. */ 250 (void)unlink(_PATH_SCREENBLANKPID); 251 change_state(FBVIDEO_ON); 252 exit(0); 253 } 254 255 static void 256 change_state(state) 257 int state; 258 { 259 struct dev_stat *dsp; 260 int fd; 261 262 for (dsp = ds_list.lh_first; dsp != NULL; dsp = dsp->ds_link.le_next) { 263 /* Don't change the state of non-framebuffers! */ 264 if (dsp->ds_isfb == 0) 265 continue; 266 if ((fd = open(dsp->ds_path, O_RDWR, 0)) < 0) { 267 warn("open: %s", dsp->ds_path); 268 continue; 269 } 270 if (ioctl(fd, FBIOSVIDEO, &state) < 0) 271 warn("ioctl: %s", dsp->ds_path); 272 (void)close(fd); 273 } 274 } 275 276 static void 277 cvt_arg(arg, tvp) 278 char *arg; 279 struct timeval *tvp; 280 { 281 char *cp; 282 double seconds = 0.0, exponent = -1.0; 283 int period = 0; 284 285 for (cp = arg; *cp != '\0'; ++cp) { 286 if (*cp == '.') { 287 if (period) 288 errx(1, "invalid argument: %s", arg); 289 period = 1; 290 continue; 291 } 292 293 if (!isdigit(*cp)) 294 errx(1, "invalid argument: %s", arg); 295 296 if (period) { 297 seconds = seconds + ((*cp - '0') * pow(10.0, exponent)); 298 exponent -= 1.0; 299 } else 300 seconds = (seconds * 10.0) + (*cp - '0'); 301 } 302 303 tvp->tv_sec = (long)seconds; 304 tvp->tv_usec = (long)((seconds - tvp->tv_sec) * 1000000); 305 } 306 307 static void 308 logpid() 309 { 310 FILE *fp; 311 312 if ((fp = fopen(_PATH_SCREENBLANKPID, "w")) != NULL) { 313 fprintf(fp, "%u\n", getpid()); 314 (void)fclose(fp); 315 } 316 } 317 318 static void 319 usage() 320 { 321 322 fprintf(stderr, "usage: %s [-k | -m] [-d timeout] [-e timeout] %s\n", 323 __progname, "[-f framebuffer]"); 324 exit(1); 325 } 326