Xinu7/src/cmd/download/lib/getdev.c

Compare this file to the similar file:
Show the results in this format:

#include "/usr/include/pwd.h"
#include "/usr/include/stdio.h"
#include "/usr/include/sys/types.h"
#include "/usr/include/sys/file.h"
#include "/usr/include/sys/stat.h"
#include "/usr/include/sys/time.h"

#include <getdev.h>
#include <freedev.h>
#include <ulock.h>

#define DEVNAME "/dev/%s"
#define	DEFCLASS "LSI"

extern char **environ;
static char *user_rsrvd;

/*
 *===================================================================
 * getdev - get the lsi that the user requests.  Return a ptr to a
 *    DevDesc struct containing info about the allocated device.
 *===================================================================
 */
DevDesc *getdev(class, request, flags)
char *class;			/* which group of machines?		*/
int  request;			/* # of machine to allocate, ANYDEV, ...*/
int  flags;			/* options to control allocation	*/
{
	char *class_lst, *name;
	char devname[MAXNAMELEN];
	int  user_rlen;
	DevDesc *dev;

	class_lst = get_db();	/* ptr to start of class info */
	user_rsrvd = get_ulock(SELF, &user_rlen);
	if (class == NULL)
		if (user_rsrvd != NULL  &&  *user_rsrvd != '\0')
			class = get_class(user_rsrvd); /* one on reserve */
		else
			class = getenv(DEV_ENV);
	if (class == NULL)
		class = DEFCLASS;
	if (!(flags & GD_HLDDEVS))	/* free all but requested dev	*/
		user_rlen = freedev(class, request, user_rsrvd, FD_HOLD);
	
	if ((dev = onreserve(class, request, user_rsrvd)) == NULL)
		if (flags & GD_MYDEV)
			return(NULL);
		else
			dev = reserve(class, request, class_lst, flags);

	if (dev != NULL) {
		name = get_name(dev->machine);
		sprintf(devname, DEVNAME, name);
		if ((dev->fd = open(devname, O_RDWR, 0)) < 0) {
			fprintf(stderr, "Cannot open %s\n", devname);
			user_rlen = freedev(dev->machine, 0, user_rsrvd,
				FD_FREE | FD_DBENTRY);
			put_ulock(SELF, user_rsrvd, user_rlen);
			return(NULL);
		} else {
			put_ureorder(SELF, user_rsrvd, dev->class, user_rlen);
			return(dev);
		}
	}

	put_ulock(SELF, user_rsrvd, user_rlen);
	if (request > 0)
		fprintf(stderr, "%s #%d unavailable.\n", class, request);
	else if (request == GD_ANYDEV)
		fprintf(stderr, "No class %s machines available.\n", class);
	else
		fprintf(stderr, "Unintelligible request: %d\n", request);
	return(NULL);
}


/*
 *========================================================================
 * onreserve - rtrn device descrip if user already holds lock on request
 *========================================================================
 */
DevDesc *onreserve(class, request, rsrvd_ptr)
char *class;
int  request;
char *rsrvd_ptr;
{
	char *mach;
	DevDesc *dev_desc;

	rsrvd_ptr = find_class(class, rsrvd_ptr);		
	if (rsrvd_ptr == NULL  ||  rsrvd_ptr == '\0')
		return(NULL);

	if (request >= 0)
		if ((rsrvd_ptr = find_num(request, rsrvd_ptr)) == NULL)
			return(NULL);

	if ((mach = lookup_db(get_phys(rsrvd_ptr))) == NULL)
		return(NULL);
	
	dev_desc = touch_lock(mach);
	if (dev_desc != NULL)
		dev_desc->class = rsrvd_ptr; /*what if rsrvd list modified?*/
	return(dev_desc);
}
	
/*
 *===========================================================
 * reserve - lock an lsi from the specified class & request
 *===========================================================
 */
DevDesc *reserve(class, request, clist, flags)
char *class;
int  request;
char *clist;
int  flags;
{
	char *mach;
	DevDesc *dev_desc;

	clist = find_class(class, clist);
	if (clist == NULL)
		return(NULL);

	switch (request) {
	  case GD_ANYDEV:
		dev_desc = getany_dev(clist, flags);
		break;

	  default:
		dev_desc = getthis_dev(clist, request, flags);
		break;
	}
	if (dev_desc == NULL)
		return(NULL);

	/* dev_desc temporarily holds the fd of the lock file */
	init_lock(dev_desc->fd, dev_desc->class);
	dev_desc->fd = INVALID;
	return (dev_desc);	
}

/*
 * getany_dev - 
 */
