Keith's at package, part 1 of 2

Keith Pyle keith at sequoia.execu.com
Thu Feb 14 15:46:02 AEST 1991


The programs which comprise this package are to replace/supplement the
functionality provided by the at(1) provided with many BSD Unix systems.
There are five components:

at - allows users to queue jobs for later execution at a specified date/time

atcat - display the commands in a job previously queued

atq - lists all or selected portions of the at queue

atrm - allows removal of queued jobs that have not yet run

atrun - controls execution of queued jobs, typically run periodically by cron

This version of at is not linked to cron, but can be a direct replacement
for the at found on systems such as Ultrix and Dynix which use cron to
execute atrun at desired intervals.  I am considering linking at to cron
in the manner of SunOS for a future version.

#! /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 1 (of 2)."
# Contents:  INSTALL MANIFEST Makefile PORTING README doc doc/atcat.1
#   doc/atq.1 doc/atrm.1 doc/atrun.8 src src/at.h src/atcat.c
#   src/atname.c src/atrm.c src/date.l src/dumpenv.c src/patchlevel.h
#   src/permit.c src/qalloc.c src/table.h
# Wrapped by keith at lime on Wed Feb 13 22:33:48 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'INSTALL' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'INSTALL'\"
else
echo shar: Extracting \"'INSTALL'\" \(708 characters\)
sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
XSoftware Requirements
X---------------------
X
X- C compiler
X
X- yacc (to build the date parser)
X
XInstallation
X------------
X
X1) Unpack the package in an appropriate directory
X
X2) Edit the Makefile to specify the desired configuration items
X
X3) If you do not run sendmail, edit the file src/at.h and follow the
X   instructions there to specify the mailer you wish to use
X
X4) Issue the command 'make' to build the binaries
X
X5) Login as root
X
X6) Verify that the parent directory for the at queue directory exists.  If
X   not, create it.  (For example, if the queue directory is to be
X   /usr/spool/at, /usr/spool must exist.)
X
X7) type 'make install' to install the binaries and create the necessary
X   directories
X
END_OF_FILE
if test 708 -ne `wc -c <'INSTALL'`; then
    echo shar: \"'INSTALL'\" unpacked with wrong size!
fi
# end of 'INSTALL'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(1618 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X INSTALL                    1	Instructions for installing kat
X MANIFEST                   1	This file
X Makefile                   1	The one and only makefile
X PORTING                    1	Hints on porting kat
X README                     1	Read this, really
X doc                        1	Man page directory
X doc/at.1                   2	Man page for at(1)
X doc/atcat.1                1	Man page for atcat(1)
X doc/atq.1                  1	Man page for atq(1)
X doc/atrm.1                 1	Man page for atrm(1)
X doc/atrun.8                1	Man page for atrun(8)
X src                        1	Source directory
X src/at.c                   2	Main program and functions for at(1)
X src/at.h                   1	Include file for kat family
X src/atcat.c                1	Main program and functions for atcat(1)
X src/atname.c               1	Function for creating at job file names
X src/atq.c                  2	Main program and functions for atq(1)
X src/atrm.c                 1	Main program and functions for atrm(1)
X src/atrun.c                2	Main program and functions for atrun(8)
X src/date.l                 1	Lexical analyzer for at(1)
X src/date.y                 2	Date parser for at(1)
X src/dumpenv.c              1	Function to put environment in at job
X src/patchlevel.h           1	The current version number for kat
X src/permit.c               1	Functions to check for allowed usage of at(1)
X src/qalloc.c               1	Allocate data structure for atrun(8)
X src/table.h                1	Tokens recognized by date.y
END_OF_FILE
if test 1618 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(4293 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#	Installation of kat (Keith's at package):
X#
X#	1) Modify the items between the 'Begin' and 'End' configuration
X#	section lines to suit your installation
X#
X#	2) Type 'make' to build the binaries
X#
X#	3) Login as root and type 'make install' to install the binaries
X#	and man pages, create the at queue directory (the parent of the
X#	directory must exist) and working directory, and set protections.
X#	(This must be done as root since at, atq, and atrm must run
X#	setuid root in order to act on the queued jobs in a protected
X#	queue directory.)
X#
X#	4) Add an entry for atrun in the root crontab (or your only crontab,
X#	depending on your system) to run at the desired interval (e.g.,
X#	every 15 minutes)
X
X#	--- Begin configuration section ---
X
X# If your cpp(1) does not define a unique system type from the known working
X# types in the following list, try uncommenting one of the generic types
X# below as a first choice.  If cpp(1) does define one but it is not listed,
X# modify at.h in the form used for the other systems and then comment out
X# the definitions below
X
X# Known system types defined by cpp(1): hpux i386 sequent sun ultrix
X
X# SYSTEM = -DGENERIC_BSD
X# SYSTEM = -DGENERIC_SYSV
X
X#	Define the compiler to be used and the compilation flags
X
XCC = cc
XCFLAGS = $(SYSTEM) -O
XLDFLAGS =
X# LDFLAGS = -lseq			# For Sequents to get getopt(3)
X
X#	Add the following to ATRUN_FLAGS for the indicated effect:
X#		-DMAXATPROC=n defines the maximum number of queued jobs
X#			that will run concurrently (default is n=16 if not specified,
X#           0 sets no limit)
X#		-DDEBUG compiles in code to permit debugging output from
X#			atrun when it is run with the debug command line switch
X#			(default is no extra debugging code compiled)
X#		-DNOSYSLOG causes error and debug messages to be written to
X#			a file instead of using syslog(3); requires -DDEBUG
X
XATRUN_FLAGS =
X
X#	Define the location of the at job files
X#		ATDIR is the primary at directory and holds the queued jobs
X#		PASTDIR is a working directory for jobs being run, usually a
X#			subdirectory of ATDIR
X
XATDIR = /usr/spool/at
XPASTDIR = $(ATDIR)/past
X
X#	Define the install directory for the at binaries and man pages
X
XBINDIR = /usr/local/bin
XMANEXT = l
XMANDIR = /usr/man/man$(MANEXT)
X
X#	--- End of configuration items ---
X
X#	The following should not need to be changed
X
XAT_BINARIES = at atcat atq atrm atrun
XAT_SHELLS = atmod
XAT_OBJS = at.o atname.o dumpenv.o date.o permit.o
XATCAT_OBJS = atcat.o permit.o
XATQ_OBJS = atq.o permit.o qalloc.o
XATRM_OBJS = atrm.o permit.o
XATRUN_OBJS = atrun.o qalloc.o
X
Xall:
X	@(cd src; make -f ../Makefile binaries)
X
Xbinaries: $(AT_BINARIES)
X	@echo "The binaries are ready for installation."
X	@echo "Type 'make install' as root to install in $(BINDIR)."
X
Xat: $(AT_OBJS)
X	$(CC) $(CFLAGS) -o at $(AT_OBJS) $(LDFLAGS) -ll
X
Xatcat: $(ATCAT_OBJS)
X	$(CC) $(CFLAGS) -o atcat $(ATCAT_OBJS) $(LDFLAGS)
X
Xatq: $(ATQ_OBJS)
X	$(CC) $(CFLAGS) -o atq $(ATQ_OBJS) $(LDFLAGS)
X
Xatrm: $(ATRM_OBJS)
X	$(CC) $(CFLAGS) -o atrm $(ATRM_OBJS) $(LDFLAGS)
X
Xatrun: $(ATRUN_OBJS)
X	$(CC) $(CFLAGS) -o atrun $(ATRUN_OBJS) $(LDFLAGS)
X
Xinstall: install.bin install.doc
X	@echo "Installation complete."
X	@echo "Remember to create the appropriate at.allow or at.deny file."
X
Xinstall.bin:
X	(cd src; cp $(AT_BINARIES) $(AT_SHELLS) $(BINDIR))
X	(cd $(BINDIR) ; chmod 4711 $(AT_BINARIES); \
X		chmod 751 atcat $(AT_SHELLS); chmod 700 atrun)
X	-if test ! -d $(ATDIR) ; then mkdir $(ATDIR) ; chmod 755 $(ATDIR) ; fi
X	-if test ! -d $(PASTDIR) ; then mkdir $(PASTDIR) ; \
X		chmod 755 $(PASTDIR) ; fi
X
Xinstall.man:
X	(cd doc ; \
X	cp at.1 $(MANDIR)/at.$(MANEXT) ; \
X	cp atcat.1 $(MANDIR)/atcat.$(MANEXT) ; \
X	cp atq.1 $(MANDIR)/atq.$(MANEXT) ; \
X	cp atrm.1 $(MANDIR)/atrm.$(MANEXT) ; \
X	cp atrun.8 $(MANDIR)/atrun.$(MANEXT))
X	chmod 644 $(MANDIR)/at.$(MANEXT) \
X		$(MANDIR)/atcat.$(MANEXT) \
X		$(MANDIR)/atq.$(MANEXT) \
X		$(MANDIR)/atrm.$(MANEXT) \
X		$(MANDIR)/atrun.$(MANEXT)
X
Xdate.c: date.y lex.yy.c table.h
X	@echo "expect 2 shift/reduce conflicts"
X	yacc date.y
X	mv y.tab.c date.c
X
Xlex.yy.c: date.l
X	lex date.l
X
Xat.o atcat.o atq.o atrm.o atname.o: $($@:.o=.c) at.h
X	$(CC) -c $(CFLAGS) -DATDIR=\"$(ATDIR)\" $<
X
Xatrun.o: $($@:.o=.c) at.h
X	$(CC) -c $(CFLAGS) $(ATRUN_FLAGS) -DATDIR=\"$(ATDIR)\" \
X		-DPASTDIR=\"$(PASTDIR)\" $<
X
Xpermit.o qalloc.o: $($@:.o=.c) at.h
END_OF_FILE
if test 4293 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'PORTING' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'PORTING'\"
else
echo shar: Extracting \"'PORTING'\" \(1868 characters\)
sed "s/^X//" >'PORTING' <<'END_OF_FILE'
XPorting
X-------
X
XThe initial porting effort identified five items which were version
Xspecific.  Each of the affect areas of the code is wrapped in cpp(1)
Xdirectives to allow selection of known alternatives through appropriate
X#define statements.  The file at.h uses preset cpp(1) definitions
X(e.g., sun on SunOS systems) to specify the correct set of #define
Xstatements.  The current code has been ported to and tested on the
Xfollowing hardware/software combinations:
X
XHP 9000/825, HP/UX A.B7.00
XSun 3, SunOS 4.1
XSequent Symmetry, DYNIX 3.0.17
XVAX 3602, Ultrix 3.1
X
XTo port the kat package to another environment:
X
X1) Try either the GENERIC_BSD or GENERIC_SYSV define in Makefile and
X   determine if a workable version results.  If so, examine the cpp(1)
X   man page and determine if a predefined value exists that uniquely
X   identifies the current environment.  Modify at.h such that this
X   definition is used to control compilation in the same manner as
X   for one of the existing ports.
X
X2) If neither of the generic types work, determine if another combination
X   of the known version specific items is needed.  The ones currently
X   identified are:
X
X   HAS_DIRENT - for systems which use a structure tagged dirent for
X        readdir, opendir, etc.  If not defined, use 'struct direct'.
X
X   HAS_GETCWD - for systems which provide getcwd(3); otherwise, use
X        getwd(3).
X
X   HAS_RINDEX - for systems which use rindex(3); otherwise, use
X        strrchr(3).
X
X   HAS_TERMIO - for systems which use the include file termio.h;
X        otherwise use sgtty.h.
X
X   HAS_TIOCNOTTY - for systems which provide the ioctl call to
X        disassociate from the controlling tty; otherwise, don't
X        bother.
X
X3) If this still isn't sufficient, get out the Veg-O-Matic and
X   start slicing and dicing.
X
X[Note for indent tidy: I use tabstops at 4 space intervals in vi.]
END_OF_FILE
if test 1868 -ne `wc -c <'PORTING'`; then
    echo shar: \"'PORTING'\" unpacked with wrong size!
