home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume27
/
vixie-cron
/
part01
next >
Wrap
Text File
|
1994-01-16
|
108KB
|
3,575 lines
Newsgroups: comp.sources.unix
From: paul@vix.com (Paul Vixie)
Subject: v27i196: vixie-cron - Vixie's Cron, V3.0, Part01/02
Message-id: <1.758778125.12895@gw.home.vix.com>
Sender: unix-sources-moderator@gw.home.vix.com
Approved: vixie@gw.home.vix.com
Submitted-By: paul@vix.com (Paul Vixie)
Posting-Number: Volume 27, Issue 196
Archive-Name: vixie-cron/part01
This is version 3.0 of vixie-cron. Previous versions are contained in
BSD/386, NetBSD, FreeBSD, 386BSD, Linux, and thousands of Usenet systems
where the local sysadmin has replaced the vendor's cron with this one. It is
essential that all systems using any previous version of this cron be
upgraded, since there are three major security holes in all previous
versions. (Two of the security holes have been well-publicized; one has
not; the Linux/NetBSD fix for one of the publicized security holes actually
adds a new hole, so even those systems ought to be upgraded to this cron.)
The other major difference between this and previous versions is that this one
has support for the 4.3BSD-style "/etc/crontab" file -- that's the one that has
an extra field between the time specification and the command; that field is a
user name. Thus commands can be made to run as non-root users without the old
"* * * * * echo /usr/bin/rnews -U | su news" trick. The support for this was
done by BSDi and contributed back to the public version of cron.
I have run an extensive beta test of this software using the alt.sources group;
this version of cron is known to compile and run on *BSD*, Linux, SunOS, OSF/1,
HP-UX, and several flavours of System V including the one running on Convex's
hardware. I have run it in production here for many months, and it is part of
the upcoming 1.1 release of BSDi's BSD/386 operating system.
Briefly, this cron is better than the older BSD/V7 cron since it permits each
user on the system to have their own private crontab. It also logs each command
as it is run (using syslog or a local log file, depending on how you configure
it). It does not contain "atrun" as does System V cron, and since those
systems do not have a separate "atrun" that this cron can run, it is unlikely
that any System V system will want to run this cron.
This cron complies with POSIX 1003.1. Actually, this cron predates POSIX
1003.1's specification by a several years, but since the interface for this
cron and POSIX's cron are both based on AT&T System V's cron, the differences
were small and this latest version has been changed to the POSIX interface
where they differed.
Paul Vixie
paul@vix.com
#! /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: CONVERSION FEATURES INSTALL MANIFEST Makefile README
# THANKS bitstring.3 bitstring.h compat.c compat.h config.h cron.8
# cron.c cron.h crontab.1 crontab.5 database.c env.c externs.h job.c
# pathnames.h popen.c putman.sh user.c
# Wrapped by vixie@gw.home.vix.com on Sun Jan 16 19:20:50 1994
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'CONVERSION' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'CONVERSION'\"
else
echo shar: Extracting \"'CONVERSION'\" \(3853 characters\)
sed "s/^X//" >'CONVERSION' <<'END_OF_FILE'
X$Id: CONVERSION,v 2.2 1993/12/28 08:34:43 vixie Exp $
X
XConversion of BSD 4.[23] crontab files:
X
XEdit your current crontab (/usr/lib/crontab) into little pieces, with each
Xusers' commands in a different file. This is different on 4.2 and 4.3,
Xbut I'll get to that below. The biggest feature of this cron is that you
Xcan move 'news' and 'uucp' cron commands into files owned and maintainable
Xby those two users. You also get to rip all the fancy 'su' footwork out
Xof the cron commands. On 4.3, there's no need for the 'su' stuff since the
Xuser name appears on each command -- but I'd still rather have separate
Xcrontabs with seperate environments and so on.
X
XLeave the original /usr/lib/crontab! This cron doesn't use it, so you may
Xas well keep it around for a while in case something goes wakko with this
Xfancy version.
X
XMost commands in most crontabs are run by root, have to run by root, and
Xshould continue to be run by root. They still have to be in their own file;
XI recommend /etc/crontab.src or /usr/adm/crontab.src.
X
X'uucp's commands need their own file; how about /usr/lib/uucp/crontab.src?
X'news' also, perhaps in /usr/lib/news/crontab.src...
X
XI say `how about' and `perhaps' because it really doesn't matter to anyone
X(except you) where you put the crontab source files. The `crontab' command
XCOPIES them into a protected directory (CRONDIR/SPOOL_DIR in cron.h), named
Xafter the user whose crontab it is. If you want to examine, replace, or
Xdelete a crontab, the `crontab' command does all of those things. The
Xvarious `crontab.src' (my suggested name for them) files are just source
Xfiles---they have to be copied to SPOOLDIR using `crontab' before they'll be
Xexecuted.
X
XOn 4.2, your crontab might have a few lines like this:
X
X 5 * * * * su uucp < /usr/lib/uucp/uudemon.hr
X 10 4 * * * su uucp < /usr/lib/uucp/uudemon.day
X 15 5 * * 0 su uucp < /usr/lib/uucp/uudemon.wk
X
X...or like this:
X
X 5 * * * * echo /usr/lib/uucp/uudemon.hr | su uucp
X 10 4 * * * echo /usr/lib/uucp/uudemon.day | su uucp
X 15 5 * * 0 echo /usr/lib/uucp/uudemon.wk | su uucp
X
XOn 4.3, they'd look a little bit better, but not much:
X
X 5 * * * * uucp /usr/lib/uucp/uudemon.hr
X 10 4 * * * uucp /usr/lib/uucp/uudemon.day
X 15 5 * * 0 uucp /usr/lib/uucp/uudemon.wk
X
XFor this cron, you'd create /usr/lib/uucp/crontab.src (or wherever you want
Xto keep uucp's commands) which would look like this:
X
X # /usr/lib/uucp/crontab.src - uucp's crontab
X #
X PATH=/usr/lib/uucp:/bin:/usr/bin
X SHELL=/bin/sh
X HOME=/usr/lib/uucp
X #
X 5 * * * * uudemon.hr
X 10 4 * * * uudemon.day
X 15 5 * * 0 uudemon.wk
X
XThe application to the `news' cron commands (if any) is left for you to
Xfigure out. Likewise if there are any other cruddy-looking 'su' commands in
Xyour crontab commands, you don't need them anymore: just find a good place
Xto put the `crontab.src' (or whatever you want to call it) file for that
Xuser, put the cron commands into it, and install it using the `crontab'
Xcommand (probably with "-u USERNAME", but see the man page).
X
XIf you run a 4.2-derived cron, you could of course just install your current
Xcrontab in toto as root's crontab. It would work exactly the way your
Xcurrent one does, barring the extra steps in installing or changing it.
XThere would still be advantages to this cron, mostly that you get mail if
Xthere is any output from your cron commands.
X
XOne note about getting mail from cron: you will probably find, after you
Xinstall this version of cron, that your cron commands are generating a lot
Xof irritating output. The work-around for this is to redirect all EXPECTED
Xoutput to a per-execution log file, which you can examine if you want to
Xsee the output from the "last time" a command was executed; if you get any
XUNEXPECTED output, it will be mailed to you. This takes a while to get
Xright, but it's amazingly convenient. Trust me.
X
END_OF_FILE
if test 3853 -ne `wc -c <'CONVERSION'`; then
echo shar: \"'CONVERSION'\" unpacked with wrong size!
fi
# end of 'CONVERSION'
fi
if test -f 'FEATURES' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'FEATURES'\"
else
echo shar: Extracting \"'FEATURES'\" \(4071 characters\)
sed "s/^X//" >'FEATURES' <<'END_OF_FILE'
X$Id: FEATURES,v 2.1 1993/12/28 08:34:43 vixie Exp $
X
XFeatures of Vixie's cron relative to BSD 4.[23] and SysV crons:
X
X-- Environment variables can be set in each crontab. SHELL, USER,
X and HOME are set from the user's passwd entry; all except USER
X can be changed in the crontab. PATH is especially useful to
X set there. TZ can be set, but cron ignores it other than passing
X it on through to the commands it runs. Format is
X
X variable=value
X
X Blanks surrounding the '=' will be eaten; other blanks in value are
X okay. Leading or trailing blanks can be preserved by quoting, single
X or double quotes are okay, just so they match.
X
X PATH=.:/bin:/usr/bin
X SHELL=/bin/sh
X FOOBAR = this is a long blanky example
X
X Above, FOOBAR would get `this is a long blanky example' as its value.
X
X SHELL and HOME will be examined when it's time to run a command; if
X you don't change them, they default to your /etc/passwd entry.
X
X *DANGER*, WILL ROBINSON! This means that all 'uucp' logins should set
X SHELL=/bin/sh or cron will try to use /usr/lib/uucp/uucico as the
X shell. This won't work.
X
X MAILTO, if set to the login name of a user on your system, will be the
X person that cron mails the output of commands in that crontab. This is
X useful if you decide on BINMAIL when configuring cron.h, since binmail
X doesn't know anything about aliasing.
X
X Setting SHELL=/bin/sh will in general speed up your commands since it
X is a much smaller shell than the one you probably use normally (csh
X or ksh) and has enough features to work non-interactively.
X
X-- Weekdays can be specified by name. Case is not significant, but only
X the first three letters should be specified.
X
X-- Months can likewise be specified by name. Three letters only.
X
X-- Ranges and lists can be mixed. Standard crons won't allow '1,3-5'.
X
X-- Ranges can specify 'step' values. '10-16/2' is like '10,12,14,16'.
X
X-- Sunday is both day 0 and day 7 -- apparently BSD and ATT disagree
X about this.
X
X-- Each user gets their own crontab file. This is a win over BSD 4.2,
X where only root has one, and over BSD 4.3, where they made the crontab
X format incompatible and although the commands can be run by non-root
X uid's, root is still the only one who can edit the crontab file. This
X feature mimics the SysV cron.
X
X-- The 'crontab' command is loosely compatible with SysV, but has more
X options which just generally make more sense. Running crontab with
X no arguments will print a cute little summary of the command syntax.
X
X-- Comments and blank lines are allowed in the crontab file. Comments
X must be on a line by themselves; leading whitespace is ignored, and
X a '#' introduces the comment.
X
X-- (big win) If the `crontab' command changes anything in any crontab, it
X tells the 'cron' daemon, who reloads all the tables before running the
X next iteration. In some crons, you have to kill and restart the
X daemon whenever you change a crontab. In other crons, the crontab
X file is reread and reparsed every minute even if it didn't change.
X
X-- In order to support the automatic reload, the crontab files are not
X readable or writable except by 'crontab' or 'cron'. This is not a
X problem, since 'crontab' will let you do pretty much whatever you
X want to your own crontab, or if you are root, to anybody's crontab.
X
X-- If any output is generated by a command (on stdout OR stderr), it will
X be mailed to the owner of the crontab that contained the command (or
X MAILTO, see discussion of environment variables, above). The headers
X of the mail message will include the command that was run, and a
X complete list of the environment that was passed to it, which will
X contain (at least) the USER (LOGNAME on SysV), HOME, and SHELL.
X
X-- the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
X first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
X on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
X is why we keep 'e->dow_star' and 'e->dom_star'. I didn't think up
X this behaviour; it's how cron has always worked but the documentation
X hasn't been very clear.
END_OF_FILE
if test 4071 -ne `wc -c <'FEATURES'`; then
echo shar: \"'FEATURES'\" unpacked with wrong size!
fi
# end of 'FEATURES'
fi
if test -f 'INSTALL' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'INSTALL'\"
else
echo shar: Extracting \"'INSTALL'\" \(4106 characters\)
sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
X/* Copyright 1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X$Id: INSTALL,v 2.5 1994/01/15 20:43:43 vixie Exp $
X
XRead the comments at the top of the Makefile, then edit the area marked
X'configurable stuff'.
X
XEdit config.h. The stuff I expect you to change is down a bit from the
Xtop of the file, but it's clearly marked. Also look at pathnames.h.
X
XYou don't have to create the /var/cron or /var/cron/tabs directories, since
Xboth the daemon and the `crontab' program will do this the first time they
Xrun if they don't exist. You do need to have a /var, though -- just "mkdir
X/var" if you don't have one, or you can "mkdir /usr/var; ln -s /usr/var /var"
Xif you expect your /var to have a lot of stuff in it.
X
XYou will also need /usr/local/etc and /usr/local/bin directories unless you
Xchange the Makefile. These will have to be created by hand, but if you are
Xa long-time Usenet user you probably have them already. /usr/local/man is
Xwhere I keep my man pages, but I have the source for `man' and you probably
Xdo not. Therefore you may have to put the man pages into /usr/man/manl,
Xwhich will be hard since there will be name collisions. (Note that the man
Xcommand was originally written by Bill Joy before he left Berkeley, and it
Xcontains no AT&T code, so it is in UUNET's archive of freely-distributable
XBSD code.)
X
XLINUX note: /usr/include/paths.h on some linux systems shows _PATH_SENDMAIL
X to be /usr/bin/sendmail even though sendmail is installed in /usr/lib.
X you should check this out.
X
Xsay:
X make all
X
Xsu and say:
X make install
X
XNote that if I can get you to "su and say" something just by asking, you have
Xa very serious security problem on your system and you should look into it.
X
XEdit your /usr/lib/crontab file into little pieces -- see the CONVERSION file
Xfor help on this.
X
XUse the `crontab' command to install all the little pieces you just created.
XSome examples (see below before trying any of these!)
X
X crontab -u uucp -r /usr/lib/uucp/crontab.src
X crontab -u news -r /usr/lib/news/crontab.src
X crontab -u root -r /usr/adm/crontab.src
X
XNotes on above examples: (1) the .src files are copied at the time the
Xcommand is issued; changing the source files later will have no effect until
Xthey are reinstalled with another `crontab -r' command. (2) The crontab
Xcommand will affect the crontab of the person using the command unless `-u
XUSER' is given; `-u' only works for root. When using most `su' commands
Xunder most BSD's, `crontab' will still think of you as yourself even though
Xyou may think of yourself as root -- so use `-u' liberally. (3) the `-r'
Xoption stands for `replace'; check the man page for crontab(1) for other
Xpossibilities.
X
XKill your existing cron daemon -- do `ps aux' and look for /etc/cron.
X
XEdit your /etc/rc or /etc/rc.local, looking for the line that starts up
X/etc/cron. Comment it out and add a line to start the new cron daemon
X-- usually /usr/local/etc/cron, unless you changed it in the Makefile.
X
XStart up this cron daemon yourself as root. Just type /usr/local/etc/cron
X(or whatever); no '&' is needed since the daemon forks itself and the
Xprocess you executed returns immediately.
X
XATT notes: for those people unfortunate enough to be stuck on a AT&T UNIX,
Xyou will need the public-domain "libndir", found in the B News source and in
Xany comp.sources.unix archive. You will also need to hack the code some.
END_OF_FILE
if test 4106 -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'\" \(1075 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X File Name Archive # Description
X-----------------------------------------------------------
X CHANGES 2
X CONVERSION 1
X FEATURES 1
X INSTALL 1
X MAIL 2
X MANIFEST 1 This shipping list
X Makefile 1
X README 1
X THANKS 1
X bitstring.3 1
X bitstring.h 1
X compat.c 1
X compat.h 1
X config.h 1
X cron.8 1
X cron.c 1
X cron.h 1
X crontab.1 1
X crontab.5 1
X crontab.c 2
X database.c 1
X do_command.c 2
X entry.c 2
X env.c 1
X externs.h 1
X job.c 1
X misc.c 2
X pathnames.h 1
X popen.c 1
X putman.sh 1
X user.c 1
END_OF_FILE
if test 1075 -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'\" \(4544 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#/* Copyright 1988,1990,1993,1994 by Paul Vixie
X# * All rights reserved
X# *
X# * Distribute freely, except: don't remove my name from the source or
X# * documentation (don't take credit for my work), mark your changes (don't
X# * get me blamed for your possible bugs), don't alter or remove this
X# * notice. May be sold if buildable source is provided to buyer. No
X# * warrantee of any kind, express or implied, is included with this
X# * software; use at your own risk, responsibility for damages (if any) to
X# * anyone resulting from the use of this software rests entirely with the
X# * user.
X# *
X# * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X# * I'll try to keep a version up to date. I can be reached as follows:
X# * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X# */
X
X# Makefile for vixie's cron
X#
X# $Id: Makefile,v 2.9 1994/01/15 20:43:43 vixie Exp $
X#
X# vix 03mar88 [moved to RCS, rest of log is in there]
X# vix 30mar87 [goodbye, time.c; hello, getopt]
X# vix 12feb87 [cleanup for distribution]
X# vix 30dec86 [written]
X
X# NOTES:
X# 'make' can be done by anyone
X# 'make install' must be done by root
X#
X# this package needs getopt(3), bitstring(3), and BSD install(8).
X#
X# the configurable stuff in this makefile consists of compilation
X# options (use -O, cron runs forever) and destination directories.
X# SHELL is for the 'augumented make' systems where 'make' imports
X# SHELL from the environment and then uses it to run its commands.
X# if your environment SHELL variable is /bin/csh, make goes real
X# slow and sometimes does the wrong thing.
X#
X# this package needs the 'bitstring macros' library, which is
X# available from me or from the comp.sources.unix archive. if you
X# put 'bitstring.h' in a non-standard place (i.e., not intuited by
X# cc(1)), you will have to define INCLUDE to set the include
X# directory for cc. INCLUDE should be `-Isomethingorother'.
X#
X# there's more configuration info in config.h; edit that first!
X
X#################################### begin configurable stuff
X#<<DESTROOT is assumed to have ./etc, ./bin, and ./man subdirectories>>
XDESTROOT = $(DESTDIR)/usr
XDESTSBIN = $(DESTROOT)/sbin
XDESTBIN = $(DESTROOT)/bin
XDESTMAN = $(DESTROOT)/share/man
X#<<need bitstring.h>>
XINCLUDE = -I.
X#INCLUDE =
X#<<need getopt()>>
XLIBS =
X#<<optimize or debug?>>
X#OPTIM = -O
XOPTIM = -g
X#<<ATT or BSD or POSIX?>>
X# (ATT untested)
X#COMPAT = -DATT
X#(BSD is only needed if <sys/params.h> does not define it, as on ULTRIX)
X#COMPAT = -DBSD
X# (POSIX)
X#COMPAT = -DPOSIX
X#<<lint flags of choice?>>
XLINTFLAGS = -hbxa $(INCLUDE) $(COMPAT) $(DEBUGGING)
X#<<want to use a nonstandard CC?>>
X#CC = vcc
X#<<manifest defines>>
XDEFS =
X#(SGI IRIX systems need this)
X#DEFS = -D_BSD_SIGNALS -Dconst=
X#<<the name of the BSD-like install program>>
X#INSTALL = installbsd
XINSTALL = install
X#<<any special load flags>>
XLDFLAGS =
X#################################### end configurable stuff
X
XSHELL = /bin/sh
XCFLAGS = $(OPTIM) $(INCLUDE) $(COMPAT) $(DEFS)
X
XINFOS = README CHANGES FEATURES INSTALL CONVERSION THANKS MAIL
XMANPAGES = bitstring.3 crontab.5 crontab.1 cron.8 putman.sh
XHEADERS = bitstring.h cron.h config.h pathnames.h \
X externs.h compat.h
XSOURCES = cron.c crontab.c database.c do_command.c entry.c \
X env.c job.c user.c popen.c misc.c compat.c
XSHAR_SOURCE = $(INFOS) $(MANPAGES) Makefile $(HEADERS) $(SOURCES)
XLINT_CRON = cron.c database.c user.c entry.c compat.c \
X misc.c job.c do_command.c env.c popen.c
XLINT_CRONTAB = crontab.c misc.c entry.c env.c compat.c
XCRON_OBJ = cron.o database.o user.o entry.o job.o do_command.o \
X misc.o env.o popen.o compat.o
XCRONTAB_OBJ = crontab.o misc.o entry.o env.o compat.o
X
Xall : cron crontab
X
Xlint :
X lint $(LINTFLAGS) $(LINT_CRON) $(LIBS) \
X |grep -v "constant argument to NOT" 2>&1
X lint $(LINTFLAGS) $(LINT_CRONTAB) $(LIBS) \
X |grep -v "constant argument to NOT" 2>&1
X
Xcron : $(CRON_OBJ)
X $(CC) $(LDFLAGS) -o cron $(CRON_OBJ) $(LIBS)
X
Xcrontab : $(CRONTAB_OBJ)
X $(CC) $(LDFLAGS) -o crontab $(CRONTAB_OBJ) $(LIBS)
X
Xinstall : all
X $(INSTALL) -c -m 111 -o root -s cron $(DESTSBIN)/
X $(INSTALL) -c -m 4111 -o root -s crontab $(DESTBIN)/
X sh putman.sh crontab.1 $(DESTMAN)
X sh putman.sh cron.8 $(DESTMAN)
X sh putman.sh crontab.5 $(DESTMAN)
X
Xclean :; rm -f *.o cron crontab a.out core tags *~ #*
X
Xkit : $(SHAR_SOURCE)
X makekit -m -s99k $(SHAR_SOURCE)
X
X$(CRON_OBJ) : cron.h compat.h config.h externs.h pathnames.h Makefile
X$(CRONTAB_OBJ) : cron.h compat.h config.h externs.h pathnames.h Makefile
END_OF_FILE
if test 4544 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3278 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X#/* Copyright 1988,1990,1993 by Paul Vixie
X# * All rights reserved
X# *
X# * Distribute freely, except: don't remove my name from the source or
X# * documentation (don't take credit for my work), mark your changes (don't
X# * get me blamed for your possible bugs), don't alter or remove this
X# * notice. May be sold if buildable source is provided to buyer. No
X# * warrantee of any kind, express or implied, is included with this
X# * software; use at your own risk, responsibility for damages (if any) to
X# * anyone resulting from the use of this software rests entirely with the
X# * user.
X# *
X# * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X# * I'll try to keep a version up to date. I can be reached as follows:
X# * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X# */
X
XVixie Cron V3.0
XDecember 27, 1993
X[V2.2 was some time in 1992]
X[V2.1 was May 29, 1991]
X[V2.0 was July 5, 1990]
X[V2.0-beta was December 9, 1988]
X[V1.0 was May 6, 1987]
XPaul Vixie
X
XThis is a version of 'cron' that is known to run on BSD 4.[23] systems. It
Xis functionally based on the SysV cron, which means that each user can have
Xtheir own crontab file (all crontab files are stored in a read-protected
Xdirectory, usually /var/cron/tabs). No direct support is provided for
X'at'; you can continue to run 'atrun' from the crontab as you have been
Xdoing. If you don't have atrun (i.e., System V) you are in trouble.
X
XA messages is logged each time a command is executed; also, the files
X"allow" and "deny" in /var/cron can be used to control access to the
X"crontab" command (which installs crontabs). It hasn't been tested on
XSysV, although some effort has gone into making the port an easy one.
X
XThis is more or less the copyright that USENET contributed software usually
Xhas. Since ATT couldn't use this version if they had to freely distribute
Xsource, and since I'd love to see them use it, I'll offer some rediculously
Xlow license fee just to have them take it. In the unlikely event that they
Xdo this, I will continue to support and distribute the pseudo-PD version, so
Xplease, don't flame me for wanting my work to see a wider distribution.
X
XTo use this: Sorry, folks, there is no cutesy 'Configure' script. You'll
Xhave to go edit a couple of files... So, here's the checklist:
X
X Read all the FEATURES, INSTALL, and CONVERSION files
X Edit config.h
X Edit Makefile
X (both of these files have instructions inside; note that
X some things in config.h are definable in Makefile and are
X therefore surrounded by #ifndef...#endif)
X 'make'
X 'su' and 'make install'
X (you may have to install the man pages by hand)
X kill your existing cron process
X (actually you can run your existing cron if you want, but why?)
X build new crontabs using /usr/lib/{crontab,crontab.local}
X (either put them all in "root"'s crontab, or divide it up
X and rip out all the 'su' commands, collapse the lengthy
X lists into ranges with steps -- basically, this step is
X as much work as you want to make it)
X start up the new cron
X (must be done as root)
X watch it. test it with 'crontab -r' and watch the daemon track your
X changes.
X if you like it, change your /etc/{rc,rc.local} to use it instead of
X the old one.
X
X$Id: README,v 2.3 1993/12/28 08:34:43 vixie Exp $
END_OF_FILE
if test 3278 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'THANKS' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'THANKS'\"
else
echo shar: Extracting \"'THANKS'\" \(1598 characters\)
sed "s/^X//" >'THANKS' <<'END_OF_FILE'
X15 January 1990
XPaul Vixie
X
XMany people have contributed to cron. Many more than I can remember, in fact.
XRich Salz and Carl Gutekunst were each of enormous help to me in V1; Carl for
Xhelping me understand UNIX well enough to write it, and Rich for helping me
Xget the features right.
X
XJohn Gilmore wrote me a wonderful review of V2, which took me a whole year to
Xanswer even though it made me clean up some really awful things in the code.
X(According to John the most awful things are still in here, of course.)
X
XPaul Close made a suggestion which led to /etc/crond.pid and the mutex locking
Xon it. Kevin Braunsdorf of Purdue made a suggestion that led to @reboot and
Xits brothers and sisters; he also sent some diffs that lead cron toward compil-
Xability with System V, though without at(1) capabilities, this cron isn't going
Xto be that useful on System V. Bob Alverson fixed a silly bug in the line
Xnumber counting. Brian Reid made suggestions which led to the run queue and
Xthe source-file labelling in installed crontabs.
X
XScott Narveson ported V2 to a Sequent, and sent in the most useful single batch
Xof diffs I got from anybody. Changes attributable to Scott are:
X -> sendmail won't time out if the command is slow to generate output
X -> day-of-week names aren't off by one anymore
X -> crontab says the right thing if you do something you shouldn't do
X -> crontab(5) man page is longer and more informative
X -> misc changes related to the side effects of fclose()
X -> Sequent "universe" support added (may also help on Pyramids)
X -> null pw_shell is dealt with now; default is /bin/sh
END_OF_FILE
if test 1598 -ne `wc -c <'THANKS'`; then
echo shar: \"'THANKS'\" unpacked with wrong size!
fi
# end of 'THANKS'
fi
if test -f 'bitstring.3' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'bitstring.3'\"
else
echo shar: Extracting \"'bitstring.3'\" \(3395 characters\)
sed "s/^X//" >'bitstring.3' <<'END_OF_FILE'
X.\" Copyright (c) 1989 The Regents of the University of California.
X.\" All rights reserved.
X.\"
X.\" This code is derived from software contributed to Berkeley by
X.\" Paul Vixie.
X.\"
X.\" Redistribution and use in source and binary forms are permitted
X.\" provided that the above copyright notice and this paragraph are
X.\" duplicated in all such forms and that any documentation,
X.\" advertising materials, and other materials related to such
X.\" distribution and use acknowledge that the software was developed
X.\" by the University of California, Berkeley. The name of the
X.\" University may not be used to endorse or promote products derived
X.\" from this software without specific prior written permission.
X.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X.\"
X.\" @(#)bitstring.3 5.1 (Berkeley) 12/13/89
X.\"
X.TH BITSTRING 3 "December 13, 1989"
X.UC 4
X.SH NAME
Xbit_alloc, bit_clear, bit_decl, bit_ffs, bit_nclear, bit_nset,
Xbit_set, bitstr_size, bit_test \- bit-string manipulation macros
X.SH SYNOPSIS
X.ft B
X.nf
X#include <bitstring.h>
X
Xname = bit_alloc(nbits)
Xbitstr_t *name;
Xint nbits;
X
Xbit_decl(name, nbits)
Xbitstr_t name;
Xint nbits;
X
Xbit_clear(name, bit)
Xbitstr_t name;
Xint bit;
X
Xbit_ffc(name, nbits, value)
Xbitstr_t name;
Xint nbits, *value;
X
Xbit_ffs(name, nbits, value)
Xbitstr_t name;
Xint nbits, *value;
X
Xbit_nclear(name, start, stop)
Xbitstr_t name;
Xint start, stop;
X
Xbit_nset(name, start, stop)
Xbitstr_t name;
Xint start, stop;
X
Xbit_set(name, bit)
Xbitstr_t name;
Xint bit;
X
Xbitstr_size(nbits)
Xint nbits;
X
Xbit_test(name, bit)
Xbitstr_t name;
Xint bit;
X.fi
X.ft R
X.SH DESCRIPTION
XThese macros operate on strings of bits.
X.PP
X.I Bit_alloc
Xreturns a pointer of type
X.I bitstr_t\ *
Xto sufficient space to store
X.I nbits
Xbits, or NULL if no space is available.
X.PP
X.I Bit_decl
Xis a macro for allocating sufficient space to store
X.I nbits
Xbits on the stack.
X.PP
X.I Bitstr_size
Xreturns the number of elements of type
X.I bitstr_t
Xnecessary to store
X.I nbits
Xbits.
XThis is useful for copying bit strings.
X.PP
X.I Bit_clear
Xand
X.I bit_set
Xclear or set the zero-based numbered bit
X.IR bit ,
Xin the bit string
X.IR name .
X.PP
X.I Bit_nset
Xand
X.I bit_nclear
Xset or clear the zero-based numbered bits from
X.I start
Xto
X.I stop
Xin the bit string
X.IR name .
X.PP
X.I Bit_test
Xevaluates to zero if the zero-based numbered bit
X.I bit
Xof bit string
X.I name
Xis set, and non-zero otherwise.
X.PP
X.I Bit_ffs
Xsets
X.I *value
Xto the zero-based number of the first bit set in the array of
X.I nbits
Xbits referenced by
X.IR name .
XIf no bits are set,
X.I *value
Xis set to -1.
X.PP
X.I Bit_ffc
Xsets
X.I *value
Xto the zero-based number of the first bit not set in the array of
X.I nbits
Xbits referenced by
X.IR name .
XIf all bits are set,
X.I value
Xis set to -1.
X.SH EXAMPLE
X.nf
X.in +5
X#include <limits.h>
X#include <bitstring.h>
X
X...
X#define LPR_BUSY_BIT 0
X#define LPR_FORMAT_BIT 1
X#define LPR_DOWNLOAD_BIT 2
X...
X#define LPR_AVAILABLE_BIT 9
X#define LPR_MAX_BITS 10
X
Xmake_lpr_available()
X{
X bitstr_t bit_decl(bitlist, LPR_MAX_BITS);
X ...
X bit_nclear(bitlist, 0, LPR_MAX_BITS - 1);
X ...
X if (!bit_test(bitlist, LPR_BUSY_BIT)) {
X bit_clear(bitlist, LPR_FORMAT_BIT);
X bit_clear(bitlist, LPR_DOWNLOAD_BIT);
X bit_set(bitlist, LPR_AVAILABLE_BIT);
X }
X}
X.fi
X.SH "SEE ALSO"
Xmalloc(3)
END_OF_FILE
if test 3395 -ne `wc -c <'bitstring.3'`; then
echo shar: \"'bitstring.3'\" unpacked with wrong size!
fi
# end of 'bitstring.3'
fi
if test -f 'bitstring.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'bitstring.h'\"
else
echo shar: Extracting \"'bitstring.h'\" \(3957 characters\)
sed "s/^X//" >'bitstring.h' <<'END_OF_FILE'
X/*
X * Copyright (c) 1989 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Paul Vixie.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley. The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * @(#)bitstring.h 5.2 (Berkeley) 4/4/90
X */
X
Xtypedef unsigned char bitstr_t;
X
X/* internal macros */
X /* byte of the bitstring bit is in */
X#define _bit_byte(bit) \
X ((bit) >> 3)
X
X /* mask for the bit within its byte */
X#define _bit_mask(bit) \
X (1 << ((bit)&0x7))
X
X/* external macros */
X /* bytes in a bitstring of nbits bits */
X#define bitstr_size(nbits) \
X ((((nbits) - 1) >> 3) + 1)
X
X /* allocate a bitstring */
X#define bit_alloc(nbits) \
X (bitstr_t *)malloc(1, \
X (unsigned int)bitstr_size(nbits) * sizeof(bitstr_t))
X
X /* allocate a bitstring on the stack */
X#define bit_decl(name, nbits) \
X (name)[bitstr_size(nbits)]
X
X /* is bit N of bitstring name set? */
X#define bit_test(name, bit) \
X ((name)[_bit_byte(bit)] & _bit_mask(bit))
X
X /* set bit N of bitstring name */
X#define bit_set(name, bit) \
X (name)[_bit_byte(bit)] |= _bit_mask(bit)
X
X /* clear bit N of bitstring name */
X#define bit_clear(name, bit) \
X (name)[_bit_byte(bit)] &= ~_bit_mask(bit)
X
X /* clear bits start ... stop in bitstring */
X#define bit_nclear(name, start, stop) { \
X register bitstr_t *_name = name; \
X register int _start = start, _stop = stop; \
X register int _startbyte = _bit_byte(_start); \
X register int _stopbyte = _bit_byte(_stop); \
X if (_startbyte == _stopbyte) { \
X _name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \
X (0xff << ((_stop&0x7) + 1))); \
X } else { \
X _name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \
X while (++_startbyte < _stopbyte) \
X _name[_startbyte] = 0; \
X _name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \
X } \
X}
X
X /* set bits start ... stop in bitstring */
X#define bit_nset(name, start, stop) { \
X register bitstr_t *_name = name; \
X register int _start = start, _stop = stop; \
X register int _startbyte = _bit_byte(_start); \
X register int _stopbyte = _bit_byte(_stop); \
X if (_startbyte == _stopbyte) { \
X _name[_startbyte] |= ((0xff << (_start&0x7)) & \
X (0xff >> (7 - (_stop&0x7)))); \
X } else { \
X _name[_startbyte] |= 0xff << ((_start)&0x7); \
X while (++_startbyte < _stopbyte) \
X _name[_startbyte] = 0xff; \
X _name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \
X } \
X}
X
X /* find first bit clear in name */
X#define bit_ffc(name, nbits, value) { \
X register bitstr_t *_name = name; \
X register int _byte, _nbits = nbits; \
X register int _stopbyte = _bit_byte(_nbits), _value = -1; \
X for (_byte = 0; _byte <= _stopbyte; ++_byte) \
X if (_name[_byte] != 0xff) { \
X _value = _byte << 3; \
X for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \
X ++_value, _stopbyte >>= 1); \
X break; \
X } \
X *(value) = _value; \
X}
X
X /* find first bit set in name */
X#define bit_ffs(name, nbits, value) { \
X register bitstr_t *_name = name; \
X register int _byte, _nbits = nbits; \
X register int _stopbyte = _bit_byte(_nbits), _value = -1; \
X for (_byte = 0; _byte <= _stopbyte; ++_byte) \
X if (_name[_byte]) { \
X _value = _byte << 3; \
X for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \
X ++_value, _stopbyte >>= 1); \
X break; \
X } \
X *(value) = _value; \
X}
END_OF_FILE
if test 3957 -ne `wc -c <'bitstring.h'`; then
echo shar: \"'bitstring.h'\" unpacked with wrong size!
fi
# end of 'bitstring.h'
fi
if test -f 'compat.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'compat.c'\"
else
echo shar: Extracting \"'compat.c'\" \(5116 characters\)
sed "s/^X//" >'compat.c' <<'END_OF_FILE'
X/* Copyright 1988,1990,1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Id: compat.c,v 1.6 1994/01/15 20:43:43 vixie Exp $";
X#endif
X
X/* vix 30dec93 [broke this out of misc.c - see RCS log for history]
X * vix 15jan87 [added TIOCNOTTY, thanks csg@pyramid]
X */
X
X
X#include "cron.h"
X#ifdef NEED_GETDTABLESIZE
X# include <limits.h>
X#endif
X#if defined(NEED_SETSID) && defined(BSD)
X# include <sys/ioctl.h>
X#endif
X#include <errno.h>
X
X
X/* the code does not depend on any of vfork's
X * side-effects; it just uses it as a quick
X * fork-and-exec.
X */
X#ifdef NEED_VFORK
XPID_T
Xvfork() {
X return (fork());
X}
X#endif
X
X
X#ifdef NEED_STRDUP
Xchar *
Xstrdup(str)
X char *str;
X{
X char *temp;
X
X temp = malloc(strlen(str) + 1);
X (void) strcpy(temp, str);
X return temp;
X}
X#endif
X
X
X#ifdef NEED_STRERROR
Xchar *
Xstrerror(error)
X int error;
X{
X extern char *sys_errlist[];
X extern int sys_nerr;
X static char buf[32];
X
X if ((error <= sys_nerr) && (error > 0)) {
X return sys_errlist[error];
X }
X
X sprintf(buf, "Unknown error: %d", error);
X return buf;
X}
X#endif
X
X
X#ifdef NEED_STRCASECMP
Xint
Xstrcasecmp(left, right)
X char *left;
X char *right;
X{
X while (*left && (MkLower(*left) == MkLower(*right))) {
X left++;
X right++;
X }
X return MkLower(*left) - MkLower(*right);
X}
X#endif
X
X
X#ifdef NEED_SETSID
Xint
Xsetsid()
X{
X int newpgrp;
X# if defined(BSD)
X int fd;
X# if defined(POSIX)
X newpgrp = setpgid((pid_t)0, getpid());
X# else
X newpgrp = setpgrp(0, getpid());
X# endif
X if ((fd = open("/dev/tty", 2)) >= 0)
X {
X (void) ioctl(fd, TIOCNOTTY, (char*)0);
X (void) close(fd);
X }
X# else /*BSD*/
X newpgrp = setpgrp();
X
X (void) close(STDIN); (void) open("/dev/null", 0);
X (void) close(STDOUT); (void) open("/dev/null", 1);
X (void) close(STDERR); (void) open("/dev/null", 2);
X# endif /*BSD*/
X return newpgrp;
X}
X#endif /*NEED_SETSID*/
X
X
X#ifdef NEED_GETDTABLESIZE
Xint
Xgetdtablesize() {
X#ifdef _SC_OPEN_MAX
X return sysconf(_SC_OPEN_MAX);
X#else
X return _POSIX_OPEN_MAX;
X#endif
X}
X#endif
X
X
X#ifdef NEED_FLOCK
X/* The following flock() emulation snarfed intact *) from the HP-UX
X * "BSD to HP-UX porting tricks" maintained by
X * system@alchemy.chem.utoronto.ca (System Admin (Mike Peterson))
X * from the version "last updated: 11-Jan-1993"
X * Snarfage done by Jarkko Hietaniemi <Jarkko.Hietaniemi@hut.fi>
X * *) well, almost, had to K&R the function entry, HPUX "cc"
X * does not grok ANSI function prototypes */
X
X/*
X * flock (fd, operation)
X *
X * This routine performs some file locking like the BSD 'flock'
X * on the object described by the int file descriptor 'fd',
X * which must already be open.
X *
X * The operations that are available are:
X *
X * LOCK_SH - get a shared lock.
X * LOCK_EX - get an exclusive lock.
X * LOCK_NB - don't block (must be ORed with LOCK_SH or LOCK_EX).
X * LOCK_UN - release a lock.
X *
X * Return value: 0 if lock successful, -1 if failed.
X *
X * Note that whether the locks are enforced or advisory is
X * controlled by the presence or absence of the SETGID bit on
X * the executable.
X *
X * Note that there is no difference between shared and exclusive
X * locks, since the 'lockf' system call in SYSV doesn't make any
X * distinction.
X *
X * The file "<sys/file.h>" should be modified to contain the definitions
X * of the available operations, which must be added manually (see below
X * for the values).
X */
X
X/* this code has been reformatted by vixie */
X
Xint
Xflock(fd, operation)
X int fd;
X int operation;
X{
X int i;
X
X switch (operation) {
X case LOCK_SH: /* get a shared lock */
X case LOCK_EX: /* get an exclusive lock */
X i = lockf (fd, F_LOCK, 0);
X break;
X
X case LOCK_SH|LOCK_NB: /* get a non-blocking shared lock */
X case LOCK_EX|LOCK_NB: /* get a non-blocking exclusive lock */
X i = lockf (fd, F_TLOCK, 0);
X if (i == -1)
X if ((errno == EAGAIN) || (errno == EACCES))
X errno = EWOULDBLOCK;
X break;
X
X case LOCK_UN: /* unlock */
X i = lockf (fd, F_ULOCK, 0);
X break;
X
X default: /* can't decipher operation */
X i = -1;
X errno = EINVAL;
X break;
X }
X
X return (i);
X}
X#endif /*NEED_FLOCK*/
X
X
X#ifdef NEED_SETENV
Xint
Xsetenv(name, value, overwrite)
X char *name, *value;
X int overwrite;
X{
X char *tmp;
X
X if (overwrite && getenv(name))
X return -1;
X
X if (!(tmp = malloc(strlen(name) + strlen(value) + 2))) {
X errno = ENOMEM;
X return -1;
X }
X
X sprintf("%s=%s", name, value);
X return putenv(tmp); /* intentionally orphan 'tmp' storage */
X}
X#endif
END_OF_FILE
if test 5116 -ne `wc -c <'compat.c'`; then
echo shar: \"'compat.c'\" unpacked with wrong size!
fi
# end of 'compat.c'
fi
if test -f 'compat.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'compat.h'\"
else
echo shar: Extracting \"'compat.h'\" \(3224 characters\)
sed "s/^X//" >'compat.h' <<'END_OF_FILE'
X/* Copyright 1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X/*
X * $Id: compat.h,v 1.8 1994/01/15 20:43:43 vixie Exp $
X */
X
X#ifndef __P
X# ifdef __STDC__
X# define __P(x) x
X# else
X# define __P(x) ()
X# define const
X# endif
X#endif
X
X#if defined(UNIXPC) || defined(unixpc)
X# define UNIXPC 1
X# define ATT 1
X#endif
X
X#if defined(hpux) || defined(_hpux) || defined(__hpux)
X# define HPUX 1
X# define seteuid(e) setresuid(-1,e,-1)
X# define setreuid(r,e) setresuid(r,e,-1)
X#endif
X
X#if defined(_IBMR2)
X# define AIX 1
X#endif
X
X#if defined(__convex__)
X# define CONVEX 1
X#endif
X
X#if defined(sgi) || defined(_sgi) || defined(__sgi)
X# define IRIX 1
X/* IRIX 4 hdrs are broken: one cannot #include both <stdio.h>
X * and <stdlib.h> because they disagree on system(), perror().
X * Therefore we must zap the "const" keyword BEFORE including
X * either of them.
X */
X# define const
X#endif
X
X#if defined(_UNICOS)
X# define UNICOS 1
X#endif
X
X#ifndef POSIX
X# if (BSD >= 199103) || defined(__linux) || defined(ultrix) || defined(AIX) ||\
X defined(HPUX) || defined(CONVEX) || defined(IRIX)
X# define POSIX
X# endif
X#endif
X
X#ifndef BSD
X# if defined(ultrix)
X# define BSD 198902
X# endif
X#endif
X
X/*****************************************************************/
X
X#if !defined(BSD) && !defined(HPUX) && !defined(CONVEX) && !defined(__linux)
X# define NEED_VFORK
X#endif
X
X#if (!defined(BSD) || (BSD < 198902)) && !defined(__linux) && \
X !defined(IRIX) && !defined(NeXT) && !defined(HPUX)
X# define NEED_STRCASECMP
X#endif
X
X#if (!defined(BSD) || (BSD < 198911)) && !defined(__linux) &&\
X !defined(IRIX) && !defined(UNICOS) && !defined(HPUX)
X# define NEED_STRDUP
X#endif
X
X#if (!defined(BSD) || (BSD < 198911)) && !defined(POSIX) && !defined(NeXT)
X# define NEED_STRERROR
X#endif
X
X#if defined(HPUX) || defined(AIX) || defined(UNIXPC)
X# define NEED_FLOCK
X#endif
X
X#ifndef POSIX
X# define NEED_SETSID
X#endif
X
X#if (defined(POSIX) && !defined(BSD)) && !defined(__linux)
X# define NEED_GETDTABLESIZE
X#endif
X
X#if (BSD >= 199103)
X# define HAVE_SAVED_UIDS
X#endif
X
X#if !defined(ATT) && !defined(__linux) && !defined(IRIX) && !defined(UNICOS)
X# define USE_SIGCHLD
X#endif
X
X#if !defined(AIX) && !defined(UNICOS)
X# define SYS_TIME_H 1
X#else
X# define SYS_TIME_H 0
X#endif
X
X#if defined(BSD) && !defined(POSIX)
X# define USE_UTIMES
X#endif
X
X#if defined(AIX) || defined(HPUX) || defined(IRIX)
X# define NEED_SETENV
X#endif
X
X#if !defined(UNICOS) && !defined(UNIXPC)
X# define HAS_FCHOWN
X#endif
X
X#if !defined(UNICOS) && !defined(UNIXPC)
X# define HAS_FCHMOD
X#endif
END_OF_FILE
if test 3224 -ne `wc -c <'compat.h'`; then
echo shar: \"'compat.h'\" unpacked with wrong size!
fi
# end of 'compat.h'
fi
if test -f 'config.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'config.h'\"
else
echo shar: Extracting \"'config.h'\" \(2974 characters\)
sed "s/^X//" >'config.h' <<'END_OF_FILE'
X/* Copyright 1988,1990,1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X/* config.h - configurables for Vixie Cron
X *
X * $Id: config.h,v 2.6 1994/01/15 20:43:43 vixie Exp $
X */
X
X#if !defined(_PATH_SENDMAIL)
X# define _PATH_SENDMAIL "/usr/lib/sendmail"
X#endif /*SENDMAIL*/
X
X/*
X * these are site-dependent
X */
X
X#ifndef DEBUGGING
X#define DEBUGGING 1 /* 1 or 0 -- do you want debugging code built in? */
X#endif
X
X /*
X * choose one of these MAILCMD commands. I use
X * /bin/mail for speed; it makes biff bark but doesn't
X * do aliasing. /usr/lib/sendmail does aliasing but is
X * a hog for short messages. aliasing is not needed
X * if you make use of the MAILTO= feature in crontabs.
X * (hint: MAILTO= was added for this reason).
X */
X
X#define MAILCMD _PATH_SENDMAIL /*-*/
X#define MAILARGS "%s -FCronDaemon -odi -oem -or0s %s" /*-*/
X /* -Fx = set full-name of sender
X * -odi = Option Deliverymode Interactive
X * -oem = Option Errors Mailedtosender
X * -or0s = Option Readtimeout -- don't time out
X */
X
X/* #define MAILCMD "/bin/mail" /*-*/
X/* #define MAILARGS "%s -d %s" /*-*/
X /* -d = undocumented but common flag: deliver locally?
X */
X
X/* #define MAILCMD "/usr/mmdf/bin/submit" /*-*/
X/* #define MAILARGS "%s -mlrxto %s" /*-*/
X
X/* #define MAIL_DATE /*-*/
X /* should we include an ersatz Date: header in
X * generated mail? if you are using sendmail
X * for MAILCMD, it is better to let sendmail
X * generate the Date: header.
X */
X
X /* if ALLOW_FILE and DENY_FILE are not defined or are
X * defined but neither exists, should crontab(1) be
X * usable only by root?
X */
X/*#define ALLOW_ONLY_ROOT /*-*/
X
X /* if you want to use syslog(3) instead of appending
X * to CRONDIR/LOG_FILE (/var/cron/log, e.g.), define
X * SYSLOG here. Note that quite a bit of logging
X * info is written, and that you probably don't want
X * to use this on 4.2bsd since everything goes in
X * /usr/spool/mqueue/syslog. On 4.[34]bsd you can
X * tell /etc/syslog.conf to send cron's logging to
X * a separate file.
X *
X * Note that if this and LOG_FILE in "pathnames.h"
X * are both defined, then logging will go to both
X * places.
X */
X#define SYSLOG /*-*/
END_OF_FILE
if test 2974 -ne `wc -c <'config.h'`; then
echo shar: \"'config.h'\" unpacked with wrong size!
fi
# end of 'config.h'
fi
if test -f 'cron.8' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cron.8'\"
else
echo shar: Extracting \"'cron.8'\" \(2218 characters\)
sed "s/^X//" >'cron.8' <<'END_OF_FILE'
X.\"/* Copyright 1988,1990,1993 by Paul Vixie
X.\" * All rights reserved
X.\" *
X.\" * Distribute freely, except: don't remove my name from the source or
X.\" * documentation (don't take credit for my work), mark your changes (don't
X.\" * get me blamed for your possible bugs), don't alter or remove this
X.\" * notice. May be sold if buildable source is provided to buyer. No
X.\" * warrantee of any kind, express or implied, is included with this
X.\" * software; use at your own risk, responsibility for damages (if any) to
X.\" * anyone resulting from the use of this software rests entirely with the
X.\" * user.
X.\" *
X.\" * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X.\" * I'll try to keep a version up to date. I can be reached as follows:
X.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X.\" */
X.\"
X.\" $Id: cron.8,v 2.2 1993/12/28 08:34:43 vixie Exp $
X.\"
X.TH CRON 8 "20 December 1993"
X.UC 4
X.SH NAME
Xcron \- daemon to execute scheduled commands (Vixie Cron)
X.SH SYNOPSIS
Xcron
X.SH DESCRIPTION
X.I Cron
Xshould be started from /etc/rc or /etc/rc.local. It will return immediately,
Xso you don't need to start it with '&'.
X.PP
X.I Cron
Xsearches /var/cron/tabs for crontab files which are named after accounts in
X/etc/passwd; crontabs found are loaded into memory.
X.I Cron
Xalso searches for /etc/crontab which is in a different format (see
X.IR crontab(5)).
X.I Cron
Xthen wakes up every minute, examining all stored crontabs, checking each
Xcommand to see if it should be run in the current minute. When executing
Xcommands, any output is mailed to the owner of the crontab (or to the user
Xnamed in the MAILTO environment variable in the crontab, if such exists).
X.PP
XAdditionally,
X.I cron
Xchecks each minute to see if its spool directory's modtime (or the modtime
Xon
X.IR /etc/crontab)
Xhas changed, and if it has,
X.I cron
Xwill then examine the modtime on all crontabs and reload those which have
Xchanged. Thus
X.I cron
Xneed not be restarted whenever a crontab file is modified. Note that the
X.IR Crontab (1)
Xcommand updates the modtime of the spool directory whenever it changes a
Xcrontab.
X.SH "SEE ALSO"
Xcrontab(1), crontab(5)
X.SH AUTHOR
X.nf
XPaul Vixie <paul@vix.com>
END_OF_FILE
if test 2218 -ne `wc -c <'cron.8'`; then
echo shar: \"'cron.8'\" unpacked with wrong size!
fi
# end of 'cron.8'
fi
if test -f 'cron.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cron.c'\"
else
echo shar: Extracting \"'cron.c'\" \(6857 characters\)
sed "s/^X//" >'cron.c' <<'END_OF_FILE'
X/* Copyright 1988,1990,1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Id: cron.c,v 2.11 1994/01/15 20:43:43 vixie Exp $";
X#endif
X
X
X#define MAIN_PROGRAM
X
X
X#include "cron.h"
X#include <sys/signal.h>
X#if SYS_TIME_H
X# include <sys/time.h>
X#else
X# include <time.h>
X#endif
X
X
Xstatic void usage __P((void)),
X run_reboot_jobs __P((cron_db *)),
X cron_tick __P((cron_db *)),
X cron_sync __P((void)),
X cron_sleep __P((void)),
X#ifdef USE_SIGCHLD
X sigchld_handler __P((int)),
X#endif
X sighup_handler __P((int)),
X parse_args __P((int c, char *v[]));
X
X
Xstatic void
Xusage() {
X fprintf(stderr, "usage: %s [-x debugflag[,...]]\n", ProgramName);
X exit(ERROR_EXIT);
X}
X
X
Xint
Xmain(argc, argv)
X int argc;
X char *argv[];
X{
X cron_db database;
X
X ProgramName = argv[0];
X
X#if defined(BSD)
X setlinebuf(stdout);
X setlinebuf(stderr);
X#endif
X
X parse_args(argc, argv);
X
X#ifdef USE_SIGCHLD
X (void) signal(SIGCHLD, sigchld_handler);
X#else
X (void) signal(SIGCLD, SIG_IGN);
X#endif
X (void) signal(SIGHUP, sighup_handler);
X
X acquire_daemonlock(0);
X set_cron_uid();
X set_cron_cwd();
X
X#if defined(POSIX)
X setenv("PATH", _PATH_DEFPATH, 1);
X#endif
X
X /* if there are no debug flags turned on, fork as a daemon should.
X */
X# if DEBUGGING
X if (DebugFlags) {
X# else
X if (0) {
X# endif
X (void) fprintf(stderr, "[%d] cron started\n", getpid());
X } else {
X switch (fork()) {
X case -1:
X log_it("CRON",getpid(),"DEATH","can't fork");
X exit(0);
X break;
X case 0:
X /* child process */
X log_it("CRON",getpid(),"STARTUP","fork ok");
X (void) setsid();
X break;
X default:
X /* parent process should just die */
X _exit(0);
X }
X }
X
X acquire_daemonlock(0);
X database.head = NULL;
X database.tail = NULL;
X database.mtime = (time_t) 0;
X load_database(&database);
X run_reboot_jobs(&database);
X cron_sync();
X while (TRUE) {
X# if DEBUGGING
X if (!(DebugFlags & DTEST))
X# endif /*DEBUGGING*/
X cron_sleep();
X
X load_database(&database);
X
X /* do this iteration
X */
X cron_tick(&database);
X
X /* sleep 1 minute
X */
X TargetTime += 60;
X }
X}
X
X
Xstatic void
Xrun_reboot_jobs(db)
X cron_db *db;
X{
X register user *u;
X register entry *e;
X
X for (u = db->head; u != NULL; u = u->next) {
X for (e = u->crontab; e != NULL; e = e->next) {
X if (e->flags & WHEN_REBOOT) {
X job_add(e, u);
X }
X }
X }
X (void) job_runqueue();
X}
X
X
Xstatic void
Xcron_tick(db)
X cron_db *db;
X{
X register struct tm *tm = localtime(&TargetTime);
X register int minute, hour, dom, month, dow;
X register user *u;
X register entry *e;
X
X /* make 0-based values out of these so we can use them as indicies
X */
X minute = tm->tm_min -FIRST_MINUTE;
X hour = tm->tm_hour -FIRST_HOUR;
X dom = tm->tm_mday -FIRST_DOM;
X month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
X dow = tm->tm_wday -FIRST_DOW;
X
X Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
X getpid(), minute, hour, dom, month, dow))
X
X /* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
X * first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
X * on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
X * is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre.
X * like many bizarre things, it's the standard.
X */
X for (u = db->head; u != NULL; u = u->next) {
X for (e = u->crontab; e != NULL; e = e->next) {
X Debug(DSCH|DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n",
X env_get("LOGNAME", e->envp),
X e->uid, e->gid, e->cmd))
X if (bit_test(e->minute, minute)
X && bit_test(e->hour, hour)
X && bit_test(e->month, month)
X && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
X ? (bit_test(e->dow,dow) && bit_test(e->dom,dom))
X : (bit_test(e->dow,dow) || bit_test(e->dom,dom))
X )
X ) {
X job_add(e, u);
X }
X }
X }
X}
X
X
X/* the task here is to figure out how long it's going to be until :00 of the
X * following minute and initialize TargetTime to this value. TargetTime
X * will subsequently slide 60 seconds at a time, with correction applied
X * implicitly in cron_sleep(). it would be nice to let cron execute in
X * the "current minute" before going to sleep, but by restarting cron you
X * could then get it to execute a given minute's jobs more than once.
X * instead we have the chance of missing a minute's jobs completely, but
X * that's something sysadmin's know to expect what with crashing computers..
X */
Xstatic void
Xcron_sync() {
X register struct tm *tm;
X
X TargetTime = time((time_t*)0);
X tm = localtime(&TargetTime);
X TargetTime += (60 - tm->tm_sec);
X}
X
X
Xstatic void
Xcron_sleep() {
X register int seconds_to_wait;
X
X do {
X seconds_to_wait = (int) (TargetTime - time((time_t*)0));
X Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
X getpid(), TargetTime, seconds_to_wait))
X
X /* if we intend to sleep, this means that it's finally
X * time to empty the job queue (execute it).
X *
X * if we run any jobs, we'll probably screw up our timing,
X * so go recompute.
X *
X * note that we depend here on the left-to-right nature
X * of &&, and the short-circuiting.
X */
X } while (seconds_to_wait > 0 && job_runqueue());
X
X while (seconds_to_wait > 0) {
X Debug(DSCH, ("[%d] sleeping for %d seconds\n",
X getpid(), seconds_to_wait))
X seconds_to_wait = (int) sleep((unsigned int) seconds_to_wait);
X }
X}
X
X
X#ifdef USE_SIGCHLD
Xstatic void
Xsigchld_handler(x) {
X WAIT_T waiter;
X PID_T pid;
X
X for (;;) {
X#ifdef POSIX
X pid = waitpid(-1, &waiter, WNOHANG);
X#else
X pid = wait3(&waiter, WNOHANG, (struct rusage *)0);
X#endif
X switch (pid) {
X case -1:
X Debug(DPROC,
X ("[%d] sigchld...no children\n", getpid()))
X return;
X case 0:
X Debug(DPROC,
X ("[%d] sigchld...no dead kids\n", getpid()))
X return;
X default:
X Debug(DPROC,
X ("[%d] sigchld...pid #%d died, stat=%d\n",
X getpid(), pid, WEXITSTATUS(waiter)))
X }
X }
X}
X#endif /*USE_SIGCHLD*/
X
X
Xstatic void
Xsighup_handler(x) {
X log_close();
X}
X
X
Xstatic void
Xparse_args(argc, argv)
X int argc;
X char *argv[];
X{
X int argch;
X
X while (EOF != (argch = getopt(argc, argv, "x:"))) {
X switch (argch) {
X default:
X usage();
X case 'x':
X if (!set_debug_flags(optarg))
X usage();
X break;
X }
X }
X}
END_OF_FILE
if test 6857 -ne `wc -c <'cron.c'`; then
echo shar: \"'cron.c'\" unpacked with wrong size!
fi
# end of 'cron.c'
fi
if test -f 'cron.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cron.h'\"
else
echo shar: Extracting \"'cron.h'\" \(7715 characters\)
sed "s/^X//" >'cron.h' <<'END_OF_FILE'
X/* Copyright 1988,1990,1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X/* cron.h - header for vixie's cron
X *
X * $Id: cron.h,v 2.10 1994/01/15 20:43:43 vixie Exp $
X *
X * vix 14nov88 [rest of log is in RCS]
X * vix 14jan87 [0 or 7 can be sunday; thanks, mwm@berkeley]
X * vix 30dec86 [written]
X */
X
X/* reorder these #include's at your peril */
X
X#include <sys/types.h>
X#include <sys/param.h>
X#include "compat.h"
X
X#include <stdio.h>
X#include <ctype.h>
X#include <bitstring.h>
X#include <pwd.h>
X#include <sys/wait.h>
X
X#include "pathnames.h"
X#include "config.h"
X#include "externs.h"
X
X /* these are really immutable, and are
X * defined for symbolic convenience only
X * TRUE, FALSE, and ERR must be distinct
X * ERR must be < OK.
X */
X#define TRUE 1
X#define FALSE 0
X /* system calls return this on success */
X#define OK 0
X /* or this on error */
X#define ERR (-1)
X
X /* turn this on to get '-x' code */
X#ifndef DEBUGGING
X#define DEBUGGING FALSE
X#endif
X
X#define READ_PIPE 0 /* which end of a pipe pair do you read? */
X#define WRITE_PIPE 1 /* or write to? */
X#define STDIN 0 /* what is stdin's file descriptor? */
X#define STDOUT 1 /* stdout's? */
X#define STDERR 2 /* stderr's? */
X#define ERROR_EXIT 1 /* exit() with this will scare the shell */
X#define OK_EXIT 0 /* exit() with this is considered 'normal' */
X#define MAX_FNAME 100 /* max length of internally generated fn */
X#define MAX_COMMAND 1000 /* max length of internally generated cmd */
X#define MAX_ENVSTR 1000 /* max length of envvar=value\0 strings */
X#define MAX_TEMPSTR 100 /* obvious */
X#define MAX_UNAME 20 /* max length of username, should be overkill */
X#define ROOT_UID 0 /* don't change this, it really must be root */
X#define ROOT_USER "root" /* ditto */
X
X /* NOTE: these correspond to DebugFlagNames,
X * defined below.
X */
X#define DEXT 0x0001 /* extend flag for other debug masks */
X#define DSCH 0x0002 /* scheduling debug mask */
X#define DPROC 0x0004 /* process control debug mask */
X#define DPARS 0x0008 /* parsing debug mask */
X#define DLOAD 0x0010 /* database loading debug mask */
X#define DMISC 0x0020 /* misc debug mask */
X#define DTEST 0x0040 /* test mode: don't execute any commands */
X#define DBIT 0x0080 /* bit twiddling shown (long) */
X
X#define CRON_TAB(u) "%s/%s", SPOOL_DIR, u
X#define REG register
X#define PPC_NULL ((char **)NULL)
X
X#ifndef MAXHOSTNAMELEN
X#define MAXHOSTNAMELEN 64
X#endif
X
X#define Skip_Blanks(c, f) \
X while (c == '\t' || c == ' ') \
X c = get_char(f);
X
X#define Skip_Nonblanks(c, f) \
X while (c!='\t' && c!=' ' && c!='\n' && c != EOF) \
X c = get_char(f);
X
X#define Skip_Line(c, f) \
X do {c = get_char(f);} while (c != '\n' && c != EOF);
X
X#if DEBUGGING
X# define Debug(mask, message) \
X if ( (DebugFlags & (mask) ) == (mask) ) \
X printf message;
X#else /* !DEBUGGING */
X# define Debug(mask, message) \
X ;
X#endif /* DEBUGGING */
X
X#define MkLower(ch) (isupper(ch) ? tolower(ch) : ch)
X#define MkUpper(ch) (islower(ch) ? toupper(ch) : ch)
X#define Set_LineNum(ln) {Debug(DPARS|DEXT,("linenum=%d\n",ln)); \
X LineNumber = ln; \
X }
X
X#define FIRST_MINUTE 0
X#define LAST_MINUTE 59
X#define MINUTE_COUNT (LAST_MINUTE - FIRST_MINUTE + 1)
X
X#define FIRST_HOUR 0
X#define LAST_HOUR 23
X#define HOUR_COUNT (LAST_HOUR - FIRST_HOUR + 1)
X
X#define FIRST_DOM 1
X#define LAST_DOM 31
X#define DOM_COUNT (LAST_DOM - FIRST_DOM + 1)
X
X#define FIRST_MONTH 1
X#define LAST_MONTH 12
X#define MONTH_COUNT (LAST_MONTH - FIRST_MONTH + 1)
X
X/* note on DOW: 0 and 7 are both Sunday, for compatibility reasons. */
X#define FIRST_DOW 0
X#define LAST_DOW 7
X#define DOW_COUNT (LAST_DOW - FIRST_DOW + 1)
X
X /* each user's crontab will be held as a list of
X * the following structure.
X *
X * These are the cron commands.
X */
X
Xtypedef struct _entry {
X struct _entry *next;
X uid_t uid;
X gid_t gid;
X char **envp;
X char *cmd;
X bitstr_t bit_decl(minute, MINUTE_COUNT);
X bitstr_t bit_decl(hour, HOUR_COUNT);
X bitstr_t bit_decl(dom, DOM_COUNT);
X bitstr_t bit_decl(month, MONTH_COUNT);
X bitstr_t bit_decl(dow, DOW_COUNT);
X int flags;
X#define DOM_STAR 0x01
X#define DOW_STAR 0x02
X#define WHEN_REBOOT 0x04
X} entry;
X
X /* the crontab database will be a list of the
X * following structure, one element per user
X * plus one for the system.
X *
X * These are the crontabs.
X */
X
Xtypedef struct _user {
X struct _user *next, *prev; /* links */
X char *name;
X time_t mtime; /* last modtime of crontab */
X entry *crontab; /* this person's crontab */
X} user;
X
Xtypedef struct _cron_db {
X user *head, *tail; /* links */
X time_t mtime; /* last modtime on spooldir */
X} cron_db;
X
X
Xvoid set_cron_uid __P((void)),
X set_cron_cwd __P((void)),
X load_database __P((cron_db *)),
X open_logfile __P((void)),
X sigpipe_func __P((void)),
X job_add __P((entry *, user *)),
X do_command __P((entry *, user *)),
X link_user __P((cron_db *, user *)),
X unlink_user __P((cron_db *, user *)),
X free_user __P((user *)),
X env_free __P((char **)),
X unget_char __P((int, FILE *)),
X free_entry __P((entry *)),
X acquire_daemonlock __P((int)),
X skip_comments __P((FILE *)),
X log_it __P((char *, int, char *, char *)),
X log_close __P((void));
X
Xint job_runqueue __P((void)),
X set_debug_flags __P((char *)),
X get_char __P((FILE *)),
X get_string __P((char *, int, FILE *, char *)),
X swap_uids __P((void)),
X load_env __P((char *, FILE *)),
X cron_pclose __P((FILE *)),
X strcmp_until __P((char *, char *, int)),
X allowed __P((char *)),
X strdtb __P((char *));
X
Xchar *env_get __P((char *, char **)),
X *arpadate __P((time_t *)),
X *mkprints __P((unsigned char *, unsigned int)),
X *first_word __P((char *, char *)),
X **env_init __P((void)),
X **env_copy __P((char **)),
X **env_set __P((char **, char *));
X
Xuser *load_user __P((int, struct passwd *, char *)),
X *find_user __P((cron_db *, char *));
X
Xentry *load_entry __P((FILE *, void (*)(),
X struct passwd *, char **));
X
XFILE *cron_popen __P((char *, char *));
X
X
X /* in the C tradition, we only create
X * variables for the main program, just
X * extern them elsewhere.
X */
X
X#ifdef MAIN_PROGRAM
X# if !defined(LINT) && !defined(lint)
Xchar *copyright[] = {
X "@(#) Copyright 1988,1989,1990,1993,1994 by Paul Vixie",
X "@(#) All rights reserved"
X };
X# endif
X
Xchar *MonthNames[] = {
X "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
X NULL
X };
X
Xchar *DowNames[] = {
X "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
X NULL
X };
X
Xchar *ProgramName;
Xint LineNumber;
Xtime_t TargetTime;
X
X# if DEBUGGING
Xint DebugFlags;
Xchar *DebugFlagNames[] = { /* sync with #defines */
X "ext", "sch", "proc", "pars", "load", "misc", "test", "bit",
X NULL /* NULL must be last element */
X };
X# endif /* DEBUGGING */
X#else /*MAIN_PROGRAM*/
Xextern char *copyright[],
X *MonthNames[],
X *DowNames[],
X *ProgramName;
Xextern int LineNumber;
Xextern time_t TargetTime;
X# if DEBUGGING
Xextern int DebugFlags;
Xextern char *DebugFlagNames[];
X# endif /* DEBUGGING */
X#endif /*MAIN_PROGRAM*/
END_OF_FILE
if test 7715 -ne `wc -c <'cron.h'`; then
echo shar: \"'cron.h'\" unpacked with wrong size!
fi
# end of 'cron.h'
fi
if test -f 'crontab.1' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'crontab.1'\"
else
echo shar: Extracting \"'crontab.1'\" \(3140 characters\)
sed "s/^X//" >'crontab.1' <<'END_OF_FILE'
X.\"/* Copyright 1988,1990,1993 by Paul Vixie
X.\" * All rights reserved
X.\" *
X.\" * Distribute freely, except: don't remove my name from the source or
X.\" * documentation (don't take credit for my work), mark your changes (don't
X.\" * get me blamed for your possible bugs), don't alter or remove this
X.\" * notice. May be sold if buildable source is provided to buyer. No
X.\" * warrantee of any kind, express or implied, is included with this
X.\" * software; use at your own risk, responsibility for damages (if any) to
X.\" * anyone resulting from the use of this software rests entirely with the
X.\" * user.
X.\" *
X.\" * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X.\" * I'll try to keep a version up to date. I can be reached as follows:
X.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X.\" */
X.\"
X.\" $Id: crontab.1,v 2.4 1993/12/31 10:47:33 vixie Exp $
X.\"
X.TH CRONTAB 1 "29 December 1993"
X.UC 4
X.SH NAME
Xcrontab \- maintain crontab files for individual users (V3)
X.SH SYNOPSIS
Xcrontab [ -u user ] file
X.br
Xcrontab [ -u user ] { -l | -r | -e }
X.SH DESCRIPTION
X.I Crontab
Xis the program used to install, deinstall or list the tables
Xused to drive the
X.IR cron (8)
Xdaemon in Vixie Cron. Each user can have their own crontab, and though
Xthese are files in /var, they are not intended to be edited directly.
X.PP
XIf the
X.I allow
Xfile exists, then you must be listed therein in order to be allowed to use
Xthis command. If the
X.I allow
Xfile does not exist but the
X.I deny
Xfile does exist, then you must \fBnot\fR be listed in the
X.I deny
Xfile in order to use this command. If neither of these files exists, then
Xdepending on site-dependent configuration parameters, only the super user
Xwill be allowed to use this command, or all users will be able to use this
Xcommand.
X.PP
XIf the
X.I -u
Xoption is given, it specifies the name of the user whose crontab is to be
Xtweaked. If this option is not given,
X.I crontab
Xexamines "your" crontab, i.e., the crontab of the person executing the
Xcommand. Note that
X.IR su (8)
Xcan confuse
X.I crontab
Xand that if you are running inside of
X.IR su (8)
Xyou should always use the
X.I -u
Xoption for safety's sake.
X.PP
XThe first form of this command is used to install a new crontab from some
Xnamed file or standard input if the pseudo-filename ``-'' is given.
X.PP
XThe
X.I -l
Xoption causes the current crontab to be displayed on standard output.
X.PP
XThe
X.I -r
Xoption causes the current crontab to be removed.
X.PP
XThe
X.I -e
Xoption is used to edit the current crontab using the editor specified by
Xthe \s-1VISUAL\s+1 or \s-1EDITOR\s+1 environment variables. After you exit
Xfrom the editor, the modified crontab will be installed automatically.
X.SH "SEE ALSO"
Xcrontab(5), cron(8)
X.SH FILES
X.nf
X/var/cron/allow
X/var/cron/deny
X.fi
X.SH STANDARDS
XThe
X.I crontab
Xcommand conforms to IEEE Std1003.2-1992 (``POSIX''). This new command syntax
Xdiffers from previous versions of Vixie Cron, as well as from the classic
XSVR3 syntax.
X.SH DIAGNOSTICS
XA fairly informative usage message appears if you run it with a bad command
Xline.
X.SH AUTHOR
X.nf
XPaul Vixie <paul@vix.com>
END_OF_FILE
if test 3140 -ne `wc -c <'crontab.1'`; then
echo shar: \"'crontab.1'\" unpacked with wrong size!
fi
# end of 'crontab.1'
fi
if test -f 'crontab.5' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'crontab.5'\"
else
echo shar: Extracting \"'crontab.5'\" \(7184 characters\)
sed "s/^X//" >'crontab.5' <<'END_OF_FILE'
X.\"/* Copyright 1988,1990,1993,1994 by Paul Vixie
X.\" * All rights reserved
X.\" *
X.\" * Distribute freely, except: don't remove my name from the source or
X.\" * documentation (don't take credit for my work), mark your changes (don't
X.\" * get me blamed for your possible bugs), don't alter or remove this
X.\" * notice. May be sold if buildable source is provided to buyer. No
X.\" * warrantee of any kind, express or implied, is included with this
X.\" * software; use at your own risk, responsibility for damages (if any) to
X.\" * anyone resulting from the use of this software rests entirely with the
X.\" * user.
X.\" *
X.\" * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X.\" * I'll try to keep a version up to date. I can be reached as follows:
X.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X.\" */
X.\"
X.\" $Id: crontab.5,v 2.4 1994/01/15 20:43:43 vixie Exp $
X.\"
X.TH CRONTAB 5 "7 January 1994"
X.UC 4
X.SH NAME
Xcrontab \- tables for driving cron
X.SH DESCRIPTION
XA
X.I crontab
Xfile contains instructions to the
X.IR cron (8)
Xdaemon of the general form: ``run this command at this time on this date''.
XEach user has their own crontab, and commands in any given crontab will be
Xexecuted as the user who owns the crontab. Uucp and News will usually have
Xtheir own crontabs, eliminating the need for explicitly running
X.IR su (1)
Xas part of a cron command.
X.PP
XBlank lines and leading spaces and tabs are ignored. Lines whose first
Xnon-space character is a pound-sign (#) are comments, and are ignored.
XNote that comments are not allowed on the same line as cron commands, since
Xthey will be taken to be part of the command. Similarly, comments are not
Xallowed on the same line as environment variable settings.
X.PP
XAn active line in a crontab will be either an environment setting or a cron
Xcommand. An environment setting is of the form,
X.PP
X name = value
X.PP
Xwhere the spaces around the equal-sign (=) are optional, and any subsequent
Xnon-leading spaces in
X.I value
Xwill be part of the value assigned to
X.IR name .
XThe
X.I value
Xstring may be placed in quotes (single or double, but matching) to preserve
Xleading or trailing blanks.
X.PP
XSeveral environment variables are set up
Xautomatically by the
X.IR cron (8)
Xdaemon.
XSHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd
Xline of the crontab's owner.
XHOME and SHELL may be overridden by settings in the crontab; LOGNAME may not.
X.PP
X(Another note: the LOGNAME variable is sometimes called USER on BSD systems...
Xon these systems, USER will be set also.)
X.PP
XIn addition to LOGNAME, HOME, and SHELL,
X.IR cron (8)
Xwill look at MAILTO if it has any reason to send mail as a result of running
Xcommands in ``this'' crontab. If MAILTO is defined (and non-empty), mail is
Xsent to the user so named. If MAILTO is defined but empty (MAILTO=""), no
Xmail will be sent. Otherwise mail is sent to the owner of the crontab. This
Xoption is useful if you decide on /bin/mail instead of /usr/lib/sendmail as
Xyour mailer when you install cron -- /bin/mail doesn't do aliasing, and UUCP
Xusually doesn't read its mail.
X.PP
XThe format of a cron command is very much the V7 standard, with a number of
Xupward-compatible extensions. Each line has five time and date fields,
Xfollowed by a command. Commands are executed by
X.IR cron (8)
Xwhen the minute, hour, and month of year fields match the current time,
X.I and
Xwhen at least one of the two day fields (day of month, or day of week)
Xmatch the current time (see ``Note'' below).
X.IR cron (8)
Xexamines cron entries once every minute.
XThe time and date fields are:
X.IP
X.ta 1.5i
Xfield allowed values
X.br
X----- --------------
X.br
Xminute 0-59
X.br
Xhour 0-23
X.br
Xday of month 0-31
X.br
Xmonth 0-12 (or names, see below)
X.br
Xday of week 0-7 (0 or 7 is Sun, or use names)
X.br
X.PP
XA field may be an asterisk (*), which always stands for ``first\-last''.
X.PP
XRanges of numbers are allowed. Ranges are two numbers separated
Xwith a hyphen. The specified range is inclusive. For example,
X8-11 for an ``hours'' entry specifies execution at hours 8, 9, 10
Xand 11.
X.PP
XLists are allowed. A list is a set of numbers (or ranges)
Xseparated by commas. Examples: ``1,2,5,9'', ``0-4,8-12''.
X.PP
XStep values can be used in conjunction with ranges. Following
Xa range with ``/<number>'' specifies skips of the number's value
Xthrough the range. For example, ``0-23/2'' can be used in the hours
Xfield to specify command execution every other hour (the alternative
Xin the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22''). Steps are
Xalso permitted after an asterisk, so if you want to say ``every two
Xhours'', just use ``*/2''.
X.PP
XNames can also be used for the ``month'' and ``day of week''
Xfields. Use the first three letters of the particular
Xday or month (case doesn't matter). Ranges or
Xlists of names are not allowed.
X.PP
XThe ``sixth'' field (the rest of the line) specifies the command to be
Xrun.
XThe entire command portion of the line, up to a newline or %
Xcharacter, will be executed by the user's login shell or by the shell
Xspecified in the SHELL variable of the cronfile.
XPercent-signs (%) in the command, unless escaped with backslash
X(\\), will be changed into newline characters, and all data
Xafter the first % will be sent to the command as standard
Xinput.
X.PP
XNote: The day of a command's execution can be specified by two
Xfields \(em day of month, and day of week. If both fields are
Xrestricted (ie, aren't *), the command will be run when
X.I either
Xfield matches the current time. For example,
X.br
X``30 4 1,15 * 5''
Xwould cause a command to be run at 4:30 am on the 1st and 15th of each
Xmonth, plus every Friday.
X.SH EXAMPLE CRON FILE
X.nf
X
X# use /bin/sh to run commands, no matter what /etc/passwd says
XSHELL=/bin/sh
X# mail any output to `paul', no matter whose crontab this is
XMAILTO=paul
X#
X# run five minutes after midnight, every day
X5 0 * * * $HOME/bin/daily.job >> $HOME/tmp/out 2>&1
X# run at 2:15pm on the first of every month -- output mailed to paul
X15 14 1 * * $HOME/bin/monthly
X# run at 10 pm on weekdays, annoy Joe
X0 22 * * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
X23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
X5 4 * * sun echo "run at 5 after 4 every sunday"
X.fi
X.SH SEE ALSO
Xcron(8), crontab(1)
X.SH EXTENSIONS
XWhen specifying day of week, both day 0 and day 7 will be considered Sunday.
XBSD and ATT seem to disagree about this.
X.PP
XLists and ranges are allowed to co-exist in the same field. "1-3,7-9" would
Xbe rejected by ATT or BSD cron -- they want to see "1-3" or "7,8,9" ONLY.
X.PP
XRanges can include "steps", so "1-9/2" is the same as "1,3,5,7,9".
X.PP
XNames of months or days of the week can be specified by name.
X.PP
XEnvironment variables can be set in the crontab. In BSD or ATT, the
Xenvironment handed to child processes is basically the one from /etc/rc.
X.PP
XCommand output is mailed to the crontab owner (BSD can't do this), can be
Xmailed to a person other than the crontab owner (SysV can't do this), or the
Xfeature can be turned off and no mail will be sent at all (SysV can't do this
Xeither).
X.SH AUTHOR
X.nf
XPaul Vixie <paul@vix.com>
END_OF_FILE
if test 7184 -ne `wc -c <'crontab.5'`; then
echo shar: \"'crontab.5'\" unpacked with wrong size!
fi
# end of 'crontab.5'
fi
if test -f 'database.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'database.c'\"
else
echo shar: Extracting \"'database.c'\" \(6518 characters\)
sed "s/^X//" >'database.c' <<'END_OF_FILE'
X/* Copyright 1988,1990,1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Id: database.c,v 2.8 1994/01/15 20:43:43 vixie Exp $";
X#endif
X
X/* vix 26jan87 [RCS has the log]
X */
X
X
X#include "cron.h"
X#include <fcntl.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X
X
X#define TMAX(a,b) ((a)>(b)?(a):(b))
X
X
Xstatic void process_crontab __P((char *, char *, char *,
X struct stat *,
X cron_db *, cron_db *));
X
X
Xvoid
Xload_database(old_db)
X cron_db *old_db;
X{
X DIR *dir;
X struct stat statbuf;
X struct stat syscron_stat;
X DIR_T *dp;
X cron_db new_db;
X user *u, *nu;
X
X Debug(DLOAD, ("[%d] load_database()\n", getpid()))
X
X /* before we start loading any data, do a stat on SPOOL_DIR
X * so that if anything changes as of this moment (i.e., before we've
X * cached any of the database), we'll see the changes next time.
X */
X if (stat(SPOOL_DIR, &statbuf) < OK) {
X log_it("CRON", getpid(), "STAT FAILED", SPOOL_DIR);
X (void) exit(ERROR_EXIT);
X }
X
X /* track system crontab file
X */
X if (stat(SYSCRONTAB, &syscron_stat) < OK)
X syscron_stat.st_mtime = 0;
X
X /* if spooldir's mtime has not changed, we don't need to fiddle with
X * the database.
X *
X * Note that old_db->mtime is initialized to 0 in main(), and
X * so is guaranteed to be different than the stat() mtime the first
X * time this function is called.
X */
X if (old_db->mtime == TMAX(statbuf.st_mtime, syscron_stat.st_mtime)) {
X Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n",
X getpid()))
X return;
X }
X
X /* something's different. make a new database, moving unchanged
X * elements from the old database, reloading elements that have
X * actually changed. Whatever is left in the old database when
X * we're done is chaff -- crontabs that disappeared.
X */
X new_db.mtime = TMAX(statbuf.st_mtime, syscron_stat.st_mtime);
X new_db.head = new_db.tail = NULL;
X
X if (syscron_stat.st_mtime) {
X process_crontab("root", "*system*",
X SYSCRONTAB, &syscron_stat,
X &new_db, old_db);
X }
X
X /* we used to keep this dir open all the time, for the sake of
X * efficiency. however, we need to close it in every fork, and
X * we fork a lot more often than the mtime of the dir changes.
X */
X if (!(dir = opendir(SPOOL_DIR))) {
X log_it("CRON", getpid(), "OPENDIR FAILED", SPOOL_DIR);
X (void) exit(ERROR_EXIT);
X }
X
X while (NULL != (dp = readdir(dir))) {
X char fname[MAXNAMLEN+1],
X tabname[MAXNAMLEN+1];
X
X /* avoid file names beginning with ".". this is good
X * because we would otherwise waste two guaranteed calls
X * to getpwnam() for . and .., and also because user names
X * starting with a period are just too nasty to consider.
X */
X if (dp->d_name[0] == '.')
X continue;
X
X (void) strcpy(fname, dp->d_name);
X sprintf(tabname, CRON_TAB(fname));
X
X process_crontab(fname, fname, tabname,
X &statbuf, &new_db, old_db);
X }
X closedir(dir);
X
X /* if we don't do this, then when our children eventually call
X * getpwnam() in do_command.c's child_process to verify MAILTO=,
X * they will screw us up (and v-v).
X */
X endpwent();
X
X /* whatever's left in the old database is now junk.
X */
X Debug(DLOAD, ("unlinking old database:\n"))
X for (u = old_db->head; u != NULL; u = nu) {
X Debug(DLOAD, ("\t%s\n", u->name))
X nu = u->next;
X unlink_user(old_db, u);
X free_user(u);
X }
X
X /* overwrite the database control block with the new one.
X */
X *old_db = new_db;
X Debug(DLOAD, ("load_database is done\n"))
X}
X
X
Xvoid
Xlink_user(db, u)
X cron_db *db;
X user *u;
X{
X if (db->head == NULL)
X db->head = u;
X if (db->tail)
X db->tail->next = u;
X u->prev = db->tail;
X u->next = NULL;
X db->tail = u;
X}
X
X
Xvoid
Xunlink_user(db, u)
X cron_db *db;
X user *u;
X{
X if (u->prev == NULL)
X db->head = u->next;
X else
X u->prev->next = u->next;
X
X if (u->next == NULL)
X db->tail = u->prev;
X else
X u->next->prev = u->prev;
X}
X
X
Xuser *
Xfind_user(db, name)
X cron_db *db;
X char *name;
X{
X char *env_get();
X user *u;
X
X for (u = db->head; u != NULL; u = u->next)
X if (!strcmp(u->name, name))
X break;
X return u;
X}
X
X
Xstatic void
Xprocess_crontab(uname, fname, tabname, statbuf, new_db, old_db)
X char *uname;
X char *fname;
X char *tabname;
X struct stat *statbuf;
X cron_db *new_db;
X cron_db *old_db;
X{
X struct passwd *pw = NULL;
X int crontab_fd = OK - 1;
X user *u;
X
X if (strcmp(fname, "*system*") && !(pw = getpwnam(uname))) {
X /* file doesn't have a user in passwd file.
X */
X log_it(fname, getpid(), "ORPHAN", "no passwd entry");
X goto next_crontab;
X }
X
X if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
X /* crontab not accessible?
X */
X log_it(fname, getpid(), "CAN'T OPEN", tabname);
X goto next_crontab;
X }
X
X if (fstat(crontab_fd, statbuf) < OK) {
X log_it(fname, getpid(), "FSTAT FAILED", tabname);
X goto next_crontab;
X }
X
X Debug(DLOAD, ("\t%s:", fname))
X u = find_user(old_db, fname);
X if (u != NULL) {
X /* if crontab has not changed since we last read it
X * in, then we can just use our existing entry.
X */
X if (u->mtime == statbuf->st_mtime) {
X Debug(DLOAD, (" [no change, using old data]"))
X unlink_user(old_db, u);
X link_user(new_db, u);
X goto next_crontab;
X }
X
X /* before we fall through to the code that will reload
X * the user, let's deallocate and unlink the user in
X * the old database. This is more a point of memory
X * efficiency than anything else, since all leftover
X * users will be deleted from the old database when
X * we finish with the crontab...
X */
X Debug(DLOAD, (" [delete old data]"))
X unlink_user(old_db, u);
X free_user(u);
X log_it(fname, getpid(), "RELOAD", tabname);
X }
X u = load_user(crontab_fd, pw, fname);
X if (u != NULL) {
X u->mtime = statbuf->st_mtime;
X link_user(new_db, u);
X }
X
Xnext_crontab:
X if (crontab_fd >= OK) {
X Debug(DLOAD, (" [done]\n"))
X close(crontab_fd);
X }
X}
END_OF_FILE
if test 6518 -ne `wc -c <'database.c'`; then
echo shar: \"'database.c'\" unpacked with wrong size!
fi
# end of 'database.c'
fi
if test -f 'env.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'env.c'\"
else
echo shar: Extracting \"'env.c'\" \(3731 characters\)
sed "s/^X//" >'env.c' <<'END_OF_FILE'
X/* Copyright 1988,1990,1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Id: env.c,v 2.6 1994/01/15 20:43:43 vixie Exp $";
X#endif
X
X
X#include "cron.h"
X
X
Xchar **
Xenv_init()
X{
X register char **p = (char **) malloc(sizeof(char **));
X
X p[0] = NULL;
X return p;
X}
X
X
Xvoid
Xenv_free(envp)
X char **envp;
X{
X char **p;
X
X for (p = envp; *p; p++)
X free(*p);
X free(envp);
X}
X
X
Xchar **
Xenv_copy(envp)
X register char **envp;
X{
X register int count, i;
X register char **p;
X
X for (count = 0; envp[count] != NULL; count++)
X ;
X p = (char **) malloc((count+1) * sizeof(char *)); /* 1 for the NULL */
X for (i = 0; i < count; i++)
X p[i] = strdup(envp[i]);
X p[count] = NULL;
X return p;
X}
X
X
Xchar **
Xenv_set(envp, envstr)
X char **envp;
X char *envstr;
X{
X register int count, found;
X register char **p;
X
X /*
X * count the number of elements, including the null pointer;
X * also set 'found' to -1 or index of entry if already in here.
X */
X found = -1;
X for (count = 0; envp[count] != NULL; count++) {
X if (!strcmp_until(envp[count], envstr, '='))
X found = count;
X }
X count++; /* for the NULL */
X
X if (found != -1) {
X /*
X * it exists already, so just free the existing setting,
X * save our new one there, and return the existing array.
X */
X free(envp[found]);
X envp[found] = strdup(envstr);
X return envp;
X }
X
X /*
X * it doesn't exist yet, so resize the array, move null pointer over
X * one, save our string over the old null pointer, and return resized
X * array.
X */
X p = (char **) realloc((void *) envp,
X (unsigned) ((count+1) * sizeof(char **)));
X p[count] = p[count-1];
X p[count-1] = strdup(envstr);
X return p;
X}
X
X
X/* return ERR = end of file
X * FALSE = not an env setting (file was repositioned)
X * TRUE = was an env setting
X */
Xint
Xload_env(envstr, f)
X char *envstr;
X FILE *f;
X{
X long filepos;
X int fileline;
X char name[MAX_TEMPSTR], val[MAX_ENVSTR];
X int fields;
X
X filepos = ftell(f);
X fileline = LineNumber;
X skip_comments(f);
X if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
X return ERR;
X
X Debug(DPARS, ("load_env, read <%s>\n", envstr))
X
X name[0] = val[0] = '\0';
X fields = sscanf(envstr, "%[^ =] = %[^\n#]", name, val);
X if (fields != 2) {
X Debug(DPARS, ("load_env, not 2 fields (%d)\n", fields))
X fseek(f, filepos, 0);
X Set_LineNum(fileline);
X return FALSE;
X }
X
X /* 2 fields from scanf; looks like an env setting
X */
X
X /*
X * process value string
X */
X /*local*/{
X int len = strdtb(val);
X
X if (len >= 2) {
X if (val[0] == '\'' || val[0] == '"') {
X if (val[len-1] == val[0]) {
X val[len-1] = '\0';
X (void) strcpy(val, val+1);
X }
X }
X }
X }
X
X (void) sprintf(envstr, "%s=%s", name, val);
X Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr))
X return TRUE;
X}
X
X
Xchar *
Xenv_get(name, envp)
X register char *name;
X register char **envp;
X{
X for (; *envp; envp++) {
X register char *p = strchr(*envp, '=');
X if (p && !strncmp(*envp, name, p - *envp))
X return p+1;
X }
X return NULL;
X}
END_OF_FILE
if test 3731 -ne `wc -c <'env.c'`; then
echo shar: \"'env.c'\" unpacked with wrong size!
fi
# end of 'env.c'
fi
if test -f 'externs.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'externs.h'\"
else
echo shar: Extracting \"'externs.h'\" \(3628 characters\)
sed "s/^X//" >'externs.h' <<'END_OF_FILE'
X/* Copyright 1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X#if defined(POSIX) || defined(ATT)
X# include <stdlib.h>
X# include <unistd.h>
X# include <string.h>
X# include <dirent.h>
X# define DIR_T struct dirent
X# define WAIT_T int
X# define WAIT_IS_INT 1
Xextern char *tzname[2];
X# define TZONE(tm) tzname[(tm).tm_isdst]
X#endif
X
X#if defined(UNIXPC)
X# undef WAIT_T
X# undef WAIT_IS_INT
X# define WAIT_T union wait
X#endif
X
X#if defined(POSIX)
X# define SIG_T sig_t
X# define TIME_T time_t
X# define PID_T pid_t
X#endif
X
X#if defined(ATT)
X# define SIG_T void
X# define TIME_T long
X# define PID_T int
X#endif
X
X#if !defined(POSIX) && !defined(ATT)
X/* classic BSD */
Xextern time_t time();
Xextern unsigned sleep();
Xextern struct tm *localtime();
Xextern struct passwd *getpwnam();
Xextern int errno;
Xextern void perror(), exit(), free();
Xextern char *getenv(), *strcpy(), *strchr(), *strtok();
Xextern void *malloc(), *realloc();
X# define SIG_T void
X# define TIME_T long
X# define PID_T int
X# define WAIT_T union wait
X# define DIR_T struct direct
X# include <sys/dir.h>
X# define TZONE(tm) (tm).tm_zone
X#endif
X
X/* getopt() isn't part of POSIX. some systems define it in <stdlib.h> anyway.
X * of those that do, some complain that our definition is different and some
X * do not. to add to the misery and confusion, some systems define getopt()
X * in ways that we cannot predict or comprehend, yet do not define the adjunct
X * external variables needed for the interface.
X */
X#if (!defined(BSD) || (BSD < 198911)) && !defined(ATT) && !defined(UNICOS)
Xint getopt __P((int, char * const *, const char *));
X#endif
X
X#if (!defined(BSD) || (BSD < 199103))
Xextern char *optarg;
Xextern int optind, opterr, optopt;
X#endif
X
X#if WAIT_IS_INT
X# ifndef WEXITSTATUS
X# define WEXITSTATUS(x) (((x) >> 8) & 0xff)
X# endif
X# ifndef WTERMSIG
X# define WTERMSIG(x) ((x) & 0x7f)
X# endif
X# ifndef WCOREDUMP
X# define WCOREDUMP(x) ((x) & 0x80)
X# endif
X#else /*WAIT_IS_INT*/
X# ifndef WEXITSTATUS
X# define WEXITSTATUS(x) ((x).w_retcode)
X# endif
X# ifndef WTERMSIG
X# define WTERMSIG(x) ((x).w_termsig)
X# endif
X# ifndef WCOREDUMP
X# define WCOREDUMP(x) ((x).w_coredump)
X# endif
X#endif /*WAIT_IS_INT*/
X
X#ifndef WIFSIGNALED
X#define WIFSIGNALED(x) (WTERMSIG(x) != 0)
X#endif
X#ifndef WIFEXITED
X#define WIFEXITED(x) (WTERMSIG(x) == 0)
X#endif
X
X#ifdef NEED_STRCASECMP
Xextern int strcasecmp __P((char *, char *));
X#endif
X
X#ifdef NEED_STRDUP
Xextern char *strdup __P((char *));
X#endif
X
X#ifdef NEED_STRERROR
Xextern char *strerror __P((int));
X#endif
X
X#ifdef NEED_FLOCK
Xextern int flock __P((int, int));
X# define LOCK_SH 1
X# define LOCK_EX 2
X# define LOCK_NB 4
X# define LOCK_UN 8
X#endif
X
X#ifdef NEED_SETSID
Xextern int setsid __P((void));
X#endif
X
X#ifdef NEED_GETDTABLESIZE
Xextern int getdtablesize __P((void));
X#endif
X
X#ifdef NEED_SETENV
Xextern int setenv __P((char *, char *, int));
X#endif
X
X#ifdef NEED_VFORK
Xextern PID_T vfork __P((void));
X#endif
END_OF_FILE
if test 3628 -ne `wc -c <'externs.h'`; then
echo shar: \"'externs.h'\" unpacked with wrong size!
fi
# end of 'externs.h'
fi
if test -f 'job.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'job.c'\"
else
echo shar: Extracting \"'job.c'\" \(1656 characters\)
sed "s/^X//" >'job.c' <<'END_OF_FILE'
X/* Copyright 1988,1990,1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Id: job.c,v 1.6 1994/01/15 20:43:43 vixie Exp $";
X#endif
X
X
X#include "cron.h"
X
X
Xtypedef struct _job {
X struct _job *next;
X entry *e;
X user *u;
X} job;
X
X
Xstatic job *jhead = NULL, *jtail = NULL;
X
X
Xvoid
Xjob_add(e, u)
X register entry *e;
X register user *u;
X{
X register job *j;
X
X /* if already on queue, keep going */
X for (j=jhead; j; j=j->next)
X if (j->e == e && j->u == u) { return; }
X
X /* build a job queue element */
X j = (job*)malloc(sizeof(job));
X j->next = (job*) NULL;
X j->e = e;
X j->u = u;
X
X /* add it to the tail */
X if (!jhead) { jhead=j; }
X else { jtail->next=j; }
X jtail = j;
X}
X
X
Xint
Xjob_runqueue()
X{
X register job *j, *jn;
X register int run = 0;
X
X for (j=jhead; j; j=jn) {
X do_command(j->e, j->u);
X jn = j->next;
X free(j);
X run++;
X }
X jhead = jtail = NULL;
X return run;
X}
END_OF_FILE
if test 1656 -ne `wc -c <'job.c'`; then
echo shar: \"'job.c'\" unpacked with wrong size!
fi
# end of 'job.c'
fi
if test -f 'pathnames.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pathnames.h'\"
else
echo shar: Extracting \"'pathnames.h'\" \(2494 characters\)
sed "s/^X//" >'pathnames.h' <<'END_OF_FILE'
X/* Copyright 1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X/*
X * $Id: pathnames.h,v 1.3 1994/01/15 20:43:43 vixie Exp $
X */
X
X#if (defined(BSD)) && (BSD >= 199103) || defined(__linux) || defined(AIX)
X# include <paths.h>
X#endif /*BSD*/
X
X#ifndef CRONDIR
X /* CRONDIR is where crond(8) and crontab(1) both chdir
X * to; SPOOL_DIR, ALLOW_FILE, DENY_FILE, and LOG_FILE
X * are all relative to this directory.
X */
X#define CRONDIR "/var/cron"
X#endif
X
X /* SPOOLDIR is where the crontabs live.
X * This directory will have its modtime updated
X * whenever crontab(1) changes a crontab; this is
X * the signal for crond(8) to look at each individual
X * crontab file and reload those whose modtimes are
X * newer than they were last time around (or which
X * didn't exist last time around...)
X */
X#define SPOOL_DIR "tabs"
X
X /* undefining these turns off their features. note
X * that ALLOW_FILE and DENY_FILE must both be defined
X * in order to enable the allow/deny code. If neither
X * LOG_FILE or SYSLOG is defined, we don't log. If
X * both are defined, we log both ways.
X */
X#define ALLOW_FILE "allow" /*-*/
X#define DENY_FILE "deny" /*-*/
X#define LOG_FILE "log" /*-*/
X
X /* where should the daemon stick its PID?
X */
X#ifdef _PATH_VARRUN
X# define PIDDIR _PATH_VARRUN
X#else
X# define PIDDIR "/etc/"
X#endif
X#define PIDFILE "%scron.pid"
X
X /* 4.3BSD-style crontab */
X#define SYSCRONTAB "/etc/crontab"
X
X /* what editor to use if no EDITOR or VISUAL
X * environment variable specified.
X */
X#if defined(_PATH_VI)
X# define EDITOR _PATH_VI
X#else
X# define EDITOR "/usr/ucb/vi"
X#endif
X
X#ifndef _PATH_BSHELL
X# define _PATH_BSHELL "/bin/sh"
X#endif
X
X#ifndef _PATH_DEFPATH
X# define _PATH_DEFPATH "/usr/bin:/bin"
X#endif
END_OF_FILE
if test 2494 -ne `wc -c <'pathnames.h'`; then
echo shar: \"'pathnames.h'\" unpacked with wrong size!
fi
# end of 'pathnames.h'
fi
if test -f 'popen.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'popen.c'\"
else
echo shar: Extracting \"'popen.c'\" \(4044 characters\)
sed "s/^X//" >'popen.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1988 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software written by Ken Arnold and
X * published in UNIX Review, Vol. 6, No. 8.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley. The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X */
X
X/* this came out of the ftpd sources; it's been modified to avoid the
X * globbing stuff since we don't need it. also execvp instead of execv.
X */
X
X#ifndef lint
Xstatic char rcsid[] = "$Id: popen.c,v 1.5 1994/01/15 20:43:43 vixie Exp $";
Xstatic char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 2/14/89";
X#endif /* not lint */
X
X#include "cron.h"
X#include <sys/signal.h>
X
X
X#define WANT_GLOBBING 0
X
X/*
X * Special version of popen which avoids call to shell. This insures noone
X * may create a pipe to a hidden program as a side effect of a list or dir
X * command.
X */
Xstatic PID_T *pids;
Xstatic int fds;
X
XFILE *
Xcron_popen(program, type)
X char *program, *type;
X{
X register char *cp;
X FILE *iop;
X int argc, pdes[2];
X PID_T pid;
X char *argv[100];
X#if WANT_GLOBBING
X char **pop, *vv[2];
X int gargc;
X char *gargv[1000];
X extern char **glob(), **copyblk();
X#endif
X
X if (*type != 'r' && *type != 'w' || type[1])
X return(NULL);
X
X if (!pids) {
X if ((fds = getdtablesize()) <= 0)
X return(NULL);
X if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T)))))
X return(NULL);
X bzero((char *)pids, fds * sizeof(PID_T));
X }
X if (pipe(pdes) < 0)
X return(NULL);
X
X /* break up string into pieces */
X for (argc = 0, cp = program;; cp = NULL)
X if (!(argv[argc++] = strtok(cp, " \t\n")))
X break;
X
X#if WANT_GLOBBING
X /* glob each piece */
X gargv[0] = argv[0];
X for (gargc = argc = 1; argv[argc]; argc++) {
X if (!(pop = glob(argv[argc]))) { /* globbing failed */
X vv[0] = argv[argc];
X vv[1] = NULL;
X pop = copyblk(vv);
X }
X argv[argc] = (char *)pop; /* save to free later */
X while (*pop && gargc < 1000)
X gargv[gargc++] = *pop++;
X }
X gargv[gargc] = NULL;
X#endif
X
X iop = NULL;
X switch(pid = vfork()) {
X case -1: /* error */
X (void)close(pdes[0]);
X (void)close(pdes[1]);
X goto pfree;
X /* NOTREACHED */
X case 0: /* child */
X if (*type == 'r') {
X if (pdes[1] != 1) {
X dup2(pdes[1], 1);
X dup2(pdes[1], 2); /* stderr, too! */
X (void)close(pdes[1]);
X }
X (void)close(pdes[0]);
X } else {
X if (pdes[0] != 0) {
X dup2(pdes[0], 0);
X (void)close(pdes[0]);
X }
X (void)close(pdes[1]);
X }
X#if WANT_GLOBBING
X execvp(gargv[0], gargv);
X#else
X execvp(argv[0], argv);
X#endif
X _exit(1);
X }
X /* parent; assume fdopen can't fail... */
X if (*type == 'r') {
X iop = fdopen(pdes[0], type);
X (void)close(pdes[1]);
X } else {
X iop = fdopen(pdes[1], type);
X (void)close(pdes[0]);
X }
X pids[fileno(iop)] = pid;
X
Xpfree:
X#if WANT_GLOBBING
X for (argc = 1; argv[argc] != NULL; argc++) {
X/* blkfree((char **)argv[argc]); */
X free((char *)argv[argc]);
X }
X#endif
X return(iop);
X}
X
Xint
Xcron_pclose(iop)
X FILE *iop;
X{
X register int fdes;
X int omask;
X WAIT_T stat_loc;
X PID_T pid;
X
X /*
X * pclose returns -1 if stream is not associated with a
X * `popened' command, or, if already `pclosed'.
X */
X if (pids == 0 || pids[fdes = fileno(iop)] == 0)
X return(-1);
X (void)fclose(iop);
X omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
X while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
X ;
X (void)sigsetmask(omask);
X pids[fdes] = 0;
X return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
X}
END_OF_FILE
if test 4044 -ne `wc -c <'popen.c'`; then
echo shar: \"'popen.c'\" unpacked with wrong size!
fi
# end of 'popen.c'
fi
if test -f 'putman.sh' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'putman.sh'\"
else
echo shar: Extracting \"'putman.sh'\" \(328 characters\)
sed "s/^X//" >'putman.sh' <<'END_OF_FILE'
X#!/bin/sh
X
X# putman.sh - install a man page according to local custom
X# vixie 27dec93 [original]
X#
X# $Id:$
X
XPAGE=$1
XDIR=$2
X
XSECT=`expr $PAGE : '[a-z]*.\([0-9]\)'`
X
X[ -d $DIR/man$SECT ] && {
X set -x
X cp $PAGE $DIR/man$SECT/$PAGE
X set +x
X} || {
X set -x
X nroff -man $PAGE >$DIR/cat$SECT/`basename $PAGE .$SECT`.0
X set +x
X}
X
Xexit 0
END_OF_FILE
if test 328 -ne `wc -c <'putman.sh'`; then
echo shar: \"'putman.sh'\" unpacked with wrong size!
fi
# end of 'putman.sh'
fi
if test -f 'user.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'user.c'\"
else
echo shar: Extracting \"'user.c'\" \(2195 characters\)
sed "s/^X//" >'user.c' <<'END_OF_FILE'
X/* Copyright 1988,1990,1993,1994 by Paul Vixie
X * All rights reserved
X *
X * Distribute freely, except: don't remove my name from the source or
X * documentation (don't take credit for my work), mark your changes (don't
X * get me blamed for your possible bugs), don't alter or remove this
X * notice. May be sold if buildable source is provided to buyer. No
X * warrantee of any kind, express or implied, is included with this
X * software; use at your own risk, responsibility for damages (if any) to
X * anyone resulting from the use of this software rests entirely with the
X * user.
X *
X * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
X * I'll try to keep a version up to date. I can be reached as follows:
X * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
X */
X
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Id: user.c,v 2.8 1994/01/15 20:43:43 vixie Exp $";
X#endif
X
X/* vix 26jan87 [log is in RCS file]
X */
X
X
X#include "cron.h"
X
X
Xvoid
Xfree_user(u)
X user *u;
X{
X entry *e, *ne;
X
X free(u->name);
X for (e = u->crontab; e != NULL; e = ne) {
X ne = e->next;
X free_entry(e);
X }
X free(u);
X}
X
X
Xuser *
Xload_user(crontab_fd, pw, name)
X int crontab_fd;
X struct passwd *pw; /* NULL implies syscrontab */
X char *name;
X{
X char envstr[MAX_ENVSTR];
X FILE *file;
X user *u;
X entry *e;
X int status;
X char **envp;
X
X if (!(file = fdopen(crontab_fd, "r"))) {
X perror("fdopen on crontab_fd in load_user");
X return NULL;
X }
X
X Debug(DPARS, ("load_user()\n"))
X
X /* file is open. build user entry, then read the crontab file.
X */
X u = (user *) malloc(sizeof(user));
X u->name = strdup(name);
X u->crontab = NULL;
X
X /*
X * init environment. this will be copied/augmented for each entry.
X */
X envp = env_init();
X
X /*
X * load the crontab
X */
X while ((status = load_env(envstr, file)) >= OK) {
X switch (status) {
X case ERR:
X free_user(u);
X u = NULL;
X goto done;
X case FALSE:
X e = load_entry(file, NULL, pw, envp);
X if (e) {
X e->next = u->crontab;
X u->crontab = e;
X }
X break;
X case TRUE:
X envp = env_set(envp, envstr);
X break;
X }
X }
X
X done:
X env_free(envp);
X fclose(file);
X Debug(DPARS, ("...load_user() done\n"))
X return u;
X}
END_OF_FILE
if test 2195 -ne `wc -c <'user.c'`; then
echo shar: \"'user.c'\" unpacked with wrong size!
fi
# end of 'user.c'
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