Better daemonization properties.
[mctap.git] / src / mctap.c
index 472af01..9fce9ac 100644 (file)
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <sys/poll.h>
+#include <syslog.h>
+#include <signal.h>
 
 #include "utils.h"
 
+static int quit = 0;
+
 static void usage(FILE *out)
 {
-    fprintf(out, "usage: mctap [-h] [-D TAPNAME] MCASTGROUP PORT\n");
+    fprintf(out, "usage: mctap [-hdp] [-P PIDFILE] [-D TAPNAME] MCASTGROUP PORT\n");
 }
 
 static __attribute__ ((unused)) char *formataddress(struct sockaddr *arg, socklen_t arglen)
@@ -118,7 +122,7 @@ static void bridge(int sock, int tap, struct sockaddr *dst, socklen_t dstlen)
     
     fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
     fcntl(tap, F_SETFL, fcntl(tap, F_GETFL) | O_NONBLOCK);
-    while(1) {
+    while(!quit) {
        pfds[0].fd = sock;
        pfds[0].events = POLLIN;
        pfds[1].fd = tap;
@@ -126,7 +130,7 @@ static void bridge(int sock, int tap, struct sockaddr *dst, socklen_t dstlen)
        ret = poll(pfds, 2, -1);
        if(ret < 0) {
            if(errno != EINTR) {
-               fprintf(stderr, "mctap: poll: %s\n", strerror(errno));
+               syslog(LOG_ERR, "mctap: poll: %s", strerror(errno));
                exit(1);
            }
            continue;
@@ -135,7 +139,7 @@ static void bridge(int sock, int tap, struct sockaddr *dst, socklen_t dstlen)
            ret = read(sock, buf, sizeof(buf));
            if(ret < 0) {
                if((errno != EINTR) && (errno != EAGAIN)) {
-                   fprintf(stderr, "mctap: mcast packet: %s\n", strerror(errno));
+                   syslog(LOG_ERR, "mctap: mcast packet: %s", strerror(errno));
                    exit(1);
                }
            } else {
@@ -146,7 +150,7 @@ static void bridge(int sock, int tap, struct sockaddr *dst, socklen_t dstlen)
                    pi.flags = 0;
                    pi.proto = 0;
                    memcpy(buf, &pi, sizeof(pi));
-                   write(tap, buf, ret);
+                   write(tap, buf, sizeof(pi) + ret);
                }
            }
        }
@@ -154,7 +158,7 @@ static void bridge(int sock, int tap, struct sockaddr *dst, socklen_t dstlen)
            ret = read(tap, buf, sizeof(buf));
            if(ret < 0) {
                if((errno != EINTR) && (errno != EAGAIN)) {
-                   fprintf(stderr, "mctap: mcast packet: %s\n", strerror(errno));
+                   syslog(LOG_ERR, "mctap: mcast packet: %s", strerror(errno));
                    exit(1);
                }
            } else {
@@ -188,6 +192,18 @@ static int maketap(char *name)
     return(fd);
 }
 
+static void sighand(int sig)
+{
+    switch(sig) {
+    case SIGINT:
+    case SIGTERM:
+       quit = 1;
+       break;
+    case SIGHUP:
+       break;
+    }
+}
+
 int main(int argc, char **argv)
 {
     int c;
@@ -195,14 +211,28 @@ int main(int argc, char **argv)
     struct in_addr group;
     int port;
     char *tapname;
+    char *pidfile;
+    int daemonize;
     struct sockaddr_in dst;
+    FILE *pidfd;
     
     tapname = "mctap";
-    while((c = getopt(argc, argv, "hD:")) >= 0) {
+    daemonize = 0;
+    pidfile = NULL;
+    while((c = getopt(argc, argv, "hD:dpP:")) >= 0) {
        switch(c) {
        case 'D':
            tapname = optarg;
            break;
+       case 'd':
+           daemonize = 1;
+           break;
+       case 'p':
+           pidfile = (void *)-1;
+           break;
+       case 'P':
+           pidfile = optarg;
+           break;
        case 'h':
            usage(stdout);
            return(0);
@@ -211,6 +241,8 @@ int main(int argc, char **argv)
            exit(1);
        }
     }
+    if(pidfile == (void *)-1)
+       pidfile = sprintf2("/var/run/mctap.%s.pid", tapname);
     if(argc - optind < 2) {
        usage(stderr);
        exit(1);
@@ -228,11 +260,32 @@ int main(int argc, char **argv)
        fprintf(stderr, "mctap: could not create TAP device: %s\n", strerror(errno));
        exit(1);
     }
+    openlog(sprintf2("mctap-%s", tapname), LOG_PID, LOG_DAEMON);
+    
+    pidfd = NULL;
+    if((pidfile != NULL) && ((pidfd = fopen(pidfile, "w")) == NULL)) {
+       fprintf(stderr, "mctap: could not create PID file %s: %s\n", pidfile, strerror(errno));
+       exit(1);
+    }
+    if(daemonize)
+       daemon(0, 0);
+    if(pidfd != NULL) {
+       fprintf(pidfd, "%i\n", getpid());
+       fclose(pidfd);
+    }
+    
+    signal(SIGTERM, sighand);
+    signal(SIGINT, sighand);
+    signal(SIGHUP, sighand);
     
     memset(&dst, 0, sizeof(dst));
     dst.sin_family = AF_INET;
     dst.sin_addr = group;
     dst.sin_port = htons(port);
     bridge(sock, tap, (struct sockaddr *)&dst, sizeof(dst));
+    syslog(LOG_INFO, "exiting");
+    
+    if(pidfile != NULL)
+       unlink(pidfile);
     return(0);
 }