Fix memory leak.
[util-vserver.git] / src / vip6-autod.c
index 0906612..2d48dcd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id$
+ * $Id: vip6-autod.c,v 1.4 2007/07/30 14:59:11 dhozac Exp $
  * Copyright (c) 2007 The Trustees of Princeton University
  * Author: Daniel Hokka Zakrisson <daniel@hozac.com>
  *
@@ -7,6 +7,10 @@
  * version 2 or later.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <ctype.h>
 #include <errno.h>
 #include <signal.h>
+#include <syslog.h>
 
 #include <asm/types.h>
 /* not defined for gcc -ansi */
-typedef uint64_t __u64;
-typedef int64_t __s64;
+typedef unsigned long long __u64;
+typedef signed long long __s64;
 #include <netlink/netlink.h>
 #include <netlink/route/addr.h>
 
-typedef unsigned int nid_t;
-typedef unsigned int xid_t;
 #include <vserver.h>
+#include "pathconfig.h"
 
 #define HAS_ADDRESS    0x01
 #define HAS_PREFIX     0x02
@@ -101,27 +105,33 @@ static int add_address_to_interface(int ifindex, struct in6_addr *address, int p
        return err;
 }
 
-static int add_nid_to_list(struct prefix_list *i, nid_t nid)
+static int add_nid_to_list(struct nid_list **l, nid_t nid)
 {
        struct nid_list *n;
+       for (n = *l; n; n = n->next) {
+               if (n->nid == nid)
+                       return 0;
+       }
        n = calloc(1, sizeof(struct nid_list));
        if (!n)
                return -1;
        n->nid = nid;
-       n->next = i->nids;
-       i->nids = n;
-       return 0;
+       n->next = *l;
+       *l = n;
+       return 1;
 }
 
 static void cleanup_prefix(struct prefix_list *i)
 {
-       struct nid_list *n;
+       struct nid_list *n, *p = NULL;
 
        for (n = i->nids; n; n = n->next) {
                struct rtnl_addr *rta;
                struct nl_addr *nl;
                struct in6_addr a;
 
+               if (p)
+                       free(p);
                memcpy(&a, &i->address.addr, sizeof(a));
                rta = rtnl_addr_alloc();
                nl = nl_addr_build(AF_INET6, &a, sizeof(a));
@@ -136,7 +146,23 @@ static void cleanup_prefix(struct prefix_list *i)
 
                nl_addr_destroy(nl);
                rtnl_addr_free(rta);
+
+               p = n;
        }
+       if (p)
+               free(p);
+}
+
+static inline void free_nid_list(struct nid_list *head)
+{
+       struct nid_list *p;
+       for (p = NULL; head; head = head->next) {
+               if (p)
+                       free(p);
+               p = head;
+       }
+       if (p)
+               free(p);
 }
 
 static void do_slices_autoconf(struct prefix_list *head)
@@ -146,6 +172,8 @@ static void do_slices_autoconf(struct prefix_list *head)
        nid_t nid;
        struct vc_net_nx addr;
        struct prefix_list *i;
+       struct nid_list *current = NULL, *n;
+       static struct nid_list *previous = NULL;
 
        if ((dp = opendir("/proc/virtnet")) == NULL)
                return;
@@ -154,13 +182,15 @@ static void do_slices_autoconf(struct prefix_list *head)
                        continue;
 
                nid = strtoul(de->d_name, NULL, 10);
-               addr.type = vcNET_IPV6;
-               addr.count = -1;
+               addr.type = vcNET_IPV6A;
+               addr.count = 0;
                if (vc_net_remove(nid, &addr) == -1) {
-                       perror("vc_net_remove");
+                       syslog(LOG_ERR, "vc_net_remove(%u): %s", nid, strerror(errno));
                        continue;
                }
 