fi
# end of 'PORTING'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2922 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThe kat (Keith's at) package
X
XCopyright (c) 1990, W. Keith Pyle, Austin, Texas
X
XDescription
X-----------
X
XThe programs which comprise this package are to replace/supplement the
Xfunctionality provided by the at(1) provided with many BSD Unix systems.
XThere are five components:
X
Xat - allows users to queue jobs for later execution at a specified date/time
X
Xatcat - display the commands in a job previously queued
X
Xatq - lists all or selected portions of the at queue
X
Xatrm - allows removal of queued jobs that have not yet run
X
Xatrun - controls execution of queued jobs, typically run periodically by cron
X
XSee the individual man pages for more information on individual commands.
XSee the file INSTALL for installation instructions.
XSee the file PORTING for porting comments.
X
XQualifications
X--------------
X
XThis program may be copied, transferred, or used in any manner subject
Xto the following conditions:
X
X1) The original README and MANIFEST files must be retained
X   in any subsequent source distributions, whether unaltered or not.
X
X2) Neither the author nor his employer make any express or implied
X   warranties as to the fitness of this program for any particular
X   purpose.  The user assumes full responsible for the use of this
X   program and any consequences of its use whether due to defect,
X   misuse, abuse, etc.
X        
X3) The origin of this program must not be misrepresented, either
X   by explicit claim or omission.
X        
X4) Altered versions of this program must be clearly identified as
X   such and may not be represented as the original.
X        
X5) This program may not be sold in any form without the express
X   written consent of the author.
X
XShould any of the above be held unenforceable, the remainder shall
Xremain in force.
X
XAcknowledgements
X----------------
X
XThe date parsing for at(1) is performed by a date parser based on the
Xone used in B news, version 2.11.19.  The parser is a complete
Xre-write, however, to extend the functionality to that needed for at(1)
Xand to correct some minor problems.  I thank Steven M. Bellovin
X(unc!smb), the original author of the B news date parser, whose code
Xgave me a number of ideas for my parser.
X
XRecommendations
X---------------
X
XIf you are running the regular BSD cron(8), which has only one crontab,
Xget Paul Vixie's cron.  This allows each user to have a crontab and
Xprovides commands for listing and replacing a crontab.  The package is
Xavailable in most comp.sources.unix archives.
X
XContacting the Author
X---------------------
X 
XReports of bugs, requests for enhancements, comments, compliments, and
Xflames may be sent to the author at the following address.  BTW, I call
Xit the kat package (1) because I want to :-), and (2) in memory of Kat
X(1973 to 1986), a great programmer's assistant and lap warmer.
X
XKeith Pyle                                UUCP: ...!uunet!execu!keith
XExecucom Systems Corp., Austin, Texas     Internet: keith at execu.com
END_OF_FILE
if test 2922 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test ! -d 'doc' ; then
    echo shar: Creating directory \"'doc'\"
    mkdir 'doc'
fi
if test -f 'doc/atcat.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/atcat.1'\"
else
echo shar: Extracting \"'doc/atcat.1'\" \(2527 characters\)
sed "s/^X//" >'doc/atcat.1' <<'END_OF_FILE'
X.TH "ATCAT" 1L "7 November 1990" "Execucom" "LOCAL USER COMMANDS"
X.SH NAME
Xatcat \- display commands in a job queued via at
X.SH SYNOPSIS
X.LP
X.B atcat
X[
X.B \-e
X] [
X.I user
X] ... [
X.I job_number
X] ...
X.SH DESCRIPTION
X.B atcat
Xdisplays the commands in a job queued with the
X.BR at (1).
XIf multiple jobs are identified through the command line arguments, the
Xcommands from all of the selected jobs will be displayed on standard output
Xin the manner of
X.BR cat (1).
XThat is, there will be no job identification information added by
X.B atcat
Xto the output.
X.LP
X.B atcat
Xcan be used to review the contents of a previously submitted
X.BR at (1)
Xjob, or to place the commands in a file by redirecting standard output.
XThese functions are most useful to verify a job or to recover the commands
Xfor correction and resubmission.  In the default mode,
X.B atcat
Xwill display only the commands actually entered by the user.
X.LP
X.B atcat
Xdoes not run with any special permissions and relies on Unix protections to
Xdetermine what jobs a user can list.  Since
X.BR at (1)
Xcreates a job using the user's umask, the same users with access to a submitting
Xuser's files will have access to the at job.  For instance, if a user's umask
Xpermits those in the primary group to read files, the group will be able
Xto list the user's
X.BR at (1)
Xjobs as well.
X.SH OPTIONS
X.TP
X.B \-e
XDisplay the environment created for the
X.BR at (1)
Xjob as well as the user commands.
X.SH EXAMPLES
X(1) To display job 314, the command is
X.sp
X.RS
X.B "atcat 314"
X.RE
X.LP
X(2) To make a copy of the commands in job 318, modify them, and resubmit the
Xjob for 3:00 PM, the command sequence could be
X.sp
X.RS
X.ft B
Xatcat 314 >foofile
Xvi foofile
Xat 3:00 pm foofile
X.ft R
X.RE
X.sp
X(The
X.BR vi (1)
Xcommands are not shown.)
X.LP
X(3) Since
X.BR at (1)
Xand
X.B atcat
Xuse standard input and standard output, respectively,
Xthe correction of a job could be done using pipes.  To change the string
X.I flie
Xto
X.I file,
Xand replace the
X.BR at (1)
Xjob, the following commands could be used:
X.sp
X.RS
X.ft B
Xatcat 314 | sed -e 's/flie/file/' | at 15:00
Xatrm 314
X.ft R
X.RE
X.SH AUTHOR
XKeith Pyle
X.SH FILES
X.ta 2.5i
X\fB/usr/spool/at\fR	spool directory
X.br
X\fB/usr/spool/at/at.allow\fR	allowed users
X.br
X\fB/usr/spool/at/at.deny\fR	prohibited users
X.SH "SEE ALSO"
X.BR at (1L),
X.BR atq (1L),
X.BR atrm (1L),
X.BR atrun (8)
X.SH DIAGNOSTICS
XThe exit status is 0 for normal execution.  For job access failures
Xand other execution problems, the exit status is set to 1.
XAn exit status of 2 is set for syntax errors.
END_OF_FILE
if test 2527 -ne `wc -c <'doc/atcat.1'`; then
    echo shar: \"'doc/atcat.1'\" unpacked with wrong size!
