1 /* $NetBSD: screenblank.c,v 1.3 1996/06/23 22:08:43 thorpej 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, int, struct sigcontext *)); 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, code, context) 246 int sig, code; 247 struct sigcontext *context; 248 { 249 250 /* Kill the pid file and re-enable the framebuffer before exit. */ 251 (void)unlink(_PATH_SCREENBLANKPID); 252 change_state(FBVIDEO_ON); 253 exit(0); 254 } 255 256 static void 257 change_state(state) 258 int state; 259 { 260 struct dev_stat *dsp; 261 int fd; 262 263 for (dsp = ds_list.lh_first; dsp != NULL; dsp = dsp->ds_link.le_next) { 264 /* Don't change the state of non-framebuffers! */ 265 if (dsp->ds_isfb == 0) 266 continue; 267 if ((fd = open(dsp->ds_path, O_RDWR, 0)) < 0) { 268 warn("open: %s", dsp->ds_path); 269 continue; 270 } 271 if (ioctl(fd, FBIOSVIDEO, &state) < 0) 272 warn("ioctl: %s", dsp->ds_path); 273 (void)close(fd); 274 } 275 } 276 277 static void 278 cvt_arg(arg, tvp) 279 char *arg; 280 struct timeval *tvp; 281 { 282 char *cp; 283 double seconds = 0.0, exponent = -1.0; 284 int period = 0; 285 286 for (cp = arg; *cp != '\0'; ++cp) { 287 if (*cp == '.') { 288 if (period) 289 errx(1, "invalid argument: %s", arg); 290 period = 1; 291 continue; 292 } 293 294 if (!isdigit(*cp)) 295 errx(1, "invalid argument: %s", arg); 296 297 if (period) { 298 seconds = seconds + ((*cp - '0') * pow(10.0, exponent)); 299 exponent -= 1.0; 300 } else 301 seconds = (seconds * 10.0) + (*cp - '0'); 302 } 303 304 tvp->tv_sec = (long)seconds; 305 tvp->tv_usec = (long)((seconds - tvp->tv_sec) * 1000000); 306 } 307 308 static void 309 logpid() 310 { 311 FILE *fp; 312 313 if ((fp = fopen(_PATH_SCREENBLANKPID, "w")) != NULL) { 314 fprintf(fp, "%u\n", getpid()); 315 (void)fclose(fp); 316 } 317 } 318 319 static void 320 usage() 321 { 322 323 fprintf(stderr, "usage: %s [-k | -m] [-d timeout] [-e timeout] %s\n", 324 __progname, "[-f framebuffer]"); 325 exit(1); 326 } 327