home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-04 | 44.6 KB | 1,456 lines |
- Newsgroups: comp.sources.misc
- From: alan@tharr.UUCP (Alan Saunders)
- Subject: v25i024: QBATCH - a queued batch processing system for UNIX, Part05/06
- Message-ID: <1991Nov5.034852.5158@sparky.imd.sterling.com>
- X-Md4-Signature: c94ab58832177a5cae6e94b86d55bf1f
- Date: Tue, 5 Nov 1991 03:48:52 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: alan@tharr.UUCP (Alan Saunders)
- Posting-number: Volume 25, Issue 24
- Archive-name: QBATCH/part05
- Environment: UNIX
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 5 (of 6)."
- # Contents: doc/chap.04 src/jk.c src/js.c src/qf.c
- # Wrapped by root@vfib_d on Thu Oct 31 15:46:40 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'doc/chap.04' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'doc/chap.04'\"
- else
- echo shar: Extracting \"'doc/chap.04'\" \(10173 characters\)
- sed "s/^X//" >'doc/chap.04' <<'END_OF_FILE'
- X QBATCH .. a queued batch processing system for UNIX
- X
- X
- X The QBATCH system and its related programs were
- X written by Alan D. Saunders and are
- X Copyright (c) Vita Services Ltd. 1990 and
- X Copyright (c) Vita Fibres Ltd. 1991
- X
- X4. USER commands.
- X
- X Note: this is a descriptive text. Full details of all the QBATCH commands
- X are provided in the relevant man pages. There is also a man page for QBATCH
- X which contains a summary of all QBATCH commands.
- X See also ADMINISTRATIVE commands.
- X
- X qa Queue availability. For a given user running qa, the accessibility of
- X all queues is checked. All fixed context queues are checked to see if
- X this user is permitted (by uid or gid) to submit jobs. All fixed
- X context queues which permit this user to submit, and all open queues
- X are listed with a brief (one line) description.
- X viz:
- X
- X Queues available to alan
- X
- X Queue No. Priority Fixed Enabled Halted Stopped
- X Name Entries (nice) Context
- X
- X fasq 2 -5 no yes no no
- X fault 0 0 no yes no no
- X fcon 14 10 yes yes no yes
- X fcsq 4 5 no yes no no
- X fcst 1 -5 no yes no no
- X intq 0 0 no no no no
- X invq 1 0 no yes no no
- X mant 2 -5 no yes no no
- X masq 2 -5 no yes no no
- X mbsq 0 10 no no no no
- X slwq 8 15 no yes no no
- X sopq 4 5 no yes no no
- X sopt 3 -5 no yes no no
- X work 14 10 no yes no no
- X
- X js Job submit. This is used to submit jobs to a QBATCH queue.
- X By default, a job is run under the bourne shell. This may be
- X overridden by using the -s option to js, or in the case of a fixed
- X context queue, by the first line of the control file. Jobs submitted
- X to a queue must be valid in terms of the syntax of the shell under
- X which the job is to be run. This said, jobs may consist of anything
- X that can be run interactively provided they don't attempt to access
- X what may be unavailable resources, in particular, the vdu of the
- X submittor. If the programs, or scripts use stdout and stderr for
- X output, and (redirected) stdin for input, then they can be submitted to
- X a queue. Programs which attempt to open /dev/tty may fail altogether
- X since QBATCH jobs do not have a controlling terminal. On some systems
- X they may use /dev/console instead. (this seems to be the case in SunOS
- X on SPARCstations.)
- X
- X js will accept the job either as a named file, or from stdin. This
- X allows regularly run jobs to be set up as 'jcl' files, and submitted
- X as:
- X js <queuename> <jclfile>
- X Alternatively, stdin can be used, either directly:
- X js <queuename>
- X <commands>
- X [..]
- X ^D
- X Or as a here document:
- X js <queuename> <<EOjob
- X <commands>
- X [..]
- X EOjob
- X
- X If submitted as a file, the 'jcl' may be created in a script, using
- X prompts, and shell parameters etc to set it up.
- X
- X js can also be used as the destination of a pipeline in the shell, or
- X as a pipe (opened for write access) in a c program.
- X
- X Main options:
- X
- X -n <name> This provides a meaningful name for the job. It's only
- X use is to give some meaning to the ql output (see
- X later).
- X
- X -m <monitor> The monitor (combined stdout and stderr) for a job is
- X normally determined automatically, either by js or qp.
- X (monitors are discussed later.) This option allows a
- X user to define exactly where the monitor for this job
- X will be written it should be a fully specified absolute
- X pathspec..
- X
- X -s <shell> As mentioned earlier, jobs are by default run under the
- X bourne shell. If the queue is fixed context, the shell
- X may be specified in the control file. This option
- X allows the user to specify the shell under which this
- X job will be run.
- X
- X -r <reply code> When the process engine has finished with a job, it
- X normally silently looks for the next. The reply code,
- X if non-zero causes qp to execute a script called
- X jobdone, which will notify the submittor as follows:
- X reply code 0 No reply.
- X 1 Write a message on the submittor's tty.
- X 2 Mail a message to the user.
- X Any other value (or not set).. no reply.
- X
- X jk Job kill. This allows the user to remove a job from a queue if they
- X own it. The super user may kill any or all jobs in any and all queues.
- X an ordinary user may kill only jobs that they themselves submitted.
- X If the job is actually running, jk will refuse to remove the job unless
- X the -k option is specified.
- X
- X jm Job monitor. This allows the addition of a monitor spec (see js) as an
- X afterthought.
- X
- X jn Job name. Allows the addition of a job name as an afterthought.
- X
- X jr Job repeat. This allows the current job being processed to be
- X repeated. If the -k option is used, the repeat flag will be set, and
- X the job will be repeated. This allows for example, a print job
- X printing on the wrong stationary to be restarted.
- X
- X jj Job jump. NB. This does not allow ANYBODY to jump the queue!
- X This allows any user to re- order a consecutive group of their own jobs
- X in a queue, by jumping a job above an adjacent prior job owned by the
- X same user. Only the administrator is permitted to jump jobs above
- X those with different owner id's.
- X No job may be jumped above a currently running job.
- X
- X ql Queue list. List the contents and status of a QBATCH queue.
- X The queue header data and flags are displayed, along with a line for
- X each job currently in the queue. The data are more meaningful if job
- X names are used when the jobs are submitted.
- X viz:
- X
- X Status of : work
- X Spooling in : /var/spool/batch/
- X Monitor is : /var/spool/batch/work.mon
- X Priority is : 10
- X Queue last started : 12/09/91 09:02:37
- X Current job started : 2/10/91 14:54:30
- X
- X No of Active Queue Job Job Queue Queue
- X Entries (pid) Accepting Repeated Killed Halted Stopped
- X 13 428 Yes No No No No
- X
- X 2 569 root ttyp0 2/10/91 14:55:10 UUCP Log Analysis
- X 3 andy tty01 2/10/91 14:59:29 Sales Report
- X 4 root console 2/10/91 15:01:00 Security Check
- X 5 accounts ttyh3 2/10/91 15:03:20 Statements Print
- X 6 jmajor tty0a 2/10/91 15:05:31 COBOL compile
- X 7 bfrances ttyp3 2/10/91 15:05:31 exit 0
- X 8 james ttyc 2/10/91 15:07:32 find ./ -name core -ls
- X 9 james ttyc 2/10/91 15:08:12 test run 1
- X 10 andy tty01 2/10/91 15:08:34 Invoice Print
- X 11 root ttyp0 2/10/91 15:10:04 Offline Backup
- X 12 accounts ttyh3 2/10/91 15:10:17 Overdue list
- X 13 prog1 ttypb 2/10/91 15:11:35 make emacs
- X 14 jmajor tty0a 2/10/91 15:11:36 cobrun update.cbl
- X
- X The output of 'ql' is in three parts:
- X
- X a. At the top is the basic information about the queue itself. The
- X name, which files it uses, it's priority, etc.
- X
- X b. The next part shows the current status of the queue header flags
- X and fields, which are self explanatory. The field headed 'Active'
- X in this case contains the pid of the queue process engine ('qp')
- X which is handling this queue. If the queue was idle (no process
- X engine) this field would contain "No".
- X
- X c. The bulk of the output consists of a list of the entries in the
- X queue, each starting with the entry number. It is this number
- X which is used to manipulate individual entries in the queue
- X (e.g. jk -e <entryno> <queuename> to kill (remove) a job).
- X
- X The next column is only ever used for the first entry in a queue,
- X and only then if the queue is active. The first entry in the queue
- X is the currently running entry, and this field contains the pid of
- X the forked child.
- X
- X Column 3 is the user who submitted the job.
- X
- X Column 4 is the tty from which the job was submitted.
- X
- X Columns 5 & 6 are the date & time that the job was submitted.
- X
- X Column 7 is the job name, which, if used, gives some indication
- X of the job running.
- X
- X qf Queue find.
- X qt Queue test. These programs are primarily provided for use in shell
- X scripts. All of the options of qf provide output on stdout relating to
- X the contents and status of a queue. Most of the options to qt cause it
- X to either fail, or not fail depending on the settings of the queue
- X flags. The exception is the -l option which is used in the qa script
- X to check the accessibility of a queue, and output the one line
- X description.
- X Examine the scripts rc.QBATCH and qa for examples of their use.
- X
- X Those options to qf which are useful interactively are:
- X -m Monitor. qf returns the full absolute pathspec of the monitor
- X used by the queue (see also MONITORS). So to check the progress
- X of a job, the user can use:
- X more `qf -m <queuename>`
- X
- X -l Provides a one line status report similar to qt -l but with the
- X columns headed.
- X
- X -j jcl. returns the full absolute pathspec of the jcl file created by
- X js for this job.
- X
- X -s Summary timings. qp maintains a limited profile timing summary for
- X jobs processed in each queue. The timings for each job are written
- X to the monitor, but qf -s will display the summary viz:
- X
- X
- X Queue started : Wed Oct 2 15:02:37 1991
- X
- X Available for : 5 Min 14.00 Sec
- X No. Jobs Processed: 10
- X
- X Times: Actual Av. Per Job
- X
- X Queued 5:45.00 Sec 34.50 Sec
- X Real 1:43.68 Sec 10.36 Sec
- X User 0.60 Sec 0.06 Sec
- X System 2.69 Sec 0.26 Sec
- X
- X Utilisation (real/available) 33.01%
- X
- X Current job not accounted for above, running for : 7.00 Sec
- X
- X The figures are:
- X Queued: The time a job was on the queue before starting to process.
- X Real: The actual (wall clock) time from start to end of processing.
- X User: The user cpu time taken by the job.
- X System: The system cpu time taken by the job.
- X
- END_OF_FILE
- if test 10173 -ne `wc -c <'doc/chap.04'`; then
- echo shar: \"'doc/chap.04'\" unpacked with wrong size!
- fi
- # end of 'doc/chap.04'
- fi
- if test -f 'src/jk.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/jk.c'\"
- else
- echo shar: Extracting \"'src/jk.c'\" \(8327 characters\)
- sed "s/^X//" >'src/jk.c' <<'END_OF_FILE'
- X/************************************************************************/
- X/* */
- X/* jk .. Job kill. remove a job from this queue (optionally kill it). */
- X/* */
- X/* usage: jk [-k] [-a] [-u <userid>] [-e <entryno>] qname */
- X/* */
- X/* Copyright (c) Vita Services 1990 */
- X/* (c) Vita Fibres 1990 1991 */
- X/* */
- X/************************************************************************/
- X
- X#include "qbatch.h"
- int fpq = 0;
- int i, l;
- int killed = 0;
- long j, k;
- int aflag = 0, kflag = 0, entryno = 0;
- pid_t jpid = 0;
- uid_t userid = 0, uid;
- off_t *entries;
- char *queuename;
- char queue[128];
- char buff [128];
- X#include "config.h"
- X
- X
- main (argc, argv, envp)
- int argc;
- char *argv[], *envp[];
- X{
- X int c;
- X extern char *optarg;
- X extern int optind;
- X if (argc == 1)
- X {
- X puts ("Usage: jk [-a] [-u <userid>] [-e <entryno>] qname");
- X qb_term (0);
- X }
- X while ((c = getopt (argc, argv, "kau:e:v")) != -1)
- X switch (c)
- X {
- X case 'a': aflag ++;
- X break;
- X case 'u': userid = atoi(optarg);
- X break;
- X case 'v': q_version();
- X case 'k': kflag ++;
- X break;
- X case 'e': entryno = atoi(optarg);
- X break;
- X case '?': qb_term (-1);
- X }
- X if (optind >= argc)
- X {
- X fprintf (stderr, "Missing queue name\n");
- X qb_term (-1);
- X }
- X if ((aflag !=0) && (entryno != 0))
- X {
- X fprintf (stderr, "-a (ALL) flag and -e (entry number) incompatible\n");
- X qb_exit (-1);
- X }
- X uid = getuid();
- X if ((aflag ==0) && (entryno == 0))
- X {
- X if (uid == 0) kflag = 999;
- X else
- X {
- X fprintf (stderr, "Must have one of -a (ALL) flag or -e (entry number)\n");
- X qb_exit (-1);
- X }
- X }
- X
- X queuename = argv[optind];
- X strcpy (queue, QUEUEPATH);
- X strcat (queue, queuename);
- X qb_setterm();
- X fpq = open (queue, O_RDWR);
- X if (fpq == -1)
- X {
- X fprintf (stderr, "Invalid queue name: %s\n", queuename);
- X qb_term (-1);
- X }
- X
- X q_lock(fpq);
- X read (fpq, &head, sizeof(head));
- X if (bad_queue()) qb_exit(-1);
- X if (head.qh_noentries == 0)
- X {
- X fprintf (stderr, " Queue %s is empty!\n", queuename);
- X qb_term (-1);
- X }
- X if (uid != 0)
- X {
- X if ((userid != uid)&&(userid != 0) && (aflag == 0))
- X {
- X fprintf (stderr, "Must be super user to kill another's jobs)\n");
- X qb_term (-1);
- X }
- X }
- X if (kflag == 999)
- X {
- X if ((head.qh_flags & qh_kill) == 0) head.qh_flags += qh_kill;
- X lseek (fpq, 0, SEEK_SET);
- X write (fpq, &head, sizeof(head));
- X q_unlock(fpq);
- X close (fpq);fpq = 0;
- X tell_qp();
- X qb_exit (0);
- X }
- X if ((head.qh_flags&qh_halt) == 0)
- X {
- X head.qh_flags += qh_halt;
- X lseek (fpq, 0, SEEK_SET);
- X write (fpq, &head, sizeof(head));
- X q_unlock(fpq);
- X close (fpq);fpq = 0;
- X tell_qp();
- X }
- X do
- X {
- X fpq = open (queue, O_RDWR);
- X q_lock(fpq);
- X read (fpq, &head, sizeof(head));
- X read (fpq, &entry, sizeof(entry));
- X jpid = entry.qe_status;
- X if (jpid != 0) /* something running */
- X {
- X q_unlock(fpq);
- X close (fpq);fpq = 0;
- X fpq = open (queue, O_RDWR);
- X q_lock(fpq);
- X read (fpq, &head, sizeof(head));
- X if (head.qh_noentries == 0)
- X {
- X fprintf (stderr, " Queue %s is empty!\n", queuename);
- X qb_term (-1);
- X }
- X read (fpq, &entry, sizeof(entry));
- X if ((entry.qe_status != jpid) && (jpid != 0)) /* job has changed */
- X {
- X jpid = 0; /* don't kill */
- X }
- X }
- X }
- X while (jpid != entry.qe_status) ;
- X /* the current job is halted */
- X if (jpid == 0) kflag = 0; /* nowt running, no need to kill */
- X if ((uid != 0) && (uid != entry.qe_uid) && (aflag == 0))
- X {
- X fprintf (stderr, "Must be super user to kill another's jobs)\n");
- X lseek (fpq, 0, SEEK_SET);
- X if ((head.qh_flags & qh_halt) != 0)
- X {
- X head.qh_flags -= qh_halt;
- X }
- X write (fpq, &head, sizeof(head));
- X qb_exit (-1);
- X }
- X
- X entries = (off_t *) calloc ((head.qh_noentries+1), sizeof(off_t));
- X lseek (fpq, sizeof(head), SEEK_SET);
- X l = 0;
- X for (i = 0; i < head.qh_noentries; i++)
- X {
- X j = lseek (fpq, 0L, SEEK_CUR);
- X read (fpq, &entry, sizeof(entry));
- X if ((uid == 0) || (uid == entry.qe_uid)) /* we can kill it */
- X {
- X if (aflag) /* kill all */
- X {
- X if ((uid == 0) && (userid == entry.qe_uid))
- X { /* we don't want this */
- X killed++;
- X strcpy (buff, head.qh_spool);
- X if (buff[strlen(buff) -1] != '/') strcat (buff, "/");
- X strcat (buff, entry.qe_jcl);
- X if (entry.qe_status == 0) unlink (buff);
- X continue;
- X }
- X if (userid == 0)
- X {
- X if (uid == entry.qe_uid)
- X { /* or this */
- X killed ++;
- X strcpy (buff, head.qh_spool);
- X if (buff[strlen(buff) -1] != '/') strcat (buff, "/");
- X strcat (buff, entry.qe_jcl);
- X if (entry.qe_status == 0) unlink (buff);
- X continue;
- X }
- X if (uid == 0)
- X { /* or this */
- X killed ++;
- X strcpy (buff, head.qh_spool);
- X if (buff[strlen(buff) -1] != '/') strcat (buff, "/");
- X strcat (buff, entry.qe_jcl);
- X if (entry.qe_status == 0) unlink (buff);
- X continue;
- X }
- X }
- X }
- X else
- X { /* just a given entry */
- X if (entry.qe_jobno == entryno)
- X
- X { /* or this */
- X killed ++;
- X strcpy (buff, head.qh_spool);
- X if (buff[strlen(buff) -1] != '/') strcat (buff, "/");
- X strcat (buff, entry.qe_jcl);
- X if (entry.qe_status == 0)
- X {
- X unlink (buff);
- X kflag = 0;
- X }
- X continue;
- X }
- X }
- X }
- X entries[l] = j; /* we must want it */
- X l++;
- X }
- X /* we now have a table (entries) containing the offsets of those wanted */
- X k = lseek (fpq, sizeof(head), SEEK_SET);
- X head.qh_noentries = 0;
- X if (k != entries[0])
- X { /* we don't want the first entry */
- X if (jpid != 0) /* job running so qp must cancel */
- X {
- X read (fpq, &entry, sizeof(entry)); /* skip first */
- X if (kflag == 0)
- X {
- X printf ("Kill option not requested .. running entry not killed!\n");
- X killed --;
- X }
- X head.qh_noentries ++;
- X }
- X }
- X i = 0;
- X while (entries[i] != 0)
- X {
- X k = lseek (fpq, 0L, SEEK_CUR); /* write offset */
- X lseek (fpq, entries[i], SEEK_SET); /* read offset */
- X read (fpq, &entry, sizeof(entry));
- X lseek (fpq, k, SEEK_SET);
- X write (fpq, &entry, sizeof(entry));
- X head.qh_noentries ++;
- X i++;
- X }
- X k = lseek (fpq, 0L, SEEK_CUR);
- X lseek (fpq, 0, SEEK_SET);
- X if ((head.qh_flags & qh_halt) != 0)
- X {
- X head.qh_flags -= qh_halt;
- X }
- X if (killed == 0) kflag = 0;
- X if ((head.qh_flags & qh_kill) == 0)
- X {
- X if (kflag != 0) head.qh_flags += qh_kill;
- X }
- X write (fpq, &head, sizeof(head));
- X ftruncate(fpq, k);
- X /* right, now either kill or continue first entry (if running) */
- X q_unlock(fpq);
- X close (fpq);fpq = 0;
- X tell_qp();
- X printf ("Queue %s, %d entries killed\n", queuename, killed);
- X exit (0);
- X}
- X
- END_OF_FILE
- if test 8327 -ne `wc -c <'src/jk.c'`; then
- echo shar: \"'src/jk.c'\" unpacked with wrong size!
- fi
- # end of 'src/jk.c'
- fi
- if test -f 'src/js.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/js.c'\"
- else
- echo shar: Extracting \"'src/js.c'\" \(14536 characters\)
- sed "s/^X//" >'src/js.c' <<'END_OF_FILE'
- X/************************************************************************/
- X/* */
- X/* js .. job submit. submit a job to an existing queue. */
- X/* */
- X/* Usage js [-l] [-d] [-r<replycode>] [-m<monitor>] [-n<jobname>] */
- X/* queuename [<jclfile>] */
- X/* */
- X/* Copyright (c) Vita Services 1990 */
- X/* (c) Vita Fibres 1990 1991 */
- X/* */
- X/************************************************************************/
- X
- X#include "qbatch.h"
- X#include <stdlib.h>
- X#include <malloc.h>
- int fpq = 0;
- XFILE *fpin, *fpout, *fp;
- char temp [16], *jcl, *jcwd = NULL;
- int i,j,k, debug = 0;
- int qpuid[10];
- int qpgid[10];
- int lflag = 0, sflag = 0, fixedcontext = 0, permission = -1;
- int gotuid, gotgid;
- uid_t jobuid, saveuid, testuid;
- gid_t jobgid, savegid;
- int envcount = 0;
- int notify = 0;
- char envar[64];
- char *fcptr;
- char shell [64] = "";
- char monitor[64] = "";
- char jobname[32];
- char *tty;
- char *queuename;
- char jclfile[128];
- char queue[128];
- char buff [256];
- char rcmd [128];
- struct envlist {
- X char *envptr;
- X struct envlist *left;
- X struct envlist *right;
- X };
- struct envlist *root = (struct envlist *) NULL;
- X#include "config.h"
- int scan_envlist (ptr, str)
- struct envlist *ptr;
- char *str;
- X{
- X int found;
- X if (ptr == (struct envlist*) NULL) return (0);
- X found = strcmp (str, ptr->envptr);
- X if (found < 0) return (scan_envlist(ptr->left, str));
- X if (found == 0) return (1);
- X return (scan_envlist(ptr->right, str));
- X}
- int free_envlist (ptr)
- struct envlist *ptr;
- X{
- X if (ptr == (struct envlist *) NULL) return;
- X if (ptr->left != (struct envlist *) NULL)
- X {
- X (free_envlist(ptr->left));
- X free (ptr->left);
- X }
- X if (ptr->right != (struct envlist *) NULL)
- X {
- X (free_envlist(ptr->right));
- X free (ptr->right);
- X }
- X}
- X
- int add_envlist (ptr, str)
- struct envlist *ptr;
- char *str;
- X{
- X int found;
- X if (ptr == (struct envlist *) NULL)
- X {
- X if (ptr != root) return (-1);
- X ptr = (struct envlist *) malloc (sizeof(struct envlist));
- X ptr->envptr = malloc(strlen(str)+1);
- X strcpy (ptr->envptr, str);
- X ptr->left = (struct envlist *) NULL;
- X ptr->right = (struct envlist *) NULL;
- X root = ptr;
- X return (1);
- X
- X }
- X found = strcmp (str, ptr->envptr);
- X if (found < 0)
- X {
- X if (ptr->left == (struct envlist *) NULL)
- X {
- X ptr->left = (struct envlist *) malloc (sizeof(struct envlist));
- X ptr->left->envptr = malloc(strlen(str)+1);
- X strcpy (ptr->left->envptr, str);
- X ptr->left->left = (struct envlist *) NULL;
- X ptr->left->right = (struct envlist *) NULL;
- X return (1);
- X }
- X else
- X return (add_envlist (ptr->left, str));
- X }
- X if (found == 0) return (0); /* already in list */
- X if (ptr->right == (struct envlist *) NULL)
- X {
- X ptr->right = (struct envlist *) malloc (sizeof(struct envlist));
- X ptr->right->envptr = malloc(strlen(str)+1);
- X strcpy (ptr->right->envptr, str);
- X ptr->right->left = (struct envlist *) NULL;
- X ptr->right->right = (struct envlist *) NULL;
- X return (1);
- X }
- X else
- X return (add_envlist (ptr->right, str));
- X}
- X
- void usage(i)
- int i;
- X{
- X puts ("Usage: js [-r<replycode>] [-m<monitor>] [-n<jobname>] [-s <shell>] queuename [<jclfile>]");
- X qb_term (i);
- X}
- main (argc, argv, envp)
- int argc;
- char *argv[], *envp[];
- X{
- X int c;
- X extern char *optarg;
- X extern int optind;
- X if (argc == 1) usage (0);
- X while ((c = getopt (argc, argv, "dlm:n:r:s:v")) != -1)
- X switch (c)
- X {
- X case 'd': if (shell[0] == 0) debug ++;
- X break;
- X case 'l': lflag ++;
- X break;
- X case 'm': if (strlen(optarg) >63)
- X {
- X fprintf (stderr, "Monitor path longer than 63 bytes!\n");
- X qb_term (-1);
- X }
- X
- X strcpy (monitor, optarg);
- X break;
- X case 'n': if (strlen(optarg) >31)
- X {
- X fprintf (stderr, "Job name longer than 31 bytes!\n");
- X qb_term (-1);
- X }
- X strcpy (jobname, optarg);
- X break;
- X case 'r': notify = atoi(optarg);
- X break;
- X case 's': strcpy (shell, optarg);
- X debug = 0;
- X break;
- X case 'v': q_version();
- X case '?': usage (-1);
- X
- X }
- X if (optind >= argc)
- X {
- X fprintf (stderr, "Missing queue name\n");
- X qb_term (-1);
- X }
- X queuename = argv[optind];
- X strcpy (queue, QUEUEPATH);
- X strcat (queue, queuename);
- X qb_setterm();
- X fpq = open (queue, O_RDWR);
- X if (fpq == -1)
- X {
- X fprintf (stderr, "Invalid queue name : %s\n", queuename);
- X qb_term (-1);
- X }
- X q_lock(fpq);
- X read (fpq, &head, sizeof(head));
- X if (bad_queue()) qb_exit(-1);
- X if ((head.qh_flags & qh_enabled) == 0)
- X {
- X fprintf (stderr, "Queue %s is not accepting entries!\n", queuename);
- X qb_exit(-1);
- X }
- X if ((strcmp (head.qh_defmon, "NONE") == 0))
- X {
- X if (*monitor == 0)
- X {
- X fcptr = getenv ("MONITOR");
- X if (fcptr == NULL)
- X {
- X fprintf(stderr, "No MONITOR environment string.. cannot submit\n");
- X qb_exit(-1);
- X }
- X strcpy (monitor, fcptr);
- X }
- X }
- X if (*monitor != 0)
- X {
- X if (*monitor != '/') /* monitor should be full pathspec */
- X { /* so add current working directory */
- X getcwd (buff, 128);
- X if (buff [strlen(buff) - 1] != '/') strcat (buff, "/");
- X strcat (buff, monitor);
- X strcpy (monitor, buff);
- X
- X }
- X if (strlen(monitor) > 63)
- X {
- X fprintf (stderr, "Monitor path > 63 characters .. aborting\n");
- X qb_exit(-1);
- X }
- X if (access(monitor, W_OK) == 0) /* monitor path is accessible */
- X {
- X fp = fopen (monitor, "w");
- X if (fp == NULL) /* monitor is a directory */
- X {
- X if (monitor [strlen(monitor) - 1] != '/')
- X strcat (monitor, "/");
- X strcat (monitor, queuename);
- X strcat (monitor, ".mon");
- X }
- X else fclose (fp);
- X }
- X else /* file does not exist or we don't have access */
- X {
- X fp = fopen (monitor, "w"); /*can we create it? */
- X if (fp == NULL)
- X {
- X fprintf (stderr, "Invalid path for monitor: %s\n", monitor);
- X qb_term (-1);
- X }
- X else
- X {
- X fclose (fp);
- X unlink (monitor);
- X }
- X }
- X }
- X strcpy (temp, queuename);
- X temp [4] = 0;
- X strcat (temp, "XXXXXX");
- X mktemp (temp);
- X strcpy (buff, head.qh_spool);
- X if (buff[strlen(buff) -1] != '/') strcat (buff, "/");
- X strcat (buff,temp);
- X jcl = temp;
- X strcpy (jclfile, buff);
- X fpout = fopen (buff, "w");
- X if (fpout == NULL)
- X {
- X fprintf (stderr, "Cannot create jcl file!\n");
- X qb_exit (-1);
- X }
- X jobuid = getuid();
- X saveuid = jobuid;
- X jobgid = getgid();
- X savegid = jobgid;
- X jcwd = getcwd (NULL, 128);
- X if ((head.qh_flags & qh_fixed) == 0)
- X {
- X if (lflag == 0) /* not needed for link */
- X {
- X if (shell[0] == 0)
- X {
- X fprintf (fpout, "#!/bin/sh");
- X if (debug != 0) fprintf (fpout, " -x\n");
- X else fprintf (fpout, "\n");
- X }
- X else fprintf (fpout, "#!%s\n",shell);
- X /* is there an exclude environment file? */
- X strcpy (buff, QUEUEPATH);
- X strcat (buff, ".qxenv");
- X fpin = fopen(buff, "r");
- X if (fpin != NULL)
- X {
- X /* set up exclude environment table */
- X while (fgets(buff, 256, fpin) != NULL)
- X {
- X if (buff[0] == '#') continue;
- X if (buff[0] == ' ') continue;
- X sscanf(buff, "%s", rcmd);
- X add_envlist(root, rcmd);
- X }
- X fclose (fpin);
- X }
- X for (i=0; envp[i] != NULL; i++)
- X {
- X strcpy (buff, envp[i]);
- X for (j = 0; buff[j] != '='; j++){}
- X buff[j] = 0;
- X if (scan_envlist(root, buff) <= 0)
- X {
- X fprintf(fpout, "#ENV %s\n", envp[i]);
- X }
- X if (strcmp (buff, "JOBNAME") == 0)
- X {
- X if (strlen (buff) > 31) buff[31] = 0;
- X if (jobname[0] == 0) strcpy (jobname, buff);
- X }
- X }
- X fprintf (fpout, "cd %s\n", jcwd);
- X if (root != (struct envlist *) NULL)
- X {
- X free_envlist(root);
- X free (root);
- X }
- X }
- X }
- X else
- X {
- X if (lflag != 0)
- X {
- X fprintf (stderr, "Cannot use linked job in fixed context queue\n");
- X qb_exit(-1);
- X }
- X strcpy (buff, QUEUEPATH);
- X strcat (buff, ".");
- X strcat (buff, queuename);
- X strcat (buff, "rc");
- X fpin = fopen (buff, "r");
- X if (fpin == NULL)
- X {
- X printf ("Can't access initialisation file: %s\n", buff);
- X fclose (fpout);
- X unlink (jclfile);
- X exit (-1);
- X }
- X fgets (buff, 128, fpin);
- X if ((*buff == '#') && (buff[1] == '!') && (buff[2] == '/'))
- X {
- X fprintf (fpout, "%s", buff);
- X fgets (buff, 128, fpin);
- X }
- X else
- X {
- X if (*shell == 0)
- X {
- X fprintf (fpout, "#!/bin/sh");
- X if (debug != 0) fprintf (fpout, " -x\n");
- X else fprintf (fpout, "\n");
- X }
- X else fprintf (fpout, "#!%s\n",shell);
- X }
- X while (*buff != 0)
- X {
- X fixedcontext = 0;
- X sscanf (buff, "%s", rcmd);
- X if (strcmp (rcmd, "#QCONTEXT") == 0)
- X {
- X fixedcontext = 1;
- X /* set job uid and gid to QCONTEXT */
- X i = sscanf (buff, "%s%d%d", rcmd, &gotuid, &gotgid);
- X switch (i)
- X {
- X case 1: jobuid = saveuid;
- X jobgid = savegid;
- X break;
- X case 2: jobgid = savegid;
- X jobuid = (gotuid==0) ? saveuid : gotuid;
- X break;
- X case 3: jobgid = (gotgid==0) ? savegid : gotgid;
- X jobuid = (gotuid==0) ? saveuid : gotuid;
- X break;
- X }
- X }
- X if (strcmp (rcmd, "#QUSERS") == 0)
- X {
- X fixedcontext = 1;
- X if (permission > 0) break;
- X permission = 0;
- X /* check uid against list of permitted id's */
- X i = sscanf (buff,"%s%d%d%d%d%d%d%d%d%d%d", rcmd,
- X &qpuid[0],&qpuid[1],&qpuid[2],&qpuid[3],
- X &qpuid[4],&qpuid[5],&qpuid[6],&qpuid[7],
- X &qpuid[8],&qpuid[9]);
- X for (j=0; j < i; j++)
- X if (qpuid[j] == saveuid)
- X {
- X permission ++;
- X break;
- X }
- X }
- X if (strcmp (rcmd, "#QGROUPS") == 0)
- X {
- X fixedcontext = 1;
- X if (permission > 0) break;
- X permission = 0;
- X /* check gid against list of permitted id's */
- X i = sscanf (buff,"%s%d%d%d%d%d%d%d%d%d%d", rcmd,
- X &qpgid[0],&qpgid[1],&qpgid[2],&qpgid[3],
- X &qpgid[4],&qpgid[5],&qpgid[6],&qpgid[7],
- X &qpgid[8],&qpgid[9]);
- X for (j=0; j < i; j++)
- X if (qpgid[j] == savegid)
- X {
- X permission ++;
- X break;
- X }
- X }
- X if (strcmp (rcmd, "#QGETENV") == 0)
- X {
- X fixedcontext = 1;
- X sscanf (buff, "%s %s", rcmd, envar);
- X if (envar == NULL) break;
- X fcptr = getenv (envar);
- X if (fcptr == NULL) break;
- X fprintf (fpout, "#ENV %s=%s\n",envar, fcptr);
- X }
- X if (fixedcontext == 0) fputs (buff, fpout);
- X *buff = 0;
- X fgets (buff, 128, fpin);
- X }
- X if ((permission == 0) && (jobuid != 0) && (jobuid != saveuid))
- X {
- X puts ("User does not have permission to submit jobs to this Queue");
- X puts ("please contact your system administrator");
- X sprintf(buff, "echo 'Permission violation in fixed context queue %s\nby UID %d on `tty`>/dev/console", queuename, saveuid);
- X system (buff);
- X fclose (fpout);
- X unlink (jclfile);
- X exit (-1);
- X }
- X }
- X optind ++;
- X if (optind < argc)
- X {
- X if (argv[optind][0] != '/')
- X {
- X /* no absolute path given so prefix with current path */
- X strcpy (buff, jcwd);
- X strcat (buff,"/");
- X strcat (buff, argv[optind]);
- X }
- X else strcpy (buff, argv[optind]);
- X }
- X if (lflag && (optind < argc))
- X {
- X fprintf (fpout, "#!L");
- X fprintf (fpout, "%s\n", buff);
- X if (jobname[0] == 0)
- X {
- X /* no jobname, & file linked, use filename for jobname */
- X for (i=0; (i < 30 && argv[optind][i] != 0 && argv[optind][i] != '\n'); i++) jobname[i] = argv[optind][i];
- X jobname[i] = 0;
- X }
- X }
- X else
- X {
- X if (optind >= argc) fpin = stdin;
- X else
- X {
- X fpin = fopen (buff, "r");
- X if (fpin == NULL)
- X {
- X fprintf (stderr, "Unable to read input file %s!\n", argv[optind]);
- X qb_exit (-1);
- X }
- X }
- X while (fgets (buff, 128, fpin) != NULL)
- X {
- X fputs (buff, fpout);
- X if (*jobname == 0)
- X {
- X fcptr = strrchr(buff, '\n');
- X if (fcptr != NULL) *fcptr = 0;
- X fcptr = strchr (buff, '=');
- X if (fcptr != NULL)
- X {
- X *fcptr = 0;
- X fcptr ++;
- X if (strcmp (buff, "JOBNAME") == 0)
- X strcpy (jobname, fcptr);
- X }
- X }
- X }
- X if (jobname[0] == 0)
- X {
- X /* no jobname (probably crqentry) so use last line of jcl for name */
- X for (i=0; (i < 30 && buff[i] != 0 && buff[i] != '\n'); i++) jobname[i] = buff[i];
- X jobname[i] = 0;
- X }
- X }
- X fclose (fpout);
- X if (!sflag) fclose (fpin);
- X entry.qe_uid = jobuid;
- X entry.qe_gid = jobgid;
- X chmod (jclfile, 0700);
- X chown (jclfile, entry.qe_uid, entry.qe_gid);
- X i = ++head.qh_hiwater;
- X i %= 999;
- X if (head.qh_noentries == 0) i = 1;
- X head.qh_hiwater = i;
- X entry.qe_jobno = i;
- X entry.qe_status = 0;
- X entry.qe_repcount = 0;
- X entry.qe_notify = notify;
- X entry.qe_submitted = time ((time_t *)0);
- X strcpy (entry.qe_jcl, temp);
- X
- X if (jobname[0] != 0) strcpy (entry.qe_jobname, jobname);
- X if (monitor[0] != 0) strcpy (entry.qe_monitor, monitor);
- X else strcpy (entry.qe_monitor, "");
- X tty = ttyname(0);
- X if (tty != NULL)
- X {
- X strcpy (buff, tty);
- X for (i = strlen(buff); buff[i] != '/'; i--){}
- X strcpy (entry.qe_tty, buff+i+1);
- X }
- X else strcpy (entry.qe_tty, "");
- X cuserid(entry.qe_uname);
- X i = head.qh_noentries ++;
- X lseek (fpq, 0, SEEK_SET);
- X write (fpq, &head, sizeof(head));
- X lseek (fpq, (sizeof(head)+(i*sizeof(entry))), SEEK_SET);
- X write (fpq, &entry, sizeof(entry));
- X q_unlock(fpq);
- X close (fpq); fpq = 0;
- X tell_qp(); /* send qp a signal */
- X printf ("Queue %s accepted entry no: %d\n", queuename, head.qh_hiwater);
- X qb_term(0);
- X}
- END_OF_FILE
- if test 14536 -ne `wc -c <'src/js.c'`; then
- echo shar: \"'src/js.c'\" unpacked with wrong size!
- fi
- # end of 'src/js.c'
- fi
- if test -f 'src/qf.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/qf.c'\"
- else
- echo shar: Extracting \"'src/qf.c'\" \(8190 characters\)
- sed "s/^X//" >'src/qf.c' <<'END_OF_FILE'
- X/************************************************************************/
- X/* */
- X/* qf .. queue find. Report information about a queue */
- X/* */
- X/* Copyright (c) Vita Services 1990 */
- X/* (c) Vita Fibres 1990 1991 */
- X/* */
- X/************************************************************************/
- X
- X#include <time.h>
- X#include <stdlib.h>
- X#include "qbatch.h"
- int mflag = 0, jflag = 0, qflag = 0, pflag = 0, aflag = 0,rflag = 0, sflag = 0, nflag = 0;
- int lflag = 0;
- char buff[128];
- XFILE *fpq, *fp;
- char *queuename;
- char *mon, *fcptr;
- int entryno = 0;
- time_t now, then;
- struct tm *jtimes;
- int idle;
- char monitor [128];
- char tval[32];
- void q_version()
- X{
- X puts (&QbSID[5]);
- X puts ("");
- X puts (&QbCR1[5]);
- X puts (&QbCR2[5]);
- X puts ("");
- X exit(0);
- X}
- int bad_queue()
- X{
- X if (strcmp (head.q_magic, "qBq") != 0)
- X {
- X fprintf(stderr,"%s is not a valid QBATCH queue\007\n", queuename);
- X return(-1);
- X }
- X return(0);
- X}
- char * print_time(val, opt)
- unsigned long val;
- int opt;
- X{
- X int temp;
- X char sval[8];
- X *tval = 0;
- X temp = val/8640000;
- X if (temp)
- X {
- X sprintf(sval, "%d", temp);
- X strcat (tval, sval);
- X if (opt) strcat (tval, " Days ");
- X else strcat (tval, ":");
- X val%=8640000;
- X }
- X temp = val/360000;
- X if ((temp) || (*tval))
- X {
- X sprintf(sval, "%d", temp);
- X strcat (tval, sval);
- X if (opt) strcat (tval, " Hrs ");
- X else strcat (tval, ":");
- X val%=360000;
- X }
- X temp = val/6000;
- X if ((temp) || (*tval))
- X {
- X if (*tval) sprintf(sval, "%02d", temp);
- X else sprintf(sval, "%d", temp);
- X strcat (tval, sval);
- X if (opt) strcat (tval, " Min ");
- X else strcat (tval, ":");
- X val%=6000;
- X }
- X temp = val/100;
- X if (*tval) sprintf(sval, "%02d", temp);
- X else sprintf(sval, "%d", temp);
- X strcat (tval, sval);
- X strcat (tval, ".");
- X temp = val%100;
- X sprintf(sval, "%02d", temp);
- X strcat (tval, sval);
- X strcat (tval, " Sec");
- X return(tval);
- X}
- main (argc, argv)
- int argc;
- char * argv[];
- X{
- X int c;
- X extern char *optarg;
- X extern int optind;
- X while ((c = getopt (argc, argv, "ae:jlmnpqrsv")) != -1)
- X switch (c)
- X {
- X case 'q':
- X qflag ++;
- X break;
- X case 'j':
- X jflag ++;
- X break;
- X case 'l':
- X lflag ++;
- X break;
- X case 'm':
- X mflag ++;
- X break;
- X case 'p':
- X pflag ++;
- X break;
- X case 'a':
- X aflag ++;
- X break;
- X case 'r':
- X rflag ++;
- X break;
- X case 'n':
- X nflag ++;
- X break;
- X case 's':
- X sflag ++;
- X break;
- X case 'e':
- X entryno = atoi (optarg);
- X break;
- X case 'v': q_version();
- X case '?': exit (-1);
- X }
- X if (optind >= argc)
- X {
- X fprintf (stderr, "Invalid or missing queue name!\n");
- X exit (-1);
- X }
- X queuename = argv[optind];
- X strcpy (buff, QUEUEPATH);
- X strcat (buff, queuename);
- X fpq = fopen (buff, "r");
- X if (fpq == NULL)
- X {
- X fprintf (stderr, "Invalid queue name: %s!\n",queuename);
- X fclose (fpq);
- X exit (-1);
- X }
- X fread (&head, sizeof(head), 1, fpq);
- X if (bad_queue())
- X {
- X fclose (fpq);
- X exit (-1);
- X }
- X if (lflag != 0)
- X {
- X fclose (fpq);
- X puts ("Queue No of Priority Fixed Enabled Halted Stopped");
- X puts ("Name Entries (nice) Context\n");
- X printf("%s %6d ", queuename, head.qh_noentries);
- X printf("%6d ", head.qh_priority);
- X printf("%s ",(head.qh_flags&qh_fixed)?"yes": "no ");
- X printf("%s ",(head.qh_flags&qh_enabled)?"yes": "no ");
- X printf("%s ",(head.qh_flags&qh_halt)?"yes": "no ");
- X printf("%s\n", (head.qh_flags&qh_stop)?"yes": "no ");
- X exit(0);
- X }
- X if (nflag != 0)
- X {
- X printf ("%d\n", head.qh_priority);
- X fclose (fpq);
- X exit (0);
- X }
- X if (pflag != 0)
- X {
- X printf("%d\n", head.qh_pid);
- X fclose (fpq);
- X exit (0);
- X }
- X if (aflag != 0)
- X {
- X printf("%d\n", head.qh_noentries);
- X fclose (fpq);
- X exit (0);
- X }
- X if (rflag != 0)
- X {
- X if (head.qh_noentries > 0)
- X {
- X fread (&entry, sizeof(entry), 1, fpq);
- X printf("%d\n", entry.qe_status);
- X }
- X else printf("%d\n",0);
- X fclose (fpq);
- X exit (0);
- X }
- X if (sflag != 0)
- X {
- X fclose (fpq);
- X if (head.qh_proc == 0)
- X {
- X printf ("Queue has not been run\n");
- X exit (0);
- X }
- X jtimes = (struct tm *)localtime (&head.qh_proc);
- X printf ("\n Queue started : %s" ,asctime (jtimes));
- X if (head.qh_pid == 0)
- X {
- X printf("\n Queue is not running\n");
- X }
- X else
- X {
- X now = time ((time_t *) 0);
- X then = now;
- X now -= head.qh_proc;
- X now *= 100;
- X printf ("\n Available for : %s\n" ,print_time (now, 1));
- X }
- X if (head.qh_jobcount == 0)
- X {
- X printf("No jobs run since queue started\n");
- X exit(0);
- X }
- X printf (" No. Jobs Processed: %d\n\n", head.qh_jobcount);
- X printf ("Times:\t\t Actual\t\t\tAv. Per Job\n\n");
- X printf ("Queued\t\t%16s", print_time(head.qh_queued, 0));
- X printf (" %16s\n", print_time(head.qh_queued/head.qh_jobcount, 0));
- X printf ("Real\t\t%16s", print_time(head.qh_real, 0));
- X printf (" %16s\n", print_time(head.qh_real/head.qh_jobcount, 0));
- X printf ("User\t\t%16s", print_time(head.qh_user, 0));
- X printf (" %16s\n", print_time(head.qh_user/head.qh_jobcount, 0));
- X printf ("System\t\t%16s", print_time(head.qh_system, 0));
- X printf (" %16s\n", print_time(head.qh_system/head.qh_jobcount, 0));
- X if (head.qh_pid == 0) exit(0);
- X head.qh_real *= 10000;
- X head.qh_real /= now ;
- X printf("\nUtilisation (real/available) %d.%02d%%\n",(head.qh_real/100), (head.qh_real%100));
- X if (head.qh_start)
- X {
- X then -= head.qh_start;
- X then *= 100;
- X printf ("\nCurrent job not accounted for above, running for : %s\n", print_time(then));
- X }
- X fclose (fpq);
- X exit(0);
- X }
- X if (qflag != 0)
- X {
- X if (strcmp (head.qh_defmon, "NONE") == 0)
- X {
- X fprintf(stderr, "%s has NO default monitor\007\n", queuename);
- X fclose (fpq);
- X exit(-1);
- X }
- X puts (head.qh_defmon);
- X }
- X else
- X {
- X if ((jflag == 0) && (mflag == 0) && (entryno == 0))
- X {
- X fprintf(stderr, "No options specified\007\n");
- X fclose (fpq);
- X exit(0);
- X }
- X if ((jflag == 0) && (mflag == 0))
- X {
- X fprintf(stderr, "Entryno specified without j or m\007\n");
- X fclose (fpq);
- X exit(0);
- X }
- X if (head.qh_noentries > 0)
- X {
- X if (entryno == 0) fread (&entry, sizeof(entry), 1, fpq);
- X else
- X {
- X entry.qe_jobno = 0;
- X while (entry.qe_jobno != entryno)
- X {
- X if (fread (&entry, sizeof(entry), 1, fpq) == 0)
- X {
- X fprintf (stderr, "entry %d does not exist\n", entryno);
- X fclose (fpq);
- X exit (-1);
- X }
- X }
- X }
- X if (jflag != 0)
- X {
- X strcpy (buff, head.qh_spool);
- X if (buff[strlen(buff) -1] != '/') strcat (buff,"/");
- X strcat (buff,entry.qe_jcl);
- X puts (buff);
- X }
- X if (mflag != 0)
- X {
- X if (entry.qe_monitor[0] != 0) puts (entry.qe_monitor);
- X else
- X {
- X if (strcmp (head.qh_defmon, "NONE") == 0)
- X {
- X fprintf(stderr, "%s has NO default monitor\007\n", queuename);
- X fclose (fpq);
- X exit(-1);
- X }
- X puts (head.qh_defmon);
- X }
- X }
- X }
- X else
- X {
- X if (mflag != 0)
- X {
- X if (strcmp (head.qh_defmon, "NONE") == 0)
- X {
- X fprintf(stderr, "%s has NO default monitor\007\n", queuename);
- X fclose (fpq);
- X exit(-1);
- X }
- X puts (head.qh_defmon);
- X }
- X else
- X {
- X fprintf (stderr, "No entries for j or m option\n");
- X fclose (fpq);
- X exit (-1);
- X }
- X }
- X }
- X fclose (fpq);
- X exit (0);
- X}
- END_OF_FILE
- if test 8190 -ne `wc -c <'src/qf.c'`; then
- echo shar: \"'src/qf.c'\" unpacked with wrong size!
- fi
- # end of 'src/qf.c'
- fi
- echo shar: End of archive 5 \(of 6\).
- cp /dev/null ark5isdone
- MISSING=""
- for I in 1 2 3 4 5 6 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 6 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-