/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* bos720 src/bos/usr/samples/ahafs/bin/aha.c 1.1.1.1 */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* Restricted Materials of IBM */ /* */ /* COPYRIGHT International Business Machines Corp. 2009,2010 */ /* All Rights Reserved */ /* */ /* US Government Users Restricted Rights - Use, duplication or */ /* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* */ /* IBM_PROLOG_END_TAG */ /* FUNCTIONS in this FILE aha.c: * main or aha * syntax * monitor_a_event * ahaMonFile * mk_parent_dirs * read_data * monitor_a_set_of_events * read_inputfile * print_monList * fdToMonListIndex * PURPOSE: * 1) Using the -i input flag, to easily monitor a set of AHA events listed in * an input file which has the format as described in the sample aha.inp file. * * This option invokes the pollset APIs in AIX to wait for occurrences * of the events listed in the . * The advantage of using the pollset APIs instead of select() is that * one does not have to re-register interest in an event each time * select() comes out of even ONE occurrence of an event. * * 2) Using the -m input flag, too monitor one AHA event represented by an * AHA-monitor-file (filetype .mon). * This option uses select() to wait for the occurrence of the AHA event. * SYNTAX: * aha -i * aha -m [=[;=;..] * e.g. * aha -i aha.inp * aha -m /aha/fs/utilFs.monFactory/tmp.mon THRESH_HI=90 * CHANGELOG: * 2008/04/01 Created by R.Burugula * 2008/04/09 Updated by J.Jann * 2008/10/30 Updated by R. Burugula, N.Dubey * 2008/11/15 Updated by J.Jann * 2009/01/21 Updated by N.Dubey * 2009/06/9 Updated by N.Dubey * 2009/07/30 Updated by N. Dubey */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_FD 128 #define MAX_LINE_LENGTH 144 #define MAX_MONITOR_FILEPATH 64 #define MAX_EVENT_NOTIFICATIONS 10 #define STKTRACE_LEN 2048 #define MAX_WRITE_STR_LEN 256 #define AHAFS_THRESH_INVALID (-1) char *progname, *cfgFile, *monFile; char monFileWrStr[MAX_WRITE_STR_LEN]; /* This structure is used to store the info read from the input file. */ typedef struct { char monFileName[MAX_MONITOR_FILEPATH+1]; int eventType; int changed; int threshHi; int fd; int stopped; } monEntry_t; monEntry_t monList[MAX_FD]; int monListSz; /* Number of valid entries in the above array */ /* Function Prototypes */ void syntax(); static int monitor_a_event(); int ahaMonFile(char *str); static int mk_parent_dirs (char *path); void read_data (int fd); static int monitor_a_set_of_events(); void read_inputfile (char *filename); void print_monList (); int fdToMonListIndex (int fd); /*----------------------------------------------------------------- * NAME: main or aha * PURPOSE: To digest the command line arguments and call the function * to monitor a file or a set of files. */ int main(int argc, char *argv[]) { int c; int rc; cfgFile = NULL; monFile = NULL; progname = argv[0]; if (argc < 2) { syntax(); return (-1); } while ((c=getopt(argc,argv,"i:m:h")) != EOF) { switch(c) { case 'i': cfgFile = optarg; break; case 'm': monFile = optarg; if (argv[optind]) sprintf (monFileWrStr, "%s", argv[optind]); else sprintf (monFileWrStr, "CHANGED=YES"); break; case 'h': syntax(); return (0); case '?': syntax(); return (-1); } } if ( (monFile) && (cfgFile)) { syntax(); return (-1); } if (monFile) rc = monitor_a_event(); /* Monitor a file using select() */ else rc = monitor_a_set_of_events(); /* Monitor a set of files using pollset() */ return (rc); } /*----------------------------------------------------------------- * NAME: syntax() * PURPOSE: To display the syntax. */ void syntax (void) { printf ("\nSYNTAX1: %s -i \n", progname); printf ("SYNTAX2: %s -m [=[;=;...]] \n", progname); printf(" where: \n"); printf(" : A file with list of AHA events and their thresholds\n"); printf(" in the format of the file \"aha.inp\".\n\n"); printf(" : Full pathname of an AHA file with suffix \".mon\".\n"); printf(" The possible keys and their values are:\n"); printf(" --------------------------------------------------------------- \n"); printf(" Keys | values | comments \n"); printf(" =============================================================== \n"); printf(" WAIT_TYPE | WAIT_IN_SELECT (default) | Uses select() to wait. \n"); printf(" | WAIT_IN_READ | Uses read() to wait. \n"); printf(" -----------|--------------------------|------------------------ \n"); printf(" CHANGED | YES (default) | Monitors state-change. \n"); printf(" | Any string other than YES| CHANGED cannot be used \n"); printf(" | | together with THRESH_HI.\n"); printf(" -----------|--------------------------|------------------------ \n"); printf(" THRESH_HI | Positive integer | Monitors high threshold.\n"); printf(" ----------------------------------------------------------------\n\n"); printf("Examples: \n"); printf(" 1: %s -i aha.inp\n", progname); printf(" 2: %s -m /aha/fs/utilFs.monFactory/tmp.mon \"THRESH_HI=90\"\n", progname); printf(" 3: %s -m /aha/fs/modFile.monFactory/etc/passwd.mon \"CHANGED=YES\" \n", progname); printf(" 4: %s -m /aha/mem/vmo.monFactory/npskill.mon \n", progname); printf(" 5: %s -m /aha/cpu/waitTmCPU.monFactory/waitTmCPU.mon \n", progname); printf(" \"WAIT_TYPE=WAIT_IN_READ;THRESH_HI=50\" \n"); } /*--------------------------------------------------------------------------- * NAME: monitor_a_event() * PURPOSE: To monitor an AHA event using select(). */ static int monitor_a_event() { int fd, rc; fd_set readfds; char waitInRead[] = "WAIT_TYPE=WAIT_IN_READ"; if ( ! ahaMonFile(monFile) ) /* Not a .mon file under /aha */ return (-1); /* Create intermediate directories of the .mon file */ rc = mk_parent_dirs(monFile); if (rc) { fprintf (stderr, "Could not create intermediate directories of the file %s !\n", monFile); perror ("mkdir: "); return(-1); } printf ("wrstr = %s\n", monFileWrStr); fd = open (monFile, O_CREAT|O_RDWR); if (fd < 0) { fprintf (stderr, "Could not open the file %s; errno = %d !\n", monFile, errno); return(-1); } rc = write(fd, monFileWrStr, strlen(monFileWrStr)+1); if (rc < 0) { perror ("write: "); fprintf (stderr, "Failed writing to monFile %s !\n", monFile); return(-1); } if (strstr(monFileWrStr, waitInRead) == NULL) { FD_ZERO(&readfds); FD_SET(fd, &readfds); printf("Entering select() to wait till the event corresponding to the AHA node %s occurs.\n", monFile); printf("Please issue a command from another window to trigger this event.\n"); rc = select (fd+1, &readfds, NULL, NULL, NULL); printf("\nThe select() completed. \n"); if (rc <= 0) /* No event occurred or an error was found. */ { fprintf (stderr, "The select() returned %d.\n", rc); perror ("select: "); return (-1); } if(! FD_ISSET(fd, &readfds)) goto end; printf("The event corresponding to the AHA node %s has occurred.\n\n", monFile); } else { printf("Entering read() to wait till the event corresponding to the AHA node %s occurs.\n",monFile); printf("Please issue a command from another window to trigger this event.\n\n"); } read_data(fd); end: close(fd); return (0); } /* -------------------------------------------------------------------------- * NAME: ahaMonFile() * PURPOSE: To check whether the file provided is an AHA monitor file. */ int ahaMonFile(char *str) { char cwd[PATH_MAX]; int len1=strlen(str), len2=strlen(".mon"); int rc = 0; struct stat sbuf; /* Make sure that /aha is mounted. */ if ((stat("/aha", &sbuf) < 0) || (sbuf.st_flag != FS_MOUNT)) { printf("ERROR: The filesystem /aha is not mounted!\n"); return (rc); } /* Make sure that the file-pathname has .mon as its suffix. */ if ( (len1 <= len2) || (strcmp ( (str + len1 - len2), ".mon")) ) goto end; if (! strncmp (str, "/aha",4)) /* The given pathname starts with /aha */ rc = 1; else /* It could be a relative path */ { getcwd (cwd, PATH_MAX); if( (str[0] != '/' ) && /* Relative path and */ (! strncmp (cwd, "/aha",4)) /* cwd starts with /aha . */ ) rc = 1; } end: if (!rc) printf("ERROR: %s is not an AHA monitor file !\n", str); return (rc); } /*----------------------------------------------------------------- * NAME: mk_parent_dirs() * PURPOSE: To create intermediate directories of a .mon file if * they were not created. */ static int mk_parent_dirs (char *path) { char s[PATH_MAX]; char *dirp; struct stat buf; int rc=0; dirp = dirname(path); if (stat(dirp, &buf) != 0) { sprintf(s, "/usr/bin/mkdir -p %s", dirp); rc = system(s); } return (rc); } /*----------------------------------------------------------------- * NAME: read_data * PURPOSE: To parse and print the data received at the occurrence * of the event. */ void read_data (int fd) { #define READ_BUF_SIZE 4096 char data[READ_BUF_SIZE]; char *p, *line; char cmd[64]; time_t sec, nsec; pid_t pid; uid_t uid, gid; gid_t luid; char curTm[64]; int n, seqnum; int stackInfo = 0; char uname[64], lname[64], gname[64]; bzero((char *)data, READ_BUF_SIZE); /* Read the info from the beginning of the file. */ n=pread(fd, data,READ_BUF_SIZE, 0); p = data; line=strsep(&p, "\n"); while (line) { if( (!stackInfo) && (sscanf(line,"TIME_tvsec=%ld",&sec) == 1)) { ctime_r(&sec, curTm); if (sscanf(p, "TIME_tvnsec=%ld\nSEQUENCE_NUM=%d\nPID=%ld\nUID=%ld\nUID_LOGIN=%ld\nGID=%ld\nPROG_NAME=%s\n", &nsec, &seqnum, &pid, &uid, &luid, &gid, cmd) == 7) { strcpy(uname, IDtouser(uid)); strcpy(lname, IDtouser(luid)); strcpy(gname, IDtogroup(gid)); printf("Time : %s",curTm); printf("Sequence Num : %d\n",++seqnum); 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); } else if (sscanf(p, "TIME_tvnsec=%ld\nSEQUENCE_NUM=%d\n", &nsec, &seqnum) == 2) { printf("Time : %s",curTm); printf("Sequence Num : %d\n",++seqnum); } stackInfo=1; } if (!stackInfo) printf ("%s\n", line); else if ((!strncmp(line, "RC_FROM_EVPROD",14)) || (!strncmp(line, "CURRENT_VALUE",13))) { printf("%s\n%s\n", line, p); goto out; } line=strsep(&p, "\n"); }; out: return; } /*----------------------------------------------------------------- * NAME: monitor_a_set_of_events() * PURPOSE: To monitor a set of events using pollset(). * DESCRIPTION: * This function opens the .mon files in the /aha filesystem, and * calls the pollset API to register for event notification * using those .mon files' descriptors. * This program waits for events to occur in an infinite loop. */ static int monitor_a_set_of_events() { pollset_t ps; int i, index, nmsgs, fd, rc; char wrStr[MAX_WRITE_STR_LEN+1]; int threshold; struct poll_ctl pollctl; struct pollfd pfds[MAX_EVENT_NOTIFICATIONS]; ps = pollset_create (MAX_FD); read_inputfile (cfgFile); /* First open all the aha nodes given in the input file, * and add them to the pollset. */ for (i=0; i