/* spacenavd - a free software replacement driver for 6dof space-mice. Copyright (C) 2007-2009 John Tsiombikas This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "config.h" #include #include #include #include #include #include #include #include #include "spnavd.h" #include "dev.h" #include "client.h" #include "proto_unix.h" #include "proto_x11.h" static void cleanup(void); static void daemonize(void); static int write_pid_file(void); static void handle_events(fd_set *rset); static void sig_handler(int s); int main(int argc, char **argv) { int i, ret, become_daemon = 1; for(i=1; i max_fd) max_fd = fd; } /* the UNIX domain socket listening for connections */ if((fd = get_unix_socket()) != -1) { FD_SET(fd, &rset); if(fd > max_fd) max_fd = fd; } /* all the UNIX socket clients */ c = first_client(); while(c) { if(get_client_type(c) == CLIENT_UNIX) { int s = get_client_socket(c); assert(s >= 0); FD_SET(s, &rset); if(s > max_fd) max_fd = s; printf("listen to client: %d\n", s); } c = next_client(); } /* and the X server socket */ #ifdef USE_X11 if((fd = get_x11_socket()) != -1) { FD_SET(fd, &rset); if(fd > max_fd) max_fd = fd; } #endif do { ret = select(max_fd + 1, &rset, 0, 0, 0); } while(ret == -1 && errno == EINTR); if(ret > 0) { handle_events(&rset); } } return 0; /* unreachable */ } static void cleanup(void) { #ifdef USE_X11 close_x11(); /* call to avoid leaving garbage in the X server's root windows */ #endif close_unix(); shutdown_dev(); remove(PIDFILE); } static void daemonize(void) { int i, pid; if((pid = fork()) == -1) { perror("failed to fork"); exit(1); } else if(pid) { exit(0); } setsid(); chdir("/"); /* redirect standard input/output/error */ for(i=0; i<3; i++) { close(i); } open("/dev/zero", O_RDONLY); if(open(LOGFILE, O_WRONLY | O_CREAT | O_TRUNC, 0644) == -1) { open("/dev/null", O_WRONLY); } dup(1); setvbuf(stdout, 0, _IOLBF, 0); setvbuf(stderr, 0, _IONBF, 0); } static int write_pid_file(void) { FILE *fp; int pid = getpid(); if(!(fp = fopen(PIDFILE, "w"))) { return -1; } fprintf(fp, "%d\n", pid); fclose(fp); return 0; } static void handle_events(fd_set *rset) { int dev_fd, hotplug_fd; /* handle anything coming through the UNIX socket */ handle_uevents(rset); #ifdef USE_X11 /* handle any X11 events (magellan protocol) */ handle_xevents(rset); #endif /* finally read any pending device input data */ if((dev_fd = get_dev_fd()) != -1) { if(FD_ISSET(dev_fd, rset)) { struct dev_input inp; /* read an event from the device ... */ if(read_dev(&inp) != -1) { /* ... and process it, possibly dispatching a spacenav event to clients */ process_input(&inp); } } } else if((hotplug_fd = get_hotplug_fd()) != -1) { if(FD_ISSET(hotplug_fd, rset)) { handle_hotplug(); } } } /* signals usr1 & usr2 are sent by the spnav_x11 script to start/stop the * daemon's connection to the X server. */ static void sig_handler(int s) { int tmp; switch(s) { case SIGHUP: tmp = cfg.led; read_cfg("/etc/spnavrc", &cfg); if(cfg.led != tmp) { set_led(cfg.led); } break; case SIGSEGV: fprintf(stderr, "Segmentation fault caught, trying to exit gracefully\n"); case SIGINT: case SIGTERM: exit(0); #ifdef USE_X11 case SIGUSR1: init_x11(); break; case SIGUSR2: close_x11(); break; #endif default: break; } }