1 /* $NetBSD: wsmoused.c,v 1.24 2009/01/13 18:09:19 christos Exp $ */
4 * Copyright (c) 2002, 2003, 2004 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julio M. Merino Vidal.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. The name authors may not be used to endorse or promote products
16 * derived from this software without specific prior written
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
35 __COPYRIGHT("@(#) Copyright (c) 2002, 2003\
36 The NetBSD Foundation, Inc. All rights reserved.");
37 __RCSID("$NetBSD: wsmoused.c,v 1.24 2009/01/13 18:09:19 christos Exp $");
40 #include <sys/ioctl.h>
42 #include <sys/types.h>
44 #include <dev/wscons/wsconsio.h>
59 #include "pathnames.h"
62 /* --------------------------------------------------------------------- */
68 static struct mouse Mouse
;
69 static char *Pid_File
= NULL
;
70 static int Foreground
= 1;
71 static int X_Console
= -1;
72 static int X_Console_Delay
= 5;
74 #ifdef WSMOUSED_SELECTION_MODE
75 extern struct mode_bootstrap Action_Mode
;
77 #ifdef WSMOUSED_SELECTION_MODE
78 extern struct mode_bootstrap Selection_Mode
;
82 static struct mode_bootstrap
*Modes
[MAX_MODES
];
83 static struct mode_bootstrap
*Avail_Modes
[] = {
84 #ifdef WSMOUSED_ACTION_MODE
87 #ifdef WSMOUSED_SELECTION_MODE
92 /* --------------------------------------------------------------------- */
95 * Prototypes for functions private to this module.
98 static void usage(void);
99 static void open_device(unsigned int);
100 static void init_mouse(void);
101 static void event_loop(void);
102 static void generic_wscons_event(struct wscons_event
);
103 static int attach_mode(const char *);
104 static void attach_modes(char *);
105 static void detach_mode(const char *);
106 static void detach_modes(void);
107 static void signal_terminate(int);
108 int main(int, char **);
110 /* --------------------------------------------------------------------- */
112 /* Shows program usage information and exits. */
117 (void)fprintf(stderr
,
118 "usage: %s [-d device] [-f config_file] [-m modes] [-n]\n",
123 /* --------------------------------------------------------------------- */
125 /* Logs the given error message to syslog if running in daemon mode, or
126 * to the console if running in the foreground. */
128 log_err(int e
, const char *fmt
, ...)
136 int olderrno
= errno
;
137 vsyslog(LOG_DAEMON
| LOG_ERR
, fmt
, ap
);
139 syslog(LOG_DAEMON
| LOG_ERR
, "%m");
146 /* --------------------------------------------------------------------- */
148 /* Logs the given error message to syslog if running in daemon mode, or
149 * to the console if running in the foreground. */
151 log_errx(int e
, const char *fmt
, ...)
159 vsyslog(LOG_DAEMON
| LOG_ERR
, fmt
, ap
);
166 /* --------------------------------------------------------------------- */
168 /* Logs the given info message to syslog if running in daemon mode, or
169 * to the console if running in the foreground. */
171 log_info(const char *fmt
, ...)
177 vfprintf(stderr
, fmt
, ap
);
178 fprintf(stderr
, "\n");
180 vsyslog(LOG_DAEMON
| LOG_INFO
, fmt
, ap
);
184 /* --------------------------------------------------------------------- */
186 /* Logs the given warning message to syslog if running in daemon mode, or
187 * to the console if running in the foreground. */
189 log_warn(const char *fmt
, ...)
197 int olderrno
= errno
;
198 vsyslog(LOG_DAEMON
| LOG_WARNING
, fmt
, ap
);
200 syslog(LOG_DAEMON
| LOG_WARNING
, "%m");
205 /* --------------------------------------------------------------------- */
207 /* Logs the given warning message to syslog if running in daemon mode, or
208 * to the console if running in the foreground. */
210 log_warnx(const char *fmt
, ...)
218 vsyslog(LOG_DAEMON
| LOG_WARNING
, fmt
, ap
);
222 /* --------------------------------------------------------------------- */
224 /* Initializes mouse information. Basically, it opens required files
225 * for the daemon to work. */
233 /* Open FIFO, if wanted */
235 if (Mouse
.m_fifoname
!= NULL
) {
236 Mouse
.m_fifofd
= open(Mouse
.m_fifoname
,
237 O_RDWR
| O_NONBLOCK
, 0);
238 if (Mouse
.m_fifofd
== -1)
239 log_err(EXIT_FAILURE
, "cannot open %s",
244 /* --------------------------------------------------------------------- */
246 /* Opens the mouse device (if not already opened). The argument `secs'
247 * specifies how much seconds the function will wait before trying to
248 * open the device; this is used when returning from the X console. */
250 open_device(unsigned int secs
)
252 int version
= WSMOUSE_EVENT_VERSION
;
254 if (Mouse
.m_devfd
!= -1)
259 /* Open mouse file descriptor */
260 Mouse
.m_devfd
= open(Mouse
.m_devname
, O_RDONLY
| O_NONBLOCK
, 0);
261 if (Mouse
.m_devfd
== -1)
262 log_err(EXIT_FAILURE
, "cannot open %s", Mouse
.m_devname
);
264 if (ioctl(Mouse
.m_devfd
, WSMOUSEIO_SETVERSION
, &version
) == -1)
265 log_err(EXIT_FAILURE
, "cannot set version %s", Mouse
.m_devname
);
268 /* --------------------------------------------------------------------- */
270 /* Main program event loop. This function polls the wscons status
271 * device and the mouse device; whenever an event is received, the
272 * appropiate callback is fired for all attached modes. If the polls
273 * times out (which only appens when the mouse is disabled), another
274 * callback is launched. */
279 struct pollfd fds
[2];
280 struct wscons_event event
;
282 fds
[0].fd
= Mouse
.m_statfd
;
283 fds
[0].events
= POLLIN
;
286 fds
[1].fd
= Mouse
.m_devfd
;
287 fds
[1].events
= POLLIN
;
288 if (Mouse
.m_disabled
)
289 res
= poll(fds
, 1, INFTIM
);
291 res
= poll(fds
, 2, 300);
294 log_warn("failed to read from devices");
296 if (fds
[0].revents
& POLLIN
) {
297 res
= read(Mouse
.m_statfd
, &event
, sizeof(event
));
298 if (res
!= sizeof(event
))
299 log_warn("failed to read from mouse stat");
301 for (i
= 0; i
< MAX_MODES
&& Modes
[i
] != NULL
; i
++)
302 if (Modes
[i
]->mb_wscons_event
!= NULL
)
303 Modes
[i
]->mb_wscons_event(event
, 1);
305 generic_wscons_event(event
);
307 for (i
= 0; i
< MAX_MODES
&& Modes
[i
] != NULL
; i
++)
308 if (Modes
[i
]->mb_wscons_event
!= NULL
)
309 Modes
[i
]->mb_wscons_event(event
, 0);
311 } else if (fds
[1].revents
& POLLIN
) {
312 res
= read(Mouse
.m_devfd
, &event
, sizeof(event
));
313 if (res
!= sizeof(event
))
314 log_warn("failed to read from mouse");
316 if (Mouse
.m_fifofd
>= 0) {
317 res
= write(Mouse
.m_fifofd
, &event
,
319 if (res
!= sizeof(event
))
320 log_warn("failed to write to fifo");
323 for (i
= 0; i
< MAX_MODES
&& Modes
[i
] != NULL
; i
++)
324 if (Modes
[i
]->mb_wsmouse_event
!= NULL
)
325 Modes
[i
]->mb_wsmouse_event(event
);
327 for (i
= 0; i
< MAX_MODES
&& Modes
[i
] != NULL
; i
++)
328 if (Modes
[i
]->mb_poll_timeout
!= NULL
)
329 Modes
[i
]->mb_poll_timeout();
334 /* --------------------------------------------------------------------- */
336 /* This function parses generic wscons status events. Actually, it
337 * handles the screen switch event to enable or disable the mouse,
338 * depending if we are entering or leaving the X console. */
340 generic_wscons_event(struct wscons_event evt
)
344 case WSCONS_EVENT_SCREEN_SWITCH
:
345 if (evt
.value
== X_Console
) {
346 Mouse
.m_disabled
= 1;
347 (void)close(Mouse
.m_devfd
);
350 if (Mouse
.m_disabled
) {
351 open_device(X_Console_Delay
);
352 Mouse
.m_disabled
= 0;
354 (void)close(Mouse
.m_devfd
);
363 /* --------------------------------------------------------------------- */
365 /* Attaches a mode to the list of active modes, based on its name.
366 * Returns 1 on success or 0 if the mode fails to initialize or there is
367 * any other problem. */
369 attach_mode(const char *name
)
372 struct mode_bootstrap
*mb
;
374 for (i
= 0, pos
= -1; i
< MAX_MODES
; i
++)
375 if (Modes
[i
] == NULL
) {
380 log_warnx("modes table full; cannot register `%s'", name
);
384 for (i
= 0; i
< MAX_MODES
; i
++) {
386 if (mb
!= NULL
&& strcmp(name
, mb
->mb_name
) == 0) {
389 res
= mb
->mb_startup(&Mouse
);
391 log_warnx("startup failed for `%s' mode",
401 log_warnx("unknown mode `%s' (see the `modes' directive)", name
);
405 /* --------------------------------------------------------------------- */
407 /* Attaches all modes given in the whitespace separated string `list'.
408 * A fatal error is produced if no active modes can be attached. */
410 attach_modes(char *list
)
415 /* Attach all requested modes */
416 (void)memset(&Modes
, 0, sizeof(struct mode_bootstrap
*) * MAX_MODES
);
417 for (count
= 0, (p
= strtok_r(list
, " ", &last
)); p
;
418 (p
= strtok_r(NULL
, " ", &last
))) {
424 log_errx(EXIT_FAILURE
, "no active modes found; exiting...");
427 /* --------------------------------------------------------------------- */
429 /* Detaches a mode from the active modes list based on its name. */
431 detach_mode(const char *name
)
434 struct mode_bootstrap
*mb
;
436 for (i
= 0; i
< MAX_MODES
; i
++) {
438 if (mb
!= NULL
&& strcmp(name
, mb
->mb_name
) == 0) {
441 res
= mb
->mb_cleanup();
443 log_warnx("cleanup failed for `%s' mode",
453 log_warnx("unknown mode `%s' (see the `modes' directive)", name
);
456 /* --------------------------------------------------------------------- */
458 /* Detaches all active modes. */
464 for (i
= 0; i
< MAX_MODES
&& Modes
[i
] != NULL
; i
++)
465 detach_mode(Modes
[i
]->mb_name
);
468 /* --------------------------------------------------------------------- */
470 /* Signal handler for close signals. The program can only be exited
471 * through this function. */
474 signal_terminate(int sig
)
482 /* --------------------------------------------------------------------- */
484 /* Main program. Parses command line options, reads the configuration
485 * file, initializes the mouse and associated files and launches the main
488 main(int argc
, char **argv
)
490 char *conffile
, *modelist
, *tstat
;
491 int needconf
, nodaemon
, opt
;
494 setprogname(argv
[0]);
496 (void)memset(&Mouse
, 0, sizeof(struct mouse
));
497 conffile
= _PATH_CONF
;
502 /* Parse command line options */
503 while ((opt
= getopt(argc
, argv
, "d:f:m:n")) != -1) {
505 case 'd': /* Mouse device name */
506 Mouse
.m_devname
= optarg
;
508 case 'f': /* Configuration file name */
512 case 'm': /* List of modes to activate */
515 case 'n': /* No daemon */
524 /* Read the configuration file and get some basic properties */
525 config_read(conffile
, needconf
);
526 conf
= config_get_mode("Global");
528 nodaemon
= block_get_propval_int(conf
, "nodaemon", 0);
529 X_Console
= block_get_propval_int(conf
, "xconsole", -1);
530 X_Console_Delay
= block_get_propval_int(conf
, "xconsole_delay",
533 /* Open wsdisplay status device */
534 tstat
= block_get_propval(conf
, "ttystat", _PATH_TTYSTAT
);
535 Mouse
.m_statfd
= open(tstat
, O_RDONLY
| O_NONBLOCK
, 0);
536 if (Mouse
.m_statfd
== -1)
537 log_err(EXIT_FAILURE
, "cannot open %s", tstat
);
539 /* Initialize mouse information and attach modes */
540 if (Mouse
.m_devname
== NULL
)
541 Mouse
.m_devname
= block_get_propval(conf
, "device",
542 _PATH_DEFAULT_MOUSE
);
543 Mouse
.m_fifoname
= block_get_propval(conf
, "fifo", NULL
);
545 if (modelist
!= NULL
)
546 attach_modes(modelist
);
548 attach_modes(block_get_propval(conf
, "modes", "selection"));
550 /* Setup signal handlers */
551 (void)signal(SIGINT
, signal_terminate
);
552 (void)signal(SIGKILL
, signal_terminate
);
553 (void)signal(SIGQUIT
, signal_terminate
);
554 (void)signal(SIGTERM
, signal_terminate
);
557 /* Become a daemon */
558 if (daemon(0, 0) == -1)
559 log_err(EXIT_FAILURE
, "failed to become a daemon");
561 /* Create the pidfile, if wanted */
562 Pid_File
= block_get_propval(conf
, "pidfile", NULL
);
563 if (pidfile(Pid_File
) == -1)
564 log_warn("pidfile %s", Pid_File
);