AIX:AHAFS ahamoddir.c: Difference between revisions
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);
}