AIX:AHAFS ahamoddir.c: Difference between revisions

From RoggeWiki
Jump to navigation Jump to search
(Created page with " /* * mon_moddir_event.c * * This program monitors for modifications to a file specified by the user. * Event occurrences are printed to the user. If the file being monit...")
 
No edit summary
Line 15: Line 15:
  *
  *
  */
  */
 
  #include <stdio.h>
  #include <stdio.h>
  #include <sys/poll.h>
  #include <sys/poll.h>
Line 30: Line 30:
  #include <usersec.h>
  #include <usersec.h>
  #include <sys/ahafs_evProds.h>  
  #include <sys/ahafs_evProds.h>  
 
  #define RDWR_BUF_SIZE  4096
  #define RDWR_BUF_SIZE  4096
 
  int    sequence_num;
  int    sequence_num;
  char  *objName;
  char  *objName;
Line 38: Line 38:
  uid_t  objUid;
  uid_t  objUid;
  gid_t  objGid;
  gid_t  objGid;
 
  /* NAME:    skip_lines
  /* NAME:    skip_lines
  * PURPOSE: Skips a specified number of lines in the buffer passed in.
  * PURPOSE: Skips a specified number of lines in the buffer passed in.
Line 51: Line 51:
  {
  {
     int lines = 0;
     int lines = 0;
 
     while(n > 0)
     while(n > 0)
     {
     {
Line 62: Line 62:
         lines++;
         lines++;
     }
     }
 
     return(lines);
     return(lines);
  }
  }
 
  /* NAME:    print_op
  /* NAME:    print_op
  * PURPOSE: Prints a string indicating what monitored file operation triggered
  * PURPOSE: Prints a string indicating what monitored file operation triggered
Line 88: Line 88:
         printf("Unknown file op: %d", evp_rc);
         printf("Unknown file op: %d", evp_rc);
  }
  }
 
  /* NAME:    mk_subdirs
  /* NAME:    mk_subdirs
  * PURPOSE: Creates necessary subdirectories in the AIX Event Infrastructure
  * PURPOSE: Creates necessary subdirectories in the AIX Event Infrastructure
Line 100: Line 100:
     char cmd[2048];
     char cmd[2048];
     char *p;
     char *p;
 
     /* Strip off the monitor file name */
     /* Strip off the monitor file name */
     p = strrchr(objName, '/');
     p = strrchr(objName, '/');
 
     if(p == NULL)
     if(p == NULL)
         return(0);
         return(0);
 
     sprintf(cmd, "/usr/bin/mkdir -p /aha/fs/modDir.monFactory/");
     sprintf(cmd, "/usr/bin/mkdir -p /aha/fs/modDir.monFactory/");
     strncat(cmd, objName, (p - objName));
     strncat(cmd, objName, (p - objName));
     return(system(cmd));
     return(system(cmd));
  }
  }
 
  /* NAME:    parse_data
  /* NAME:    parse_data
  * PURPOSE: This function will parse the event occurrence data and take
  * PURPOSE: This function will parse the event occurrence data and take
Line 136: Line 136:
     char  curTm[64], cmd[64];
     char  curTm[64], cmd[64];
     char  uname[64], lname[64], gname[64];
     char  uname[64], lname[64], gname[64];
 
     p = buf;
     p = buf;
 
     /* Check for BUF_WRAP */
     /* Check for BUF_WRAP */
     if(strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0)
     if(strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0)
