How to constantly monitor the state of a file

From Wiki-UX.info
Jump to: navigation, search

Abstract[edit]

This article presents two methods to constantly monitor the state of a file or directory. This kind of monitoring is require to diagnose when a file is created in a file system and how fast is populated with data. The following alternatives are presented:

  1. POSIX SHELL Script
  2. ANSI C Program

Both are technically equivalent and implement the same logic for parameter reading. Also, a similar while infinite loop is used to process the file attributes.

The ANSI C program requires compilation, but it is not so "resource hog" as the the POSIX SHELL script. It is only intended for usage when a large number of individual files needs to be monitored. Likewise, code has been added to handle [Ctrl]-[C] and kill <pid> (SIGTERM) signals.

Last but not least, the ANSI C program works with standard Signal Handling and UNIX System Calls that allow to use it as a functional example of the fstat, getpwuid, getgrgid, signal and time system calls.

POSIX SHELL Script (existence.sh)[edit]

# This POSIX SHELL script constantly monitors if an arbitrary
# file exists and returns the "ls -ld output"
# It comes with no support and HP makes no representations as to its
# fitness for purpose. It is up to whoever uses this program to ensure
# that whatever functionality it provides is what they require.
# (c) Wiki-UX.info (2010)

# Usage: existence.sh [-t time] -f filename

sleeptime=1
myfile=""

# Process parameters
while [[ $# -gt 0 ]]; do

   if [[ $1 = "-t" ]]; then
      sleeptime=$2
   fi

   if [[ $1 = "-f" ]]; then
      myfile="$2"
   fi

   shift
done

# Verify that -f filename is defined
if [[ ! -n $myfile ]]; then
   echo "usage: existence.sh [-t time] -f filename"
   exit 1
fi

# Check that the file exists and prints file information
while true
do
if [[ -f $myfile ]]; then
   ls -ld $myfile
fi
sleep $sleeptime
done

Example:

# ./existence.sh -t 5 -f /usr/bin/cp
-t 5 -f /usr/bin/cp
-r-xr-xr-x   1 bin        bin          53248 Apr 17  2008 /usr/bin/cp
-r-xr-xr-x   1 bin        bin          53248 Apr 17  2008 /usr/bin/cp
-r-xr-xr-x   1 bin        bin          53248 Apr 17  2008 /usr/bin/cp

ANSI C Program (existence.c)[edit]

/*
This program (existence.c) constantly monitors if an arbitrary
file exists and returns its size
It comes with no support and Wiki-UX.info makes no representations as to its
fitness for purpose. It is up to whoever uses this program to ensure
that whatever functionality it provides is what they require.
(c) Wiki-UX.info (2010)

Default time delay is 1 second
Usage: existence [-t time] -f filename

2009.11.23 - Added code to detect and report inode number changes.
*/

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <pwd.h>
# include <grp.h>
# include <signal.h>
# include <fcntl.h>
# include <time.h>
# include <sys/types.h>
# include <sys/stat.h>

/* Public variables */
FILE *fp;
int fo;

/* Prototypes */
int errors(int errorcode);
void catch_int(int sig_num);
void catch_term(int sig_num);

int main(int argc, char** argv) {
struct stat mystat;
struct passwd *pwd;
struct group *grp;
struct tm *ts;
int i, status;
signed int inodenum=-1;
char myfile[256];
char fdate[80];
int sleeptime = 1; /* Default sleep time is 1 second */

signal(SIGINT, catch_int); /* Traps SIGINT */
signal(SIGTERM, catch_term); /* Traps SIGINT */

/* Read command options */
for(i = 1; i < argc; i++) {
 if(argv[i][0] == '-') {
 switch (argv[i][1]) {
  case 't':
   sleeptime = atoi(argv[i+1]);
   break;
  case 'f':
   strcpy(myfile, argv[i+1]);
   break;
  default:
   return(errors(1));
  }
 }
}

/* Verify that -f filename is defined */
if(strlen(myfile) < 1)
 return(errors(1));

printf("PID: %d\n", getpid());

/* Check that the file exists and prints file information */
while(1) {
 fo = open(myfile, O_RDONLY);
 if (fo != -1) {
  status = fstat(fo, &mystat);
  close(fo);

/* Compares previous inode with current inode and returns a warning */
/* Set the current inode to inum if this is the first pass */
  if(inodenum == -1)
     inodenum = mystat.st_ino;

/* Return information if the inode change from previous file */
  if(inodenum != mystat.st_ino) {
     errors(3);
     inodenum = mystat.st_ino;
  }

  printf("%d\t", inodenum);
  
  if(pwd = getpwuid(mystat.st_uid))
     fprintf(stdout, "%s\t", pwd->pw_name);
  else
     fprintf(stdout, "%d\t", mystat.st_uid);

  if(grp = getgrgid(mystat.st_gid))
     fprintf(stdout, "%s\t", grp->gr_name);
  else
     fprintf(stdout, "%d\t", mystat.st_gid);

  ts = localtime(&mystat.st_mtime);
  strftime(fdate, sizeof(fdate), "%a %Y-%m-%d %H:%M:%S %Z", ts);
  printf("%s\t", fdate);

  fprintf(stdout, "%d\t%s\n",
     mystat.st_size,
     myfile);
  } else errors(2);
sleep(sleeptime);
 }
}

/* Error message handler */
int errors(int errorcode) {

switch (errorcode) {
   case 1:
      fprintf(stderr, "usage: existence [-t delay] -f filename\n");
      break;
   case 2:
      fprintf(stderr, "Cannot open file or directory!\n");
      break;
   case 3:
      fprintf(stderr, "Inode Number since the previous test!\n");
      break;
   }
return errorcode;
}

/* UNIX Signal handlers */
void catch_int(int sig_num)
{
    signal(SIGINT, catch_int);
        if (fo != -1)
         close(fo);
    fprintf(stderr, "Program interrupted\n");
        exit(0);
}

void catch_term(int sig_num)
{
    signal(SIGTERM, catch_int);
        if (fo != -1)
         close(fo);
    fprintf(stderr, "Program terminated.\n");
        exit(0);
}


Example:

On the following example the program verifies the existence of /var/tmp/test directory. The directory is removed during the execution of the program to demonstrate how the error is handle. The directory is recreated and the inode number change is reported too.

# ./existence -t 2 -f /var/tmp/test
PID: 1176
7845    root    sys     Tue 2009-11-24 19:40:41 CST     96      /var/tmp/test
7845    root    sys     Tue 2009-11-24 19:40:41 CST     96      /var/tmp/test
7845    root    sys     Tue 2009-11-24 19:40:41 CST     96      /var/tmp/test
7845    root    sys     Tue 2009-11-24 19:40:41 CST     96      /var/tmp/test
7845    root    sys     Tue 2009-11-24 19:40:41 CST     96      /var/tmp/test
Cannot open file or directory!
Cannot open file or directory!
Cannot open file or directory!
Inode Number since the previous test!
1626    root    sys     Tue 2009-11-24 19:42:56 CST     96      /var/tmp/test
1626    root    sys     Tue 2009-11-24 19:42:56 CST     96      /var/tmp/test
Program interrupted

Authors[edit]