Decrease granularity to reduce the size of the dataset
[fprobe-ulog.git] / src / fprobe-ulog.c
index c5be35f..8c66067 100644 (file)
@@ -6,10 +6,13 @@
 
        $Id: fprobe-ulog.c,v 1.1.2.4 2005/01/30 09:06:19 sla Exp $
 
-       7/11/2007       Sapan Bhatia <sapanb@cs.princeton.edu> 
+                       Sapan Bhatia <sapanb@cs.princeton.edu> 
                        
-               Added data collection (-f) functionality, xid support in the header and log file
-               rotation.
+       7/11/2007       Added data collection (-f) functionality, xid support in the header and log file
+                       rotation.
+
+       15/11/2007      Added check to make sure fprobe doesn't overflow the disk. Also added a test facility.
+
 */
 
 #include <common.h>
@@ -31,7 +34,7 @@
 
 /* statfs() */
 
-#include <sys/statfs.h>
+#include <sys/vfs.h>
 
 #include <libipulog/libipulog.h>
 struct ipulog_handle {
@@ -92,6 +95,9 @@ struct ipulog_handle {
 #include <hash.h>
 #include <mem.h>
 
+#define PIDFILE "/var/log/fprobe-ulog.pid"
+#define STD_NETFLOW_PDU
+
 enum {
        aflag,
        Bflag,
@@ -126,6 +132,7 @@ static struct getopt_parms parms[] = {
        {'b', MY_GETOPT_ARG_REQUIRED, 0, 0},
        {'c', MY_GETOPT_ARG_REQUIRED, 0, 0},
        {'d', MY_GETOPT_ARG_REQUIRED, 0, 0},
+       {'D', MY_GETOPT_ARG_REQUIRED, 0, 0},
        {'e', MY_GETOPT_ARG_REQUIRED, 0, 0},
        {'E', MY_GETOPT_ARG_REQUIRED, 0, 0},
        {'f', MY_GETOPT_ARG_REQUIRED, 0, 0},
@@ -379,12 +386,18 @@ inline void copy_flow(struct Flow *src, struct Flow *dst)
 }
 
 void get_cur_epoch() {
-       int fd, len;
+       int fd;
        fd = open("/tmp/fprobe_last_epoch",O_RDONLY);
        if (fd != -1) {
                char snum[7];
-               read(fd, snum, 7);
-               sscanf(snum,"%d",&cur_epoch);
+               ssize_t len;
+               len = read(fd, snum, sizeof(snum)-1);
+               if (len != -1) {
+                       snum[len]='\0';
+                       sscanf(snum,"%d",&cur_epoch);
+                       cur_epoch++; /* Let's not stone the last epoch */
+                       close(fd);
+               }
        }
        return;
 }
@@ -403,7 +416,7 @@ void update_cur_epoch_file(int n) {
        close(fd);
 }
 
-unsigned get_log_fd(char *fname, unsigned cur_fd) {
+unsigned get_log_fd(char *fname, int cur_fd) {
        struct Time now;
        unsigned cur_uptime;
        /* We check if the amount of space left on the disk < some threshold and start reusing logs, or bail out if that
@@ -414,28 +427,32 @@ unsigned get_log_fd(char *fname, unsigned cur_fd) {
        gettime(&now);
        cur_uptime = getuptime_minutes(&now);
 
-       if (fstatfs(cur_fd, &statfs) && cur_fd!=START_VALUE) {
-               my_log(LOG_ERR, "PANIC! Can't stat disk to calculate free blocks");
-       }
-       else {
-               if (min_free && statfs.f_bfree < min_free) 
-                       switch(cur_epoch) {
-                               case 0: /* Uh oh. Our first file filled up all of the free space. Just bail out. */
-                                       my_log(LOG_ERR, "The first epoch filled up all the free space on disk. Bailing out.");
-                                       exit(1);
-                               default:
-                                       my_log(LOG_INFO, "Disk almost full. I'm going to drop data. Max epochs = %d\n",cur_epoch);
-                                       cur_epoch = -1;
-                       }
+
+       if (cur_fd!=START_VALUE) {
+               if (fstatfs(cur_fd, &statfs) == -1) {
+                       my_log(LOG_ERR, "PANIC! Can't stat disk to calculate free blocks");
+               }
+               else {
+                       if (min_free && (statfs.f_bavail < min_free)) 
+                               switch(cur_epoch) {
+                                       case 0: /* Uh oh. Our first file filled up all of the free space. Just bail out. */
+                                               my_log(LOG_ERR, "The first epoch filled up all the free space on disk. Bailing out.");
+                                               exit(1);
+                                       default:
+                                               my_log(LOG_INFO, "Disk almost full (%u free blocks). I'm going to drop data. Max epochs = %d\n",statfs.f_bavail,cur_epoch);
+                                               cur_epoch = -1;
+                               }
+               }
        }
 
        /* Epoch length in minutes */
-       if ((cur_uptime - prev_uptime) > epoch_length || cur_fd<0 || cur_epoch==-1) {
+       if (((cur_uptime - prev_uptime) > epoch_length) || (cur_fd < 0) || (cur_epoch==-1)) {
                char nextname[MAX_PATH_LEN];
                int write_fd;
                prev_uptime = cur_uptime;
                cur_epoch = (cur_epoch + 1) % log_epochs;
-               close(cur_fd);
+               if (cur_fd>0)
+                       close(cur_fd);
                snprintf(nextname,MAX_PATH_LEN,"%s.%d",fname,cur_epoch);
                if ((write_fd = open(nextname, O_WRONLY|O_CREAT|O_TRUNC)) < 0) {
                        my_log(LOG_ERR, "open(): %s (%s)\n", nextname, strerror(errno));
@@ -444,8 +461,9 @@ unsigned get_log_fd(char *fname, unsigned cur_fd) {
                update_cur_epoch_file(cur_epoch);
                ret_fd = write_fd;
        }
-       else
+       else {
                ret_fd = cur_fd;
+       }
        return(ret_fd);
 }
 
@@ -801,7 +819,9 @@ void *emit_thread()
                        p = fill(netflow->HeaderFields, netflow->HeaderFormat, 0, &emit_packet);
                        size = netflow->HeaderSize + emit_count * netflow->FlowSize;
                        /* Netflow PDUs need to be padded to 1464 bytes - Sapan */
+#ifdef STD_NETFLOW_PDU
                        if (size < NETFLOW_PDU_SIZE) size = NETFLOW_PDU_SIZE;
+#endif
                        peer_rot_cur = 0;
                        for (i = 0; i < npeers; i++) {
                                if (peers[i].type == PEER_FILE) {
@@ -1234,6 +1254,44 @@ void *cap_thread()
        return 0;
 }
 
+/* Copied out of CoDemux */
+
+static int init_daemon() {
+  pid_t pid;
+  FILE *pidfile;
+
+  pidfile = fopen(PIDFILE, "w");
+  if (pidfile == NULL) {
+    my_log(LOG_ERR, "%s creation failed\n", PIDFILE);
+  }
+
+  if ((pid = fork()) < 0) {
+    fclose(pidfile);
+    my_log(LOG_ERR, "Could not fork!\n");
+    return(-1);
+  }
+  else if (pid != 0) {
+    /* i'm the parent, writing down the child pid  */
+    fprintf(pidfile, "%u\n", pid);
+    fclose(pidfile);
+    exit(0);
+  }
+
+  /* close the pid file */
+  fclose(pidfile);
+
+  /* routines for any daemon process
+     1. create a new session 
+     2. change directory to the root
+     3. change the file creation permission 
+  */
+  setsid();
+  chdir("/usr/local/fprobe");
+  umask(0);
+
+  return(0);
+}
+
 int main(int argc, char **argv)
 {
        char errpbuf[512];
@@ -1482,6 +1540,9 @@ bad_collector:
        /* Daemonize (if log destination stdout-free) */
 
        my_log_open(ident, verbosity, log_dest);
+
+       init_daemon();
+
        if (!(log_dest & 2)) {
                /* Crash-proofing - Sapan*/
                while (1) {