SourceForge.net Logo

AEM - The Linux Asynchronous Event Mechanism





Back to main page





























AEM File and Directory Change Notification

DESCRIPTION

This module provides asynchronous notification for changes happening on files and/or directories. For that purpose only file and directory (string) names are used for the registration. This makes AEM a very  convenient mechanism to handle recursive notification in user space.

DEFINITIONS

#include <aem.h>
This file is located in the directory  {AEMSRC}/include/user in the AEM source package. It must be installed and included with your source code.

libaem
This is the AEM library. It is located in the directory  {AEMSRC}/lib in the AEM source package. It must be installed and linked with your source code.

Registration (inerest) events:
F_BIN   
F_BOUT  
F_BHUP  
F_BOPEN 
F_BOWNER
F_BMODE 
F_BLOCK 
F_BCREATE
F_BREMOVE
F_BRENAME

State (notification) flags:
B_IN    
B_OUT   
B_HUP   
B_OPEN  
B_OWNER
B_MODE  
B_LOCK  
B_CREATE
B_REMOVE
B_RENAME

total number of  notification band:
NR_BAND

Array of integers (event ID) called idset:
 int idset[NR_BAND];

INTERFACES


The following set of API is provided by libaem.

int aemFD_init (void);

Initialize the aem-fd functionality. This module alseo require memory allocation through vmtable.

int aemFD_clear_idset (int *);

Clear an idset.

int aemFD_notify_register (char *, unsigned long, void *, int *);

Register events for the file/directory name  given as the first parameter. The second parameter is a OR of event flags (F_Bflags given above) wich represent events of interest. The third parameter  is the handler to called asynchronously . An idset pointer is given in the last parameter which is filled up by the call. It containts the event Id for each interest flags.

Handler prototype:

        void notiication_handler (int event_id, char *filename, int len, int pid, int band);

The first parameter is the event Id obtained during registration. The name of the file/directory on which an event occured is givent in parameter as well as the length of the string. The other parameters are the pid of the process that triggered the action (event) and the event itself (B_flags givent above).

int aemFD_notify_start (int *);

Enable notification for the idset in parameter.

int aemFD_notify_stop (int *);

Disbale notification for the idset in parameter.

int aemFD_notify_unregister (int *);

Unregister events for the idset in parameter.

int aemFD_hash (int *);

Hash the idset in parameter. This permits to retrieve later the idset corresponding to a specific event Id. This is typically called after registration.

int aemFD_unhash (int *);

Unhash the idset given in parameter. This is typically called before un-registration of events.

int *aemFD_get_idset (int );

Retrieve the idset corresponding to a specific event Id.

EXAMPLE

The following example illustrates a server that gets asynchronous notification for changes on files and directories starting at /tmp. This example is also available in the examples that come with the source package.

#include <stdio.h>
#include <fcntl.h>
#include <aem.h>

/*
 * This example illustrates how to get notifications for changes on files
 * and how to handle sub-directory and recursive registrations with AEM.
 */

const char *band_helper[NR_BAND] = {
    "B_IN",
    "B_OUT",
    "B_HUP",
    "B_OPEN",
    "B_OWNER",
    "B_MODE",
    "B_LOCK",
    "B_CREATE",
    "B_REMOVE",
    "B_RENAME"
};

static void check_idset (int *idset)
{
    int i;
   
    for (i=0 ; i<NR_BAND ; i++) {
        if (idset[i] <= 0)
            printf ("Could not register for '%s' - value = %d\n", band_helper[i], idset[i]);
    }
}

/*
 * This is the handler for file and directory change notifications
 * The file/directory name is directly received by the process.
 */

void fd_events (int jid, char *filename, int len, int pid, int band)
{
    int err;
    int idset[NR_BAND];
    int *set;

    if (len <= 0)
        return;

    *(filename + len) = '\0';

    printf ("[%d] notification '%s' for '%s'\n", jid, band_helper[band], filename);

    switch (band) {
    case B_REMOVE:
        printf ("[%d] removing entry '%s'\n", jid, filename);
        set = aemFD_get_idset (jid);
        if (!set) {
            printf ("Event un-registration cannot find idset from jid=%d. Aborting.\n", jid);
            exit (1);
        }

        err = aemFD_notify_unregister (set);
        if (err > 0) {
            printf ("%d event un-registration errors in handler. Aborting.\n", err);
            exit (1);
        }

        err = aemFD_unhash (set);
        if (err < 0) {
            perror ("");
            exit (1);
        }
       
        break;

    case B_CREATE:
        /*
         * Recursively register newly created entries
         */
        aemFD_clear_idset (idset);

        printf ("[%d] event registration for '%s'\n", jid, filename);
        err = aemFD_notify_register (filename, F_BIN | F_BOUT | F_BHUP | F_BOPEN | F_BOWNER
                         | F_BMODE | F_BLOCK | F_BCREATE | F_BREMOVE | F_BRENAME,
                         fd_events, idset);
        if (err == NR_BAND) {
            printf ("No events could be registered for '%s'. Bailing out.\n", filename);
            return;
        }

        if (err > 0)
            check_idset (idset);
       
        err = aemFD_hash (idset);
        if (err < 0) {
            perror ("hash:");
            return;
        }

        err = aemFD_notify_start (idset);
        if (err < 0) {
            perror ("start:");
            exit (1);
        }
        break;

    default:
        break;
    }
}

main (int argc, char **argv)
{
    int err;
    int idset[NR_BAND];

    /* We need the AEM memory management here */
    if (aemCORE_init (TBL_UZONE) < 0)
        exit (1);

    if (aemFD_init () < 0)
        exit (1);
   
    aemFD_clear_idset (idset);

    /* we want to receive all possible notifications for changes happening in /tmp */
    err = aemFD_notify_register ("/tmp", F_BIN | F_BOUT | F_BHUP | F_BOPEN | F_BOWNER
                     | F_BMODE | F_BLOCK | F_BREMOVE | F_BCREATE | F_BRENAME,
                     fd_events, idset);
    if (err == NR_BAND) {
        printf ("No events could be registered for /tmp. Bailing out.\n");
        exit (1);
    }

    if (err > 0)
        check_idset (idset);
   
    err = aemFD_hash (idset);
    if (err < 0) {
        perror ("");
        exit (1);
    }

    /* let's go */
    err = aemFD_notify_start (idset);
    if (err < 0) {
        perror ("");
        exit (1);
    }

    printf ("Monitoring changes under /tmp ...\n");
    while (1)
        pause ();
}