Line 145: Line 145:
         return(0);
         return(0);
     }
     }
 
     /* Since we are using the default buffer size (4K), and have specified
     /* Since we are using the default buffer size (4K), and have specified
     * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions.  Applications
     * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions.  Applications
Line 151: Line 151:
     * higher, and have a buffer size of <= 4K
     * higher, and have a buffer size of <= 4K
     */
     */
 
     /* Skip "BEGIN_EVENT_INFO" header */
     /* Skip "BEGIN_EVENT_INFO" header */
     if(skip_lines(&p, 1) != 1)
     if(skip_lines(&p, 1) != 1)
         return(2);
         return(2);
 
     /* Get timestamp and sequence number. */
     /* Get timestamp and sequence number. */
     if(sscanf(p,"TIME_tvsec=%ld\nTIME_tvnsec=%ld\nSEQUENCE_NUM=%d\n",
     if(sscanf(p,"TIME_tvsec=%ld\nTIME_tvnsec=%ld\nSEQUENCE_NUM=%d\n",
Line 163: Line 163:
         if(skip_lines(&p, 3) != 3)
         if(skip_lines(&p, 3) != 3)
             return(2);
             return(2);
 
         printf("Time            : %s", curTm);
         printf("Time            : %s", curTm);
         printf("Seq num        : %d", seq_num);
         printf("Seq num        : %d", seq_num);
Line 170: Line 170:
         else
         else
             printf("\n");
             printf("\n");
 
         sequence_num = seq_num + 1;
         sequence_num = seq_num + 1;
     }
     }
     else
     else
         return(2);
         return(2);
 
     if(err)
     if(err)
     {
     {
Line 209: Line 209:
             strcpy(lname, IDtouser(luid));
             strcpy(lname, IDtouser(luid));
             strcpy(gname, IDtogroup(gid));
             strcpy(gname, IDtogroup(gid));
 
             printf("Process ID  : %d\n", pid);
             printf("Process ID  : %d\n", pid);
             printf("User Info  : userName=%s, loginName=%s, groupName=%s\n",
             printf("User Info  : userName=%s, loginName=%s, groupName=%s\n",
                       uname, lname, gname);
                       uname, lname, gname);
             printf("Program Name        : %s\n", cmd);
             printf("Program Name        : %s\n", cmd);
 
             /* Get the RC_FROM_EVPROD */
             /* Get the RC_FROM_EVPROD */
             if(skip_lines(&p, 5) != 5)
             if(skip_lines(&p, 5) != 5)
                 return(2);
                 return(2);
 
             if(sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1)
             if(sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1)
             {
             {
Line 242: Line 242:
         else
         else
             return(2);
             return(2);
 
     }
     }
 
     if(recreate)
     if(recreate)
     {
     {
Line 253: Line 253:
             rc = chown(objName, objUid, objGid);
             rc = chown(objName, objUid, objGid);
         }
         }
 
         if((fd == -1) || rc)
         if((fd == -1) || rc)
         {
         {
Line 262: Line 262:
             rc = 1;
             rc = 1;
     }
     }
 
     return(rc);
     return(rc);
  }
  }
 
  int
  int
  main(int argc, char *argv[])
  main(int argc, char *argv[])
Line 276: Line 276:
     char  monFileWrStr[RDWR_BUF_SIZE];
     char  monFileWrStr[RDWR_BUF_SIZE];
     struct stat statbuf;
     struct stat statbuf;
 
     if(argc != 2)
     if(argc != 2)
     {
     {
Line 283: Line 283:
         return(-1);
         return(-1);
     }
     }
 
 
     /* Create monitor file name for object */
     /* Create monitor file name for object */
     objName = argv[1];
     objName = argv[1];
Line 293: Line 293:
         return(ENAMETOOLONG);
         return(ENAMETOOLONG);
     }
     }
 
     /* Make the necessary subdirectories for the monitor file */
     /* Make the necessary subdirectories for the monitor file */
     if(rc = mk_subdirs())
     if(rc = mk_subdirs())
         return(rc);
         return(rc);
 
     strcat(monFile, objName);
     strcat(monFile, objName);
     strcat(monFile, ".mon");
     strcat(monFile, ".mon");
 
     /* Save off the mode and ownership of monitored object */
     /* Save off the mode and ownership of monitored object */
     if(stat(objName, &statbuf) < 0)
     if(stat(objName, &statbuf) < 0)