fi
# end of 'doc/atcat.1'
fi
if test -f 'doc/atq.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/atq.1'\"
else
echo shar: Extracting \"'doc/atq.1'\" \(1755 characters\)
sed "s/^X//" >'doc/atq.1' <<'END_OF_FILE'
X.TH "ATQ" 1L "7 November 1990" "Execucom" "LOCAL USER COMMANDS"
X.SH NAME
Xatq \- summarize the contents of the at job queue
X.SH SYNOPSIS
X.LP
X.B atq
X[
X.B \-c
X] [
X.B \-n
X] [
X.I user
X] ...
X.SH DESCRIPTION
X.B atq
Xdisplays a summary of the jobs queued for execution via the
X.BR at (1)
Xcommand.  One line will be printed to standard output for each
Xjob in the queue and will show the job's position in the queue, the time
Xat which execution has been requested, the user who submitted the job,
Xa unique job number assigned by
X.BR at (1),
Xand the source of the commands.  This source will be either stdin for
Xstandard input or the name of the
X.I script
Xspecified on the
X.BR at (1)
Xcommand line.
X.LP
XWith no command line options,
X.B atq
Xwill list all jobs in the queue, sorted in order of execution time.
XIf one or more user names are specified, only those queue entries submitted
Xby the indicated user(s) will be listed.
X.SH OPTIONS
X.TP
X.B \-c
XThe queue entries displayed are presented in order of creation time (earliest
Xfirst) instead of in execution order.
X.TP
X.B \-n
XShow only the count of jobs in the queue.
X.SH EXAMPLES
X(1) To list all jobs submitted by the users bill and ted, the command could
Xbe
X.sp
X.RS
X.B "atq bill ted"
X.RE
X.LP
X(2) To obtain a count of the jobs for bill and ted, use
X.sp
X.RS
X.B "atq -n bill ted"
X.RE
X.SH AUTHOR
XKeith Pyle
X.SH FILES
X.ta 2.5i
X\fB/usr/spool/at\fR	spool directory
X.br
X\fB/usr/spool/at/at.allow\fR	allowed users
X.br
X\fB/usr/spool/at/at.deny\fR	prohibited users
X.SH "SEE ALSO"
X.BR at (1L),
X.BR atcat (1L),
X.BR atrm (1L),
X.BR atrun (8)
X.SH DIAGNOSTICS
XThe exit status is 0 for normal execution.  For file access failures
Xand other execution problems, the exit status is set to 1.
XAn exit status of 2 is set for syntax errors.
END_OF_FILE
if test 1755 -ne `wc -c <'doc/atq.1'`; then
    echo shar: \"'doc/atq.1'\" unpacked with wrong size!
fi
# end of 'doc/atq.1'
fi
if test -f 'doc/atrm.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/atrm.1'\"
else
echo shar: Extracting \"'doc/atrm.1'\" \(2023 characters\)
sed "s/^X//" >'doc/atrm.1' <<'END_OF_FILE'
X.TH "ATRM" 1L "7 November 1990" "Execucom" "LOCAL USER COMMANDS"
X.SH NAME
Xatrm \- remove jobs from the at job queue
X.SH SYNOPSIS
X.LP
X.B atrm
X[
X.B \-fi
X] [
X.B \-
X] [
X.I user
X] ... [
X.I job_number
X] ...
X.SH DESCRIPTION
X.B atrm
Xremoves jobs from the at job queue.  These jobs are created with the
X.BR at (1)
Xcommand and the queue can be displayed with
X.BR atq (1).
X.LP
XThe jobs to be removed are selected by the command line arguments.  If a
X.I user
Xname is specified, all jobs owned by the user will be removed providing
Xthat you own those jobs.  If a 
X.I job_number
Xis given, then only that job will be removed.
XThe special option
X.B \-
Xcan be used to remove all jobs owned by the current user.
XThere can be more than
Xone job identifier on the command line, if desired.
X.LP
XThe super-user can remove queued jobs belonging to any user.  If the
X.B \-
Xoption is used, all jobs in the queue are removed.
X.SH OPTIONS
X.TP
X.B \-f
XThe specified jobs are removed silently.  No error messages are displayed
Xconcerning incorrect job specifications or permission denials.
X.TP
X.B \-i
XJob removal is interactive.
X.SH EXAMPLES
X(1) To remove all jobs submitted by the user bill, the command could
Xbe
X.sp
X.RS
X.B "atrm bill"
X.RE
X.LP
X(2) To remove jobs 314 and 318, the command could be
X.sp
X.RS
X.B "atrm 314 318"
X.RE
X.LP
X(3) To selectively remove some or all of your jobs from the queue, the
Xfollowing command would be appropriate
X.sp
X.RS
X.B "atrm -i -"
X.RE
X.sp
XThis will generate a prompt for each job in the queue owned by the current
Xuser.  The desired jobs can be removed by entering a
X.B y
Xin response.
X.SH AUTHOR
XKeith Pyle
X.SH FILES
X.ta 2.5i
X\fB/usr/spool/at\fR	spool directory
X.br
X\fB/usr/spool/at/at.allow\fR	allowed users
X.br
X\fB/usr/spool/at/at.deny\fR	prohibited users
X.SH "SEE ALSO"
X.BR at (1L),
X.BR atcat (1L),
X.BR atq (1L),
X.BR atrun (8)
X.SH DIAGNOSTICS
XThe exit status is 0 for normal execution.  For job removal failures
Xand other execution problems, the exit status is set to 1.
XAn exit status of 2 is set for syntax errors.
END_OF_FILE
if test 2023 -ne `wc -c <'doc/atrm.1'`; then
    echo shar: \"'doc/atrm.1'\" unpacked with wrong size!
