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