[BACK]Return to fam.c++ CVS log [TXT][DIR] Up to [Development] / fam / libfam

File: [Development] / fam / libfam / fam.c++ (download)

Revision 1.1.1.1 (vendor branch), Thu Apr 24 19:08:27 2003 UTC (14 years, 5 months ago) by trev
Branch: sgi-fam, MAIN
CVS Tags: fam-2-6-10, HEAD
Changes since 1.1: +0 -0 lines

Initial FAM CVS repository build..

-- Trev


//  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
//  
//  This program is free software; you can redistribute it and/or modify it
//  under the terms of version 2.1 of the GNU Lesser General Public License
//  as published by the Free Software Foundation.
//
//  This program is distributed in the hope that it would be useful, but
//  WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
//  license provided herein, whether implied or otherwise, is limited to
//  this program in accordance with the express provisions of the GNU Lesser
//  General Public License.  Patent licenses, if any, provided herein do not
//  apply to combinations of this program with other product or programs, or
//  any other product whatsoever. This program is distributed without any
//  warranty that the program is delivered free of the rightful claim of any
//  third person by way of infringement or the like.  See the GNU Lesser
//  General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with this program; if not, write the Free Software Foundation, Inc., 59
//  Temple Place - Suite 330, Boston MA 02111-1307, USA.

#include <sys/types.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/param.h>
#include <syslog.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>

#include "fam.h"
#include "Client.h"

//#define DEBUG


// Some libserver stuff
#define FAMNUMBER 391002 // This is the official rpc number for fam.
#define FAMNAME "sgi_fam"
#define FAMVERS 2
#define LOCALHOSTNUMBER 0x7f000001 // Internet number for loopback.

// Error variables - XXX currently not dealt with
#define FAM_NUM_ERRORS 1
int FAMErrno;
char *FamErrlist[FAM_NUM_ERRORS];

struct GroupStuff
{
    GroupStuff();
    ~GroupStuff() { delete [] groups; }
    int groupString(char *buf, int buflen);

    gid_t *groups;
    int   ngroups;
};

static int findFreeReqnum();
static int checkRequest(FAMRequest *fr, const char *filename);
static int sendSimpleMessage(char code, FAMConnection *fc, const FAMRequest *fr);

/**************************************************************************
* FAMOpen, FAMClose - opening, closing FAM connections
**************************************************************************/

int FAMOpen2(FAMConnection* fc, const char* appName)
{
    int famnumber = FAMNUMBER, famversion = FAMVERS;
    struct rpcent *fament = getrpcbyname(FAMNAME);
    if(fament != NULL)
    {
        famnumber = fament->r_number;
    }

    //  Try to connect.
    fc->client = new Client(LOCALHOSTNUMBER, famnumber, famversion);
    fc->fd = ((Client *)fc->client)->getSock();
    if (fc->fd < 0) {
	delete (Client *)fc->client;
        fc->client = NULL;
	return(-1);
    }

    // Send App name 
    if (appName) {
	char msg[200];
	snprintf(msg, sizeof(msg), "N0 %d %d %s\n", geteuid(), getegid(), appName);
	((Client *)fc->client)->writeToServer(msg, strlen(msg)+1);
    }

    return(0);
}

int FAMOpen(FAMConnection* fc)
{
    return FAMOpen2(fc, NULL);
}

int FAMClose(FAMConnection* fc)
{
    delete (Client *)fc->client;
    return(0);
}



/**************************************************************************
* FAMMonitorDirectory, FAMMonitorFile - monitor directory or file
**************************************************************************/

#define ILLEGAL_REQUEST -1

static int FAMMonitor(FAMConnection *fc, const char *filename, FAMRequest* fr,
	       void* userData, int code)
{

    if (!filename || filename[0] != '/')
	return -1;

    int reqnum = fr->reqnum;
    Client *client = (Client *)fc->client;
    // store user data if necessary
    if(userData != NULL) client->storeUserData(reqnum, userData);

    GroupStuff groups;
    char msg[MSGBUFSIZ];
    int msgLen;
    snprintf(msg, MSGBUFSIZ, "%c%d %d %d %s\n", code, reqnum, geteuid(),
                             groups.groups[0], filename);
    msgLen = strlen(msg) + 1;  // include terminating \0 in msg
    if(groups.ngroups > 1)
    {
        msgLen += groups.groupString(msg + msgLen, MSGBUFSIZ - msgLen);
        ++msgLen;  //  include terminating \0
    }

    // Send to FAM
    client->writeToServer(msg, msgLen);
    return(0);
}
int FAMMonitorDirectory(FAMConnection *fc,
			const char *filename,
			FAMRequest* fr,
			void* userData)
{
    if(checkRequest(fr, filename) != 0) return -1;

#ifdef DEBUG
printf("FAMMonitorDirectory filename:%s, reqnum:%d, ud:%d\n", filename, fr->reqnum, (int) userData);
#endif
    return FAMMonitor(fc, filename, fr, userData, 'M');
}
int FAMMonitorDirectory2(FAMConnection *fc,
			 const char *filename,
			 FAMRequest* fr)
{
    return FAMMonitor(fc, filename, fr, NULL, 'M');
}