fi
# end of 'doc/atrm.1'
fi
if test -f 'doc/atrun.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/atrun.8'\"
else
echo shar: Extracting \"'doc/atrun.8'\" \(3375 characters\)
sed "s/^X//" >'doc/atrun.8' <<'END_OF_FILE'
X.TH "ATRUN" 8L "7 November 1990" "Execucom" "LOCAL USER COMMANDS"
X.SH NAME
Xatrun \- execute the commands queued by at
X.SH SYNOPSIS
X.LP
X.B atrun
X[
X.B \-x
X]
X.SH DESCRIPTION
X.B atrun
Xsupervises the execution of jobs previously submitted via
X.BR at (1)
Xand forwards any output generated by these jobs to the submitting user.
X.B atrun
Xis typically run periodically by cron (e.g., every 15 minutes).
XIt may only be run by root. Following is a typical cron entry for
X.B atrun
X.sp
X.RS
X0,15,30,45 * * * * /usr/local/bin/atrun
X.RE
X.LP
X.B atrun
Xforks immediately after being executed and the parent exits.  The child
Xthen disassociates itself from the parent process group and begins scanning
Xthe
X.B at
Xspool directory to determine which jobs should be run.  All jobs which have
Xbeen submitted
Xfor execution on or before the current time are selected.  These jobs are
Xmoved to the working directory and the master
X.B atrun
Xforks once for each of these jobs, in order of the specified execution time.
XThus, each submitted job is controlled by
Xa slave
X.B atrun.
XSince this could lead to a large number of concurrent processes, it is possible
Xto limit the number of slave processes through a compile time configuration
Xoption.
X.LP
XEach slave will create a shell to process the actual user commands.  Once the
Xshell process completes, the slave
X.B atrun
Xwill send mail to the submitting user if any one of the following conditions
Xare met: (1) output was generated by the user's commands and was not redirected,
X(2) the shell processing the commands exited with an error status, or (3) the
Xuser requested mail confirming completion of the job.
X.LP
XIf
X.B atrun
Xdetects an error from which it can recover after the jobs have been selected
Xand moved to the working directory, it will attempt to return the affected
Xjob files to the normal spool directory.  Thus, the recovered job will be
Xavailable for selection on the next execution of
X.B atrun.
X.LP
X.B atrun
Xexecution can be temporarily disabled by creating a lock file
X.B atrun.lock
Xin the spool directory.  If this file exists,
X.B atrun
Xsimply places a message in the log file and exits.
X.LP
XError messages are processed through
X.BR syslogd (8).
X.SH OPTIONS
X.TP
X.B \-x
XRun in debug mode.  This generates verbose output to the logger and requires
Xthat the program be compiled with the DEBUG option.
X.SH AUTHOR
XKeith Pyle
X.SH FILES
X.ta 2.5i
X\fB/usr/spool/at\fR	spool directory
X.br
X\fB/usr/spool/at/atrun.lock\fR	file to prevent atrun execution
X.br
X\fB/usr/spool/at/lasttimedone\fR	time of last
X.B atrun
Xexecution
X.br
X\fB/usr/spool/at/past\fR	working directory
X.SH "SEE ALSO"
X.BR at (1L),
X.BR atcat (1L),
X.BR atq (1L),
X.BR atrm (1L)
X.SH DIAGNOSTICS
XThe exit status is 0 for mormal execution.  For the various execution failures,
Xwhich generate log entries, the exit status is set to 1.
X.SH BUGS
X.LP
XIf a job does not complete due to a system failure, it will not be requeued.
XHowever, it would be possible to affect this function by modification of the
Xappropriate boot file (e.g., rc.local on a BSD system).  Assuming that the
X.B at
Xqueue directory is /usr/spool/at and the working directory is
X/usr/spool/at/past, the following shell
Xcommand could be used:
X.sp
X.RS
X.ft B
Xfind /usr/spool/at/past -name '[1-9]*'
X.if n \{ \\
X.br
X.ti +0.5i
X\}
X-exec mv {} /usr/spool/at \\;
X.ft R
X.RE
X.LP
XThe next execution of
X.B atrun
Xwill restart these jobs.
END_OF_FILE
if test 3375 -ne `wc -c <'doc/atrun.8'`; then
    echo shar: \"'doc/atrun.8'\" unpacked with wrong size!
fi
# end of 'doc/atrun.8'
fi
if test ! -d 'src' ; then
    echo shar: Creating directory \"'src'\"
    mkdir 'src'
fi
if test -f 'src/at.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/at.h'\"
else
echo shar: Extracting \"'src/at.h'\" \(3358 characters\)
sed "s/^X//" >'src/at.h' <<'END_OF_FILE'
X/* at.h --- definitions and the like for kat: Keith's at package */
X
X/*
X
XCopyright (c) 1990, W. Keith Pyle, Austin, Texas
X
X*/
X
X/* --- This section contains definitions which may need to be modified --- */
X/* --- to conform to a given site --- */
X
X/* Define the mailer that is used to send output to a user */
X/* (Only one of the following should be uncommented) */
X
X#define USE_SENDMAIL				/* /usr/lib/sendmail is used */
X/*#define USE_BINMAIL					/* /bin/mail is used */
X/*#define USE_UCBMAIL					/* /usr/ucb/Mail is used */
X
X/* Define the maximum number of concurrent queued processes that can be run */
X/* by atrun.  This definition is usually set in the Makefile, but define */
X/* can be placed here.  If the value is set to 0, there is no limit. */
X
X#ifndef MAXATPROC
X#define MAXATPROC	16
X#endif
X
X/* --- The next section is typically only modified for a new port --- */
X
X/* Define the characteristics of the system being used */
X
X/* The system type is often available directly from cpp(1).  If not, */
X/* define either GENERIC_BSD or GENERIC_SYSV as a first attempt. */
X/* Then, modify the section below to work automagically, if possible. */
X
X#if !defined(GENERIC_BSD) && !defined(GENERIC_SYSV)
X
X#ifdef hpux
X#define GENERIC_SYSV
X#endif
X
X#ifdef sequent
X/* This assumes a BSD universe Sequent */
X#define GENERIC_BSD
X#define HAS_SYSLOGFACILTY
X#else
X/* All other 386 systems assumed to be System V */
X#ifdef i386
X#define GENERIC_SYSV
X#endif
X#endif
X
X#ifdef sun
X/* Dual personalities */
X#define GENERIC_BSD
X#define GENERIC_SYSV
X#endif
X
X#ifdef ultrix
X#define GENERIC_BSD
X#endif
X
X#endif	/* Neither GENERIC_BSD or GENERIC_SYSV already defined */
X
X#ifdef GENERIC_BSD
X#define HAS_RINDEX
X#define HAS_TIOCNOTTY
X#endif
X
X#ifdef GENERIC_SYSV
X#define HAS_DIRENT
X#define HAS_GETCWD
X#define HAS_SYSLOGFACILTY
X#define HAS_TERMIO
X#endif
X
X/* Files used by at */
X
X#define SEQUENCE	".seq"			/* Contains job sequence number */
X#define ALLOW_FILE	"at.allow"		/* Specifies users allowed to use at */
X#define DENY_FILE	"at.deny"		/* Specifies users not allowed to use at */
X
X/* Shells which can be specified through at options */
X
X#define BOURNE_SHELL	"/bin/sh"
X#define C_SHELL			"/bin/csh"
X#define KORN_SHELL		"/bin/ksh"
X
X/* --- Items below this line should rarely be changed --- */
X
X#include "patchlevel.h"
X
X/* Define logical values */
X
X#define FALSE			0
X#define TRUE			1
X
X/* Maximum length of an input line */
X
X#define MAXLINE		1024
X
X/* Maximum sequence number which at will assign */
X
X#define MAX_JOBNO	65535
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <ctype.h>
X#ifdef HAS_DIRENT
X#include <dirent.h> 
X#else
X#include <sys/dir.h>
X#ifndef dirent
X#define dirent direct
X#endif
X#endif
X#include <errno.h> 
X#include <fcntl.h>
X#include <pwd.h>
X#include <signal.h>
X#include <sys/file.h>
X#include <sys/param.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <sys/timeb.h>
X
X#ifndef HAS_RINDEX
X#define rindex strrchr
X#endif
X
X#ifdef HAS_GETCWD
Xchar *getcwd();
X#else
Xchar *getwd();
X#endif
X
Xchar *strcpy();
Xchar *strncpy();
Xchar *strcat();
X
Xvoid exit();
X
X/* Handle those things that none of the include files on this system */
X/* covered */
X
X#ifndef F_OK
X#define F_OK 0
X#endif
X
X#ifndef MAXPATHLEN
X#define MAXPATHLEN 1024
X#endif
X
X/* Define the structure used to hold queue information */
X
Xstruct queue {
X	time_t qu_start;
X	time_t qu_ctime;
X	int qu_jobno;
X	char qu_name[24];
X	};
END_OF_FILE
if test 3358 -ne `wc -c <'src/at.h'`; then
    echo shar: \"'src/at.h'\" unpacked with wrong size!
