1 /* $NetBSD: screenblank.c,v 1.7 1997/10/18 11:37:45 lukem 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 FOUNDATION OR CONTRIBUTORS 30 * BE 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/cdefs.h> 44 #ifndef lint 45 __COPYRIGHT( 46 "@(#) Copyright (c) 1996 The NetBSD Foundation, Inc. All rights reserved."); 47 __RCSID("$NetBSD: screenblank.c,v 1.7 1997/10/18 11:37:45 lukem Exp $"); 48 #endif 49 50 #include <sys/types.h> 51 #include <sys/time.h> 52 #include <sys/stat.h> 53 #include <sys/ioctl.h> 54 #include <sys/queue.h> 55 #include <ctype.h> 56 #include <err.h> 57 #include <errno.h> 58 #include <fcntl.h> 59 #include <limits.h> 60 #include <math.h> 61 #include <paths.h> 62 #include <stdlib.h> 63 #include <stdio.h> 64 #include <string.h> 65 #include <signal.h> 66 #include <unistd.h> 67 68 #include <machine/fbio.h> 69 70 #include "pathnames.h" 71 72 struct dev_stat { 73 LIST_ENTRY(dev_stat) ds_link; /* linked list */ 74 char *ds_path; /* path to device */ 75 int ds_isfb; /* boolean; framebuffer? */ 76 time_t ds_atime; /* time device last accessed */ 77 time_t ds_mtime; /* time device last modified */ 78 }; 79 LIST_HEAD(ds_list, dev_stat) ds_list; 80 81 extern char *__progname; 82 83 int main __P((int, char *[])); 84 static void add_dev __P((char *, int)); 85 static void change_state __P((int)); 86 static void cvt_arg __P((char *, struct timeval *)); 87 static void logpid __P((void)); 88 static void sighandler __P((int)); 89 static void usage __P((void)); 90 91 int 92 main(argc, argv) 93 int argc; 94 char *argv[]; 95 { 96 struct dev_stat *dsp; 97 struct timeval timo_on, timo_off, *tvp; 98 struct sigaction sa; 99 struct stat st; 100 int ch, change, fflag = 0, kflag = 0, mflag = 0, state; 101 102 LIST_INIT(&ds_list); 103 104 /* 105 * Set the default timeouts: 10 minutes on, .25 seconds off. 106 */ 107 timo_on.tv_sec = 600; 108 timo_on.tv_usec = 0; 109 timo_off.tv_sec = 0; 110 timo_off.tv_usec = 250000; 111 112 while ((ch = getopt(argc, argv, "d:e:f:km")) != -1) { 113 switch (ch) { 114 case 'd': 115 cvt_arg(optarg, &timo_on); 116 break; 117 118 case 'e': 119 cvt_arg(optarg, &timo_off); 120 break; 121 122 case 'f': 123 fflag = 1; 124 add_dev(optarg, 1); 125 break; 126 127 case 'k': 128 if (mflag || kflag) 129 usage(); 130 kflag = 1; 131 break; 132 133 case 'm': 134 if (kflag || mflag) 135 usage(); 136 mflag = 1; 137 break; 138 139 default: 140 usage(); 141 } 142 } 143 argc -= optind; 144 if (argc) 145 usage(); 146 147 /* 148 * Add the keyboard, mouse, and default framebuffer devices 149 * as necessary. We _always_ check the console device. 150 */ 151 add_dev(_PATH_CONSOLE, 0); 152 if (!kflag) 153 add_dev(_PATH_KEYBOARD, 0); 154 if (!mflag) 155 add_dev(_PATH_MOUSE, 0); 156 if (!fflag) 157 add_dev(_PATH_FB, 1); 158 159 /* Ensure that the framebuffer is on. */ 160 state = FBVIDEO_ON; 161 change_state(state); 162 tvp = &timo_on; 163 164 /* 165 * Make sure the framebuffer gets turned back on when we're 166 * killed. 167 */ 168 sa.sa_handler = sighandler; 169 sa.sa_flags = SA_NOCLDSTOP; 170 if (sigemptyset(&sa.sa_mask)) 171 err(1, "sigemptyset"); 172 if (sigaction(SIGINT, &sa, NULL) || sigaction(SIGTERM, &sa, NULL) || 173 sigaction(SIGHUP, &sa, NULL)) 174 err(1, "sigaction"); 175 176 /* Detach. */ 177 if (daemon(0, 0)) 178 err(1, "daemon"); 179 logpid(); 180 181 /* Start the state machine. */ 182 for (;;) { 183 change = 0; 184 for (dsp = ds_list.lh_first; dsp != NULL; 185 dsp = dsp->ds_link.le_next) { 186 /* Don't check framebuffers. */ 187 if (dsp->ds_isfb) 188 continue; 189 if (stat(dsp->ds_path, &st) < 0) 190 err(1, "stat: %s", dsp->ds_path); 191 if (st.st_atime > dsp->ds_atime) { 192 change = 1; 193 dsp->ds_atime = st.st_atime; 194 } 195 if (st.st_mtime > dsp->ds_mtime) { 196 change = 1; 197 dsp->ds_mtime = st.st_mtime; 198 } 199 } 200 201 switch (state) { 202 case FBVIDEO_ON: 203 if (!change) { 204 state = FBVIDEO_OFF; 205 change_state(state); 206 tvp = &timo_off; 207 } 208 break; 209 210 case FBVIDEO_OFF: 211 if (change) { 212 state = FBVIDEO_ON; 213 change_state(state); 214 tvp = &timo_on; 215 } 216 break; 217 } 218 219 if (select(0, NULL, NULL, NULL, tvp) < 0) 220 err(1, "select"); 221 } 222 /* NOTREACHED */ 223 } 224 225 static void 226 add_dev(path, isfb) 227 char *path; 228 int isfb; 229 { 230 struct dev_stat *dsp1, *dsp2; 231 232 /* Create the entry... */ 233 dsp1 = malloc(sizeof(struct dev_stat)); 234 if (dsp1 == NULL) 235 errx(1, "can't allocate memory for %s", path); 236 memset(dsp1, 0, sizeof(struct dev_stat)); 237 dsp1->ds_path = path; 238 dsp1->ds_isfb = isfb; 239 240 /* ...and put it in the list. */ 241 if (ds_list.lh_first == NULL) { 242 LIST_INSERT_HEAD(&ds_list, dsp1, ds_link); 243 } else { 244 for (dsp2 = ds_list.lh_first; dsp2->ds_link.le_next != NULL; 245 dsp2 = dsp2->ds_link.le_next) 246 /* Nothing. */ ; 247 LIST_INSERT_AFTER(dsp2, dsp1, ds_link); 248 } 249 } 250 251 /* ARGSUSED */ 252 static void 253 sighandler(sig) 254 int sig; 255 { 256 257 /* Kill the pid file and re-enable the framebuffer before exit. */ 258 (void)unlink(_PATH_SCREENBLANKPID); 259 change_state(FBVIDEO_ON); 260 exit(0); 261 } 262 263 static void 264 change_state(state) 265 int state; 266 { 267 struct dev_stat *dsp; 268 int fd; 269 270 for (dsp = ds_list.lh_first; dsp != NULL; dsp = dsp->ds_link.le_next) { 271 /* Don't change the state of non-framebuffers! */ 272 if (dsp->ds_isfb == 0) 273 continue; 274 if ((fd = open(dsp->ds_path, O_RDWR, 0)) < 0) { 275 warn("open: %s", dsp->ds_path); 276 continue; 277 } 278 if (ioctl(fd, FBIOSVIDEO, &state) < 0) 279 warn("ioctl: %s", dsp->ds_path); 280 (void)close(fd); 281 } 282 } 283 284 static void 285 cvt_arg(arg, tvp) 286 char *arg; 287 struct timeval *tvp; 288 { 289 char *cp; 290 double seconds = 0.0, exponent = -1.0; 291 int period = 0; 292 293 for (cp = arg; *cp != '\0'; ++cp) { 294 if (*cp == '.') { 295 if (period) 296 errx(1, "invalid argument: %s", arg); 297 period = 1; 298 continue; 299 } 300 301 if (!isdigit(*cp)) 302 errx(1, "invalid argument: %s", arg); 303 304 if (period) { 305 seconds = seconds + ((*cp - '0') * pow(10.0, exponent)); 306 exponent -= 1.0; 307 } else 308 seconds = (seconds * 10.0) + (*cp - '0'); 309 } 310 311 tvp->tv_sec = (long)seconds; 312 tvp->tv_usec = (long)((seconds - tvp->tv_sec) * 1000000); 313 } 314 315 static void 316 logpid() 317 { 318 FILE *fp; 319 320 if ((fp = fopen(_PATH_SCREENBLANKPID, "w")) != NULL) { 321 fprintf(fp, "%u\n", getpid()); 322 (void)fclose(fp); 323 } 324 } 325 326 static void 327 usage() 328 { 329 330 fprintf(stderr, "usage: %s [-k | -m] [-d timeout] [-e timeout] %s\n", 331 __progname, "[-f framebuffer]"); 332 exit(1); 333 } 334