Home | History | Annotate | Download | only in avahi-utils
      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