fi
# end of 'src/at.h'
fi
if test -f 'src/atcat.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/atcat.c'\"
else
echo shar: Extracting \"'src/atcat.c'\" \(4473 characters\)
sed "s/^X//" >'src/atcat.c' <<'END_OF_FILE'
X/* atcat --- a member of the kat family (Keith's at package) */
X
X/* atcat(1) displays the commands in a job queued by at(1).  Options are */
X/* provided to display only the user entered commands or the entire job. */
X
X/* Copyright (c) 1990, W. Keith Pyle, Austin, Texas */
X
X#include "at.h"
X
Xchar *verstring = PATCHLEVEL;
X
Xextern char *sys_errlist[];
Xextern char *optarg;
X
Xextern int opterr;
Xextern int optind;
X
X/* -------------------------------------------------------------------------- */
X
Xmain(argc, argv)
X
Xint argc;
Xchar *argv[];
X
X{
X	char at_allow[MAXPATHLEN];
X	char at_deny[MAXPATHLEN];
X	char owner[16];
X
X	int flag;
X	int i;
X	int show_no;
X	int rc;
X	int show_all;
X
X	DIR *dp;
X
X	show_all = FALSE;
X
X	/* Get the user name */
X
X	whoami(owner);
X
X	/* Change to the at spool directory */
X
X	if (chdir(ATDIR) < 0) {
X
X		perror("can't change directory to the at directory");
X		exit(1);
X	}
X
X	/* Check for allowed at usage */
X	 
X	if (!permit(owner, ALLOW_FILE, DENY_FILE)) {
X 
X		fprintf(stderr, "you are not authorized to use at.  Sorry.\n");
X		exit(1);
X	}
X
X	/* Check for at least one argument */
X
X	if (argc == 1) {
X
X		fprintf(stderr, "usage: atcat [-e] job-number\n");
X		exit(2);
X	}
X
X	/* Process any option flags found */
X
X	while ((flag = getopt(argc, argv, "e")) != EOF) {
X
X		switch (flag) {
X
X			case 'e':
X
X				show_all = TRUE;
X				break;
X			
X			default:
X
X				fprintf(stderr, "usage: atcat [-e] job-number\n");
X				exit(2);
X		}
X	}
X
X	/* Open the spool directory */
X 
X	if ((dp = opendir(".")) == NULL) {
X
X		perror("can't read the at directory");
X		exit(1);
X	}
X
X	/* Loop through all remaining arguments */
X
X	rc = 0;
X
X	for ( ; optind < argc ; optind++) {
X
X		int jobno;
X
X		/* Make sure we start at the beginning of the directory for each */
X
X		rewinddir(dp);
X
X		/* Try converting the argument to a number */
X
X		show_no = atoi(argv[optind]);
X
X		/* If the conversion didn't succeed (0 can't be a job no.), */
X		/* then assume we have a user name and delete all entries for user */
X
X		if (show_no == 0)
X			rc |= find_all(argv[optind], show_all, dp);
X		
X		/* else, just delete the specified job number */
X
X		else
X			rc |= find_one(show_no, show_all, dp);
X	}
X
X	/* Close the spool directory and say bye */
X
X	closedir(dp);
X	exit(rc);
X}
X
X/* -------------------------------------------------------------------------- */
X
X/* display -- display all or part of a job file */
X
Xdisplay(name, jobno, show_all)
X
Xchar *name;
Xint jobno;
Xint show_all;
X
X{
X	char line[MAXLINE];
X
X	int rc;
X	int uid;
X
X	FILE *fp;
X
X	if ((fp = fopen(name, "r")) == NULL) {
X
X		sprintf(line, "can't open jobfile %d", jobno);
X		perror(line);
X		return(1);
X	}
X
X	if (!show_all) {
X
X		while (fgets(line, sizeof(line), fp)) {
X
X			if (strncmp(line, "umask ", 6) == 0)
X				break;
X		}
X	}
X
X	while (fgets(line, sizeof(line), fp))
X		fputs(line, stdout);
X	
X	return(0);
X}
X
X/* -------------------------------------------------------------------------- */
X
Xfind_one(show_no, show_all, dp)
X
Xint show_no;
Xint show_all;
XDIR *dp;
X
X{
X	int jobno;
X	int tod;
X
X	struct dirent *entry;
X
X	/* Scan the directory for one entry which matches the jobno */
X
X	while ((entry = readdir(dp)) != NULL) {
X
X		if (sscanf(entry->d_name, "%d.%d", &tod, &jobno) != 2)
X			continue;
X
X		if (jobno == show_no)
X			return(display(entry->d_name, jobno, show_all));
X	}
X
X	fprintf(stderr, "atcat: %d: no such job number\n", show_no);
X
X	return(1);
X}
X
X/* -------------------------------------------------------------------------- */
X
Xfind_all(name, show_all, dp)
X
Xchar *name;
Xint show_all;
XDIR *dp;
X
X{
X	int jobno;
X	int rc;
X	int tod;
X	int uid;
X
X	struct dirent *entry;
X	struct stat statbuf;
X
X	rc = 0;
X
X	/* If the owner name is "-", then delete all jobs for this user. */
X	/* If the user is root, delete all jobs. */
X
X	if (strcmp(name, "-") == 0) {
X
X		uid = geteuid();
X
X		if (uid == 0)
X			uid = -1;		/* A flag meaning all jobs match */
X	}
X
X	else {
X
X		struct passwd *pw;
X
X		/* Get the uid of the named owner */
X
X		if ((pw = getpwnam(name)) == NULL) {
X
X			fprintf(stderr, "atrm: can't locate %s in /etc/passwd: %s\n",
X				name, sys_errlist[errno]);
X			return(1);
X		}
X
X		uid = pw->pw_uid;
X	}
X
X	/* Scan the directory for all job files with this owner */
X
X	while ((entry = readdir(dp)) != NULL) {
X
X		if (sscanf(entry->d_name, "%d.%d", &tod, &jobno) != 2)
X			continue;
X
X		if (uid >= 0) {
X
X			if (stat(entry->d_name, &statbuf) < 0) {
X
X				perror(entry->d_name);
X				continue;
X			}
X
X			if (statbuf.st_uid != uid)
X				continue;
X		}
X
X		rc |= display(entry->d_name, jobno, show_all);
X	}
X
X	return(rc);
X}
END_OF_FILE
if test 4473 -ne `wc -c <'src/atcat.c'`; then
    echo shar: \"'src/atcat.c'\" unpacked with wrong size!
fi
# end of 'src/atcat.c'
fi
if test -f 'src/atname.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/atname.c'\"
else
echo shar: Extracting \"'src/atname.c'\" \(1004 characters\)
sed "s/^X//" >'src/atname.c' <<'END_OF_FILE'
X/* atname --- build a file name from the specified time */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <sys/param.h>
X#include <sys/time.h>
X
X#include "at.h"
X
Xstatic char buf[64];
X
Xchar *
Xatname(filetime, seqno)
X
Xtime_t filetime;
Xint seqno;
X
X{
X	sprintf(buf, "%d.%d", filetime, seqno);
X	return(buf);
X}
X
X/* -------------------------------------------------------------------------- */
X
Xatseq()
X
X{
X	char seqfile[MAXPATHLEN];
X
X	int seqno;
X	int sq_handle;
X
X	sprintf(seqfile, "%s/%s", ATDIR, SEQUENCE);
X
X	if ((sq_handle = open(seqfile, O_RDWR | O_CREAT, 0640)) < 0 ||
X			lockf(sq_handle, F_LOCK, 0L) < 0) {
X
X		perror(seqfile);
X		exit(1);
X	}
X
X	if (read(sq_handle, buf, sizeof(buf)) > 0) {
X
X		seqno = atoi(buf) + 1;
X
X		if (seqno > MAX_JOBNO)
X			seqno = 1;
X
X		if (lseek(sq_handle, (off_t)0, 0) < 0) {
X
X			perror(seqfile);
X			exit(1);
X		}
X	}
X
X	else
X		seqno = 1;
X	
X	sprintf(buf, "%d\n", seqno);
X	write(sq_handle, buf, strlen(buf));
X	close(sq_handle);
X
X	return(seqno);
X}
END_OF_FILE
if test 1004 -ne `wc -c <'src/atname.c'`; then
    echo shar: \"'src/atname.c'\" unpacked with wrong size!
