Linux daemon with inode watch

A simple example of a linux daemon watching a directory or file with inode watch. Changes are logged to syslog

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <linux/unistd.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <sys/types.h>


#define DAEMON_NAME            "demodaemon"
#define NUM_ALLOCED_FILES    1024    /* num of file entries which get alloced at once */
#define EVENT_SIZE            (sizeof(struct inotify_event))
#define EVENT_BUFF_LEN        (1024 * (EVENT_SIZE + 16))


static char s_szWatchDir[256] = "/tmp/";
static unsigned long s_ulNumAllocedEntries = NUM_ALLOCED_FILES;
static int fd, wd;


void onExit(int sig) {
    inotify_rm_watch(fd, wd);
    close(fd);
    
    syslog(LOG_INFO, "bye from daemon");
    exit(0);
}

void daemonize(char *szLogname, int iFacility) {
    int i;
    pid_t pid;
    struct sigaction sa;
    
    /* if parent process, exit */
    if ((pid = fork()) != 0)
        exit(0);
    
    if (setsid() == -1) {
        fprintf(stderr, "setsid() failed\n");
        exit(0);
    }
    
    chdir("/");
    umask(0);
    
    /* close open filedescriptors */
    for (i=sysconf(_SC_OPEN_MAX); i>0; --i)
        close(i);
    
    openlog(szLogname, LOG_PID, iFacility);
    
    
    /* add signal handler for cleaning up */
    sa.sa_handler = &onExit;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGTERM,&sa,0);
}


int main(int argc, char **argv) {
    int c, i, length;
    struct stat s;
    char evtBuff[EVENT_BUFF_LEN];
    
    printf("forking into background...\n");
    daemonize(DAEMON_NAME, LOG_USER);
    
    syslog(LOG_INFO, "hello from daemon");


    fd = inotify_init();
    if (fd<0) {
        syslog(LOG_EMERG, "inotify initialization failed, exiting...");
        return 1;
    }
    
    /* watch for modified and created inodes */
    wd = inotify_add_watch(fd, s_szWatchDir, IN_MODIFY | IN_CREATE);
    if (wd<0) {
        syslog(LOG_EMERG, "inotify watch failed, exiting...");
        return 1;
    }
    
    
    while(1) {
        /* following read is blocking, no need for sleep or pause */
        length = read(fd, evtBuff, EVENT_BUFF_LEN);
        if (length < 0) {
            syslog(LOG_EMERG, "event reading failed, exiting...");
            break;    /* guess if this happens we're fucked */
        }
        
        i = 0;
        while (i<length) {
            struct inotify_event *event = (struct inotify_event *) &evtBuff[i];
            
            if (event->len) {
                syslog(LOG_INFO, "modifed file %s", event->name);

            }
            
            i += EVENT_SIZE + event->len;
        }

    }
    
    /* clean up */
    onExit(0);
    
    return 0;
}
comments powered by Disqus