1 /*** 2 This file is part of avahi. 3 4 avahi is free software; you can redistribute it and/or modify it 5 under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 2.1 of the 7 License, or (at your option) any later version. 8 9 avahi is distributed in the hope that it will be useful, but WITHOUT 10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 12 Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with avahi; if not, write to the Free Software 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 17 USA. 18 ***/ 19 20 #ifdef HAVE_CONFIG_H 21 #include <config.h> 22 #endif 23 24 #include <unistd.h> 25 #include <assert.h> 26 #include <string.h> 27 #include <errno.h> 28 #include <signal.h> 29 #include <fcntl.h> 30 #include <stdio.h> 31 32 #include <avahi-common/gccmacro.h> 33 #include "sigint.h" 34 35 static AvahiSimplePoll *simple_poll = NULL; 36 static struct sigaction old_sigint_sa, old_sigterm_sa; 37 static int pipe_fds[2] = { -1, -1 }; 38 static AvahiWatch *watch = NULL; 39 40 static int set_nonblock(int fd) { 41 int n; 42 43 assert(fd >= 0); 44 45 if ((n = fcntl(fd, F_GETFL)) < 0) 46 return -1; 47 48 if (n & O_NONBLOCK) 49 return 0; 50 51 return fcntl(fd, F_SETFL, n|O_NONBLOCK); 52 } 53 54 static void handler(int s) { 55 write(pipe_fds[1], &s, sizeof(s)); 56 } 57 58 static void close_pipe_fds(void) { 59 if (pipe_fds[0] >= 0) 60 close(pipe_fds[0]); 61 if (pipe_fds[1] >= 0) 62 close(pipe_fds[1]); 63 64 pipe_fds[0] = pipe_fds[1] = -1; 65 } 66 67 static void watch_callback(AvahiWatch *w, int fd, AvahiWatchEvent event, AVAHI_GCC_UNUSED void *userdata) { 68 int s; 69 ssize_t l; 70 71 assert(w); 72 assert(fd == pipe_fds[0]); 73 assert(event == AVAHI_WATCH_IN); 74 75 l = read(fd, &s, sizeof(s)); 76 assert(l == sizeof(s)); 77 78 fprintf(stderr, "Got %s, quitting.\n", s == SIGINT ? "SIGINT" : "SIGTERM"); 79 avahi_simple_poll_quit(simple_poll); 80 } 81 82 int sigint_install(AvahiSimplePoll *spoll) { 83 struct sigaction sa; 84 const AvahiPoll *p; 85 86 assert(spoll); 87 assert(!simple_poll); 88 assert(pipe_fds[0] == -1 && pipe_fds[1] == -1); 89 90 if (pipe(pipe_fds) < 0) { 91 fprintf(stderr, "pipe() failed: %s\n", strerror(errno)); 92 return -1; 93 } 94 95 set_nonblock(pipe_fds[0]); 96 set_nonblock(pipe_fds[1]); 97 98 memset(&sa, 0, sizeof(sa)); 99 sa.sa_handler = handler; 100 sa.sa_flags = SA_RESTART; 101 102 if (sigaction(SIGINT, &sa, &old_sigint_sa) < 0) { 103 fprintf(stderr, "sigaction() failed: %s\n", strerror(errno)); 104 close_pipe_fds(); 105 return -1; 106 } 107 108 if (sigaction(SIGTERM, &sa, &old_sigterm_sa) < 0) { 109 sigaction(SIGINT, &old_sigint_sa, NULL); 110 fprintf(stderr, "sigaction() failed: %s\n", strerror(errno)); 111 close_pipe_fds(); 112 return -1; 113 } 114 115 p = avahi_simple_poll_get(spoll); 116 watch = p->watch_new(p, pipe_fds[0], AVAHI_WATCH_IN, watch_callback, NULL); 117 assert(watch); 118 119 simple_poll = spoll; 120 return 0; 121 } 122 123 void sigint_uninstall(void) { 124 125 if (!simple_poll) 126 return; 127 128 sigaction(SIGTERM, &old_sigterm_sa, NULL); 129 sigaction(SIGINT, &old_sigint_sa, NULL); 130 131 close_pipe_fds(); 132 133 if (watch) { 134 const AvahiPoll *p; 135 136 assert(simple_poll); 137 p = avahi_simple_poll_get(simple_poll); 138 139 p->watch_free(watch); 140 watch = NULL; 141 } 142 143 simple_poll = NULL; 144 } 145