fi
# end of 'src/atname.c'
fi
if test -f 'src/atrm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/atrm.c'\"
else
echo shar: Extracting \"'src/atrm.c'\" \(5832 characters\)
sed "s/^X//" >'src/atrm.c' <<'END_OF_FILE'
X/* atrm --- a member of the kat family (Keith's at package) */
X
X/* atrm(1) removes jobs queued by at(1) from the queue.  Options are */
X/* provided to remove specific jobs or all of those by specified users. */
X
X/* Copyright (c) 1990, W. Keith Pyle, Austin, Texas */
X
X#include "at.h"
X
Xchar *verstring = PATCHLEVEL;
X
Xextern char *sys_errlist[];
Xextern char *optarg;
X
Xextern int opterr;
Xextern int optind;
X
X/* -------------------------------------------------------------------------- */
X
Xmain(argc, argv)
X
Xint argc;
Xchar *argv[];
X
X{
X	char at_allow[MAXPATHLEN];
X	char at_deny[MAXPATHLEN];
X	char owner[16];
X
X	int flag;
X	int force;
X	int i;
X	int interact;
X	int killno;
X	int rc;
X
X	DIR *dp;
X
X	/* Some initialization */
X
X	force = FALSE;
X	interact = FALSE;
X
X	/* Get the user name */
X
X	whoami(owner);
X
X	/* Change to the at spool directory */
X
X	if (chdir(ATDIR) < 0) {
X
X		perror("can't change directory to the at directory");
X		exit(1);
X	}
X
X	/* Check for allowed at usage */
X	 
X	if (!permit(owner, ALLOW_FILE, DENY_FILE)) {
X 
X		fprintf(stderr, "you are not authorized to use at.  Sorry.\n");
X		exit(1);
X	}
X
X	/* Check for at least one argument */
X
X	if (argc == 1) {
X
X		fprintf(stderr, "usage: atrm [job-number] ... [username] ...\n");
X		exit(2);
X	}
X
X	/* Process any option flags found */
X
X	while ((flag = getopt(argc, argv, "fi")) != EOF) {
X
X		switch (flag) {
X
X			case 'f':
X
X				force = TRUE;
X				break;
X			
X			case 'i':
X
X				interact = TRUE;
X				break;
X			
X			default:
X
X				fprintf(stderr,
X					"usage: atrm [job-number] ... [username] ...\n");
X				exit(2);
X		}
X	}
X
X	/* If interaction was specified, turn off force and make sure stdin is */
X	/* from a terminal device */
X
X	if (interact) {
X
X		force = FALSE;
X
X		if (isatty(0) == 0)
X			interact = FALSE;
X	}
X
X	/* Open the spool directory */
X 
X	if ((dp = opendir(".")) == NULL) {
X
X		perror("can't read the at directory");
X		exit(1);
X	}
X
X	/* Loop through all remaining arguments */
X
X	rc = 0;
X
X	for ( ; optind < argc ; optind++) {
X
X		int jobno;
X
X		/* Make sure we start at the beginning of the directory for each */
X
X		rewinddir(dp);
X
X		/* Try converting the argument to a number */
X
X		killno = atoi(argv[optind]);
X
X		/* If the conversion didn't succeed (0 can't be a job no.), */
X		/* then assume we have a user name and delete all entries for user */
X
X		if (killno == 0)
X			rc |= find_all(argv[optind], force, interact, dp);
X		
X		/* else, just delete the specified job number */
X
X		else
X			rc |= find_one(killno, force, interact, dp);
X	}
X
X	/* Close the spool directory and say bye */
X
X	closedir(dp);
X	exit(rc);
X}
X
X/* -------------------------------------------------------------------------- */
X
X/* delete --- handle all of the actual deletion work after an entry has been */
X/* identified */
X
Xdelete(name, jobno, force, interact)
X
Xchar *name;
Xint jobno;
Xint force;
Xint interact;
X
X{
X	int rc;
X	int uid;
X
X	struct stat statbuf;
X
X	/* Get some info on the job file */
X
X	if (stat(name, &statbuf) < 0) {
X
X		fprintf(stderr, "atrm: couldn't stat job file %s: %s\n",
X			name, sys_errlist[errno]);
X		return(1);
X	}
X
X	if (!force)
X		printf("%6d: ", jobno);
X	
X	/* If this isn't being done by root, make sure the user owns the job */
X
X	uid = geteuid();
X
X	if (uid != 0) {
X	
X		if (statbuf.st_uid != uid) {
X
X			if (!force)
X				printf("permission denied\n", jobno);
X			return(1);
X		}
X	}
X
X	/* Ick, we have to talk to a user */
X
X	if (interact) {
X
X		char response[80];
X
X		/* Is root blasting someone else's job? */
X
X		if (uid == 0 && statbuf.st_uid != uid) {
X
X			struct passwd *pw;
X
X			if ((pw = getpwuid(statbuf.st_uid)) == NULL)
X				fprintf(stderr,
X					"atrm: can't locate uid %d in /etc/passwd: %s\n",
X					uid, sys_errlist[errno]);
X			else
X				printf("(owned by %s) ", pw->pw_name);
X		}
X
X		printf("remove it? ");
X
X		if (fgets(response, sizeof(response), stdin) == NULL)
X			exit(1);
X		
X		if (response[0] != 'y' && response[0] != 'Y')
X			return(0);
X	}
X
X	/* Try to remove the job file */
X
X	rc = unlink(name);
X
X	/* Report on the results, if appropriate */
X
X	if (!force && !interact) {
X
X		if (rc == 0)
X			printf("removed\n", jobno);
X		else
X			printf("could not remove\n");
X	}
X
X	return(rc != 0);
X}
X
X/* -------------------------------------------------------------------------- */
X
Xfind_one(killno, force, interact, dp)
X
Xint killno;
Xint force;
Xint interact;
XDIR *dp;
X
X{
X	int jobno;
X	int tod;
X
X	struct dirent *entry;
X
X	/* Scan the directory for one entry which matches the jobno */
X
X	while ((entry = readdir(dp)) != NULL) {
X
X		if (sscanf(entry->d_name, "%d.%d", &tod, &jobno) != 2)
X			continue;
X
X		if (jobno == killno)
X			return(delete(entry->d_name, jobno, force, interact));
X	}
X
X	if (!force)
X		printf("atrm: %d: no such job number\n", killno);
X	
X	return(1);
X}
X
X/* -------------------------------------------------------------------------- */
X
Xfind_all(name, force, interact, dp)
X
Xchar *name;
Xint force;
Xint interact;
XDIR *dp;
X
X{
X	int jobno;
X	int rc;
X	int tod;
X	int uid;
X
X	struct dirent *entry;
X	struct stat statbuf;
X
X	rc = 0;
X
X	/* If the owner name is "-", then delete all jobs for this user. */
X	/* If the user is root, delete all jobs. */
X
X	if (strcmp(name, "-") == 0) {
X
X		uid = geteuid();
X
X		if (uid == 0)
X			uid = -1;		/* A flag meaning all jobs match */
X	}
X
X	else {
X
X		struct passwd *pw;
X
X		/* Get the uid of the named owner */
X
X		if ((pw = getpwnam(name)) == NULL) {
X
X			fprintf(stderr, "atrm: can't locate %s in /etc/passwd: %s\n",
X				name, sys_errlist[errno]);
X			return(1);
X		}
X
X		uid = pw->pw_uid;
X	}
X
X	/* Scan the directory for all job files with this owner */
X
X	while ((entry = readdir(dp)) != NULL) {
X
X		if (sscanf(entry->d_name, "%d.%d", &tod, &jobno) != 2)
X			continue;
X
X		if (uid >= 0) {
X
X			if (stat(entry->d_name, &statbuf) < 0) {
X
X				perror(entry->d_name);
X				continue;
X			}
X
X			if (statbuf.st_uid != uid)
X				continue;
X		}
X
X		rc |= delete(entry->d_name, jobno, force, interact);
X	}
X
X	return(rc);
X}
END_OF_FILE
if test 5832 -ne `wc -c <'src/atrm.c'`; then
    echo shar: \"'src/atrm.c'\" unpacked with wrong size!
fi
# end of 'src/atrm.c'
fi
if test -f 'src/date.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/date.l'\"
else
echo shar: Extracting \"'src/date.l'\" \(884 characters\)
sed "s/^X//" >'src/date.l' <<'END_OF_FILE'
X/* date.l --- lex routine for the date parser */
X
XNUMBER		[0-9]+
XSTRING		[a-z][a-z.]*
XWHITE		[ \t]+
X
X%{
X
X/* Make sure we use our own input, output, unput */
X
X#undef input
X#undef output
X#undef unput
X
X%}
X
X/* -------------------------------------------------------------------------- */
X
X%%
X
X{NUMBER}	{
X
X	yylval = atoi(yytext);
X	return(NUMBER);
X	}
X
X{STRING}	{
X
X	return(lookup_string(yytext));
X	}
X
X{WHITE}		;
X
X.			{
X
X	return(yytext[0]);
X	}
X
X%%
X
X/* -------------------------------------------------------------------------- */
X
Xinput()
X
X{
X	if (*lptr != '\0')
X		return(*lptr++);
X	
X	else
X		return(0);
X}
X
X/* -------------------------------------------------------------------------- */
X
Xoutput()
X
X{
X}
X
X/* -------------------------------------------------------------------------- */
X
Xunput(ch)
X
Xint ch;
X
X{
X	if (lptr > lstring  && ch != 0 && *--lptr == ch)
X		return(ch);
X
X	else
X		return(0);
X}
END_OF_FILE
if test 884 -ne `wc -c <'src/date.l'`; then
    echo shar: \"'src/date.l'\" unpacked with wrong size!