Line 307: Line 307:
         return(errno);
         return(errno);
     }
     }
 
     objGid = statbuf.st_gid;
     objGid = statbuf.st_gid;
     objUid = statbuf.st_uid;
     objUid = statbuf.st_uid;
     objMode = statbuf.st_mode;
     objMode = statbuf.st_mode;
 
  open:
  open:
     restart = 0;
     restart = 0;
     sequence_num = 0;
     sequence_num = 0;
 
     /* Open the monitor file, creating it if necessary */
     /* Open the monitor file, creating it if necessary */
     fd = open(monFile, O_CREAT|O_RDWR);
     fd = open(monFile, O_CREAT|O_RDWR);
Line 323: Line 323:
         return(errno);
         return(errno);
     }
     }
 
     /* Write out the monitoring specifications.
     /* Write out the monitoring specifications.
     * In this case, we are monitoring for a state change event type
     * In this case, we are monitoring for a state change event type
Line 334: Line 334:
     */
     */
     sprintf(monFileWrStr, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
     sprintf(monFileWrStr, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
 
     rc = write(fd, monFileWrStr, strlen(monFileWrStr)+1);
     rc = write(fd, monFileWrStr, strlen(monFileWrStr)+1);
     if (rc < 0)
     if (rc < 0)
Line 341: Line 341:
         return(errno);
         return(errno);
     }
     }
 
     /* Keep monitoring for event occurrences until stopped */
     /* Keep monitoring for event occurrences until stopped */
     while(1)
     while(1)
Line 349: Line 349:
         FD_SET(fd, &readfds);
         FD_SET(fd, &readfds);
         err = 0;
         err = 0;
 
         rc = select(fd+1, &readfds, NULL, NULL, NULL);
         rc = select(fd+1, &readfds, NULL, NULL, NULL);
         if (rc <= 0)
         if (rc <= 0)
Line 359: Line 359:
             err = 1;
             err = 1;
         }
         }
 
 
         bytes = pread(fd, resultData, RDWR_BUF_SIZE, 0);
         bytes = pread(fd, resultData, RDWR_BUF_SIZE, 0);
         if(bytes < 0)
         if(bytes < 0)
