/*
* kqueue_monitor.c
* This program demonstrates how to use the kqueue function.
*
* to compile: gcc -O -pipe kqueue_monitor.c -o kqueue_monitor
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
/* our defines */
#define MAX_TIME (60 * 60 * 2)
#define PAGE_END ("\n\n----------------------END-OF-PAGE-----------------------\n\n")
#define LETTERS (" abcdefghijklmnopqrstuvwxyz\n ABCDEFGHIJKLMNOPQRSTUVWXYZ.! \n ")
#define END_LEN (60)
#define PAGE_LEN (500 * 4)
#define MODE (S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH)
#define MAXPROC (64)
#define MAXBUFF (1024)
#define TIMEOUT (1024)
#define NFILES (4)
#define NSIGNALS (3) /* SIGHUP, SIGTERM, SIGQUIT */
#define SIGNALS {SIGHUP, SIGINT, SIGQUIT }
#define FILES {"LOG_1", "LOG_2", "LOG_3", "LOG_4" }
#define KEVENT_SIZE (MAXPROC + NFILES + NSIGNALS)
#define KV_TIMEOUT (0)
#define KV_ERR (-1)
/* our declerations */
void child_function(int fd);
int main(int argc, char **argv)
{
int i, fds[NFILES], kq, kindex = 0;
int signals[NSIGNALS] = SIGNALS;
pid_t child[MAXPROC];
char *files[NFILES] = FILES;
struct kevent kfds[KEVENT_SIZE];
struct timespec tm;
/* start the kqueue */
kq = kqueue();
/* check to see if we have a valid kqueue */
if( kq < 0 )
{
perror("Cannot create a kqueue !\n");
exit(1);
}
/*
* Set up our signals for kqueue
*/
for( i = 0; i < NSIGNALS; i++ )
{
/* even though we ignore them, we will still get kevents */
signal(signals[i], SIG_IGN);
kfds[i].ident = signals[i];
kfds[i].flags = EV_ADD;
kfds[i].filter = EVFILT_SIGNAL;
}
/* keep track of our current index */
kindex = i;
kindex++;
/*
* open our files first and set our kqueue information
*/
for( i = 0; i < NFILES; i++ )
{
fds[i] = open(files[i], (O_RDWR | O_CREAT), MODE);
if( fds[i] < 0 )
{
perror("Cannot open file!\n");
exit(1);
}
/* set kqueue structure information, with many fields */
kfds[kindex].ident = fds[i];
kfds[kindex].flags = EV_ADD;
kfds[kindex].filter = EVFILT_VNODE;
kfds[kindex].fflags = (NOTE_EXTEND | NOTE_DELETE | NOTE_ATTRIB);
kfds[kindex].udata = (void *)files[i];
/* advance our kindex */
kindex++;
}
/*
* Now fork off our children and set our kqueue structure information again.
*/
for( i = 0; i < MAXPROC; i++ )
{
child[i] = fork();
if( child[i] == 0 )
{
/* Child */
child_function( fds[ i % NFILES] );
/* if we return then simply exit */
exit(1);
}
/* Parent */
/* set kqueue structure information */
kfds[kindex].ident = child[i];
kfds[kindex].flags = EV_ADD;
kfds[kindex].filter = EVFILT_PROC;
kfds[kindex].fflags = (NOTE_EXIT | NOTE_FORK );
/* advance our kindex */
kindex++;
}
/*
* So we can use the same array for events and register them.
* we first call kevent before the main loop.
*/
kindex = kevent(kq, kfds, KEVENT_SIZE, kfds, KEVENT_SIZE, &tm);
/*
* Our main event loop. All we have to do is wait for kqueue to return
* with specific information to
* determine what has happend.
*/
while( 1 )
{
/*
* Call kevent. When kevent returns there are three possiblities:
* I) (n) events are ready
* II) an error
* III) a timeout
*/
switch( kindex )
{
case KV_TIMEOUT:
break;
case KV_ERR:
break;
default:
/*
* Check to see if we have more events than
* we have space for. This is important because
* we could have more events than the size of
* our array.
*/
printf("We have [%d] events\n", kindex);
kindex >= KEVENT_SIZE ? KEVENT_SIZE : kindex;
for( i =0; i < kindex; i++ )
{
switch( kfds[i].filter )
{
case EVFILT_SIGNAL:
printf("We recieved the signal [%d]\n", kfds[i].ident);
exit(1);
break;
case EVFILT_PROC:
printf("We have a child issue, process [%d] has: \n",kfds[i].ident);
switch( kfds[i].fflags )
{
case NOTE_EXIT:
printf("[ EXITED ]\n");
break;
case NOTE_FORK:
printf("[ FORKED ]\n");
}
break;
case EVFILT_VNODE:
printf("File [%s] was ", (char *)kfds[i].udata);
switch( kfds[i].fflags )
{
case NOTE_EXTEND:
printf("[ EXTENDED ]\n");
break;
case NOTE_ATTRIB:
printf("[ ATTRIBUTES ]\n");
break;
case NOTE_DELETE:
printf("[ DELETED ]\n");
}
break;
}
}
}
kindex = kevent(kq, (struct kevent*)NULL, 0, kfds, KEVENT_SIZE, &tm);
}
/* FIN */
return(0);
} /* main */
/*
* child_function
* Simular to monkey book, except we don't have to lock, and
* at a radnom interval we will simply exit.
*/
void child_function(int fd)
{
int i, len, c;
char buff[PAGE_LEN], *letters = LETTERS;
/* seed our random generator */
srand( (time(NULL) - getpid()) / getpid() );
len = strlen(letters);
while( 1 )
{
for( i = 0; i < PAGE_LEN; i++ )
{
buff[i] = letters[ (rand() % len) ];
}
/*
* Just for fun, check a random character in the
* buffer. If its 'K' then die, if its F then fork.
*/
c = buff[rand() % PAGE_LEN];
switch( c )
{
case 'K':
exit(1);
break;
case 'F':
if( fork() == 0 )
{
/* child */
child_function(fd);
}
else
{
/* parent */
exit(0);
}
break;
} /* switch */
write(fd, buff, PAGE_LEN);
write(fd, PAGE_END, END_LEN);
sleep( (rand() % getpid()) * 10 );
} /* while */
}
syntax highlighted by Code2HTML, v. 0.9