fi
# end of 'src/date.l'
fi
if test -f 'src/dumpenv.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/dumpenv.c'\"
else
echo shar: Extracting \"'src/dumpenv.c'\" \(997 characters\)
sed "s/^X//" >'src/dumpenv.c' <<'END_OF_FILE'
X/* dumpenv --- dump the environment in a usable form to a file */
X
X#include <stdio.h>
X
Xdumpenv(envp, fp)
X
Xchar *envp[];
XFILE *fp;
X
X{
X	char varname[512];
X	register char *ch;
X	register char **string;
X
X	/* Loop through all of the environment variables */
X
X	for (string = envp ; *string != NULL ; string++) {
X
X		/* Skip the TERM variable */
X
X		if (strncmp(*string, "TERM=", 5) == 0)
X			continue;
X
X		/* Copy the variable name to output, looking for the equal sign */
X
X		for (ch = *string ; *ch != '\0' ; ch++) {
X
X			fputc(*ch, fp);
X
X			if (*ch == '=') {
X
X				int len;
X
X				/* Equal sign found, save the variable name */
X
X				len = ch - *string;
X				strncpy(varname, *string, len);
X				varname[len] = '\0';
X				break;
X			}
X		}
X
X		/* Quote the variable's value */
X
X		fputc('\'', fp);
X
X		for (ch++ ; *ch != '\0' ; ch++) {
X
X			/* Quote any single quotes in the variable's value */
X
X			if (*ch == '\'')
X				fputs("'\\''", fp);
X			else
X				fputc(*ch, fp);
X		}
X
X		fprintf(fp, "'\nexport %s\n", varname);
X	}
X}
END_OF_FILE
if test 997 -ne `wc -c <'src/dumpenv.c'`; then
    echo shar: \"'src/dumpenv.c'\" unpacked with wrong size!
fi
# end of 'src/dumpenv.c'
fi
if test -f 'src/patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/patchlevel.h'\"
else
echo shar: Extracting \"'src/patchlevel.h'\" \(51 characters\)
sed "s/^X//" >'src/patchlevel.h' <<'END_OF_FILE'
X#define PATCHLEVEL "kat version 1.0, patchlevel 0"
END_OF_FILE
if test 51 -ne `wc -c <'src/patchlevel.h'`; then
    echo shar: \"'src/patchlevel.h'\" unpacked with wrong size!
fi
# end of 'src/patchlevel.h'
fi
if test -f 'src/permit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/permit.c'\"
else
echo shar: Extracting \"'src/permit.c'\" \(1792 characters\)
sed "s/^X//" >'src/permit.c' <<'END_OF_FILE'
X/* permit --- check for permission to use a resource */
X
X#include "at.h"
X
X/* -------------------------------------------------------------------------- */
X
Xpermit(username, allow_file, deny_file)
X
Xchar *username;
Xchar *allow_file;
Xchar *deny_file;
X
X{
X	/* root always has access. */
X
X	if (strcmp(username, "root") == 0)
X		return (TRUE);
X
X	/* If the allow file does exist, determine if the user's name */
X	/* is listed there. */
X
X	if (access(allow_file, F_OK) == 0)
X		return (finduser(username, allow_file) > 0);
X	
X	/* The allow file didn't exist.  If the deny file doesn't exist */
X	/* either, only root is permitted (through above check). */
X
X	if (access(deny_file, F_OK) != 0)
X		return (FALSE);
X	
X	/* The allow file doesn't exist but the deny file does.  Determine */
X	/* if the user is listed in the deny file or if the file is empty. */
X
X	return (finduser(username, deny_file) <= 0);
X}
X
X/* -------------------------------------------------------------------------- */
X
Xfinduser(username, file)
X
Xchar *username;
Xchar *file;
X
X{
X	char line[64];
X	int entries;
X	int found = FALSE;
X	FILE *listfile;
X
X	if ((listfile = fopen(file, "r")) == NULL) {
X
X		perror(file);
X		return(-1);
X	}
X
X	for (entries = 0 ; fgets(line, 64, listfile) ; ) {
X
X		line[strlen(line) - 1] = '\0';
X
X		if (line[0] == '\0')
X			continue;
X
X		entries++;
X
X		if (strcmp(username, line) == 0) {
X
X			found = TRUE;
X			break;
X		}
X	}
X
X	fclose(listfile);
X
X	if (!found)
X		entries = -entries;
X	
X	return (entries);
X}
X
X/* -------------------------------------------------------------------------- */
X
Xwhoami(owner)
X
Xchar *owner;
X
X{
X	struct passwd *pw;
X
X	uid_t uid;
X
X	uid = getuid();
X
X	if ((pw = getpwuid(uid)) == NULL) {
X
X		fprintf(stderr, "you are not a valid user (no entry in /etc/passwd)\n");
X		exit(1);
X	}
X
X	strcpy(owner, pw->pw_name);
X}
END_OF_FILE
if test 1792 -ne `wc -c <'src/permit.c'`; then
    echo shar: \"'src/permit.c'\" unpacked with wrong size!
fi
# end of 'src/permit.c'
fi
if test -f 'src/qalloc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/qalloc.c'\"
else
echo shar: Extracting \"'src/qalloc.c'\" \(449 characters\)
sed "s/^X//" >'src/qalloc.c' <<'END_OF_FILE'
X/* qalloc --- allocate or reallocate a queue data structure */
X/*            for the kat package programs */
X
X#include "at.h"
X
Xqalloc(qptr, size)
X
Xstruct queue **qptr;
Xint size;
X
X{
X	if (size == 0) {
X
X		if ((*qptr = (struct queue *)malloc(16 * sizeof(struct queue)))
X				!= NULL) 
X			return(16);
X	}
X
X	else {
X		
X		size *= 2;
X
X		if ((*qptr = (struct queue *)realloc(qptr,
X				size * sizeof(struct queue))) != NULL) 
X			return(size);
X	}
X
X	return(-1);
X}
END_OF_FILE
if test 449 -ne `wc -c <'src/qalloc.c'`; then
    echo shar: \"'src/qalloc.c'\" unpacked with wrong size!