+               add_nid_to_list(&current, nid);
+
                for (i = head->next; i;) {
                        /* expired */
                        if (i->mask & HAS_PREFIX && i->prefix.valid_until < time(NULL)) {
@@ -168,7 +198,7 @@ static void do_slices_autoconf(struct prefix_list *head)
                                char buf[64];
 
                                inet_ntop(AF_INET6, &i->address.addr, buf, sizeof(buf));
-                               printf("Address %s timed out.\n", buf);
+                               syslog(LOG_NOTICE, "Address %s timed out", buf);
 
                                if (i->next)
                                        i->next->prev = i->prev;
@@ -185,28 +215,32 @@ static void do_slices_autoconf(struct prefix_list *head)
                        if (i->mask != (HAS_ADDRESS|HAS_PREFIX))
                                goto next;
 
+                       addr.type = vcNET_IPV6;
                        addr.count = 1;
                        addr.mask[0] = i->prefix.prefix_len;
                        memcpy(addr.ip, &i->address.addr, sizeof(struct in6_addr));
-                       addr.ip[2] = htonl((ntohl(addr.ip[2]) & 0xffffff00) | ((nid & 0x7f00) >> 7));
-                       addr.ip[3] = htonl((ntohl(addr.ip[3]) & 0x00ffffff) | ((nid & 0xff) << 25));
+                       addr.ip[2] = htonl((ntohl(addr.ip[2]) & 0xffffff00) | ((nid & 0x7f80) >> 7));
+                       addr.ip[3] = htonl((ntohl(addr.ip[3]) & 0x00ffffff) | ((nid & 0x7f) << 25));
                        if (vc_net_add(nid, &addr) == -1) {
-                               perror("vc_net_add");
-                               exit(1);
+                               syslog(LOG_ERR, "vc_net_add(%u): %s", nid, strerror(errno));
+                               goto next;
                        }
                        if (add_address_to_interface(i->ifindex, (struct in6_addr *) addr.ip, i->prefix.prefix_len) == -1) {
-                               perror("add_address_to_interface");
-                               exit(1);
+                               syslog(LOG_ERR, "add_address_to_interface: %s", strerror(errno));
+                               goto next;
                        }
-                       if (add_nid_to_list(i, nid) == -1) {
-                               perror("add_nid_to_list");
-                               exit(1);
+                       if (add_nid_to_list(&i->nids, nid) == -1) {
+                               syslog(LOG_ERR, "add_nid_to_list: %s", strerror(errno));
+                               goto next;
                        }
 next:
                        i = i->next;
                }
        }
        closedir(dp);
+
+       free_nid_list(previous);
+       previous = current;
 }
 
 static int add_prefix(struct prefix_list *head, struct prefixmsg *msg,
@@ -307,7 +341,7 @@ int handle_valid_msg(struct nl_msg *msg, void *arg)
                struct nlattr *tb[PREFIX_MAX+1];
 
                if (nlmsg_parse(nlh, sizeof(struct prefixmsg), tb, PREFIX_MAX, prefix_policy) < 0) {
-                       printf("Failed to parse prefixmsg.\n");
+                       syslog(LOG_ERR, "Failed to parse prefixmsg");
                        return -1;
                }
 
@@ -325,7 +359,7 @@ int handle_valid_msg(struct nl_msg *msg, void *arg)
                struct nlattr *tb[IFA_MAX+1];
 
                if (nlmsg_parse(nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX, addr_policy) < 0) {
-                       printf("Failed to parse ifaddrmsg.\n");
+                       syslog(LOG_ERR, "Failed to parse ifaddrmsg");
                        return -1;
                }
 
@@ -345,7 +379,7 @@ int handle_valid_msg(struct nl_msg *msg, void *arg)
 int handle_error_msg(struct sockaddr_nl *source, struct nlmsgerr *err,
                     void *arg)
 {
-       perror("Got an error");
+       syslog(LOG_ERR, "%s", strerror(err->error));
        return 0;
 }
 
@@ -365,12 +399,23 @@ void signal_handler(int signal)
        }
 }
 
+static int write_pidfile(const char *filename)
+{
+       FILE *fp;
+       fp = fopen(filename, "w");
+       if (!fp)
+               return -1;
+       fprintf(fp, "%d\n", getpid());
+       fclose(fp);
+       return 0;
+}
+
 int main(int argc, char *argv[])
 {
        struct nl_cb *cbs;
-
        head.prev = head.next = NULL;
-       signal(SIGUSR1, signal_handler);
+
+       openlog("vip6-autod", LOG_PERROR, LOG_DAEMON);
 
        handle = nl_handle_alloc_nondefault(NL_CB_VERBOSE);
        cbs = nl_handle_get_cb(handle);
@@ -381,12 +426,21 @@ int main(int argc, char *argv[])
 
        nl_join_groups(handle, RTMGRP_IPV6_PREFIX|RTMGRP_IPV6_IFADDR);
        if (nl_connect(handle, NETLINK_ROUTE) == -1) {
-               perror("nl_connect");
+               syslog(LOG_CRIT, "nl_connect: %s", strerror(errno));
                exit(1);
        }
 
+       if (daemon(0, 0) == -1)
+               return -1;
+
+       /* XXX .. here is a hack */
+       write_pidfile(DEFAULT_PKGSTATEDIR "/../vip6-autod.pid");
+
+       signal(SIGUSR1, signal_handler);
+
        while (nl_recvmsgs(handle, cbs) > 0);
 
        nl_close(handle);
+       closelog();
        return 0;
 }