From 7bf6b7b95b7c3327000794a24e104242598a9f3f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 31 Aug 2006 19:48:42 +0000 Subject: add support for interface configuration with user supplied event script git-svn-id: file:///home/lennart/svn/public/avahi/trunk@1301 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-autoipd/main.c | 176 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 153 insertions(+), 23 deletions(-) (limited to 'avahi-autoipd/main.c') diff --git a/avahi-autoipd/main.c b/avahi-autoipd/main.c index 6d83d3a..82dba88 100644 --- a/avahi-autoipd/main.c +++ b/avahi-autoipd/main.c @@ -127,6 +127,19 @@ typedef enum CalloutEvent { CALLOUT_MAX } CalloutEvent; +static const char * const callout_event_table[CALLOUT_MAX] = { + [CALLOUT_BIND] = "BIND", + [CALLOUT_CONFLICT] = "CONFLICT", + [CALLOUT_UNBIND] = "UNBIND", + [CALLOUT_STOP] = "STOP" +}; + +typedef struct CalloutEventInfo { + CalloutEvent event; + uint32_t address; + int ifindex; +} CalloutEventInfo; + #define RANDOM_DEVICE "/dev/urandom" #define DEBUG(x) do {\ @@ -243,7 +256,7 @@ static int packet_parse(const void *data, size_t packet_len, ArpPacketInfo *info } static void set_state(State st, int reset_counter, uint32_t address) { - const char* const state_table[] = { + static const char* const state_table[] = { [STATE_START] = "START", [STATE_WAITING_PROBE] = "WAITING_PROBE", [STATE_PROBING] = "PROBING", @@ -315,23 +328,6 @@ fail: return -1; } -static int do_callout(CalloutEvent event, int iface, uint32_t addr) { - char buf[64], ifname[IFNAMSIZ]; - const char * const event_table[CALLOUT_MAX] = { - [CALLOUT_BIND] = "BIND", - [CALLOUT_CONFLICT] = "CONFLICT", - [CALLOUT_UNBIND] = "UNBIND", - [CALLOUT_STOP] = "STOP" - }; - - daemon_log(LOG_INFO, "Callout %s, address %s on interface %s", - event_table[event], - inet_ntop(AF_INET, &addr, buf, sizeof(buf)), - if_indextoname(iface, ifname)); - - return 0; -} - static int open_socket(int iface, uint8_t *hw_address) { int fd = -1; struct sockaddr_ll sa; @@ -458,6 +454,125 @@ static struct timeval *elapse_time(struct timeval *tv, unsigned msec, unsigned j return tv; } +static FILE* fork_dispatcher(void) { + FILE *ret; + int fds[2]; + pid_t pid; + + if (pipe(fds) < 0) { + daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno)); + goto fail; + } + + if ((pid = fork()) < 0) + goto fail; + else if (pid == 0) { + FILE *f = NULL; + int r = 1; + + /* Please note that the signal pipe is not closed at this + * point, signals will thus be dispatched in the main + * process. */ + + daemon_retval_done(); + + setsid(); + + avahi_set_proc_title(argv0, "%s(%s): callout dispatcher", argv0, interface_name); + + close(fds[1]); + + if (!(f = fdopen(fds[0], "r"))) { + daemon_log(LOG_ERR, "fdopen() failed: %s", strerror(errno)); + goto dispatcher_fail; + } + + for (;;) { + CalloutEventInfo info; + char name[IFNAMSIZ], buf[64]; + int k; + + if (fread(&info, sizeof(info), 1, f) != 1) { + if (feof(f)) + break; + + daemon_log(LOG_ERR, "fread() failed: %s", strerror(errno)); + goto dispatcher_fail; + } + + assert(info.event <= CALLOUT_MAX); + + if (!if_indextoname(info.ifindex, name)) { + daemon_log(LOG_ERR, "if_indextoname() failed: %s", strerror(errno)); + continue; + } + + if (daemon_exec("/", &k, + AVAHI_IPCONF_SCRIPT, AVAHI_IPCONF_SCRIPT, + callout_event_table[info.event], + name, + inet_ntop(AF_INET, &info.address, buf, sizeof(buf)), NULL) < 0) { + + daemon_log(LOG_ERR, "Failed to run script: %s", strerror(errno)); + continue; + } + + if (k != 0) + daemon_log(LOG_WARNING, "Script execution failed with return value %i", k); + } + + r = 0; + + dispatcher_fail: + + if (f) + fclose(f); + + _exit(r); + } + + /* parent */ + + close(fds[0]); + fds[0] = -1; + + if (!(ret = fdopen(fds[1], "w"))) { + daemon_log(LOG_ERR, "fdopen() failed: %s", strerror(errno)); + goto fail; + } + + return ret; + +fail: + if (fds[0] >= 0) + close(fds[0]); + if (fds[1] >= 0) + close(fds[1]); + + return NULL; +} + +static int do_callout(FILE *f, CalloutEvent event, int iface, uint32_t addr) { + CalloutEventInfo info; + char buf[64], ifname[IFNAMSIZ]; + + daemon_log(LOG_INFO, "Callout %s, address %s on interface %s", + callout_event_table[event], + inet_ntop(AF_INET, &addr, buf, sizeof(buf)), + if_indextoname(iface, ifname)); + + info.event = event; + info.ifindex = iface; + info.address = addr; + + if (fwrite(&info, sizeof(info), 1, f) != 1 || fflush(f) != 0) { + daemon_log(LOG_ERR, "Failed to write callout event: %s", strerror(errno)); + return -1; + } + + return 0; +} + static int loop(int iface, uint32_t addr) { enum { FD_ARP, @@ -480,15 +595,22 @@ static int loop(int iface, uint32_t addr) { Event event = EVENT_NULL; int retval_sent = !daemonize; State st; + FILE *dispatcher = NULL; daemon_signal_init(SIGINT, SIGTERM, SIGCHLD, SIGHUP,0); + if (!(dispatcher = fork_dispatcher())) + goto fail; + if ((fd = open_socket(iface, hw_address)) < 0) goto fail; if ((iface_fd = iface_init(iface)) < 0) goto fail; +/* if (drop_privs() < 0) */ +/* goto fail; */ + if (force_bind) st = STATE_START; else if (iface_get_initial_state(&st) < 0) @@ -571,7 +693,9 @@ static int loop(int iface, uint32_t addr) { next_wakeup_valid = 1; if (n_iteration == 0) { - do_callout(CALLOUT_BIND, iface, addr); + if (do_callout(dispatcher, CALLOUT_BIND, iface, addr) < 0) + goto fail; + n_conflict = 0; if (!retval_sent) { @@ -610,7 +734,8 @@ static int loop(int iface, uint32_t addr) { if (conflict) { if (state == STATE_RUNNING || state == STATE_ANNOUNCING) - do_callout(CALLOUT_CONFLICT, iface, addr); + if (do_callout(dispatcher, CALLOUT_CONFLICT, iface, addr) < 0) + goto fail; /* Pick a new address */ addr = pick_addr(addr); @@ -637,7 +762,8 @@ static int loop(int iface, uint32_t addr) { daemon_log(LOG_INFO, "A routable address has been configured."); if (state == STATE_RUNNING || state == STATE_ANNOUNCING) - do_callout(CALLOUT_UNBIND, iface, addr); + if (do_callout(dispatcher, CALLOUT_UNBIND, iface, addr) < 0) + goto fail; if (!retval_sent) { daemon_retval_send(0); @@ -775,7 +901,7 @@ static int loop(int iface, uint32_t addr) { fail: if (state == STATE_RUNNING || state == STATE_ANNOUNCING) - do_callout(CALLOUT_STOP, iface, addr); + do_callout(dispatcher, CALLOUT_STOP, iface, addr); avahi_free(out_packet); avahi_free(in_packet); @@ -788,6 +914,9 @@ fail: if (daemonize && !retval_sent) daemon_retval_send(ret); + + if (dispatcher) + fclose(dispatcher); return ret; } @@ -925,6 +1054,8 @@ int main(int argc, char*argv[]) { avahi_init_proc_title(argc, argv); + signal(SIGPIPE, SIG_IGN); + if ((argv0 = strrchr(argv[0], '/'))) argv0++; else @@ -1048,7 +1179,6 @@ finish: /* TODO: - chroot/drop privs/caps -- user script - store last used address - man page -- cgit