/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/samples/ahafs/samplePrograms/evMon/mon_1event.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 mon_1event.c:
 *     main or mon_1event
 *     syntax
 *     ahaMonFile
 *     mk_paraent_dirs
 *     read_data
 * PURPOSE:
 *    To test monitoring an AHA event represented by an AHA file
 *     with suffix ".mon".
 *    In more details, this programe issues a select() call on the
 *       the corresponding  .mon file, and waits for the event to happen.
 * SYNTAX:
 *    mon_1event <aha-monitor-file> [<key1>=<value1>[;<key2>=<value2>;...]]
 *      e.g. mon_1event  /aha/fs/utilFs.monFactory/var.mon "THRESH_HI=95"
 *           mon_1event  /aha/mem/vmo.monFactory/npskill.mon
 * 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/07/30 Updated by N.Dubey
 */
#include <stdio.h>
#include <string.h> /* for strcmp() */
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <libgen.h>
#include <usersec.h>

#define MAX_WRITE_STR_LEN    255

void       syntax(char *prog);
int        ahaMonFile(char *str);
static int mk_parent_dirs (char *path);
void       read_data (int fd);

char       *monFile;
/* -------------------------------------------------------------------------- */
int main (int argc, char *argv[])
{
    int    fd, rc;
    fd_set readfds;
    char   wrStr[MAX_WRITE_STR_LEN+1];
    char   waitInRead[] = "WAIT_TYPE=WAIT_IN_READ";

    if (argc < 2)
       syntax( argv[0]);

    monFile = argv[1];
    if ( ! ahaMonFile(monFile) )  /* Not a .mon file under /aha */
       syntax( argv[0]);

    /* 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);
        return(-1);
    }

    printf("Monitor file name: %s\n", monFile);
    if (argc >= 3)
        sprintf (wrStr, "%s", argv[2]);
    else
        sprintf (wrStr, "CHANGED=YES");

    printf("Write String  : %s\n", wrStr);

    fd = open (monFile, O_CREAT|O_RDWR);
    if (fd < 0)
    {
       fprintf (stderr,"Could not open the file %s; errno = %d\n", monFile,errno);
        exit (1);
    }

    rc=write(fd, wrStr, strlen(wrStr));
    if (rc < 0)
    {
        perror ("write: ");
        fprintf (stderr, "Failed writing to monFile %s !\n", monFile);
        return(-1);
    }
 

    if (strstr(wrStr, 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);
}

/* -------------------------------------------------------------------------- */
void syntax(char *prog)
{
  printf("\nSYNTAX: %s <aha-monitor-file> [<key1>=<value1>[;<key2>=<value2>;...]] \n",prog);
  printf(" where: \n");
  printf("  <aha-monitor-file> : 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("              | or not-YES               | It cannot be used with  \n");
  printf("              |                          |  THRESH_HI.             \n");
  printf("   -----------|--------------------------|------------------------ \n");
  printf("    THRESH_HI | positive integer         | monitors high threshold.\n");
  printf("   ----------------------------------------------------------------\n\n");
  printf("Examples: \n");
  printf("   1: %s /aha/fs/utilFs.monFactory/var.mon  \"THRESH_HI=95\"\n", prog);
  printf("   2: %s /aha/fs/modFile.monFactory/etc/passwd.mon \"CHANGED=YES\" \n", prog);
  printf("   3: %s /aha/mem/vmo.monFactory/npskill.mon  \n", prog);
  printf("   4: %s /aha/cpu/waitTmCPU.monFactory/waitTmCPU.mon \n", prog);
  printf("                     \"WAIT_TYPE=WAIT_IN_READ;THRESH_HI=50\" \n");
  exit (1);
}

/* --------------------------------------------------------------------------
 * 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 /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 the path has .mon as a suffix. */
    if ((len1 <= len2) ||
        (strcmp ( (str + len1 - len2), ".mon"))
        )
       goto end;

    if (! strncmp (str, "/aha",4))  /* The given path 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 are 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, luid;
    gid_t  gid;
    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;
}
