Xinu7/src/cmd/download/lib/getdev.c
#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);
}