Patch #: 61 Type: operational change Priority: none Modification: Add AUFS Application Manager Submitted: David Hornsby Archived: munnari.OZ.AU mac/cap.patches/cap60.patch061 Application: 'cd cap60; patch -p < cap60.patches/cap60.patch061' Summary: control number of times applications on AUFS may be run File: cap60/Configure File: cap60/applications/aufs/aufs.c File: cap60/applications/aufs/afpos.c File: cap60/applications/aufs/afps.h File: cap60/contrib/Makefile.m4 File: cap60/contrib/AppManager/Makefile File: cap60/contrib/AppManager/README File: cap60/contrib/AppManager/aufslock.c File: cap60/contrib/AppManager/aufsmon.c *** Configure.orig Sun Sep 1 14:23:05 1991 --- Configure Sun Sep 22 01:42:03 1991 *************** *** 1,7 **** #!/bin/sh ! # $Author: djh $ $Date: 1991/09/01 04:22:47 $ ! # $Header: /mac/src/cap60/RCS/Configure,v 2.27 1991/09/01 04:22:47 djh Rel djh $ ! # $Revision: 2.27 $ # CAP configuration shell script. This ain't perfect, but it's a start. # Execute with /bin/sh Configure if your system won't run it (ksh is okay too) # --- 1,7 ---- #!/bin/sh ! # $Author: djh $ $Date: 1991/09/21 15:41:52 $ ! # $Header: /mac/src/cap60/RCS/Configure,v 2.28 1991/09/21 15:41:52 djh Rel djh $ ! # $Revision: 2.28 $ # CAP configuration shell script. This ain't perfect, but it's a start. # Execute with /bin/sh Configure if your system won't run it (ksh is okay too) # *************** *** 551,556 **** --- 551,559 ---- # # + DEV_NIT specifies alternate NIT device name (default "/dev/nit") # define(`specialcflags',concat(specialcflags,` -DDEV_NIT=\"/dev/nit\"')) + # + # + APPLICATION_MANAGER control the use of designated applications + # define(`specialcflags',concat(specialcflags,` -DAPPLICATION_MANAGER')) # EOT0 result=0 *** applications/aufs/aufs.c.orig Sat Aug 31 19:11:24 1991 --- applications/aufs/aufs.c Sun Sep 22 01:44:51 1991 *************** *** 1,7 **** /* ! * $Author: djh $ $Date: 1991/08/31 09:11:12 $ ! * $Header: /mac/src/cap60/applications/aufs/RCS/aufs.c,v 2.5 1991/08/31 09:11:12 djh Rel djh $ ! * $Revision: 2.5 $ */ /* --- 1,7 ---- /* ! * $Author: djh $ $Date: 1991/09/21 15:44:39 $ ! * $Header: /mac/src/cap60/applications/aufs/RCS/aufs.c,v 2.6 1991/09/21 15:44:39 djh Rel djh $ ! * $Revision: 2.6 $ */ /* *************** *** 84,89 **** --- 84,92 ---- #ifdef LWSRV_AUFS_SECURITY export char *userlogindir = NULL; /* budd -- name of userlogin file */ #endif LWSRV_AUFS_SECURITY + #ifdef APPLICATION_MANAGER + export char *enforcelist = NULL;/* name of list for appln run control */ + #endif APPLICATION_MANAGER export int mcs, qs; /* maxcmdsize and quantum size */ export int sqs = atpMaxNum; /* maximum send quantum */ export int n_rrpkts = atpMaxNum; /* maximum send quantum to allow remote */ *************** *** 165,170 **** --- 168,176 ---- #else LWSRV_AUFS_SECURITY fprintf(stderr,"[-n name] [-t packets] [-s] [-V afpvols]\n"); #endif LWSRV_AUFS_SECURITY + #ifdef APPLICATION_MANAGER + fprintf(stderr,"[-A applistfile]\n"); + #endif APPLICATION_MANAGER fprintf(stderr,"\t-d for CAP debugging flags:\n"); fprintf(stderr,"\t l = lap, d = ddp, a = atp, n = nbp, p = pap,"); fprintf(stderr,"i = ini, s = asp\n"); *************** *** 189,194 **** --- 195,203 ---- #ifdef LWSRV_AUFS_SECURITY fprintf(stderr,"\t-X datafile of logged in users\n"); /* budd */ #endif LWSRV_AUFS_SECURITY + #ifdef APPLICATION_MANAGER + fprintf(stderr,"\t-A application run manager\n"); + #endif APPLICATION_MANAGER fprintf(stderr,"\nExample: %s -t 'bdelete irename' -a 'file fork dir' -s\n", name); exit(1); *************** *** 221,229 **** extern int optind; #ifdef LWSRV_AUFS_SECURITY ! while ((c = getopt(argc,argv,"a:d:D:n:N:t:sV:U:G:P:c:l:z:S:R:X:")) != EOF) { #else LWSRV_AUFS_SECURITY ! while ((c = getopt(argc,argv,"a:d:D:n:N:t:sV:U:G:P:c:l:z:S:R:")) != EOF) { #endif LWSRV_AUFS_SECURITY switch (c) { case 'z': --- 230,238 ---- extern int optind; #ifdef LWSRV_AUFS_SECURITY ! while ((c = getopt(argc,argv,"a:d:D:n:N:t:sV:U:G:P:c:l:z:S:R:X:A:")) != EOF) { #else LWSRV_AUFS_SECURITY ! while ((c = getopt(argc,argv,"a:d:D:n:N:t:sV:U:G:P:c:l:z:S:R:A:")) != EOF) { #endif LWSRV_AUFS_SECURITY switch (c) { case 'z': *************** *** 299,304 **** --- 308,320 ---- userlogindir = optarg; break; /* ...budd */ #endif LWSRV_AUFS_SECURITY + case 'A': + #ifdef APPLICATION_MANAGER + enforcelist = optarg; + #else APPLICATION_MANAGER + usage(argv[0]); + #endif APPLICATION_MANAGER + break; default: usage(argv[0]); break; *************** *** 431,436 **** --- 447,458 ---- logit(0,"Aufs: user login database in %s", userlogindir); } /* ...budd */ #endif LWSRV_AUFS_SECURITY + #ifdef APPLICATION_MANAGER + if (enforcelist != NULL) { + logit(4,"aufs: application manager database in %s", enforcelist); + readAppList(enforcelist); + } + #endif APPLICATION_MANAGER ctp_stack_cnt = 0; { int i; for (i = 0 ; i < maxsess; i++) { *************** *** 1302,1305 **** --- 1324,1429 ---- } /* make_userlogin */ /**************** ...budd ****************/ #endif LWSRV_AUFS_SECURITY + #ifdef APPLICATION_MANAGER + /* + * read the -A specified file for a list of pathnames + * and an indication of the maximum number of times that + * the file (resource fork) can be opened (colon separated). + * Build a sorted list so that searching can be more efficient. + * When the file is opened, read lock the next available byte, + * return 'aeLockErr' if no locks available. If the maximum number + * is specified with a trailing 'P', then the file is PROTECTED from + * Finder copying. + * + * djh@munnari.OZ.AU + * September, 1991 + * + */ + struct flist *applist = NULL; /* head ptr for file list */ + int fdplist[NOFILE]; /* fd list for protections */ + + readAppList(file) + char *file; + { + char *c; + int qty = 0; + int num, protect; + FILE *fp, *fopen(); + char linebuf[MAXPATHLEN*2]; + struct flist *newapplp, *p, *q; + + for (num = 0; num < NOFILE; num++) + fdplist[num] = -1; + + if ((fp = fopen(file, "r")) == NULL) { + logit(0, "readAppList(): cannot open %s for reading", file); + return; + } + while (fgets(linebuf, sizeof(linebuf), fp) != NULL) { + if (linebuf[0] == '#') + continue; + if ((c = (char *) rindex(linebuf, ':')) == NULL) { + logit(0, "readAppList(): bad format (line %d) in %s", qty+1, file); + fclose(fp); + return; + } + *c++ = '\0'; + if ((num = atoi(c)) <= 0) { + logit(0, "readAppList(): illegal value (%d) in %s", num, file); + fclose(fp); + return; + } + protect = ((char *)index(c, 'P') == NULL) ? 0 : 1; + if ((newapplp = (struct flist *)malloc(sizeof(struct flist))) == NULL) { + logit(0, "readAppList(): malloc(%d) failed", sizeof(struct flist)); + fclose(fp); + return; + } + if ((newapplp->filename = (char *)malloc(strlen(linebuf)+12)) == NULL) { + logit(0, "readAppList(): malloc(%d) failed", strlen(linebuf)+12); + fclose(fp); + return; + } + if ((c = (char *)rindex(linebuf,'/')) == NULL) + continue; + *c++ = '\0'; + strcpy(newapplp->filename, linebuf); + strcat(newapplp->filename, "/.resource/"); + strcat(newapplp->filename, c); + newapplp->incarnations = num; + newapplp->protected = protect; + newapplp->next = NULL; + qty++; + + /* start list if none */ + if (applist == NULL) { + applist = newapplp; + continue; + } + /* else insert in-order */ + q = NULL; + p = applist; + while (p != NULL) { + if (strcmp(p->filename, newapplp->filename) > 0) + break; + q = p; + p = p->next; + } + newapplp->next = p; + if (q == NULL) + applist = newapplp; + else + q->next = newapplp; + } + fclose(fp); + p = applist; + logit(0, "Read %d application restrictions from %s", qty, file); + while (p != NULL) { + logit(0, " %s, %d%s", p->filename, p->incarnations, + (p->protected) ? " (no copy)" : ""); + p = p->next; + } + return; + } + #endif APPLICATION_MANAGER *** applications/aufs/afpos.c.orig Sat Aug 31 15:45:13 1991 --- applications/aufs/afpos.c Sun Sep 22 01:44:55 1991 *************** *** 1,7 **** /* ! * $Author: djh $ $Date: 1991/08/31 05:45:00 $ ! * $Header: /mac/src/cap60/applications/aufs/RCS/afpos.c,v 2.12 1991/08/31 05:45:00 djh Rel djh $ ! * $Revision: 2.12 $ */ /* --- 1,7 ---- /* ! * $Author: djh $ $Date: 1991/09/21 15:44:39 $ ! * $Header: /mac/src/cap60/applications/aufs/RCS/afpos.c,v 2.13 1991/09/21 15:44:39 djh Rel djh $ ! * $Revision: 2.13 $ */ /* *************** *** 103,108 **** --- 103,112 ---- # endif #endif + #ifdef APPLICATION_MANAGER + # define NEEDFCNTLDOTH + #endif APPLICATION_MANAGER + #ifdef NEEDFCNTLDOTH # include #endif *************** *** 1026,1031 **** --- 1030,1048 ---- if (DBOSI) printf("OSRead: fd=%d, pos=%d, off=%d, req=%d\n", fd, *fpos, offs, reqcnt); + #ifdef APPLICATION_MANAGER + { + extern int fdplist[NOFILE]; + extern struct flist *applist; + + if (applist != NULL && fdplist[fd] == 1) { + /* we want Finder copy protection */ + if (offs == 0 && reqcnt > 128) + return(aeAccessDenied); + } + } + #endif APPLICATION_MANAGER + /* want to probe for eof -- probably there */ /* back off this. If the request count is zero, then */ /* don't tell them about EOF because zero length files */ *************** *** 1038,1046 **** --- 1055,1094 ---- if (offs != *fpos) lseek(fd,(off_t)offs,L_SET); + #ifdef APPLICATION_MANAGER + /* + * we have to resort to fcntl() lock tests + * because lockf() as used by OSTestLock() + * returns "permission denied" if more than + * one single byte read lock exists on fd. + * This is probably a bug, but since we are + * only interested in any write lock in the + * range it doesn't matter ... + * + */ + { + struct flock flck; + extern struct flist *applist; + + if (applist != NULL) { + flck.l_type = F_RDLCK; + flck.l_whence = 1; /* SEEK_CUR */ + flck.l_start = 0; + flck.l_len = reqcnt; + if (fcntl(fd, F_GETLK, &flck) != -1) { + if (flck.l_type == F_WRLCK) + return(aeLockErr); + } + } else { + if (OSTestLock(fd, reqcnt) != noErr) + return(aeLockErr); + } + } + #else APPLICATION_MANAGER if (OSTestLock(fd, reqcnt) != noErr) { return(aeLockErr); } + #endif APPLICATION_MANAGER cnt = read(fd,r,reqcnt); if (cnt < 0) { *************** *** 3217,3222 **** --- 3265,3292 ---- *fd = open(path,mode); + #ifdef APPLICATION_MANAGER + { + int lockn, protect; + extern int fdplist[NOFILE]; + extern struct flist *applist; + + /* don't check if we aren't read-only or open failed */ + if (applist != NULL && *fd >=0 && mode == O_RDONLY) { + if (wantLock(path, &lockn, &protect) == 0) { + if (enforceLock(*fd, lockn) == 0) { + if (DBUNX) + printf("unix_open: open refused for %s (O > %d)\n", path, lockn); + close(*fd); + return(aeLockErr); + } + if (protect == 1) /* protect from copying */ + fdplist[*fd] = 1; + } + } + } + #endif APPLICATION_MANAGER + if (DBUNX) printf("unix_open: fd=%d, mode=%d, path=%s\n",*fd,mode,path); *************** *** 3236,3241 **** --- 3306,3318 ---- if (DBUNX) printf("unix_close: fd=%d\n",fd); + #ifdef APPLICATION_MANAGER + { + extern int fdplist[NOFILE]; + fdplist[fd] = -1; + } + #endif APPLICATION_MANAGER + if (close(fd) == 0) return(noErr); *************** *** 3542,3544 **** --- 3619,3689 ---- return(crypt(pwd, pw->pw_passwd)); } #endif ULTRIX_SECURITY + #ifdef APPLICATION_MANAGER + + /* + * Enforce control on the number of file opens (or Applications + * run) by checking our 'Application List' and attempting to apply + * a single byte-range read lock on the file resource fork at byte N. + * Can also specify no Finder copying with 'P' flag on number. + * + * djh@munnari.OZ.AU + * September, 1991 + * + */ + + int + wantLock(file, num, protect) + char *file; + int *num, *protect; + { + int cmpval; + struct flist *applp; + extern struct flist *applist; + + applp = applist; + while (applp != NULL) { + /* check the SORTED list, return 0 if found */ + if ((cmpval = strcmp(file, applp->filename)) <= 0) { + *num = applp->incarnations; + *protect = applp->protected; + return(cmpval); + } + applp = applp->next; + } + return(1); + } + + int + enforceLock(fd, maxm) + int fd, maxm; + { + int i; + struct flock flck; + + for (i = 1; i <= maxm; i++) { + flck.l_type = F_WRLCK; + flck.l_whence = 0; /* SEEK_SET */ + flck.l_start = i; + flck.l_len = 1; + + if (fcntl(fd, F_GETLK, &flck) == -1) + return(-1); /* not supported ? */ + + if (flck.l_type == F_RDLCK) + continue; + + if (flck.l_type == F_UNLCK) { + flck.l_type = F_RDLCK; + flck.l_whence = 0; /* SEEK_SET */ + flck.l_start = i; + flck.l_len = 1; + if (fcntl(fd, F_SETLK, &flck) == -1) + return(-1); /* not supported ? */ + + return(1); /* success */ + } + } + return(0); /* no locks left */ + } + #endif APPLICATION_MANAGER *** applications/aufs/afps.h.orig Thu Feb 28 23:44:28 1991 --- applications/aufs/afps.h Sun Sep 22 01:44:59 1991 *************** *** 1,7 **** /* ! * $Author: djh $ $Date: 91/02/15 21:09:10 $ ! * $Header: afps.h,v 2.1 91/02/15 21:09:10 djh Rel $ ! * $Revision: 2.1 $ */ /* --- 1,7 ---- /* ! * $Author: djh $ $Date: 1991/09/21 15:44:39 $ ! * $Header: /mac/src/cap60/applications/aufs/RCS/afps.h,v 2.2 1991/09/21 15:44:39 djh Rel djh $ ! * $Revision: 2.2 $ */ /* *************** *** 234,236 **** --- 234,245 ---- #define AFPVersion1DOT0 100 #define AFPVersion1DOT1 110 #define AFPVersion2DOT0 200 + + #ifdef APPLICATION_MANAGER + struct flist { + char *filename; /* full pathname to resource fork */ + int protected; /* we don't want it to be copied */ + short incarnations; /* can be opened this many times */ + struct flist *next; /* this is a sorted linked list */ + }; + #endif APPLICATION_MANAGER *** contrib/Makefile.m4.orig Sat Jul 27 21:08:30 1991 --- contrib/Makefile.m4 Sun Sep 22 01:47:40 1991 *************** *** 49,54 **** --- 49,55 ---- clean: -rm -f ${PROGS} *.o core make.log err att_getopt.c *~ + -(cd AppManager; make clean) -(cd AsyncATalk; make clean) -(cd AufsTools; make clean) -(cd MacPS; make clean) *** contrib/AppManager/Makefile.orig Sun Sep 22 01:48:42 1991 --- contrib/AppManager/Makefile Sun Sep 22 01:50:47 1991 *************** *** 0 **** --- 1,10 ---- + all: aufsmon aufslock + + aufsmon: aufsmon.c + cc -o aufsmon aufsmon.c + + aufslock: aufslock.c + cc -o aufslock aufslock.c + + clean: + rm -f *.o aufsmon aufslock *** contrib/AppManager/README.orig Sun Sep 22 01:48:54 1991 --- contrib/AppManager/README Sun Sep 22 01:50:58 1991 *************** *** 0 **** --- 1,93 ---- + Application Manager v1.0 - CAP 6.0 + ---------------------------------- + + The Application Manager controls the number of times an Application + may be run. This is most useful in restricting use to the number of legal + copies of software. The Application Manager uses a new argument to aufs: + + aufs -A + + The file contains information of the format + + /full/Path/To/Application1:N + /full/Path/To/Application2:M + /full/Path/To/Application3:O + ... + + where N/M/O are integers that specify the number of times that each + application may be run. The full path is to the DATA fork. If you + specify the character flag 'P' after the number, the file will be + protected from simple Finder copying. + + EG: + /mac/servers/studeApplications/Word 4.0/Word:20P + + limits Word to 20 simultaneous uses. The file cannot be Finder copied + (copy protection can be broken by a determined user, run control cannot). + NB: If the maximum run count is reached, file copying will fail, this is + independant of the state of the protection flag. + + When the run limit is reached, a Mac user attempting to start the + Application receives a message which varies somewhat with system version ... + + 6.0.2 "The following application is busy or damaged + ." + + 6.0.5 "The file could not be + opened/printed (the file/folder is locked)." + + 7.0 "The Application program could + not be opened, because it is locked." + + There is no need for extra software to be loaded onto the Mac, this is + strictly a UNIX AppleShare server modification. The basic functionality + for the Application Manager exists on SUN, ULTRIX and SGI machines. It is + known to not work under HP-UX. + + The Application Manager is included in AUFS with the m4.features define + APPLICATION_MANAGER. This can be edited within Configure or edited into + an existing m4.features and 'gen.makes' rerun. + + There are a couple of tools, 'aufsmon' which lists the files in + together with the number of time each is open, it can also optionally list + the process IDs of the running aufs'. The second is 'aufslock' which can be + used simply to add another lock from the UNIX end, it aids testing. It is + IMPORTANT to note that the filename specified to aufslock must be for the + resource fork, IE: include "/.resource/". + + aufsmon [-fpv] [-s N] + + -f print a formfeed before each section + -p print the process IDs of the locking aufs + -v be verbose, print a 'bitmap' of the locks + -s N sleep for N seconds (default 10 seconds) + is the same file provided to aufs with -A + + aufslock [ ] + + is the actual file (resource fork!!). + is an optional numeric argument specifying the + byte to lock, otherwise the next free is used. + + Caveats + ------- + + The only major problem I have found is with TMON (2.8) and System 6.0.2 and + 6.0.5. The machine simply bombs on locked applications. Removing TMON restores + normality. These are only 1 Mb machines so I suspect a memory problem. + + A minor problem is due to a probable bug in the lockf() implementation + (SunOS only so far). Any aufs server that isn't running with the Application + Manager will see a block on the file if more than one other person and the + modified aufs has the application open. This could be seen as a feature. + You shouldn't be using two aufs servers on the same directory tree anyway! + + NOTE CAREFULLY: + Locks are neither set nor checked if the aufs session has write permission + on the application resource fork. I recommend that once set up, write + permission for owner, group and other is removed from the application's + resource fork. Since the Application Manager works by using read locking + on the resource fork, copying or writing the application on a server with + the file in use is a no-no. + + The AM uses fcntl(2) locking, see the manual entry for more information. *** contrib/AppManager/aufslock.c.orig Sun Sep 22 01:49:03 1991 --- contrib/AppManager/aufslock.c Sun Sep 22 02:22:49 1991 *************** *** 0 **** --- 1,90 ---- + static char rcsid[] = "$Author: djh $ $Date: 1991/09/21 16:22:27 $"; + static char rcsident[] = "$Header: /mac/src/cap60/contrib/AppManager/RCS/aufslock.c,v 2.1 1991/09/21 16:22:27 djh Rel djh $"; + static char revision[] = "$Revision: 2.1 $"; + + /* + * aufslock [ ] + * + * Add an advisory shared lock to a single byte of (mark it busy). + * This is a program to assist in testing the CAP/AUFS Application Manager. + * NB: must specify a path to the resource fork of the Application. + * + * Copyright (c) 1991, The University of Melbourne + * djh@munnari.OZ.AU + * September 1991 + * + */ + + #include + #include + #include + #include + #include + + main(argc, argv) + int argc; + char *argv[]; + { + int fd, i; + void dolock(); + + if (argc < 2 || argc > 3) { + printf("usage: %s [ ]\n", argv[0]); + exit(1); + } + + if ((fd = open(argv[1], O_RDONLY, 0644)) < 0) { + perror("read()"); + exit(1); + } + + printf("Locking %s", argv[1]); + dolock(fd, (argc == 3) ? atoi(argv[2]) : -1); + + /* hang around to keep the fd open */ + + for (;;) + sleep(3600); + } + + void + dolock(fd, byten) + int fd; + int byten; + { + int i, qty; + struct flock flck; + + if (byten == -1) { + for (i = 1; i <= 128 ; i++) { + flck.l_type = F_WRLCK; + flck.l_whence = SEEK_SET; + flck.l_start = i; + flck.l_len = 1; + if (fcntl(fd, F_GETLK, &flck) == -1) { + printf("lock test failed at %d\n", i); + exit(1); + } + if (flck.l_type == F_UNLCK) { + byten = i; + break; + } + } + if (i > 128) { + printf("no free locks\n"); + exit(1); + } + } + + flck.l_type = F_RDLCK; + flck.l_whence = SEEK_SET; + flck.l_start = byten; + flck.l_len = 1; + + if (fcntl(fd, F_SETLK, &flck) == -1) { + printf("FAIL @%d\n", byten); + close(fd); + exit(1); + } + printf(" (byte %d)\n", byten); + } *** contrib/AppManager/aufsmon.c.orig Sun Sep 22 01:49:15 1991 --- contrib/AppManager/aufsmon.c Sun Sep 22 02:22:57 1991 *************** *** 0 **** --- 1,201 ---- + static char rcsid[] = "$Author: djh $ $Date: 1991/09/21 16:22:27 $"; + static char rcsident[] = "$Header: /mac/src/cap60/contrib/AppManager/RCS/aufsmon.c,v 2.1 1991/09/21 16:22:27 djh Rel djh $"; + static char revision[] = "$Revision: 2.1 $"; + + /* + * aufsmon [-fpv] [-s N] + * + * Display the number of uses (eg: copies of an application running) + * for each file named in the file. The running aufs server + * must have had 'APPLICATION_MANAGER' defined and have been started with + * the -A option. + * + * Options: + * -v verbose, print a '1' if byte in range is locked, else '0' + * -p verbose, print the process ids of the locking process + * -f formfeed, print a ^L at the start of each group of files + * -s N sleep for N seconds between printouts, default 10 seconds + * + * Copyright (c) 1991, The University of Melbourne + * djh@munnari.OZ.AU + * September 1991 + * + */ + + #include + #include + #include + #include + #include + + #include + + struct flist { + char *filename; + int protected; + short incarnations; + struct flist *next; + }; + + #define PERIOD 10 + + struct flist *head, *newp; /* file list */ + int verboseflag = 0; /* more detail */ + int processid = 0; /* show process ids */ + int formfeed = 0; /* show a ^L */ + int period = PERIOD; + char *progname; + + + main(argc, argv) + int argc; + char *argv[]; + { + char buf[MAXPATHLEN*2]; + FILE *fp, *fopen(); + void checklocks(); + int num, protect; + char *cp; + + head = NULL; + progname = *argv; + + while(--argc > 0 && (*++argv)[0] == '-') { + for(cp = argv[0]+1 ; *cp != '\0' ; cp++) { + switch (*cp) { + case 'f': + formfeed++; + break; + case 'p': + processid++; + /* fall thro' */ + case 'v': + verboseflag++; + break; + case 's': + if (--argc > 0) + period = atoi(*++argv); + if (period == 0) + period = PERIOD; + break; + default: + usage(); + break; + } + } + } + + if (argc != 1) + usage(); + + if ((fp = fopen(*argv, "r")) == NULL) { + perror(progname); + exit(1); + } + + /* read the file contents */ + + while (fgets(buf, sizeof(buf), fp) != NULL) { + if (buf[0] == '#') /* comment, ignore */ + continue; + if ((cp = (char *)rindex(buf,':')) == NULL) { + printf("%s: bad format in %s\n", progname, *argv); + exit(1); + } + *cp++ = '\0'; + if ((num = atoi(cp)) <= 0) { + printf("%s: illegal count in %s (%d)\n", progname, *argv, num); + exit(1); + } + protect = ((char *)index(cp, 'P') == NULL) ? 0 : 1; + if ((newp = (struct flist *) malloc(sizeof(struct flist))) == NULL) { + perror(progname); + exit(1); + } + if ((newp->filename = (char *) malloc(strlen(buf)+12)) == NULL) { + perror(progname); + exit(1); + } + if ((cp = (char *)rindex(buf,'/')) == NULL) + continue; /* just ignore it */ + *cp++ = '\0'; + strcpy(newp->filename, buf); + strcat(newp->filename, "/.resource/"); + strcat(newp->filename, cp); + newp->incarnations = num; + newp->protected = protect; + newp->next = head; + head = newp; + } + fclose(fp); + + for ( ; ; ) { + if (formfeed) + putchar(014); + for (num = 0, newp = head ; newp != NULL ; newp = newp->next) { + if ((cp = (char *)rindex(newp->filename, '/')) == NULL) + cp = newp->filename; + else + cp++; + printf("%-16s\t%4d\t", cp, newp->incarnations); + checklocks(newp->filename, newp->incarnations); + if (newp->protected) + printf(" (no copy)"); + printf("\n"); + num++; + } + if (num > 1) + putchar('\n'); + fflush(stdout); + sleep(period); + } + } + + /* + * check the file 'name' for a shared advisory lock + * on a single byte in the range 1 - maxm + * + */ + + void + checklocks(name, maxm) + char *name; + int maxm; + { + int i, fd, qty; + struct flock flck; + + if ((fd = open(name, O_RDONLY, 0644)) < 0) { + perror(name); + return; + } + for (i = 1, qty = 0 ; i <= maxm ; i++) { + flck.l_type = F_WRLCK; + flck.l_whence = SEEK_SET; + flck.l_start = i; + flck.l_len = 1; + if (fcntl(fd, F_GETLK, &flck) != -1) { + if (flck.l_type == F_UNLCK) { + if (verboseflag) + if(!processid) + printf("0"); + } else { + if (verboseflag) + if (processid) + printf("%d ", flck.l_pid); + else + printf("1"); + qty++; + } + } else + printf("F"); + } + close(fd); + printf(" [%d open]", qty); + } + + usage() + { + printf("usage: %s [-fpv] [-s N] \n", progname); + exit(1); + } *** README.orig Sun Sep 22 02:32:37 1991 --- README Sun Sep 22 02:33:18 1991 *************** *** 3,9 **** (For use with AppleTalk/Ethernet bridge) o RELEASE NOTES ! o CAP Distribution 6.0, Patch Level 60, September 1991 Introduction ------------ --- 3,9 ---- (For use with AppleTalk/Ethernet bridge) o RELEASE NOTES ! o CAP Distribution 6.0, Patch Level 61, September 1991 Introduction ------------