home *** CD-ROM | disk | FTP | other *** search
- Subject: v13i048: Resource allocation program
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Rob McMahon <daisy.warwick.ac.uk!cudcv>
- Posting-number: Volume 13, Issue 48
- Archive-name: with
-
- With will reserve exclusive use of a device by creating a lock file,
- changing ownership of the device to your current user id, setting the
- device to mode 600 (rw by you, nothing to others), and giving you a new
- shell. When the shell terminates, the device is released. In the event
- that a device is in use by another user you will be notified of this, and
- with can wait until it is available.
-
- For example:
- with -n tape "Rob's tape, to read, please"
- with tape "..." -c "tar xvp ; mt offl" > tar.out &
- ----
- #!/bin/sh
- echo 'Start of pack.out, part 01 of 01:'
- echo 'x - Makefile'
- sed 's/^X//' > Makefile << '/'
- X# makefile for with
- X
- X# DESTDIR is the destination directory (in which the compiled source lives)
- X# CFLAGS contains the arguments passed to the C compiler
- X# SEPID whether to be compiled with -i or -n (not used on the VAX)
- X# R prefix to destination names (ie. an optional root)
- X# HACKS - local flags to the C compiler to define/undefine symbols
- X
- XDESTDIR=/usr/local
- XHACKS=
- XSEPID=
- XCFLAGS=-O $(SEPID) $(HACKS)
- XR=
- X
- X.SUFFIXES: .c,v
- X
- Xall with: with.o
- X $(CC) $(CFLAGS) with.o -o with
- X
- Xcp install: with
- X install -s -o root -g general -m 4710 with $R$(DESTDIR)
- X
- Xcmp: with
- X -cmp with $R$(DESTDIR)/with
- X rm -f with *.o
- X
- Xclean:
- X rm -f with *.o
- X
- X.c,v.o:
- X co -q $*.c
- X $(CC) $(CFLAGS) -c $*.c
- X rm -f $*.c
- X
- X# entry points are (at least):
- X# all, with - compile with and leave it where it is
- X# cp, install - compile and install with
- X# cmp - compile and compare with, remove dross
- X# clean - removes any garbage
- X# default action is to compile and leave the binary in situ
- X
- X
- X# there are problems if the command name is the same as an entry point.
- X# there are problems moving mv to /usr/ucb/mv (text in use)
- X# or cping cp to /bin/cp
- X#
- X# clean does not remove .c files when the source is in sccs s. ... .c format
- /
- echo 'x - README'
- sed 's/^X//' > README << '/'
- XWith is based on a set of programs, written by Dave Butterfield at the
- XUCLA Dept. of Mathamatics, called get & rls. These programs had a
- Xnumber of problems in our environment, the worst being that you couldn't
- Xuse them to run a job in the background. Out of this grew with.
- X
- XWith uses a lockfile (LOCKSFILE, "/etc/locks/lockfiles" by default),
- Xwith lines consisting of: name of file to create and flock, name of
- Xresources as known to user, and a list of up to MAXPDEV (16) devices
- Xwhich are chown'ed to the user, and given mode OWNERONLY (0600,
- X-rw-------), before a subshell is started. When the shell exits, the
- Xdevices are chown'ed back to Rootuid, Rootgid (0,3), and the flock is
- Xremoved by with exiting. (The lockfile is not removed, as someone else
- Xcould have an flock pending on it.)
- X
- XA second argument can be given to with, and if it is not an empty string
- Xit is a request which is sent to the operators via syslog, and with then
- Xwaits for a signal back from the operators to say whether the request
- Xhas been fulfilled or denied (SIGEMT or SIGTERM). Any extra arguments
- Xare passed to the subshell.
- X
- XA pseudo-resource '-' is available, which allows a request to the
- Xoperators without actually getting any resource. This is useful for
- Xe.g. loading the second tape.
- X
- Xe.g.
- X
- Xwith -n tape "Rob's tape, to read, please"
- X...
- Xmt offl
- Xwith - "second tape, please"
- X...
- Xmt offl
- X^D
- X
- XThe -n tells with not to wait if someone else is already using the tape
- Xdeck. We recommend the 'mt offl's so that your tape is unavailable to
- Xanyone else using with after you release the tape deck.
- X
- XIn an 'at' job:
- X
- Xwith tape "..." << EOF
- X...
- Xmt offl
- XEOF
- X
- XIn the background:
- X
- Xwith tape "..." -c "tar xvp ; mt offl" > tar.out &
- X
- X---
- XUUCP: ...!mcvax!ukc!warwick!cudcv PHONE: +44 203 523037
- XJANET: cudcv@uk.ac.warwick.daisy ARPA: cudcv@daisy.warwick.ac.uk
- XRob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England
- /
- echo 'x - with.1'
- sed 's/^X//' > with.1 << '/'
- X.TH with 1 local
- X.SH NAME
- Xwith \- a program to reserve exclusive use of a device
- X.SH SYNOPSIS
- X.I
- X.B with
- X[
- X.B \-sn
- X]
- X.I dev
- X[
- X.I request
- X[
- X.I shell parameters
- X]
- X]
- X.SH DESCRIPTION
- X.I With
- Xwill reserve exclusive use of a device by creating a lock file, changing
- Xownership of the device to your current user id, setting the device to
- Xmode 600 (rw by you, nothing to others), and giving you a new shell. When the
- Xshell terminates, the device is released.
- XIn the event that a device is in
- Xuse by another user you will be notified of this, and
- X.I with
- Xwill wait until it is available, or if the
- X.B \-n
- Xflag is given will return immediately with an indication of failure.
- XThe
- X.B \-s
- Xswitch causes
- X.I with
- Xto perform its work silently.
- X.I With
- Xreturns a nonzero return code to indicate failure.
- X.PP
- XIf a request is specified, the operators are asked to fulfil the request once
- Xthe device is available. E.g.
- X.PP
- Xwith tape "cudcv's tape to read, please"
- X.PP
- XA request can be made without actually locking a device by specifying the
- Xdevice as `-'. In this case no shell is started, but with waits until the
- Xrequest is fulfilled, and then exits.
- X.PP
- XArguments after the
- X.I request
- Xare handed to the shell. A null request can be specified as `-', to grab a
- Xdevice and execute a command without making a request.
- X.PP
- XCurrently known devices are:
- X.TP 8
- Xtape
- XThe magtape; all 16 logical devices 800 & 1600 BPI: ({,n}{,r}mt{0,4,8,12}).
- X.SH FILES
- X.TP 30
- X/etc/locks/lockfiles
- Xfor device names, lock file names, and /dev/minordev names.
- X.SH ENVIRONMENT
- X.TP 20
- XSHELL
- Xfor user's default shell
- X.SH DIAGNOSTICS
- XA non-zero return code indicates one of the devices was not available, or with
- Xwas interrupted.
- X.nf
- Xdev is yours.
- Xdev is in use ... waiting
- Xdev is in use - try again later.
- Xdev released.
- XI don't know how to get dev.
- X.fi
- X.SH BUGS
- /
- echo 'x - with.c'
- sed 's/^X//' > with.c << '/'
- X/*
- X * with --- a program to do simple device locking.
- X */
- X/*
- X * format of working file (lockfiles)
- X * full_name_of_lock_file name_of_device minor0 minor1 ...
- X * full name of files must include path (in great detail /.../.../...)
- X * there may be as many as MAXPDEV minor devices associated with name_of_device
- X * note that name_of_device need not be the same as any minor device
- X * example
- X * /etc/tape0.lock tape0 /dev/mt0 /dev/mt4 /dev/rmt0 /dev/rmt4
- X * /usr/spool/uucp/LCK..cul0 cul0 /dev/cul0
- X *
- X * $Log: with.c,v $
- X * Revision 2.0 87/10/26 09:32:15 cudcv
- X * "Stable"
- X *
- X * Revision 1.11 87/10/26 09:19:37 cudcv
- X * Cleanup comments, lint
- X *
- X * Revision 1.10 86/09/17 09:01:42 cudcv
- X * 'waiting for confirmation' message wasn't getting out if stderr buffered.
- X *
- X * Revision 1.9 86/08/06 10:34:33 cudcv
- X * Make handling of null resource cleaner, allow - as null request.
- X *
- X * Revision 1.8 86/06/17 13:14:44 cudcv
- X * Allow further arguments to be passed to the shell
- X * Return status from shell
- X *
- X * Revision 1.7 86/06/17 12:28:45 cudcv
- X * Slip of the editor
- X *
- X * Revision 1.6 86/01/24 15:01:36 cudcv
- X * Restart shell when with is restarted
- X *
- X * Revision 1.5 86/01/24 12:09:59 cudcv
- X * With would hang if shell was stopped
- X *
- X * Revision 1.4 86/01/23 09:38:23 cudcv
- X * Was ignoring last device
- X *
- X * Revision 1.3 86/01/23 09:02:20 cudcv
- X * Make more portable for Gould
- X *
- X * Revision 1.2 86/01/21 15:04:35 cudcv
- X * Allow second argument with request to operators
- X * Record usercode of requester
- X * With no arguments lists current locks
- X *
- X * Revision 1.1 85/10/07 10:31:25 cudcv
- X * Initial revision
- X *
- X */
- Xstatic char RCSid[] = "$Header: with.c,v 2.0 87/10/26 09:32:15 cudcv Exp $";
- X#include <ctype.h>
- X#include <pwd.h>
- X#include <signal.h>
- X#include <stdio.h>
- X#include <strings.h>
- X#include <syslog.h>
- X#include <sys/time.h>
- X#include <sys/types.h>
- X#include <sys/dir.h>
- X#include <sys/file.h>
- X#include <sys/resource.h>
- X#include <sys/stat.h>
- X#include <sys/wait.h>
- X
- X#ifndef PW_NAMEL
- X#define PW_NAMEL 8
- X#endif
- X
- X#ifndef LOCKSFILE
- X#define LOCKSDIR "/etc/locks"
- X#define LOCKSFILE "/etc/locks/lockfiles"
- X#endif
- X#define MAXSTLEN 40 /*much more than necessary*/
- X#define NLOCKS 10 /* " " " " */
- X#define MAXPDEV 16 /* max # phys. devices associate with a name*/
- X#define OWNERONLY 0600 /*protection mode for the devices*/
- X#define LOGLEVEL LOG_CRIT /* level for syslog's */
- X
- X#define subdev(LP,n) (& ( (LP)->physdev[n][0])) /*all dave's fault*/
- X#define mask(i) (1 << (i-1)) /* for signals */
- X
- XFILE *fopen();
- X
- X#ifdef RLIMIT_INTACT
- Xstruct rlimit intact = {1, 1}; /* make ourselves interactive */
- X#endif
- X
- Xtypedef struct {
- X char lok[MAXSTLEN], /* lock (flock) */
- X dev[MAXSTLEN], /* what the user calls it (with dev) */
- X physdev[MAXPDEV][MAXSTLEN]; /* /dev/dev */
- X int locked; /*got lock on this*/
- X} dev_lk;
- X
- Xdev_lk locks[NLOCKS];
- Xdev_lk nolok;
- X
- Xchar *progname;
- Xextern int optind;
- Xchar *malloc(), *sprintf();
- Xstruct passwd *getpwuid();
- Xextern char *sys_siglist[];
- Xextern char *sys_errlist[];
- Xextern int errno;
- X
- Xint silent = 0;
- Xint nowait = 0; /* don't wait until available */
- Xint nerrs = 0;
- Xint nlock = 0;
- Xint Rootuid = 0, Rootgid = 3; /* magic numbers */
- Xint uuid, ugid;
- Xchar *resource;
- Xint needrequest = 0; /* got resource, need extra request */
- Xint requested = 0; /* have warned of need, while waiting */
- Xint fulfilled = 0; /* request fulfilled */
- Xstruct passwd *pw;
- Xchar buf[BUFSIZ];
- Xchar **shellargs;
- X
- Xvoid print_locks();
- X
- Xmain(argc,argv)
- Xint argc;
- Xchar *argv[];
- X{
- X register int i, pdev;
- X register dev_lk *lkp;
- X char *request = NULL;
- X int c, lockfile, omask;
- X int mypid = getpid();
- X int cleanup(), fulfil();
- X
- X uuid = getuid();
- X ugid = getgid();
- X if ((pw = getpwuid(uuid)) == (struct passwd *)NULL) {
- X Printf("Who are you ?\n");
- X exit(1);
- X }
- X (void) endpwent();
- X progname = argv[0];
- X while ((c = getopt(argc, argv, "sn")) != EOF)
- X switch (c) {
- X case 's': silent++; break;
- X case 'n': nowait++; break;
- X case '?': nerrs++; break;
- X }
- X if (nerrs){
- X Printf("usage: %s [-sn] device [request [parameters]]\n",
- X progname);
- X Printf("eg: %s tape \"cudcv's tape for read, please\"",
- X progname);
- X Printf(" -c dd if=/dev/rmt8 ...\n");
- X exit(1);
- X }
- X if((nlock = read_loks(LOCKSFILE, locks)) < 0){
- X Printf("%s:%s unopenable or messed up.\n",progname,LOCKSFILE);
- X exit(1);
- X }
- X /* locks have been read-in */
- X
- X if (argc == optind) {
- X print_locks();
- X exit(0);
- X }
- X
- X /*can't be interrupted once we start linking things so ...*/
- X omask = sigsetmask((int)0x7fffffff);
- X for(i = 1; i < NSIG; i++) {
- X /* allow stopping */
- X if (i == SIGTSTP || i == SIGTTIN || i == SIGTTOU) continue;
- X /* don't catch those normally ignored */
- X if (i == SIGURG || i == SIGCONT ||
- X i == SIGCHLD || i == SIGIO
- X#ifdef SIGENQ
- X || i == SIGENQ
- X#endif
- X ) continue;
- X /* don't catch those currently ignored */
- X if (signal(i, cleanup) == SIG_IGN)
- X (void) signal(i, SIG_IGN);
- X }
- X (void) sigsetmask(omask);
- X /* don't want to get clobbered by XCPU either */
- X#ifdef RLIMIT_INTACT
- X if (setrlimit(RLIMIT_INTACT, &intact)) {
- X perror("setrlimit");
- X exit(1);
- X }
- X#endif
- X /*now get resource*/
- X resource = argv[optind++];
- X if (argc > optind) {
- X request = argv[optind++];
- X if (!*request || !strcmp(request, "-"))
- X request = NULL;
- X (void) sprintf(buf, "(%s) with", pw->pw_name);
- X openlog(buf, LOG_PID);
- X }
- X shellargs = &argv[optind-1];
- X if (!strcmp(resource, "-")) {
- X resource = NULL;
- X lkp = &nolok;
- X (void) sprintf(lkp->lok, "%s/%d", LOCKSDIR, getpid());
- X (void) strcpy(lkp->dev, "request");
- X } else {
- X for (i = 0;i < nlock; i++)
- X if (strcmp(locks[i].dev, resource) == 0) break;
- X if(i >= nlock){
- X Printf("I don't know how to get %s.\n", resource);
- X nerrs++;
- X cleanup(0);
- X }
- X lkp = &locks[i];
- X }
- X
- X if ((lockfile = open(lkp->lok, O_WRONLY|O_CREAT, 0644)) < 0) {
- X Printf("%s : cannot open %s : %s\n",
- X progname, lkp->lok, sys_errlist[errno]);
- X nerrs++;
- X cleanup(0);
- X }
- X if (flock(lockfile, LOCK_EX|LOCK_NB) < 0) {
- X if (!resource) {
- X Printf("%s: cannot lock %s : %s\n",
- X progname, lkp->lok, sys_errlist[errno]);
- X nerrs++;
- X cleanup(0);
- X }
- X Printf("%s is in use", lkp->dev);
- X if (nowait) {
- X Printf(" - try again later.\n");
- X nerrs++;
- X cleanup(0);
- X } else {
- X Printf(" ... waiting");
- X (void) fflush(stderr);
- X if (request)
- X syslog(LOGLEVEL, "will need %s, when %s is available",
- X request, resource);
- X requested++;
- X if (flock(lockfile, LOCK_EX) < 0) {
- X Printf("\n%s : cannot lock : %s\n",
- X progname, sys_errlist[errno]);
- X nerrs++;
- X cleanup(0);
- X } else
- X Printf("\n");
- X }
- X }
- X (void) write(lockfile, (char *)&mypid, sizeof(int));
- X (void) write(lockfile, pw->pw_name, PW_NAMEL);
- X (void) ftruncate(lockfile, sizeof(int) + PW_NAMEL);
- X lkp->locked++;
- X for(pdev = 0;pdev < MAXPDEV && (*subdev(lkp,pdev));pdev++){
- X (void) chown( subdev(lkp,pdev),uuid,ugid );
- X (void) chmod( subdev(lkp,pdev),OWNERONLY);
- X }
- X if (resource)
- X Printf("%s is yours", lkp->dev);
- X if (request) {
- X if (resource)
- X Printf(" - ");
- X Printf("waiting for confirmation of request");
- X (void) fflush(stderr);
- X omask = sigblock(SIGEMT);
- X (void) signal(SIGEMT, fulfil);
- X needrequest++; requested = 0;
- X (void) write(lockfile, request, strlen(request));
- X if (resource)
- X syslog(LOGLEVEL, "have %s, need %s", resource, request);
- X else
- X syslog(LOGLEVEL, "need %s", request);
- X syslog(LOGLEVEL, "`kill -EMT %d' or `kill -TERM %d'",
- X getpid(), getpid());
- X do {
- X sigpause(omask & ~mask(SIGEMT));
- X } while (!fulfilled);
- X (void) ftruncate(lockfile, sizeof(int) + PW_NAMEL);
- X Printf(" - going");
- X syslog(LOGLEVEL, "going");
- X }
- X Printf("\n");
- X
- X if (resource) shell();
- X
- X cleanup(0);
- X}
- X
- X
- Xint
- Xread_loks(lf, lks)
- Xchar *lf;
- Xregister dev_lk lks[];
- X{
- X register FILE *lfp;
- X register dev_lk *dp;
- X register int i;
- X int n;
- X char line[BUFSIZ];
- X
- X lfp = fopen(lf, "r");
- X if(lfp == NULL)
- X return -1; /*error*/
- X
- X /*now read in the entries*/
- X for(dp = lks,i=0; i < NLOCKS ;dp++, i++){
- X if( fgets(line,sizeof(line),lfp) == NULL) /* if EOF*/
- X break;
- X /*read at most 2 + MAXPDEV entries from line*/
- X n = sscanf(line,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
- X dp->lok, dp->dev,
- X subdev(dp,0),subdev(dp,1),
- X subdev(dp,2),subdev(dp,3),
- X subdev(dp,4),subdev(dp,5),
- X subdev(dp,6),subdev(dp,7),
- X subdev(dp,8),subdev(dp,9),
- X subdev(dp,10),subdev(dp,11),
- X subdev(dp,12),subdev(dp,13),
- X subdev(dp,14),subdev(dp,15));
- X if(n < 3){ /*if line was bad format or blank ...*/
- X dp--;i--; /*try again*/
- X continue;}
- X if(n < MAXPDEV + 2)
- X *subdev(dp, n - 2) = '\0'; /*no string*/
- X dp->locked = 0;
- X }
- X (void) fclose(lfp);
- X return i; /*'i' is the # of lines read successfully*/
- X}
- X
- Xvoid
- Xprint_locks()
- X{
- X register dev_lk *lkp;
- X int nent;
- X struct direct **dp, **names;
- X int pids(), numsort();
- X
- X for (lkp = &locks[0]; lkp < &locks[nlock]; lkp++) {
- X print_lock(lkp->lok, lkp->dev);
- X }
- X if (chdir(LOCKSDIR)) {
- X perror(LOCKSDIR);
- X return;
- X }
- X if ((nent = scandir(".", &names, pids, numsort)) < 0) {
- X perror("scandir");
- X return;
- X }
- X for (dp = &names[0]; dp < &names[nent]; dp++) {
- X print_lock((*dp)->d_name, (char *)NULL);
- X }
- X}
- X
- Xprint_lock(lok, dev)
- X char *lok, *dev;
- X{
- X int i, lockfile, pid;
- X
- X if ((lockfile = open(lok, O_RDONLY)) < 0)
- X return;
- X if (flock(lockfile, LOCK_SH|LOCK_NB) < 0) {
- X (void) read(lockfile, (char *)&pid, sizeof(int));
- X (void) read(lockfile, buf, PW_NAMEL);
- X buf[PW_NAMEL] = '\0';
- X if (dev)
- X Printf("%s in use by ", dev);
- X Printf("%u (%s)", pid, buf);
- X if ((i = read(lockfile, buf, BUFSIZ)) > 0) {
- X buf[i] = '\0';
- X Printf(": needs %s", buf);
- X }
- X Printf("\n");
- X }
- X (void) close(lockfile);
- X}
- X
- Xint
- Xpids(dp)
- X struct direct *dp;
- X{
- X register char *p = dp->d_name;
- X while (*p)
- X if (!isdigit(*p++))
- X return(0);
- X return(1);
- X}
- X
- Xint
- Xnumsort(d1, d2)
- X struct direct **d1, **d2;
- X{
- X int p1, p2;
- X
- X p1 = atoi((*d1)->d_name);
- X p2 = atoi((*d2)->d_name);
- X return p1 - p2;
- X}
- X
- Xstatic int child;
- X
- Xsigcont()
- X{
- X (void) kill(child, SIGCONT);
- X}
- X
- Xshell()
- X{
- X register i;
- X char *myshell, *shellt;
- X union wait status;
- X char *getenv(), *rindex();
- X int omask;
- X
- X if (!(myshell = getenv("SHELL")))
- X myshell = "/bin/sh";
- X if (shellt = rindex(myshell, '/'))
- X shellt++;
- X else
- X shellt = myshell;
- X
- X /* ignore keyboard generated signals now - could manipulate process
- X * groups I suppose, but I'm lazy
- X * First block them over the fork
- X */
- X omask = sigblock(mask(SIGINT)|mask(SIGQUIT));
- X (void) fflush(stderr);
- X if ((child = vfork()) == 0) {
- X /* normal keyboard signals in shell */
- X (void) sigsetmask(omask);
- X child = getpid();
- X (void) setuid(uuid);
- X (void) setgid(ugid);
- X for(i = getdtablesize(); i > 3; )
- X (void) close(--i);
- X shellargs[0] = shellt;
- X execv(myshell, shellargs);
- X Printf("%s : couldn't execute %s : %s\n",
- X progname, myshell, sys_errlist[errno]);
- X _exit(1);
- X } else if (child < 0) {
- X Printf("%s : couldn't fork : %s\n",
- X progname, sys_errlist[errno]);
- X } else {
- X /* ignore keyboard signals in parent */
- X (void) signal(SIGINT, SIG_IGN);
- X (void) signal(SIGQUIT, SIG_IGN);
- X (void) signal(SIGCONT, sigcont);
- X (void) sigsetmask(omask);
- X do {
- X while((i = wait3(&status,
- X WUNTRACED,
- X (struct rusage *)NULL)) > 0
- X && i != child);
- X if (status.w_stopval == WSTOPPED)
- X (void) kill(0, (int)status.w_stopsig);
- X else
- X nerrs = status.w_retcode;
- X } while (status.w_stopval == WSTOPPED);
- X }
- X}
- X
- Xrestore(lkp) /*restores ownership and protections for resources unlocked*/
- Xregister dev_lk *lkp;
- X{
- X register int pdev;
- X
- X for(pdev = 0;pdev < MAXPDEV && (*subdev(lkp,pdev));pdev++){
- X (void) chown( subdev(lkp,pdev),Rootuid,Rootgid );
- X (void) chmod( subdev(lkp,pdev),OWNERONLY);
- X }
- X}
- X
- X/* VARARGS1 */
- XPrintf(f, a, b, c, d) char *f;
- X{
- X if (!silent) (void) fprintf(stderr, f, a, b, c, d);
- X}
- X
- Xfulfil() { fulfilled = 1; }
- X
- Xcleanup(sig)
- X{
- X register dev_lk *lkp;
- X
- X /* wait for child to finish before we go ourselves */
- X if (!nerrs || sig) Printf("\n");
- X if (sig) Printf("%s\n", sys_siglist[sig]);
- X if (requested) syslog(LOGLEVEL, "request withdrawn");
- X if (needrequest) {
- X if (sig) {
- X Printf("Request denied\n");
- X syslog(LOGLEVEL, "request denied");
- X } else if (resource) {
- X syslog(LOGLEVEL, "done with %s", resource);
- X }
- X }
- X /* check if there's anything to wait for */
- X if (!wait3((union wait *)NULL, WNOHANG, (struct rusage *)NULL))
- X Printf("waiting for shell to exit\n");
- X (void) fflush(stderr);
- X while (wait((union wait *)NULL) > 0);
- X for (lkp = &locks[0]; lkp < &locks[nlock]; lkp++)
- X if (lkp->locked) {
- X restore(lkp);
- X Printf("%s released.\n", lkp->dev);
- X }
- X if (!resource)
- X (void) unlink(nolok.lok);
- X exit(sig ? -1 : nerrs);
- X}
- /
- echo 'Part 01 of pack.out complete.'
- exit
- ----
- UUCP: ...!mcvax!ukc!warwick!cudcv PHONE: +44 203 523037
- JANET: cudcv@uk.ac.warwick.daisy ARPA: cudcv@daisy.warwick.ac.uk
- Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England
-