Line 369: Line 369:
         else
         else
             restart = parse_data(resultData, err);
             restart = parse_data(resultData, err);
 
         if(restart == 2)
         if(restart == 2)
             break;
             break;
 
         if(restart)
         if(restart)
         {
         {

Revision as of 15:16, 26 May 2015

/*
* mon_moddir_event.c
*
* This program monitors for modifications to a file specified by the user.
* Event occurrences are printed to the user.  If the file being monitored is
* removed or renamed, it will be recreated and monitoring will continue.
*
* If the filesystem containing the file is unmounted, or the file itself is
* overmounted, monitoring will cease and the program will exit.
*
* This program assumes the AIX Event Infrastructure file system has been
* mounted on /aha.  To mount it, run:
*      mkdir /aha
*      mount -v ahafs /aha /aha
*
*/

#include <stdio.h>
#include <sys/poll.h>
#include <sys/pollset.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <libgen.h>
#include <usersec.h>
#include <sys/ahafs_evProds.h> 

#define RDWR_BUF_SIZE   4096

int    sequence_num;
char   *objName;
ushort objMode;
uid_t  objUid;
gid_t  objGid;

/* NAME:    skip_lines
* PURPOSE: Skips a specified number of lines in the buffer passed in.
* PARAMETERS:
*      p - Address of the pointer to the head of the buffer
*      n - The number of lines to skip
* RETURNS:
*      Total number of lines skipped
*/
int
skip_lines(char **p, int n)
{
   int lines = 0;

   while(n > 0)
   {
       *p = strchr(*p, '\n');
       if(!p)
           return(lines);
       (*p)++;
       n--;
       lines++;
   }

   return(lines);
}

/* NAME:    print_op
* PURPOSE: Prints a string indicating what monitored file operation triggered
*          the event occurrence.
* PARAMETERS:
*      evp_rc - The return code from RC_FROM_EVPROD
* RETURNS:
*      Nothing.
*/
void
print_op(int evp_rc)
{
   if(evp_rc == AHAFS_MODDIR_CREATE)
       printf("File created.");
   else if(evp_rc == AHAFS_MODDIR_UNMOUNT)
       printf("Filesystem unmounted.");
   else if(evp_rc == AHAFS_MODDIR_REMOVE)
       printf("File removed.");
   else if(evp_rc == AHAFS_MODDIR_REMOVE_SELF)
       printf("File renamed.");
   else
       printf("Unknown file op: %d", evp_rc);
}

/* NAME:    mk_subdirs
* PURPOSE: Creates necessary subdirectories in the AIX Event Infrastructure
*          file system for monitoring the object specified.
* RETURNS:
*      Return code from mkdir call
*/
int
mk_subdirs()
{
   char cmd[2048];
   char *p;

   /* Strip off the monitor file name */
   p = strrchr(objName, '/');

   if(p == NULL)
       return(0);

   sprintf(cmd, "/usr/bin/mkdir -p /aha/fs/modDir.monFactory/");
   strncat(cmd, objName, (p - objName));
   return(system(cmd));
}

/* NAME:    parse_data
* PURPOSE: This function will parse the event occurrence data and take
*          corrective action if necessary.
* PARAMETERS:
*      buf - A pointer to the buffer containing the event occurrence data
*      err - Indicates if the previous select() call returned an error
*            (a different parsing format is required).
* RETURNS:
*        0 - No corrective action needed.
*        1 - Corrective action taken, monitoring must be restarted.
*        2 - Unrecoverable error in parsing
*/
int
parse_data(char *buf, int err)
{
   int    rc = 0, evp_rc, recreate = 0;
   char   *p;
   time_t sec, nsec;
   int    seq_num;
   pid_t  pid;
   uid_t  uid, gid;
   gid_t  luid;
   char   curTm[64], cmd[64];
   char   uname[64], lname[64], gname[64];

   p = buf;

   /* Check for BUF_WRAP */
   if(strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0)
   {
       printf("Buffer wrap detected, Some event occurrences lost!\n");
       return(0);
   }

   /* Since we are using the default buffer size (4K), and have specified
    * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions.  Applications
    * should check for this keyword if they are using an INFO_LVL of 2 or
    * higher, and have a buffer size of <= 4K
    */

   /* Skip "BEGIN_EVENT_INFO" header */
   if(skip_lines(&p, 1) != 1)
       return(2);

   /* Get timestamp and sequence number. */
   if(sscanf(p,"TIME_tvsec=%ld\nTIME_tvnsec=%ld\nSEQUENCE_NUM=%d\n",
       &sec, &nsec, &seq_num) == 3)
   {
       ctime_r(&sec, curTm);
       if(skip_lines(&p, 3) != 3)
           return(2);

       printf("Time            : %s", curTm);
       printf("Seq num         : %d", seq_num);
       if(seq_num != sequence_num)
           printf(" (%d duplicates)\n", (seq_num - sequence_num));
       else
           printf("\n");

       sequence_num = seq_num + 1;
   }
   else
       return(2);

   if(err)
   {
       /* We just expect to see the RC_FROM_EVPROD and the "END_EVENT_DATA"
        * footer after the timestamp and sequence number in the error case */
       if(sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1)
       {
           printf("Error in event monitoring: %d.", evp_rc);
           if(evp_rc == ENODEV)
           {
               /* Object being monitored doesn't exist, recreate it */
               printf(" Recreating object.\n");
               recreate = 1;
           }
           else
           {
               /* Some other error occurred which we can't correct */
               printf(" Unable to recover.\n");
               rc = 2;
           }
       }
       else
           return(2);
   }
   else
   {
       /* Collect user and process info */
       if(sscanf(p,
               "PID=%ld\nUID=%ld\nUID_LOGIN=%ld\nGID=%ld\nPROG_NAME=%s\n",
               &pid, &uid, &luid, &gid, cmd) == 5)
       {
           strcpy(uname, IDtouser(uid));
           strcpy(lname, IDtouser(luid));
           strcpy(gname, IDtogroup(gid));

           printf("Process ID  : %d\n", pid);
           printf("User Info   : userName=%s, loginName=%s, groupName=%s\n",
                      uname, lname, gname);
           printf("Program Name        : %s\n", cmd);

           /* Get the RC_FROM_EVPROD */
           if(skip_lines(&p, 5) != 5)
               return(2);

           if(sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1)
           {
               print_op(evp_rc);
               switch(evp_rc)
               {
                   case AHAFS_MODDIR_CREATE:
                       /* Recreate the object */
                       printf(" A file has been created in the directory.\n\n");
                       break;
                   case AHAFS_MODDIR_REMOVE:
                       /* Unrecoverable "unavailable" events. */
                       printf(" A file has been removed in the directory.\n\n");
                       break;
                   default:
                       printf(" No action required.\n\n");
               }
           }
           else
               return(2);
       }
       else
           return(2);

   }

   if(recreate)
   {
       int fd;
       fd = creat(objName, objMode);
       if(fd != -1)
       {
           rc = chown(objName, objUid, objGid);
       }

       if((fd == -1) || rc)
       {
           perror("Error recreating object");
           rc = 2;
       }
       else
           rc = 1;
   }

   return(rc);
}

int
main(int argc, char *argv[])
{
   int    c, i = 0;
   int    fd, rc, bytes, err=0, restart;
   fd_set readfds;
   char   monFile[PATH_MAX];
   char   resultData[RDWR_BUF_SIZE];
   char   monFileWrStr[RDWR_BUF_SIZE];
   struct stat statbuf;

   if(argc != 2)
   {
       printf("Usage: %s <full path to file to monitor>\n", argv[0]);
       printf("  Example: %s /etc/passwd\n", argv[0]);
       return(-1);
   }


   /* Create monitor file name for object */
   objName = argv[1];
   sprintf(monFile, "/aha/fs/modDir.monFactory");
   if((strlen(monFile) + strlen(objName) + 5) > PATH_MAX)
   {
       fprintf(stderr, "Error: Cannot monitor object, path name too long\n");
       return(ENAMETOOLONG);
   }

   /* Make the necessary subdirectories for the monitor file */
   if(rc = mk_subdirs())
       return(rc);

   strcat(monFile, objName);
   strcat(monFile, ".mon");

   /* Save off the mode and ownership of monitored object */
   if(stat(objName, &statbuf) < 0)
   {
       perror("Error stating file");
       return(errno);
   }

   objGid = statbuf.st_gid;
   objUid = statbuf.st_uid;
   objMode = statbuf.st_mode;

open:
   restart = 0;
   sequence_num = 0;

   /* Open the monitor file, creating it if necessary */
   fd = open(monFile, O_CREAT|O_RDWR);
   if(fd < 0)
   {
       perror("Error opening monitor file");
       return(errno);
   }

   /* Write out the monitoring specifications.
    * In this case, we are monitoring for a state change event type
    * (modFile):
    *    CHANGED=YES
    * We will be waiting in select call, rather than a read:
    *    WAIT_TYPE=WAIT_IN_SELECT
    * we only want minimal information:
    *    INFO_LVL=1
    */
   sprintf(monFileWrStr, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");

   rc = write(fd, monFileWrStr, strlen(monFileWrStr)+1);
   if (rc < 0)
   {
       perror("Error writing to monitor file");
       return(errno);
   }

   /* Keep monitoring for event occurrences until stopped */
   while(1)
   {
       /* Initialize the set */
       FD_ZERO(&readfds);
       FD_SET(fd, &readfds);
       err = 0;

       rc = select(fd+1, &readfds, NULL, NULL, NULL);
       if (rc <= 0)
       {
           /* All errors in event monitoring will cause select to return
            * EBADF.  Read to see if any additional data is available.
            */
           perror("Error issuing select");
           err = 1;
       }


       bytes = pread(fd, resultData, RDWR_BUF_SIZE, 0);
       if(bytes < 0)
           perror("Error reading monitor file");
       else if(bytes == 0)
           fprintf(stderr,
               "Error reading monitor file.  No data to be read\n");
       else
           restart = parse_data(resultData, err);

       if(restart == 2)
           break;

       if(restart)
       {
           close(fd);
           goto open;
       }
    }
    close(fd);
    return(err);
}