int FAMMonitorFile(FAMConnection *fc,
		   const char *filename,
		   FAMRequest* fr,
		   void* userData)
{
    if(checkRequest(fr, filename) != 0) return -1;

#ifdef DEBUG
printf("FAMMonitorFile filename:%s, reqnum:%d, ud:%d\n", filename, fr->reqnum, (int) userData);
#endif
    return FAMMonitor(fc, filename, fr, userData, 'W');
}
int FAMMonitorFile2(FAMConnection *fc,
		    const char *filename,
		    FAMRequest* fr)
{
    return FAMMonitor(fc, filename, fr, NULL, 'W');
}


int 
FAMMonitorCollection(FAMConnection* fc,
		     const char* filename,
		     FAMRequest* fr,
		     void* userData,
		     int depth,
		     const char* mask)
{
    if(checkRequest(fr, filename) != 0) return -1;

    Client *client = (Client *)fc->client;

    // store user data if necessary
    if (userData) client->storeUserData(fr->reqnum, userData);

    GroupStuff groups;
    char msg[MSGBUFSIZ];
    int msgLen;
    snprintf(msg, MSGBUFSIZ, "F%d %d %d %s\n", fr->reqnum, geteuid(),
                             groups.groups[0], filename);
    msgLen = strlen(msg) + 1;  // include terminating \0 in msg

    if(groups.ngroups > 1)
    {
        msgLen += groups.groupString(msg + msgLen, MSGBUFSIZ - msgLen);
    }

    snprintf(msg + msgLen, MSGBUFSIZ - msgLen, "0 %d %s\n", depth, mask);
    ++msgLen;  //  include terminating \0

    // Send to FAM
    client->writeToServer(msg, msgLen);
    return(0);
}


/**************************************************************************
* FAMSuspendMonitor, FAMResumeMonitor - suspend FAM monitoring
**************************************************************************/

int FAMSuspendMonitor(FAMConnection *fc, const FAMRequest *fr)
{
    return sendSimpleMessage('S', fc, fr);
}

int FAMResumeMonitor(FAMConnection *fc, const FAMRequest *fr)
{
    return sendSimpleMessage('U', fc, fr);
}



/**************************************************************************
* FAMCancelMonitor - cancel FAM monitoring
**************************************************************************/

int FAMCancelMonitor(FAMConnection *fc, const FAMRequest* fr)
{
#ifdef DEBUG
printf("FAMCancelMonitor reqnum:%d\n", fr->reqnum);
#endif
    // Remove from user Data array
    // Actually, we will do this when we receive the ack back from fam
    // FAMFreeRequest(fr->reqnum);

    return sendSimpleMessage('C', fc, fr);
}


/**************************************************************************
* FAMNextEvent() - find the next fam event
* FAMPending() - return if events are ready yet
**************************************************************************/

//  FAMNextEvent tries to read one complete message into the input buffer.
//  If it's successful, it parses the message and returns 1.
//  Otherwise (EOF or errors), it returns -1.

int FAMNextEvent(FAMConnection* fc, FAMEvent* fe)
{
    fe->fc = fc;
    return ((Client *)fc->client)->nextEvent(fe);
}

//  FAMPending tries to read one complete message into the input buffer.
//  If it's successful, then it returns true.  Also, if it reads EOF, it
//  returns true.

int FAMPending(FAMConnection* fc)
{
    return ((Client *)fc->client)->eventPending();
}



/**************************************************************************
* FAMDebugLevel() - doesn't do anything
**************************************************************************/
int FAMDebugLevel(FAMConnection*, int)
{
    return(1);
}



/**************************************************************************
* Support Functions
**************************************************************************/

static int
findFreeReqnum()
{
    static int reqnum=1;
    return(reqnum++);
}

static int
checkRequest(FAMRequest *fr, const char *filename)
{
    // Fill out request structure
    int reqnum;
    if ((reqnum = findFreeReqnum()) == ILLEGAL_REQUEST) {
	return(-1);
    }
    fr->reqnum = reqnum;

    // Check path length of file
    if (strlen(filename) > MAXPATHLEN) {
	syslog(LOG_ALERT, "path too long\n");
	errno = ENAMETOOLONG;
	return (-1);
    }
    return 0;
}

static int
sendSimpleMessage(char code, FAMConnection *fc, const FAMRequest *fr)
{
    // Create FAM String
    char msg[MSGBUFSIZ];
    snprintf(msg, MSGBUFSIZ, "%c%d %d %d\n", code, fr->reqnum, geteuid(), getegid());

    // Send to FAM
    ((Client *)fc->client)->writeToServer(msg, strlen(msg)+1);
    return(0);
}

GroupStuff::GroupStuff()
{
    ngroups = sysconf(_SC_NGROUPS_MAX);
    groups = new gid_t[ngroups];
    ngroups = getgroups(ngroups, groups);
}

int
GroupStuff::groupString(char *buf, int buflen)
{
    if(ngroups < 2) return 0;
    const int GROUP_STRLEN = 8;  // max length of " %d" output, we hope
    if(buflen < (ngroups * GROUP_STRLEN)) return 0;
    //XXX that should create some error condition

    char *p = buf;
    snprintf(p, GROUP_STRLEN, "%d", ngroups - 1);
    p += strlen(p);
    for(int i = 1; i < ngroups; ++i)  //  group[0] doesn't go in string
    {
        snprintf(p, GROUP_STRLEN, " %d", groups[i]);
        p += strlen(p);
    }
    *p = '\0';

    return p - buf;
}