DevDesc *getany_dev(clist, flags)
char *clist;
int flags;
{
	char *clptr, *class, *mach;
	DevDesc *dev_desc;

	class = get_class(clist);
	clptr = clist;
	while (clptr != NULL  &&  strcmp(class, get_class(clptr)) == 0) {
		if ((mach = lookup_db(get_phys(clptr))) != NULL) {
			dev_desc = create_lock(mach, flags);
			if (dev_desc != NULL) {
				dev_desc->class = clptr;
				return(dev_desc);
			}
		}
		clptr = nextdb_entry(clptr);
	}

	clptr = clist;		/* Check for expired time limits now */
	while (clptr != NULL  &&  strcmp(class, get_class(clptr)) == 0) {
		if ((mach = lookup_db(get_phys(clptr))) != NULL)
			if (atoi(get_limit(clptr)) <= idletime(mach)) {
				dev_desc = create_lock(mach, flags|GD_FORCE);
				if (dev_desc != NULL) {
					dev_desc->class = clptr;
					return(dev_desc);
				}
			}
		clptr = nextdb_entry(clptr);
	}
	return(NULL);
}

DevDesc *getthis_dev(clist, request, flags)
char *clist;		/* already points to correct class */
int  request;
int  flags;
{
	char *mach;
	DevDesc *dev_desc;

	clist = find_num(request, clist);
	if (clist == NULL)
		return(NULL);
	if ((mach = lookup_db(get_phys(clist))) == NULL)
		return(NULL);
	dev_desc = create_lock(mach, flags);
	if (dev_desc == NULL)
		if (atoi(get_limit(clist)) <= idletime(mach))
			dev_desc = create_lock(mach, flags|GD_FORCE);
	if (dev_desc != NULL)
		dev_desc->class = clist;
	return(dev_desc);
}

/*
 * idletime - return how long the machine has been idle
 */
idletime(mach)
char *mach;
{
	char lknm[MAXNAMELEN];
	struct stat stbuf;
	struct timeval tp;
	struct timezone tzp;
	int idle;

	sprintf(lknm, LOCKNAME, get_name(mach));
	if (stat(lknm, &stbuf) < 0)
		return(MAXTIME);
	gettimeofday(&tp, &tzp);
	idle = (tp.tv_sec - stbuf.st_mtime) / SECPERMIN;
	return(idle);
}
	
/*
 * create_lock - return device descriptor with machine and lockname
 *    filled in if possible to open the lock.
 */
DevDesc *create_lock(mach, flags)
char *mach;
int  flags;
{
	char *lknm;
	int fd;
	DevDesc *dev_desc;

	if (mach == NULL)
		return(NULL);

	if (access(LOCKDIR, F_OK) == -1) {
		umask(0);
		mkdir(LOCKDIR, 0777);
	}
	lknm = (char *) malloc(MAXNAMELEN);
	sprintf(lknm, LOCKNAME, get_name(mach));

	fd = open(lknm, O_CREAT | O_RDWR | O_EXCL, LOCKMODE);
	if (fd < 0  &&  flags & GD_FORCE) {
		freedev(mach, 0, NULL, FD_DBENTRY | FD_RELES);
		fd = open(lknm, O_CREAT | O_RDWR | O_EXCL, LOCKMODE);
	}

	if (fd >= 0) {
		fchmod(fd, 0666);
		dev_desc = (DevDesc *) malloc(sizeof(DevDesc));
		dev_desc->fd = fd;	/* temp hold lock fd in DevDesc blk */
		dev_desc->locknm = lknm;
		dev_desc->machine = mach;
		return(dev_desc);
	} else
		return(NULL);
}

/*
 * touch_lock - user already has the lock file assigned.  Just need
 *    to update info.  Return device desciptor with machine and
 *    lockname fields filled in.  
 */
DevDesc *touch_lock(mach, clmap)
char *mach;
char *clmap;
{
	char *locknm;
	int  fd_lk, slen;
	DevDesc *dev_desc;

	locknm = (char *) malloc(MAXNAMELEN);
	sprintf(locknm, LOCKNAME, get_name(mach));
	if ((fd_lk = open(locknm, O_RDWR, 0)) < 0)
		return(NULL);
	close(fd_lk);

	dev_desc = (DevDesc *) malloc(sizeof(DevDesc));
	dev_desc->locknm = locknm;
	dev_desc->machine = mach;
	return(dev_desc);
}

/*
 * init_lock - called after lock file is open, but no initialization of
 *    the locks have been done.  Enter user/class info in machine lock,
 *    and class/machine info in user lock file.
 */
init_lock(lk_fd, clmap)
int  lk_fd;
char *clmap;
{
	char *loginid;
	int  maplen, slen;

	if ( (loginid=getlogin()) == NULL || *loginid == '\0')
		loginid = (getpwuid(getuid()))->pw_name;

	if ((maplen = index(clmap, NEWLINE) - clmap) <= 0) {
		fprintf(stderr, "init_lock() -- database format incorrect\n");
		exit(1);
	}
	maplen++;	/* count the NEWLINE */

	/* init the actual lock for the device */
	slen = strlen(loginid);
	loginid[slen] = FIELDSEP;
	write(lk_fd, loginid, slen + 1);
	write(lk_fd, clmap, maplen);
	close(lk_fd);
}


touch(lknm)
char *lknm;
{
	int fd;
	char a;

	if (access(LOCKDIR, F_OK) == -1) {
		umask(0);
		mkdir(LOCKDIR, 0777);
	}
	fd = open(lknm, O_RDWR, 0);
	read(fd, &a, 1);
	lseek(fd, 0,0);
	write(fd, &a, 1);
	close(fd);
}