fi
# end of 'src/qalloc.c'
fi
if test -f 'src/table.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/table.h'\"
else
echo shar: Extracting \"'src/table.h'\" \(5977 characters\)
sed "s/^X//" >'src/table.h' <<'END_OF_FILE'
X#define HRS		*3600
X#define HALFHR	1800
X
Xstruct table_def {
X
X	char *ta_name;
X	int ta_type;
X	int ta_value;
X	};
X
Xstatic struct table_def string_table[] = {
X
X/* Months of the year */
X
X"january",		MONTH,		0,
X"jan",			MONTH,		0,
X"february",		MONTH,		1,
X"feb",			MONTH,		1,
X"march",		MONTH,		2,
X"mar",			MONTH,		2,
X"april",		MONTH,		3, 
X"apr",			MONTH,		3, 
X"may",			MONTH,		4,
X"june",			MONTH,		5,
X"jun",			MONTH,		5,
X"july",			MONTH,		6,
X"jul",			MONTH,		6,
X"august",		MONTH,		7,
X"aug",			MONTH,		7,
X"september",	MONTH,		8,
X"sept",			MONTH,		8,
X"sep",			MONTH,		8,
X"october",		MONTH,		9,
X"oct",			MONTH,		9,
X"november",		MONTH,		10,
X"nov",			MONTH,		10,
X"december",		MONTH,		11,
X"dec",			MONTH,		11,
X
X/* Days of the week */
X
X"sunday",		DAY,		0,
X"sun",			DAY,		0,
X"monday",		DAY,		1,
X"mon",			DAY,		1,
X"tuesday",		DAY,		2,
X"tues",			DAY,		2,
X"tue",			DAY,		2,
X"wednesday",	DAY,		3,
X"wed",			DAY,		3,
X"thursday",		DAY,		4,
X"thurs",		DAY,		4,
X"thur",			DAY,		4,
X"thu",			DAY,		4,
X"friday",		DAY,		5,
X"fri",			DAY,		5,
X"saturday",		DAY,		6,
X"sat",			DAY,		6,
X
X/* The meridian names */
X
X"am",			MERIDIAN,	AM,
X"a.m.",			MERIDIAN,	AM,
X"pm",			MERIDIAN,	PM,
X"p.m.",			MERIDIAN,	PM,
X
X/* Some special time names */
X
X"midnight",		ABSHOUR,	0,
X"noon",			ABSHOUR,	12,
X"now",			RELDAY,		0,
X"today",		RELDAY,		0,
X"tomorrow",		RELDAY,		SEC_PER_DAY,
X"yesterday",	RELDAY,		-1 * SEC_PER_DAY,
X
X/* Units in terms of months */
X
X"year",			MONUNIT,	12,
X"yr",			MONUNIT,	12,
X"years",		MONUNIT,	12,
X"yrs",			MONUNIT,	12,
X"y",			MONUNIT,	12,
X"month",		MONUNIT,	1,
X"months",		MONUNIT,	1,
X
X/* Units in terms of seconds */
X
X"fortnight",	UNIT,		2 * DAY_PER_WEEK * SEC_PER_DAY,
X"fortnights",	UNIT,		2 * DAY_PER_WEEK * SEC_PER_DAY,
X"week",			UNIT,		DAY_PER_WEEK * SEC_PER_DAY,
X"wk",			UNIT,		DAY_PER_WEEK * SEC_PER_DAY,
X"weeks",		UNIT,		DAY_PER_WEEK * SEC_PER_DAY,
X"wks",			UNIT,		DAY_PER_WEEK * SEC_PER_DAY,
X"w",			UNIT,		DAY_PER_WEEK * SEC_PER_DAY,
X"day",			UNIT,		SEC_PER_DAY,
X"days",			UNIT,		SEC_PER_DAY,
X"d",			UNIT,		SEC_PER_DAY,
X"hour",			UNIT,		SEC_PER_HOUR,
X"hr",			UNIT,		SEC_PER_HOUR,
X"hours",		UNIT,		SEC_PER_HOUR,
X"hrs",			UNIT,		SEC_PER_HOUR,
X"h",			UNIT,		SEC_PER_HOUR,
X"minute",		UNIT,		SEC_PER_MIN,
X"min",			UNIT,		SEC_PER_MIN,
X"minutes",		UNIT,		SEC_PER_MIN,
X"mins",			UNIT,		SEC_PER_MIN,
X"m",			UNIT,		SEC_PER_MIN,
X	/* This token doubles as a unit (1 second) and a relative count */
X	/* (second Friday) */
X"second",		SECOND,		1,
X	/* These forms are units only */
X"seconds",		UNIT,		1,
X"sec",			UNIT,		1,
X"secs",			UNIT,		1,
X"s",			UNIT,		1,
X
X/* Names for ordinal values */
X
X"last",			ORDINAL,	-1,
X"this",			ORDINAL,	0,
X"first",		ORDINAL,	1,
X"next",			ORDINAL,	1,
X"third",		ORDINAL,	3,
X"fourth",		ORDINAL,	4,
X"fifth",		ORDINAL,	5,
X"sixth",		ORDINAL,	6,
X"seventh",		ORDINAL,	7,
X"eighth",		ORDINAL,	8,
X"ninth",		ORDINAL,	9,
X"tenth",		ORDINAL,	10,
X"eleventh",		ORDINAL,	11,
X"twelfth",		ORDINAL,	12,
X
X/* Time zone names with seconds offset from GMT */
X
X"gmt",			STDZONE,	0, 		/* Greenwich */
X"g.m.t.",		STDZONE,	0,		/* Greenwich */
X"eet",			STDZONE,	0,		/* European Eastern Time */
X"e.e.t.",		STDZONE,	0,		/* European Eastern Time */
X"nst",			STDZONE,	3 HRS + HALFHR, /* Newfoundland */
X"n.s.t.",		STDZONE,	3 HRS + HALFHR, /* Newfoundland */
X"ast",			STDZONE,	4 HRS,	/* Atlantic */
X"a.s.t.",		STDZONE,	4 HRS,	/* Atlantic */
X"adt",			DSTZONE,	4 HRS,	/* Atlantic DST */
X"a.d.t.",		DSTZONE,	4 HRS,	/* Atlantic DST */
X"est",			STDZONE,	5 HRS,	/* Eastern */
X"e.s.t.",		STDZONE,	5 HRS,	/* Eastern */
X"edt",			DSTZONE,	5 HRS,	/* Eastern DST*/
X"e.d.t.",		DSTZONE,	5 HRS,	/* Eastern DST*/
X"cst",			STDZONE,	6 HRS,	/* Central */
X"c.s.t.",		STDZONE,	6 HRS,	/* Central */
X"cdt",			DSTZONE,	6 HRS,	/* Central DST */
X"c.d.t.",		DSTZONE,	6 HRS,	/* Central DST */
X"mst",			STDZONE,	7 HRS,	/* Mountain */
X"m.s.t.",		STDZONE,	7 HRS,	/* Mountain */
X"mdt",			DSTZONE,	7 HRS,	/* Mountain DST */
X"m.d.t.",		DSTZONE,	7 HRS,	/* Mountain DST */
X"pst",			STDZONE,	8 HRS,	/* Pacific */
X"p.s.t.",		STDZONE,	8 HRS,	/* Pacific */
X"pdt",			DSTZONE,	8 HRS,	/* Pacific DST */
X"p.d.t.",		DSTZONE,	8 HRS,	/* Pacific DST */
X"yst",			STDZONE,	9 HRS,	/* Yukon */
X"y.s.t.",		STDZONE,	9 HRS,	/* Yukon */
X"ydt",			DSTZONE,	9 HRS,	/* Yukon DST */
X"y.d.t.",		DSTZONE,	9 HRS,	/* Yukon DST */
X"hst",			STDZONE,	10 HRS,	/* Hawaii */
X"h.s.t.",		STDZONE,	10 HRS,	/* Hawaii */
X"hdt",			DSTZONE,	10 HRS,	/* Hawaii DST */
X"h.d.t.",		DSTZONE,	10 HRS,	/* Hawaii DST */
X"bst",			DSTZONE,	0,		/* British Summer Time */
X"b.s.t.",		DSTZONE,	0,		/* British Summer Time */
X"eet",			STDZONE,	0,		/* European Eastern Time */
X"e.e.t.",		STDZONE,	0,		/* European Eastern Time */
X"eest",			DSTZONE,	0,		/* European Eastern Summer Time */
X"e.e.s.t.",		DSTZONE,	0,		/* European Eastern Summer Time */
X"met",			STDZONE,	-1 HRS,	/* Middle European Time */
X"m.e.t.",		STDZONE,	-1 HRS,	/* Middle European Time */
X"mest",			DSTZONE,	-1 HRS,	/* Middle European Summer Time */
X"m.e.s.t.",		DSTZONE,	-1 HRS,	/* Middle European Summer Time */
X"wet",			STDZONE,	-2 HRS,	/* Western European Time */
X"w.e.t.",		STDZONE,	-2 HRS,	/* Western European Time */
X"west",			DSTZONE,	-2 HRS,	/* Western European Summer Time */
X"w.e.s.t.",		DSTZONE,	-2 HRS,	/* Western European Summer Time */
X"jst",			STDZONE,	-9 HRS,	/* Japan Standard Time */
X"j.s.t.",		STDZONE,	-9 HRS,	/* Japan Standard Time */
X"aest",			STDZONE,	-10 HRS,	/* Australian Eastern Time */
X"a.e.s.t.",		STDZONE,	-10 HRS,	/* Australian Eastern Time */
X"aesst",		DSTZONE,	-10 HRS,	/* Australian Eastern Summer Time */
X"a.e.s.s.t.",	DSTZONE,	-10 HRS,	/* Australian Eastern Summer Time */
X"acst",			STDZONE,	-(9 HRS + HALFHR),	/* Australian Central Time */
X"a.c.s.t.",		STDZONE,	-(9 HRS + HALFHR),	/* Australian Central Time */
X"acsst",		DSTZONE,	-(9 HRS + HALFHR),
X										/* Australian Central Summer Time */
X"a.c.s.s.t."  ,	DSTZONE,	-(9 HRS + HALFHR),
X										/* Australian Central Summer Time */
X"awst",			STDZONE,	-8 HRS,		/* Australian Western Time */
X"a.w.s.t.",		STDZONE,	-8 HRS,		/* Australian Western Time */
X};
END_OF_FILE
if test 5977 -ne `wc -c <'src/table.h'`; then
    echo shar: \"'src/table.h'\" unpacked with wrong size!
fi
# end of 'src/table.h'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both 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
-- 
-----------------------------------------------------------------------------
Keith Pyle                                UUCP: ...!cs.utexas.edu!execu!keith
Execucom Systems Corp., Austin, Texas     Internet: keith at execu.com
"It's 10 o'clock.  Do you know where      Disclaimer: Everything I say is
   your child processes are?"               true unless I use the word 'the'.
-----------------------------------------------------------------------------



More information about the Alt.sources mailing list