1 1.29 andvar /* $NetBSD: wsmoused.c,v 1.29 2022/05/20 21:31:24 andvar Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.14 jmmv * Copyright (c) 2002, 2003, 2004 The NetBSD Foundation, Inc. 5 1.1 christos * All rights reserved. 6 1.1 christos * 7 1.1 christos * This code is derived from software contributed to The NetBSD Foundation 8 1.11 jmmv * by Julio M. Merino Vidal. 9 1.1 christos * 10 1.1 christos * Redistribution and use in source and binary forms, with or without 11 1.1 christos * modification, are permitted provided that the following conditions 12 1.1 christos * are met: 13 1.1 christos * 1. Redistributions of source code must retain the above copyright 14 1.1 christos * notice, this list of conditions and the following disclaimer. 15 1.1 christos * 2. The name authors may not be used to endorse or promote products 16 1.1 christos * derived from this software without specific prior written 17 1.1 christos * permission. 18 1.1 christos * 19 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS 20 1.1 christos * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 1.1 christos * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 23 1.1 christos * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 25 1.1 christos * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 christos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 1.1 christos * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 1.1 christos * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 1.1 christos * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 1.1 christos */ 31 1.1 christos 32 1.1 christos #include <sys/cdefs.h> 33 1.1 christos 34 1.1 christos #ifndef lint 35 1.23 lukem __COPYRIGHT("@(#) Copyright (c) 2002, 2003\ 36 1.23 lukem The NetBSD Foundation, Inc. All rights reserved."); 37 1.29 andvar __RCSID("$NetBSD: wsmoused.c,v 1.29 2022/05/20 21:31:24 andvar Exp $"); 38 1.1 christos #endif /* not lint */ 39 1.1 christos 40 1.1 christos #include <sys/ioctl.h> 41 1.1 christos #include <sys/time.h> 42 1.1 christos #include <sys/types.h> 43 1.1 christos #include <sys/tty.h> 44 1.1 christos #include <dev/wscons/wsconsio.h> 45 1.1 christos 46 1.1 christos #include <err.h> 47 1.22 dholland #include <errno.h> 48 1.1 christos #include <fcntl.h> 49 1.1 christos #include <poll.h> 50 1.1 christos #include <signal.h> 51 1.1 christos #include <stdio.h> 52 1.13 jmmv #include <stdarg.h> 53 1.13 jmmv #include <stdlib.h> 54 1.1 christos #include <string.h> 55 1.13 jmmv #include <syslog.h> 56 1.1 christos #include <unistd.h> 57 1.9 jmmv #include <util.h> 58 1.1 christos 59 1.1 christos #include "pathnames.h" 60 1.1 christos #include "wsmoused.h" 61 1.1 christos 62 1.11 jmmv /* --------------------------------------------------------------------- */ 63 1.1 christos 64 1.1 christos /* 65 1.11 jmmv * Global variables. 66 1.1 christos */ 67 1.11 jmmv 68 1.11 jmmv static struct mouse Mouse; 69 1.11 jmmv static char *Pid_File = NULL; 70 1.13 jmmv static int Foreground = 1; 71 1.11 jmmv static int X_Console = -1; 72 1.16 jmmv static int X_Console_Delay = 5; 73 1.11 jmmv 74 1.27 mlelstv #ifdef WSMOUSED_ACTION_MODE 75 1.12 jmmv extern struct mode_bootstrap Action_Mode; 76 1.12 jmmv #endif 77 1.12 jmmv #ifdef WSMOUSED_SELECTION_MODE 78 1.11 jmmv extern struct mode_bootstrap Selection_Mode; 79 1.11 jmmv #endif 80 1.11 jmmv 81 1.12 jmmv #define MAX_MODES 2 82 1.11 jmmv static struct mode_bootstrap *Modes[MAX_MODES]; 83 1.11 jmmv static struct mode_bootstrap *Avail_Modes[] = { 84 1.12 jmmv #ifdef WSMOUSED_ACTION_MODE 85 1.12 jmmv &Action_Mode, 86 1.12 jmmv #endif 87 1.11 jmmv #ifdef WSMOUSED_SELECTION_MODE 88 1.11 jmmv &Selection_Mode, 89 1.11 jmmv #endif 90 1.11 jmmv }; 91 1.11 jmmv 92 1.11 jmmv /* --------------------------------------------------------------------- */ 93 1.11 jmmv 94 1.11 jmmv /* 95 1.11 jmmv * Prototypes for functions private to this module. 96 1.11 jmmv */ 97 1.11 jmmv 98 1.26 christos static void usage(void) __attribute__((__noreturn__)); 99 1.11 jmmv static void open_device(unsigned int); 100 1.11 jmmv static void init_mouse(void); 101 1.11 jmmv static void event_loop(void); 102 1.11 jmmv static void generic_wscons_event(struct wscons_event); 103 1.11 jmmv static int attach_mode(const char *); 104 1.11 jmmv static void attach_modes(char *); 105 1.11 jmmv static void detach_mode(const char *); 106 1.11 jmmv static void detach_modes(void); 107 1.11 jmmv static void signal_terminate(int); 108 1.26 christos 109 1.26 christos static int debug; 110 1.11 jmmv 111 1.11 jmmv /* --------------------------------------------------------------------- */ 112 1.11 jmmv 113 1.11 jmmv /* Shows program usage information and exits. */ 114 1.1 christos static void 115 1.1 christos usage(void) 116 1.1 christos { 117 1.11 jmmv 118 1.1 christos (void)fprintf(stderr, 119 1.17 jmmv "usage: %s [-d device] [-f config_file] [-m modes] [-n]\n", 120 1.1 christos getprogname()); 121 1.1 christos exit(EXIT_FAILURE); 122 1.1 christos } 123 1.1 christos 124 1.11 jmmv /* --------------------------------------------------------------------- */ 125 1.1 christos 126 1.13 jmmv /* Logs the given error message to syslog if running in daemon mode, or 127 1.13 jmmv * to the console if running in the foreground. */ 128 1.13 jmmv void 129 1.13 jmmv log_err(int e, const char *fmt, ...) 130 1.13 jmmv { 131 1.13 jmmv va_list ap; 132 1.13 jmmv 133 1.13 jmmv va_start(ap, fmt); 134 1.13 jmmv if (Foreground) 135 1.13 jmmv verr(e, fmt, ap); 136 1.13 jmmv else { 137 1.13 jmmv int olderrno = errno; 138 1.13 jmmv vsyslog(LOG_DAEMON | LOG_ERR, fmt, ap); 139 1.13 jmmv errno = olderrno; 140 1.13 jmmv syslog(LOG_DAEMON | LOG_ERR, "%m"); 141 1.13 jmmv exit(e); 142 1.13 jmmv } 143 1.13 jmmv /* NOTREACHED */ 144 1.13 jmmv va_end(ap); 145 1.13 jmmv } 146 1.13 jmmv 147 1.13 jmmv /* --------------------------------------------------------------------- */ 148 1.13 jmmv 149 1.13 jmmv /* Logs the given error message to syslog if running in daemon mode, or 150 1.13 jmmv * to the console if running in the foreground. */ 151 1.13 jmmv void 152 1.13 jmmv log_errx(int e, const char *fmt, ...) 153 1.13 jmmv { 154 1.13 jmmv va_list ap; 155 1.13 jmmv 156 1.13 jmmv va_start(ap, fmt); 157 1.13 jmmv if (Foreground) 158 1.13 jmmv verrx(e, fmt, ap); 159 1.13 jmmv else { 160 1.13 jmmv vsyslog(LOG_DAEMON | LOG_ERR, fmt, ap); 161 1.13 jmmv exit(e); 162 1.13 jmmv } 163 1.13 jmmv /* NOTREACHED */ 164 1.13 jmmv va_end(ap); 165 1.13 jmmv } 166 1.13 jmmv 167 1.13 jmmv /* --------------------------------------------------------------------- */ 168 1.13 jmmv 169 1.13 jmmv /* Logs the given info message to syslog if running in daemon mode, or 170 1.13 jmmv * to the console if running in the foreground. */ 171 1.13 jmmv void 172 1.13 jmmv log_info(const char *fmt, ...) 173 1.13 jmmv { 174 1.13 jmmv va_list ap; 175 1.13 jmmv 176 1.13 jmmv va_start(ap, fmt); 177 1.20 jmmv if (Foreground) { 178 1.13 jmmv vfprintf(stderr, fmt, ap); 179 1.20 jmmv fprintf(stderr, "\n"); 180 1.20 jmmv } else 181 1.13 jmmv vsyslog(LOG_DAEMON | LOG_INFO, fmt, ap); 182 1.13 jmmv va_end(ap); 183 1.13 jmmv } 184 1.13 jmmv 185 1.13 jmmv /* --------------------------------------------------------------------- */ 186 1.13 jmmv 187 1.13 jmmv /* Logs the given warning message to syslog if running in daemon mode, or 188 1.13 jmmv * to the console if running in the foreground. */ 189 1.13 jmmv void 190 1.13 jmmv log_warn(const char *fmt, ...) 191 1.13 jmmv { 192 1.13 jmmv va_list ap; 193 1.13 jmmv 194 1.13 jmmv va_start(ap, fmt); 195 1.13 jmmv if (Foreground) 196 1.13 jmmv vwarn(fmt, ap); 197 1.13 jmmv else { 198 1.13 jmmv int olderrno = errno; 199 1.13 jmmv vsyslog(LOG_DAEMON | LOG_WARNING, fmt, ap); 200 1.13 jmmv errno = olderrno; 201 1.13 jmmv syslog(LOG_DAEMON | LOG_WARNING, "%m"); 202 1.13 jmmv } 203 1.13 jmmv va_end(ap); 204 1.13 jmmv } 205 1.13 jmmv 206 1.13 jmmv /* --------------------------------------------------------------------- */ 207 1.13 jmmv 208 1.13 jmmv /* Logs the given warning message to syslog if running in daemon mode, or 209 1.13 jmmv * to the console if running in the foreground. */ 210 1.13 jmmv void 211 1.13 jmmv log_warnx(const char *fmt, ...) 212 1.13 jmmv { 213 1.13 jmmv va_list ap; 214 1.13 jmmv 215 1.13 jmmv va_start(ap, fmt); 216 1.13 jmmv if (Foreground) 217 1.13 jmmv vwarnx(fmt, ap); 218 1.13 jmmv else 219 1.13 jmmv vsyslog(LOG_DAEMON | LOG_WARNING, fmt, ap); 220 1.13 jmmv va_end(ap); 221 1.13 jmmv } 222 1.13 jmmv 223 1.13 jmmv /* --------------------------------------------------------------------- */ 224 1.13 jmmv 225 1.11 jmmv /* Initializes mouse information. Basically, it opens required files 226 1.11 jmmv * for the daemon to work. */ 227 1.1 christos static void 228 1.11 jmmv init_mouse(void) 229 1.1 christos { 230 1.1 christos 231 1.11 jmmv Mouse.m_devfd = -1; 232 1.11 jmmv open_device(0); 233 1.1 christos 234 1.11 jmmv /* Open FIFO, if wanted */ 235 1.11 jmmv Mouse.m_fifofd = -1; 236 1.11 jmmv if (Mouse.m_fifoname != NULL) { 237 1.11 jmmv Mouse.m_fifofd = open(Mouse.m_fifoname, 238 1.11 jmmv O_RDWR | O_NONBLOCK, 0); 239 1.11 jmmv if (Mouse.m_fifofd == -1) 240 1.13 jmmv log_err(EXIT_FAILURE, "cannot open %s", 241 1.13 jmmv Mouse.m_fifoname); 242 1.1 christos } 243 1.1 christos } 244 1.1 christos 245 1.11 jmmv /* --------------------------------------------------------------------- */ 246 1.11 jmmv 247 1.11 jmmv /* Opens the mouse device (if not already opened). The argument `secs' 248 1.11 jmmv * specifies how much seconds the function will wait before trying to 249 1.11 jmmv * open the device; this is used when returning from the X console. */ 250 1.1 christos static void 251 1.11 jmmv open_device(unsigned int secs) 252 1.1 christos { 253 1.28 uwe int status; 254 1.1 christos 255 1.11 jmmv if (Mouse.m_devfd != -1) 256 1.11 jmmv return; 257 1.11 jmmv 258 1.11 jmmv sleep(secs); 259 1.1 christos 260 1.11 jmmv /* Open mouse file descriptor */ 261 1.11 jmmv Mouse.m_devfd = open(Mouse.m_devname, O_RDONLY | O_NONBLOCK, 0); 262 1.11 jmmv if (Mouse.m_devfd == -1) 263 1.13 jmmv log_err(EXIT_FAILURE, "cannot open %s", Mouse.m_devname); 264 1.24 christos 265 1.28 uwe const int version = WSMOUSE_EVENT_VERSION; 266 1.28 uwe status = ioctl(Mouse.m_devfd, WSMOUSEIO_SETVERSION, &version); 267 1.28 uwe if (status == -1) 268 1.24 christos log_err(EXIT_FAILURE, "cannot set version %s", Mouse.m_devname); 269 1.28 uwe 270 1.28 uwe 271 1.28 uwe /* 272 1.28 uwe * Get calibration data for touch panel. Not fatal if we can't. 273 1.28 uwe */ 274 1.28 uwe Mouse.m_doabs = 0; 275 1.28 uwe 276 1.28 uwe unsigned int mouse_type = 0; /* defined WSMOUSE_TYPE_* start at 1 */ 277 1.28 uwe status = ioctl(Mouse.m_devfd, WSMOUSEIO_GTYPE, &mouse_type); 278 1.28 uwe if (status == -1) { 279 1.28 uwe log_warn("WSMOUSEIO_GTYPE"); 280 1.28 uwe return; 281 1.28 uwe } 282 1.28 uwe 283 1.28 uwe /* absolute position events make no sense for free-ranging mice */ 284 1.28 uwe if (mouse_type != WSMOUSE_TYPE_TPANEL) 285 1.28 uwe return; 286 1.28 uwe 287 1.28 uwe status = ioctl(Mouse.m_devfd, WSMOUSEIO_GCALIBCOORDS, &Mouse.m_calib); 288 1.28 uwe if (status == -1) { 289 1.28 uwe log_warn("WSMOUSEIO_GCALIBCOORDS"); 290 1.28 uwe return; 291 1.28 uwe } 292 1.28 uwe 293 1.28 uwe Mouse.m_doabs = 1; 294 1.1 christos } 295 1.1 christos 296 1.28 uwe 297 1.11 jmmv /* --------------------------------------------------------------------- */ 298 1.11 jmmv 299 1.11 jmmv /* Main program event loop. This function polls the wscons status 300 1.11 jmmv * device and the mouse device; whenever an event is received, the 301 1.29 andvar * appropriate callback is fired for all attached modes. If the polls 302 1.29 andvar * times out (which only happens when the mouse is disabled), another 303 1.11 jmmv * callback is launched. */ 304 1.1 christos static void 305 1.1 christos event_loop(void) 306 1.1 christos { 307 1.11 jmmv int i, res; 308 1.1 christos struct pollfd fds[2]; 309 1.1 christos struct wscons_event event; 310 1.1 christos 311 1.11 jmmv fds[0].fd = Mouse.m_statfd; 312 1.1 christos fds[0].events = POLLIN; 313 1.1 christos 314 1.1 christos for (;;) { 315 1.11 jmmv fds[1].fd = Mouse.m_devfd; 316 1.1 christos fds[1].events = POLLIN; 317 1.11 jmmv if (Mouse.m_disabled) 318 1.1 christos res = poll(fds, 1, INFTIM); 319 1.1 christos else 320 1.1 christos res = poll(fds, 2, 300); 321 1.4 christos 322 1.1 christos if (res < 0) 323 1.13 jmmv log_warn("failed to read from devices"); 324 1.1 christos 325 1.1 christos if (fds[0].revents & POLLIN) { 326 1.11 jmmv res = read(Mouse.m_statfd, &event, sizeof(event)); 327 1.26 christos if (debug) 328 1.26 christos (void)fprintf(stderr, "event [type=%u,value=%d," 329 1.26 christos "time=[%lld,%ld]\n", event.type, 330 1.26 christos event.value, (long long)event.time.tv_sec, 331 1.26 christos (long)event.time.tv_nsec); 332 1.1 christos if (res != sizeof(event)) 333 1.13 jmmv log_warn("failed to read from mouse stat"); 334 1.11 jmmv 335 1.15 jmmv for (i = 0; i < MAX_MODES && Modes[i] != NULL; i++) 336 1.15 jmmv if (Modes[i]->mb_wscons_event != NULL) 337 1.18 matt Modes[i]->mb_wscons_event(event, 1); 338 1.15 jmmv 339 1.11 jmmv generic_wscons_event(event); 340 1.11 jmmv 341 1.11 jmmv for (i = 0; i < MAX_MODES && Modes[i] != NULL; i++) 342 1.11 jmmv if (Modes[i]->mb_wscons_event != NULL) 343 1.18 matt Modes[i]->mb_wscons_event(event, 0); 344 1.11 jmmv 345 1.1 christos } else if (fds[1].revents & POLLIN) { 346 1.11 jmmv res = read(Mouse.m_devfd, &event, sizeof(event)); 347 1.1 christos if (res != sizeof(event)) 348 1.13 jmmv log_warn("failed to read from mouse"); 349 1.1 christos 350 1.26 christos if (debug) 351 1.26 christos (void)fprintf(stderr, "event [type=%u,value=%d," 352 1.26 christos "time=[%lld,%ld]\n", event.type, 353 1.26 christos event.value, (long long)event.time.tv_sec, 354 1.26 christos (long)event.time.tv_nsec); 355 1.11 jmmv if (Mouse.m_fifofd >= 0) { 356 1.11 jmmv res = write(Mouse.m_fifofd, &event, 357 1.1 christos sizeof(event)); 358 1.1 christos if (res != sizeof(event)) 359 1.13 jmmv log_warn("failed to write to fifo"); 360 1.1 christos } 361 1.1 christos 362 1.11 jmmv for (i = 0; i < MAX_MODES && Modes[i] != NULL; i++) 363 1.11 jmmv if (Modes[i]->mb_wsmouse_event != NULL) 364 1.11 jmmv Modes[i]->mb_wsmouse_event(event); 365 1.11 jmmv } else { 366 1.11 jmmv for (i = 0; i < MAX_MODES && Modes[i] != NULL; i++) 367 1.11 jmmv if (Modes[i]->mb_poll_timeout != NULL) 368 1.11 jmmv Modes[i]->mb_poll_timeout(); 369 1.11 jmmv } 370 1.1 christos } 371 1.1 christos } 372 1.1 christos 373 1.11 jmmv /* --------------------------------------------------------------------- */ 374 1.11 jmmv 375 1.11 jmmv /* This function parses generic wscons status events. Actually, it 376 1.11 jmmv * handles the screen switch event to enable or disable the mouse, 377 1.11 jmmv * depending if we are entering or leaving the X console. */ 378 1.1 christos static void 379 1.11 jmmv generic_wscons_event(struct wscons_event evt) 380 1.1 christos { 381 1.1 christos 382 1.11 jmmv switch (evt.type) { 383 1.11 jmmv case WSCONS_EVENT_SCREEN_SWITCH: 384 1.11 jmmv if (evt.value == X_Console) { 385 1.11 jmmv Mouse.m_disabled = 1; 386 1.11 jmmv (void)close(Mouse.m_devfd); 387 1.11 jmmv Mouse.m_devfd = -1; 388 1.11 jmmv } else { 389 1.11 jmmv if (Mouse.m_disabled) { 390 1.16 jmmv open_device(X_Console_Delay); 391 1.11 jmmv Mouse.m_disabled = 0; 392 1.11 jmmv } else { 393 1.11 jmmv (void)close(Mouse.m_devfd); 394 1.11 jmmv Mouse.m_devfd = -1; 395 1.11 jmmv open_device(0); 396 1.11 jmmv } 397 1.11 jmmv } 398 1.11 jmmv break; 399 1.11 jmmv } 400 1.1 christos } 401 1.1 christos 402 1.11 jmmv /* --------------------------------------------------------------------- */ 403 1.11 jmmv 404 1.11 jmmv /* Attaches a mode to the list of active modes, based on its name. 405 1.11 jmmv * Returns 1 on success or 0 if the mode fails to initialize or there is 406 1.11 jmmv * any other problem. */ 407 1.11 jmmv static int 408 1.11 jmmv attach_mode(const char *name) 409 1.11 jmmv { 410 1.11 jmmv int i, pos; 411 1.11 jmmv struct mode_bootstrap *mb; 412 1.11 jmmv 413 1.11 jmmv for (i = 0, pos = -1; i < MAX_MODES; i++) 414 1.11 jmmv if (Modes[i] == NULL) { 415 1.11 jmmv pos = i; 416 1.11 jmmv break; 417 1.11 jmmv } 418 1.11 jmmv if (pos == -1) { 419 1.13 jmmv log_warnx("modes table full; cannot register `%s'", name); 420 1.11 jmmv return 0; 421 1.11 jmmv } 422 1.11 jmmv 423 1.11 jmmv for (i = 0; i < MAX_MODES; i++) { 424 1.11 jmmv mb = Avail_Modes[i]; 425 1.11 jmmv if (mb != NULL && strcmp(name, mb->mb_name) == 0) { 426 1.11 jmmv int res; 427 1.11 jmmv 428 1.11 jmmv res = mb->mb_startup(&Mouse); 429 1.11 jmmv if (res == 0) { 430 1.13 jmmv log_warnx("startup failed for `%s' mode", 431 1.11 jmmv mb->mb_name); 432 1.11 jmmv return 0; 433 1.11 jmmv } else { 434 1.11 jmmv Modes[pos] = mb; 435 1.11 jmmv return 1; 436 1.11 jmmv } 437 1.11 jmmv } 438 1.11 jmmv } 439 1.11 jmmv 440 1.13 jmmv log_warnx("unknown mode `%s' (see the `modes' directive)", name); 441 1.11 jmmv return 0; 442 1.1 christos } 443 1.1 christos 444 1.11 jmmv /* --------------------------------------------------------------------- */ 445 1.11 jmmv 446 1.11 jmmv /* Attaches all modes given in the whitespace separated string `list'. 447 1.11 jmmv * A fatal error is produced if no active modes can be attached. */ 448 1.11 jmmv static void 449 1.11 jmmv attach_modes(char *list) 450 1.1 christos { 451 1.11 jmmv char *last, *p; 452 1.11 jmmv int count; 453 1.11 jmmv 454 1.11 jmmv /* Attach all requested modes */ 455 1.21 jmmv (void)memset(&Modes, 0, sizeof(struct mode_bootstrap *) * MAX_MODES); 456 1.11 jmmv for (count = 0, (p = strtok_r(list, " ", &last)); p; 457 1.11 jmmv (p = strtok_r(NULL, " ", &last))) { 458 1.11 jmmv if (attach_mode(p)) 459 1.11 jmmv count++; 460 1.11 jmmv } 461 1.11 jmmv 462 1.11 jmmv if (count == 0) 463 1.13 jmmv log_errx(EXIT_FAILURE, "no active modes found; exiting..."); 464 1.1 christos } 465 1.1 christos 466 1.11 jmmv /* --------------------------------------------------------------------- */ 467 1.11 jmmv 468 1.11 jmmv /* Detaches a mode from the active modes list based on its name. */ 469 1.11 jmmv static void 470 1.11 jmmv detach_mode(const char *name) 471 1.1 christos { 472 1.11 jmmv int i; 473 1.11 jmmv struct mode_bootstrap *mb; 474 1.1 christos 475 1.11 jmmv for (i = 0; i < MAX_MODES; i++) { 476 1.11 jmmv mb = Modes[i]; 477 1.11 jmmv if (mb != NULL && strcmp(name, mb->mb_name) == 0) { 478 1.11 jmmv int res; 479 1.11 jmmv 480 1.11 jmmv res = mb->mb_cleanup(); 481 1.11 jmmv if (res == 0) { 482 1.13 jmmv log_warnx("cleanup failed for `%s' mode", 483 1.11 jmmv mb->mb_name); 484 1.11 jmmv return; 485 1.11 jmmv } else { 486 1.11 jmmv Modes[i] = NULL; 487 1.11 jmmv return; 488 1.11 jmmv } 489 1.11 jmmv } 490 1.1 christos } 491 1.11 jmmv 492 1.13 jmmv log_warnx("unknown mode `%s' (see the `modes' directive)", name); 493 1.1 christos } 494 1.1 christos 495 1.11 jmmv /* --------------------------------------------------------------------- */ 496 1.11 jmmv 497 1.11 jmmv /* Detaches all active modes. */ 498 1.11 jmmv static void 499 1.11 jmmv detach_modes(void) 500 1.1 christos { 501 1.11 jmmv int i; 502 1.1 christos 503 1.11 jmmv for (i = 0; i < MAX_MODES && Modes[i] != NULL; i++) 504 1.11 jmmv detach_mode(Modes[i]->mb_name); 505 1.11 jmmv } 506 1.1 christos 507 1.11 jmmv /* --------------------------------------------------------------------- */ 508 1.1 christos 509 1.11 jmmv /* Signal handler for close signals. The program can only be exited 510 1.11 jmmv * through this function. */ 511 1.11 jmmv /* ARGSUSED */ 512 1.11 jmmv static void 513 1.11 jmmv signal_terminate(int sig) 514 1.11 jmmv { 515 1.1 christos 516 1.11 jmmv detach_modes(); 517 1.11 jmmv config_free(); 518 1.11 jmmv exit(EXIT_SUCCESS); 519 1.1 christos } 520 1.1 christos 521 1.11 jmmv /* --------------------------------------------------------------------- */ 522 1.11 jmmv 523 1.11 jmmv /* Main program. Parses command line options, reads the configuration 524 1.11 jmmv * file, initializes the mouse and associated files and launches the main 525 1.11 jmmv * event loop. */ 526 1.1 christos int 527 1.1 christos main(int argc, char **argv) 528 1.1 christos { 529 1.11 jmmv char *conffile, *modelist, *tstat; 530 1.11 jmmv int needconf, nodaemon, opt; 531 1.11 jmmv struct block *conf; 532 1.1 christos 533 1.1 christos setprogname(argv[0]); 534 1.1 christos 535 1.11 jmmv (void)memset(&Mouse, 0, sizeof(struct mouse)); 536 1.7 jmmv conffile = _PATH_CONF; 537 1.11 jmmv modelist = NULL; 538 1.11 jmmv needconf = 0; 539 1.11 jmmv nodaemon = -1; 540 1.6 jmmv 541 1.1 christos /* Parse command line options */ 542 1.26 christos while ((opt = getopt(argc, argv, "Dd:f:m:n")) != -1) { 543 1.1 christos switch (opt) { 544 1.26 christos case 'D': 545 1.26 christos debug++; 546 1.26 christos break; 547 1.1 christos case 'd': /* Mouse device name */ 548 1.11 jmmv Mouse.m_devname = optarg; 549 1.1 christos break; 550 1.7 jmmv case 'f': /* Configuration file name */ 551 1.7 jmmv needconf = 1; 552 1.7 jmmv conffile = optarg; 553 1.1 christos break; 554 1.11 jmmv case 'm': /* List of modes to activate */ 555 1.11 jmmv modelist = optarg; 556 1.11 jmmv break; 557 1.1 christos case 'n': /* No daemon */ 558 1.7 jmmv nodaemon = 1; 559 1.1 christos break; 560 1.1 christos default: 561 1.1 christos usage(); 562 1.1 christos /* NOTREACHED */ 563 1.1 christos } 564 1.1 christos } 565 1.1 christos 566 1.11 jmmv /* Read the configuration file and get some basic properties */ 567 1.7 jmmv config_read(conffile, needconf); 568 1.11 jmmv conf = config_get_mode("Global"); 569 1.11 jmmv if (nodaemon == -1) 570 1.11 jmmv nodaemon = block_get_propval_int(conf, "nodaemon", 0); 571 1.11 jmmv X_Console = block_get_propval_int(conf, "xconsole", -1); 572 1.16 jmmv X_Console_Delay = block_get_propval_int(conf, "xconsole_delay", 573 1.16 jmmv X_Console_Delay); 574 1.7 jmmv 575 1.11 jmmv /* Open wsdisplay status device */ 576 1.11 jmmv tstat = block_get_propval(conf, "ttystat", _PATH_TTYSTAT); 577 1.11 jmmv Mouse.m_statfd = open(tstat, O_RDONLY | O_NONBLOCK, 0); 578 1.11 jmmv if (Mouse.m_statfd == -1) 579 1.13 jmmv log_err(EXIT_FAILURE, "cannot open %s", tstat); 580 1.11 jmmv 581 1.11 jmmv /* Initialize mouse information and attach modes */ 582 1.11 jmmv if (Mouse.m_devname == NULL) 583 1.11 jmmv Mouse.m_devname = block_get_propval(conf, "device", 584 1.7 jmmv _PATH_DEFAULT_MOUSE); 585 1.14 jmmv Mouse.m_fifoname = block_get_propval(conf, "fifo", NULL); 586 1.11 jmmv init_mouse(); 587 1.11 jmmv if (modelist != NULL) 588 1.11 jmmv attach_modes(modelist); 589 1.11 jmmv else 590 1.11 jmmv attach_modes(block_get_propval(conf, "modes", "selection")); 591 1.1 christos 592 1.1 christos /* Setup signal handlers */ 593 1.1 christos (void)signal(SIGINT, signal_terminate); 594 1.1 christos (void)signal(SIGKILL, signal_terminate); 595 1.1 christos (void)signal(SIGQUIT, signal_terminate); 596 1.1 christos (void)signal(SIGTERM, signal_terminate); 597 1.1 christos 598 1.9 jmmv if (!nodaemon) { 599 1.9 jmmv /* Become a daemon */ 600 1.9 jmmv if (daemon(0, 0) == -1) 601 1.13 jmmv log_err(EXIT_FAILURE, "failed to become a daemon"); 602 1.9 jmmv 603 1.9 jmmv /* Create the pidfile, if wanted */ 604 1.11 jmmv Pid_File = block_get_propval(conf, "pidfile", NULL); 605 1.11 jmmv if (pidfile(Pid_File) == -1) 606 1.13 jmmv log_warn("pidfile %s", Pid_File); 607 1.13 jmmv 608 1.13 jmmv Foreground = 0; 609 1.9 jmmv } 610 1.11 jmmv 611 1.1 christos event_loop(); 612 1.1 christos 613 1.7 jmmv /* NOTREACHED */ 614 1.1 christos return EXIT_SUCCESS; 615 1.1 christos } 616