[comp.sources.misc] PD Cron 01/03

paul@vixie.UUCP (Paul Vixie, Esq.) (06/12/87)

[This is a "cron" for 4.3BSD (also 4.2) which implements the "user crontabs"
feature in System V cron.  Now all we need for it is to include "at" and a
way to define multiple "at" queues.  It also should have cron.allow and
cron.deny; emagine someone putting the line

* 5-60/5 * * * echo "THE ROOT IS A FINK!" > /dev/console

in their crontab.  The environment setting is also useful, and is NOT in
System V (cron/.proto is a poor substitute).  Also: the interaction of day-of-
month and day-of-week is incompatible with existing crons.  ++bsa]

#! /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".  If this archive is complete, you will
##  see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  INFO.conversion INFO.features INFO.install MANIFEST
#   Makefile README crond.c crond.man8 crontab.man1 crontab.man5
#   database.c env.c misc.c user.c
# Wrapped by paul@vixie on Wed May  6 10:18:50 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f INFO.conversion -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"INFO.conversion\"
else
echo shar: Extracting \"INFO.conversion\" \(3060 characters\)
sed "s/^X//" >INFO.conversion <<'END_OF_INFO.conversion'
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 seperate
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 in case something goes wakko with this fancy 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 (SPOOLDIR in cron.h), named after
Xthe user whose crontab it is.  If you want to examine, replace, remove, or
Xappend to a crontab, the 'crontab' command does those things too.  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
Xbe executed.
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
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
XIn this cron, you'd create /usr/lib/uucp/crontab.src (or wherever you want
Xto keep uucp's commands) to 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				# otherwise it's uucico
X	HOME=/usr/lib/uucp			# '' '' /usr/spool/uucppublic
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
Xin your crontab commands, you don't need them anymore.
X
XYou could, of course, just install your current crontab in toto as root's
Xcrontab.  It would work exactly the way your current one does, barring the
Xextra steps in installing or changing it.  There would still be an advantage
Xto this cron, namely that the 'crontab' command pokes the cron daemon when
Xany crontab file is changed, causing the daemon to reread all crontabs the
Xnext time it wakes up -- in every standard cron I know of, you have to kill
Xand restart the daemon to get it to reread the crontabs.
END_OF_INFO.conversion
if test 3060 -ne `wc -c <INFO.conversion`; then
    echo shar: \"INFO.conversion\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f INFO.features -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"INFO.features\"
else
echo shar: Extracting \"INFO.features\" \(3980 characters\)
sed "s/^X//" >INFO.features <<'END_OF_INFO.features'
XFeatures of Vixie's cron relative to BSD 4.[23] and SysV crons:
X
X--	(questionable)  There is no cron.allow or cron.deny file.
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 was taken from 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 complete 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.  I don't know if BSD or ATT support
X	this, and I've heard conflicting stories which makes me think that
X	some versions have it and others don't.
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 ATT and BSD cron, you have to kill and restart the
X	daemon yourself.  (Debatable: some ATT crons do this)
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.
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, 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'.
END_OF_INFO.features
if test 3980 -ne `wc -c <INFO.features`; then
    echo shar: \"INFO.features\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f INFO.install -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"INFO.install\"
else
echo shar: Extracting \"INFO.install\" \(2380 characters\)
sed "s/^X//" >INFO.install <<'END_OF_INFO.install'
X*** This does not work on ATT SysV yet, and given the feature overlap,
X    it may never do so.
X
XRead the comments at the top of the Makefile, then edit the area marked
X'configurable stuff'.
X
XEdit cron.h.  The stuff I expect you to change is down a bit from the
Xtop of the file, but it's clearly marked.  Pay special attention to the
XSPOOLDIR and LIBDIR defines.
X
XCreate directories for LIBDIR and SPOOLDIR as you defined them in cron.h.
XI use /usr/spool/cron and /usr/spool/cron/crontabs here, but suit yourself.
XThe directories should be owned by root, mode 'u=rwx,g=,o=' (700).
X
Xsay:
X	make all
X
Xsu and say:
X	make install
X
XEdit your /usr/lib/crontab file into little pieces -- see INFO.conversion
Xfor help on this.
X
XUse the 'crontab' command to install all the little pieces you just created.
XThere may not be a man page yet, although if entered with no options you do
Xget a pretty little usage summary.  Some examples (see below before trying
Xany 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 command
Xis issued; changing the source files later will have no effect until they are
Xreinstalled with another 'crontab -r' command.  (2) The crontab command will
Xaffect the crontab of the person using the command unless '-u <user>' is
Xgiven; '-u' only works for root.  When using most 'su' commands under most
XBSD's, crontab will still think of you as yourself even though you may think
Xof yourself as root.  (3) the '-r' option stands for 'replace' or 'remove',
Xdepending on whether a filename follows it.  You could also use '-a' for
Xappend, or '-c' to check the syntax of a crontab file without installing it.
XFor other options, see the non-existent man page or check the usage summary
Xthat you get if you enter 'crontab' with no arguments.
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/lib/crond, unless you changed it in the Makefile.
X
XStart up this cron daemon yourself as root.  Just type /usr/lib/crond (or
Xwhatever); no '&' is needed since the cron daemon forks itself and the
Xcommand you executed returns immediately.
END_OF_INFO.install
if test 2380 -ne `wc -c <INFO.install`; then
    echo shar: \"INFO.install\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f MANIFEST -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MANIFEST\"
else
echo shar: Extracting \"MANIFEST\" \(654 characters\)
sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X INFO.conversion           1	
X INFO.features             1	
X INFO.install              1	
X MANIFEST                  1	This shipping list
X Makefile                  1	
X README                    1	
X cron.h                    2	
X crond.c                   1	
X crond.man8                1	
X crontab.c                 2	
X crontab.man1              1	
X crontab.man5              1	
X database.c                1	
X do_command.c              2	
X entry.c                   2	
X env.c                     1	
X misc.c                    1	
X user.c                    1	
END_OF_MANIFEST
if test 654 -ne `wc -c <MANIFEST`; then
    echo shar: \"MANIFEST\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(4294 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X# Makefile for vixie's cron
X#
X# $Header: Makefile,v 1.5 87/05/06 10:15:05 paul Exp $
X# $Source: /usr/src/local/vix/cron/Makefile,v $
X# $Revision: 1.5 $
X# $Log:	Makefile,v $
X# Revision 1.2  87/04/02  17:08:06  paul
X# ATT/BSD compat stuff -- this is not complete
X# 
X# Revision 1.1  87/03/31  12:05:46  paul
X# Initial revision
X#
X# vix 30mar87 [goodbye, time.c; hello, getopt]
X# vix 12feb87 [cleanup for distribution]
X# vix 30dec86 [written]
X
X#############################################################################
X# Copyright 1987 by Vixie Enterprises
X# All rights reserved
X# 
X# Distribute freely, except: don't sell it, don't remove my name from the
X# source or documentation (don't take credit for my work), mark your changes
X# (don't get me blamed for your possible bugs), don't alter or remove this
X# notice.  Commercial redistribution is negotiable; contact me for details.
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, Vixie Enterprises, 329 Noe Street, San Francisco, CA, 94114,
X# (415) 864-7013, {ucbvax!dual,ames,ucsfmis,lll-crg,sun}!ptsfa!vixie!paul.
X#############################################################################
X
X# NOTES:
X#	'make' can be done by anyone
X#	'make install' must be done by root
X#
X#	why keep the cron daemon in /etc?  sendmail is in /usr/lib, why
X#	not the cron daemon?  i can't see a big use for cron while running
X#	single user... besides, the crontabs have always been in /usr/lib...
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 wrong things.  BINDIR is where the
X#	'crontab' command goes, and should be a common place like /usr/bin.
X#	LIBDIR is where the cron daemon lives; /usr/lib seems very logical
X#	(see note above).  the cron daemon's name is 'crond', so if you
X#	decide to call the spool or library directory /usr/lib/cron, the
X#	name will be available.
X#
X#	this package needs the 'bitstring macros' library, which is
X#	available from me or from the mod.sources 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 cron.h; edit that first!
X
X#################################### begin configurable stuff
XSHELL		=	/bin/sh
XBINDIR		=	/usr/bin
XLIBDIR		=	/usr/lib
X#<<need bitstring.h>>
X#INCLUDE	=	-I/usr/local/include
XINCLUDE		=
X#<<need getopt()>>
Xlibs		=	/usr/local/lib/libvix.a
X#<<>>
X#COMPAT		=	-DATT
XCOMPAT		=	-DBSD
XCFLAGS		=	-O $(INCLUDE) $(COMPAT)
X#################################### end configurable stuff
X
X.SUFFIXES	:	.c,v .h,v
X
X.c,v.o		:;	co -q $*.c ; $(CC) -c $(CFLAGS) $*.c
X			@rm -f $*.c
X
X.c,v.c		:;	co -q $*.c
X
X.h,v.h		:;	co -q $*.h
X
XINFOS		=	README INFO.features INFO.install INFO.conversion
XMANPAGES	=	crontab.man5 crontab.man1 crond.man8
XHEADERS		=	cron.h
XSOURCES		=	crond.c crontab.c database.c do_command.c \
X			entry.c env.c misc.c user.c
XSHAR_SOURCE	=	$(INFOS) $(MANPAGES) Makefile $(HEADERS) $(SOURCES)
X
Xcron_obj	=	crond.o database.o user.o entry.o \
X			misc.o do_command.o env.o
Xcrontab_obj	=	crontab.o misc.o entry.o env.o
X
Xall		:	crond crontab
X
Xcrond		:	$(cron_obj)
X			cc -o crond $(cron_obj) $(libs)
X
Xcrontab		:	$(crontab_obj)
X			cc -o crontab $(crontab_obj) $(libs)
X
Xinstall		:	all
X			install -c -m 4100 -o root -s crond $(LIBDIR)
X			install -c -m 4111 -o root -s crontab $(BINDIR)
X			@echo " "
X			@echo "Install the man pages according to local"
X			@echo "convention.  The man page files are:"
X			@echo $(MANPAGES)
X
Xclean		:;	rm -f *.o crond crontab a.out core
X
Xshar		:	$(SHAR_SOURCE)
X			makekit -m -s50k $(SHAR_SOURCE)
X
X# there are better ways to do lint, like linting the sources that will be
X# loaded together, specifying more options, etc; however, the s/375 version
X# of lint just doesn't make all that stuff worthwhile.
Xlint		:
X			lint $(SOURCES)
X
X$(cron_obj)	:	cron.h
X$(crontab_obj)	:	cron.h
END_OF_Makefile
if test 4294 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(2782 characters\)
sed "s/^X//" >README <<'END_OF_README'
XVixie's Cron V1.0
XMay 6, 1987
XPaul Vixie
X
XThis is a version of 'cron' that is known to run on BSD 4.[23] systems.
XIt is functionally based on the SysV cron, which means that each user
Xcan have their own crontab file (all crontab files are stored in a
Xread-protected directory, usually /usr/spool/cron/crontabs).  No direct
Xsupport is provided for 'at'; you can continue to run 'atrun' from the
Xcrontab as you have been doing.  No log file is written; also, the
Xcron.allow and cron.deny files were not implemented.  It doesn't run on
XSysV, although some effort has gone into making that port an easy one.
X
XThe code was all written by me, and is (quoted from Makefile):
X
X# Copyright 1987 by Vixie Enterprises
X# All rights reserved
X# 
X# Distribute freely, except: don't sell it, don't remove my name from the
X# source or documentation (don't take credit for my work), mark your changes
X# (don't get me blamed for your possible bugs), don't alter or remove this
X# notice.  Commercial redistribution is negotiable; contact me for details.
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, Vixie Enterprises, 329 Noe Street, San Francisco, CA, 94114,
X# (415) 864-7013, {ucbvax!dual,ames,ucsfmis,lll-crg,sun}!ptsfa!vixie!paul.
X
XThis is more or less the copyright that USENET contributed softwaree usually
Xhas; the 'commercial...negotiable' is in case Berkeley or even ATT finds this
Xcron superior to their versions -- I certainly do.  Since ATT couldn't use
Xthis version if they had to freely distribute source, and since I'd love to
Xsee them use it, I'll offer some rediculously low license fee just to have
Xthem take it.  In the unlikely event that they do this, I will continue to
Xsupport and distribute the pseudo-PD version, so please, don't flame me for
Xwanting 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 INFO.* files
X	Edit cron.h			/* both of these files have
X	Edit Makefile			 * instructions inside */
X	'make'
X	'su' and 'make install'		/* you will be told to install the
X					 * man pages by hand... */
X	kill your existing cron process
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 (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.
END_OF_README
if test 2782 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f crond.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"crond.c\"
else
echo shar: Extracting \"crond.c\" \(5987 characters\)
sed "s/^X//" >crond.c <<'END_OF_crond.c'
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Header: crond.c,v 1.6 87/05/02 17:33:16 paul Exp $";
X#endif
X
X/* $Source: /usr/src/local/vix/cron/crond.c,v $
X * $Revision: 1.6 $
X * $Log:	crond.c,v $
X * Revision 1.6  87/05/02  17:33:16  paul
X * baseline for mod.sources release
X * 
X * Revision 1.5  87/03/31  00:23:08  paul
X * another GREAT idea from rs@mirror...
X *   do all time calculations in int instead of double -- the double
X *   stuff was for a previous kludge that turned out to be unneeded.
X *   time.c went away as of this change, also.
X * 
X * Revision 1.4  87/02/12  18:20:29  paul
X * fixed target_time scope misdesign, lots of fixes to sigchld stuff
X * 
X * Revision 1.3  87/02/10  18:26:38  paul
X * POKECRON, time_d(), target_time, other massive changes
X * 
X * Revision 1.2  87/02/02  19:25:43  paul
X * various
X * 
X * Revision 1.1  87/01/26  23:48:55  paul
X * Initial revision
X */
X
X/* Copyright 1987 by Vixie Enterprises
X * All rights reserved
X *
X * Distribute freely, except: don't sell it, don't remove my name from the
X * source or documentation (don't take credit for my work), mark your changes
X * (don't get me blamed for your possible bugs), don't alter or remove this
X * notice.  Commercial redistribution is negotiable; contact me for details.
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, Vixie Enterprises, 329 Noe Street, San Francisco, CA, 94114,
X * (415) 864-7013, {ucbvax!dual,ames,ucsfmis,lll-crg,sun}!ptsfa!vixie!paul.
X */
X
X
X#define	MAIN_PROGRAM
X
X
X#include "cron.h"
X#include <sys/time.h>
X#include <sys/signal.h>
X#include <sys/types.h>
X#if defined(BSD)
X# include <sys/wait.h>
X# include <sys/resource.h>
X#endif /*BSD*/
X
Xextern int	fprintf(), exit(), fork(), unlink(), sleep();
Xextern time_t	time();
X
X
Xvoid
Xusage()
X{
X	(void) fprintf(stderr, "usage:  %s [-x debugflag[,...]]\n", PROGNAME);
X	(void) exit(ERROR_EXIT);
X}
X
X
Xvoid
Xmain(argc, argv)
X	int	argc;
X	char	*argv[];
X{
X	extern void	set_cron_uid(), be_different(), parse_args(),
X			free_database(), sigchld_handler();
X	extern user	*load_database();
X	extern long	cron();
X
X	register user	*database;
X	register long	target_time;
X
X	PROGNAME = argv[0];
X
X	setlinebuf(stdout);
X	setlinebuf(stderr);
X
X	/* if there is only one argument, it's the program name.  this means
X	 * that debugging can't be on (it would require '-x'), thus test-mode
X	 * can't be on, thus we should fork and exit, to be compatible with
X	 * the real cron.
X	 */
X	if (argc == 1)
X	{
X		if (fork() != 0)
X			_exit(0);
X
X		be_different();
X	}
X	else
X	{
X		(void) fprintf(stderr, "[%d] vcron started\n", getpid());
X	}
X
X#if defined(BSD)
X	(void) signal(SIGCHLD, sigchld_handler);
X#endif /*BSD*/
X
X#if defined(ATT)
X	(void) signal(SIGCLD, SIG_IGN);
X#endif /*ATT*/
X
X	parse_args(argc, argv);
X	set_cron_uid();
X	(void) unlink(POKECRON);
X	target_time = (long) time((time_t*)0);
X	while (TRUE)
X	{
X		database = load_database();
X		target_time = cron(database, target_time);
X		free_database(database);
X	}
X}
X
X
Xstatic long
Xcron(db, target_time)
X	register user	*db;
X	register long	target_time;
X{
X	extern int	unlink();
X	extern void	cron_tick(), cron_sleep();
X
X	/*
X	 * if the POKECRON file exists (i.e., we can successfully delete
X	 * it), return to the mainline, which will reread the database
X	 * and call us again.
X	 */
X	while (OK != unlink(POKECRON))
X	{
X		/* do this iteration
X		 */
X		cron_tick(db, target_time);
X
X		/* sleep 1 minute
X		 */
X		target_time += 60;
X		cron_sleep(target_time);
X	}
X	Debug(DSCH, ("POKECRON file detected\n"))
X	return target_time;
X}
X
X
Xstatic void
Xcron_tick(db, target_time)
X	user	*db;
X	long	target_time;
X{
X	extern void		do_command();
X	extern struct tm	*localtime();
X	register struct tm	*tm = localtime((time_t*) &target_time);
X	/**/ int		minute, hour, dom, month, dow;
X	register user		*u;
X	register entry		*e;
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, ("tick(%d,%d,%d,%d,%d)\n", 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'.
X	 */
X	for (u = db;  u != NULL;  u = u->next)
X		for (e = u->crontab;  e != NULL;  e = e->next)
X			if (bit_test(e->minute, minute)
X			 && bit_test(e->hour, hour)
X			 && bit_test(e->month, month)
X			 && ( (e->dom_star || e->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				do_command(e->cmd, u);
X}
X
X
Xstatic void
Xcron_sleep(target_time)
X	long	target_time;
X{
X	register int	seconds_to_wait;
X
X	seconds_to_wait = (int) (target_time - (long) time((time_t*)0));
X	Debug(DSCH, ("target_time=%ld, sec-to-wait=%d\n",
X		target_time, seconds_to_wait))
X
X	if (seconds_to_wait > 0)
X	{
X		Debug(DSCH, ("sleeping for %d seconds\n", seconds_to_wait))
X		(void) sleep((unsigned int) seconds_to_wait);
X	}
X}
X
X
X#if defined(BSD)
Xstatic void
Xsigchld_handler()
X{
X	union wait	waiter;
X	int		pid;
X
X	for (;;)
X	{
X		pid = wait3(&waiter, WNOHANG, (struct rusage *)0);
X		switch (pid)
X		{
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, waiter.w_status))
X		}
X	}
X}
X#endif /*BSD*/
X
X
Xstatic void
Xparse_args(argc, argv)
X	int	argc;
X	char	*argv[];
X{
X	extern	int	optind, getopt();
X	extern	void	usage();
X	extern	char	*optarg;
X
X	int	argch;
X
X	while (EOF != (argch = getopt(argc, argv, "x:")))
X	{
X		switch (argch)
X		{
X		default:
X			usage();
X		case 'x':
X			if (!set_debug_flags(optarg))
X				usage();
X			break;
X		}
X	}
X}
END_OF_crond.c
if test 5987 -ne `wc -c <crond.c`; then
    echo shar: \"crond.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f crond.man8 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"crond.man8\"
else
echo shar: Extracting \"crond.man8\" \(1079 characters\)
sed "s/^X//" >crond.man8 <<'END_OF_crond.man8'
X.TH CROND 8 "6 March 1987"
X.UC 4
X.SH NAME
Xcrond \- daemon to execute scheduled commands (Vixie's Cron)
X.SH SYNOPSIS
Xcrond
X.SH DESCRIPTION
X.I Crond
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 Crond
Xsearches for a crontab file for each user listed in /etc/passwd; those
Xcrontabs found are loaded into memory.
X.I Crond
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, if such exists).
X.PP
XAdditionally,
X.I crond
Xchecks each minute for the existence of a POKECRON file in it's spool
Xdirectory.  If it exists, it is removed, and
X.I crond
Xwill reload its memory-resident cron tables.
X.IR Crontab (1)
Xcreates the POKECRON file whenever it makes a change to any crontab.
X.SH "SEE ALSO"
Xcrontab(1),
Xcrontab(5)
X.SH AUTHOR
X.nf
XPaul Vixie
Xucbvax!dual!ptsfa!vixie!paul
Xptsfa!vixie!paul@ames.ARPA
END_OF_crond.man8
if test 1079 -ne `wc -c <crond.man8`; then
    echo shar: \"crond.man8\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f crontab.man1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"crontab.man1\"
else
echo shar: Extracting \"crontab.man1\" \(1278 characters\)
sed "s/^X//" >crontab.man1 <<'END_OF_crontab.man1'
X.TH CRONTAB 1 "30 March 1987"
X.UC 4
X.SH NAME
Xcrontab \- maintain crontab files for individual users
X.SH SYNOPSIS
Xcrontab [ -u user ] { -l | -d | -r file | -a file }
X.SH DESCRIPTION
X.I Crontab
Xis the program used to install, deinstall, list, or check the tables
Xused to drive the
X.IR crond (8)
Xdaemon in Vixie's Cron.  Each user has their own crontab, but though these are
Xfiles in /usr/spool, they are not readable or writable by anyone or anything
Xexcept the super-user or the
X.IR crond (8)
Xor
X.I crontab
Xprograms.
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.
X.PP
XThe
X.I -l
Xoption causes the current crontab to be displayed on standard output.
X.PP
XThe
X.I -d
Xoption causes the current crontab to be deleted.
X.PP
XThe
X.I -r
Xoption is used to replace the current
Xcrontab (if any) with the contents of the named file.
X.PP
XThe
X.I -a
Xoption lets you "append" the contents of some file to your crontab.
X.SH "SEE ALSO"
Xcrontab(5),
Xcrond(8)
X.SH DIAGNOSTICS
XFairly informative usage message if you run it with a bad command line.
X.SH AUTHOR
X.nf
XPaul Vixie
Xucbvax!dual!ptsfa!vixie!paul
Xptsfa!vixie!paul@ames.ARPA
END_OF_crontab.man1
if test 1278 -ne `wc -c <crontab.man1`; then
    echo shar: \"crontab.man1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f crontab.man5 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"crontab.man5\"
else
echo shar: Extracting \"crontab.man5\" \(4668 characters\)
sed "s/^X//" >crontab.man5 <<'END_OF_crontab.man5'
X.TH CRONTAB 5 "19 March 1987"
X.UC 4
X.SH NAME
Xcrontab \- tables for driving Vixie's Cron
X.SH DESCRIPTION
XA
X.I crontab
Xfile contains instructions to the
X.IR crond (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 "su news"
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 number-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
Xspaces 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 crond (8)
Xdaemon from the /etc/passwd line of the crontab's owner: USER, HOME, and SHELL.
XHOME and SHELL may be overridden by settings in the crontab; USER may not.
X.PP
X(Note: for UUCP, always set SHELL=/bin/sh, or
X.IR crond (8)
Xwill cheerfully try to execute your commands using /usr/lib/uucp/uucico.)
X.PP
X(Another note: the USER variable is sometimes called LOGNAME or worse on
XSystem V... on these systems, you should set LOGNAME rather than USER.)
X.PP
XIn addition to USER, HOME, and SHELL,
X.IR crond (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
Xextensions.  Each line has five time and date fields, followed by a command.
XThe time and date fields are: minute, hour, day of month, month, and day of
Xweek.  Lists and/or ranges are allowed, as in "1-3,7-9"; a step value is also
Xallowed, so that if you want to run a command every two hours, you can say
X"0-23/2" instead of listing every second hour.  Months or days of the week may
Xbe specified by name, using the first three letters of the name.  Numerics are
Xalso allowed for this, but this is mostly a backward-compatibility issue --
Xnames are nicer.
X.PP
XSpaces or tabs subsequent to the one that seperates the last time/date field
Xfrom the command are considered part of the command.  Percent-signs (`%') in
Xthe command, unless escaped with backslash (`\\'), will be changed into newline
Xcharacters, and all data after the first `%' will be sent to the command as
Xstandard input.
X.SH EXAMPLES
X.nf
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#
X5 0 * * *       echo "run five minutes after midnight, every day"
X15 14 1 * *     echo "run at 2:15pm on the first of every month"
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"
XCrond(8), crontab(1)
X.SH EXTENSIONS
XWhen specifying day of week, both day 0 and day 7 will be considered Sunday.
XBerkeley 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
Xucbvax!dual!ptsfa!vixie!paul
Xptsfa!vixie!paul@ames.ARPA
END_OF_crontab.man5
if test 4668 -ne `wc -c <crontab.man5`; then
    echo shar: \"crontab.man5\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f database.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"database.c\"
else
echo shar: Extracting \"database.c\" \(1658 characters\)
sed "s/^X//" >database.c <<'END_OF_database.c'
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Header: database.c,v 1.2 87/05/02 17:33:31 paul Exp $";
X#endif
X
X/* $Source: /usr/src/local/vix/cron/database.c,v $
X * $Revision: 1.2 $
X * $Log:	database.c,v $
X * Revision 1.2  87/05/02  17:33:31  paul
X * baseline for mod.sources release
X * 
X * Revision 1.1  87/01/26  23:46:36  paul
X * Initial revision
X * 
X */
X
X/* Copyright 1987 by Vixie Enterprises
X * All rights reserved
X *
X * Distribute freely, except: don't sell it, don't remove my name from the
X * source or documentation (don't take credit for my work), mark your changes
X * (don't get me blamed for your possible bugs), don't alter or remove this
X * notice.  Commercial redistribution is negotiable; contact me for details.
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, Vixie Enterprises, 329 Noe Street, San Francisco, CA, 94114,
X * (415) 864-7013, {ucbvax!dual,ames,ucsfmis,lll-crg,sun}!ptsfa!vixie!paul.
X */
X
X
X#include "cron.h"
X#include <pwd.h>
X
X
Xvoid
Xfree_database(db)
X	user	*db;
X{
X	void	free_user();
X	user	*u;
X
X	for (u = db;  u != NULL;  u = u->next)
X		free_user(u);
X}
X
X
Xuser *
Xload_database()
X{
X	user		*load_user();
X
X	struct passwd	*pw;
X	user		*db, *u;
X
X	Debug(DPARS, ("load_database()\n"))
X
X	db = NULL;
X	while (NULL != (pw = getpwent()))
X	{
X		Debug(DPARS, ("\t%s\n", pw->pw_name))
X
X		u = load_user(
X			pw->pw_name,
X			pw->pw_uid,
X			pw->pw_gid,
X			pw->pw_dir,
X			pw->pw_shell
X		);
X		if (u == NULL)
X		{
X			/* no crontab for this user
X			 */
X			continue;
X		}
X		u->next = db;
X		db = u;
X	}
X	endpwent();
X	return db;
X}
END_OF_database.c
if test 1658 -ne `wc -c <database.c`; then
    echo shar: \"database.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f env.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"env.c\"
else
echo shar: Extracting \"env.c\" \(3649 characters\)
sed "s/^X//" >env.c <<'END_OF_env.c'
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Header: env.c,v 1.3 87/05/02 17:34:00 paul Exp $";
X#endif
X
X/* $Source: /usr/src/local/vix/cron/env.c,v $
X * $Revision: 1.3 $
X * $Log:	env.c,v $
X * Revision 1.3  87/05/02  17:34:00  paul
X * baseline for mod.sources release
X * 
X * Revision 1.2  87/03/19  12:48:19  paul
X * suggestions from rs@mirror (Rich $alz):
X *    allow quotes around value string
X * 
X * Revision 1.1  87/02/13  00:26:58  paul
X * Initial revision
X * 
X */
X
X/* Copyright 1987 by Vixie Enterprises
X * All rights reserved
X *
X * Distribute freely, except: don't sell it, don't remove my name from the
X * source or documentation (don't take credit for my work), mark your changes
X * (don't get me blamed for your possible bugs), don't alter or remove this
X * notice.  Commercial redistribution is negotiable; contact me for details.
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, Vixie Enterprises, 329 Noe Street, San Francisco, CA, 94114,
X * (415) 864-7013, {ucbvax!dual,ames,ucsfmis,lll-crg,sun}!ptsfa!vixie!paul.
X */
X
X
X#include "cron.h"
X
X
Xchar **
Xenv_init()
X{
X	extern char	*malloc();
X	register char	**p = (char **) malloc(sizeof(char **));
X
X	p[0] = NULL;
X	return p;
X}
X
X
Xchar **
Xenv_set(envp, envstr)
X	char	**envp;
X	char	*envstr;
X{
X	extern char	*realloc(), *savestr();
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	{
X		if (!strcmp_until(envp[count], envstr, '='))
X			found = count;
X	}
X	count++;		/* for the null pointer
X				 */
X
X	if (found != -1)
X	{
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] = savestr(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(
X			(char *)   envp,
X			(unsigned) ((count+1) * sizeof(char **))
X	);
X	p[count] = p[count-1];
X	p[count-1] = savestr(envstr);
X	return p;
X}
X
X
Xint
Xload_env(envstr, f)
X	char	*envstr;
X	FILE	*f;
X{
X	/* return	ERR = end of file
X	 *		FALSE = not an env setting (file was repositioned)
X	 *		TRUE = was an env setting
X	 */
X	char	*strcpy(), *sprintf();
X	long	filepos = ftell(f);
X	char	name[MAX_TEMPSTR], val[MAX_TEMPSTR];
X	int	fields, strdtb();
X	void	skip_comments();
X
X	skip_comments(f);
X	if (EOF == get_string(envstr, MAX_TEMPSTR, 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	{
X		Debug(DPARS, ("load_env, not 2 fields (%d)\n", fields))
X		fseek(f, filepos, 0);
X		Set_LineNum(LINE_NUMBER - 1)		/* kludge */
X		return FALSE;
X	}
X
X	/* 2 fields from scanf; looks like an env setting
X	 */
X
X	/*
X	 * process value string
X	 */
X	{
X		int	len = strdtb(val);
X
X		if (len >= 2)
X			if (val[0] == '\'' || val[0] == '"')
X				if (val[len-1] == val[0])
X				{
X					val[len-1] = '\0';
X					(void) strcpy(val, val+1);
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	char	*name;
X	char	**envp;
X{
X	char	*index();
X
X	for (;  *envp;  envp++)
X		if (!strcmp_until(*envp, name, '='))
X			return index(*envp, '=') + 1;  /* we know it's there */
X	return NULL;
X}
END_OF_env.c
if test 3649 -ne `wc -c <env.c`; then
    echo shar: \"env.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f misc.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"misc.c\"
else
echo shar: Extracting \"misc.c\" \(6692 characters\)
sed "s/^X//" >misc.c <<'END_OF_misc.c'
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Header: misc.c,v 1.5 87/05/02 17:34:04 paul Exp $";
X#endif
X
X/* $Source: /usr/src/local/vix/cron/misc.c,v $
X * $Revision: 1.5 $
X * $Log:	misc.c,v $
X * Revision 1.5  87/05/02  17:34:04  paul
X * baseline for mod.sources release
X * 
X * Revision 1.4  87/04/02  16:54:45  paul
X * added BSD/ATT differences in be_different()
X *   (another idea from rs@mirror)
X * 
X * Revision 1.3  87/02/11  00:55:10  paul
X * added strcmp_until; moved get_shell into user.c
X * 
X * Revision 1.2  87/02/02  19:25:01  paul
X * various
X * 
X * Revision 1.1  87/01/26  23:47:57  paul
X * Initial revision
X * 
X * vix 15jan87 [added TIOCNOTTY, thanks csg@pyramid]
X * vix 30dec86 [written]
X */
X
X/* Copyright 1987 by Vixie Enterprises
X * All rights reserved
X *
X * Distribute freely, except: don't sell it, don't remove my name from the
X * source or documentation (don't take credit for my work), mark your changes
X * (don't get me blamed for your possible bugs), don't alter or remove this
X * notice.  Commercial redistribution is negotiable; contact me for details.
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, Vixie Enterprises, 329 Noe Street, San Francisco, CA, 94114,
X * (415) 864-7013, {ucbvax!dual,ames,ucsfmis,lll-crg,sun}!ptsfa!vixie!paul.
X */
X
X
X#include "cron.h"
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/ioctl.h>
X
X
Xchar *
Xsavestr(str)
X	char	*str;
X{
X	char	*malloc(), *strcpy();
X	char	*temp;
X
X	temp = malloc((unsigned) (strlen(str) + 1));
X	(void) strcpy(temp, str);
X	return temp;
X}
X
X
Xint
Xnocase_strcmp(left, right)
X	char	*left;
X	char	*right;
X{
X	while (*left && (MkLower(*left) == MkLower(*right)))
X	{
X		left++;
X		right++;
X	}
X	return MkLower(*left) - MkLower(*right);
X}
X
X
Xint
Xstrcmp_until(left, right, until)
X	char	*left;
X	char	*right;
X	char	until;
X{
X	register int	diff;
X
X	Debug(DPARS|DEXT, ("strcmp_until(%s,%s,%c) ... ", left, right, until))
X
X	while (*left && *left != until && *left == *right)
X	{
X		left++;
X		right++;
X	}
X
X	if (	(*left=='\0' || *left == until) 
X	    &&	(*right=='\0' || *right == until)
X	   )
X		diff = 0;
X	else
X		diff = *left - *right;
X
X	Debug(DPARS|DEXT, ("%d\n", diff))
X
X	return diff;
X}
X
X
X/* strdtb(s) - delete trailing blanks in string 's' and return new length
X */
Xint
Xstrdtb(s)
X	register char	*s;
X{
X	register char	*x = s;
X
X	/* scan forward to the null
X	 */
X	while (*x)
X		x++;
X
X	/* scan backward to either the first character before the string,
X	 * or the last non-blank in the string, whichever comes first.
X	 */
X	do	{x--;}
X	while (x >= s && isspace(*x));
X
X	/* one character beyond where we stopped above is where the null
X	 * goes.
X	 */
X	*++x = '\0';
X
X	/* the difference between the position of the null character and
X	 * the position of the first character of the string is the length.
X	 */
X	return x - s;
X}
X
X
Xint
Xset_debug_flags(flags)
X	char	*flags;
X{
X	/* debug flags are of the form    flag[,flag ...]
X	 *
X	 * if an error occurs, print a message to stdout and return FALSE.
X	 * otherwise return TRUE after setting ERROR_FLAGS.
X	 */
X
X#if !DEBUGGING
X
X	printf("this program was compiled without debugging enabled\n");
X	return FALSE;
X
X#else /* DEBUGGING */
X
X	char	*pc = flags;
X
X	DEBUG_FLAGS = 0;
X
X	while (*pc)
X	{
X		char	**test;
X		int	mask;
X
X		/* try to find debug flag name in our list.
X		 */
X		for (	test = DEBUG_FLAG_NAMES, mask = 1;
X			*test && strcmp_until(*test, pc, ',');
X			test++, mask <<= 1
X		    )
X			;
X
X		if (!*test)
X		{
X			fprintf(stderr,
X				"unrecognized debug flag <%s> <%s>\n",
X				flags, pc);
X			return FALSE;
X		}
X
X		DEBUG_FLAGS |= mask;
X
X		/* skip to the next flag
X		 */
X		while (*pc && *pc != ',')
X			pc++;
X		if (*pc == ',')
X			pc++;
X	}
X
X	if (DEBUG_FLAGS)
X	{
X		int	flag;
X
X		fprintf(stderr, "debug flags enabled:");
X
X		for (flag = 0;  flag < DCOUNT;  flag++)
X			if (DEBUG_FLAGS & (1 << flag))
X				fprintf(stderr, " %s", DEBUG_FLAG_NAMES[flag]);
X		fprintf(stderr, "\n");
X	}
X
X	return TRUE;
X
X#endif /* DEBUGGING */
X}
X
X
Xvoid
Xset_cron_uid()
X{
X	int	seteuid();
X
X	if (ERR == seteuid(ROOT_UID))
X	{
X		perror("seteuid");
X		exit(ERROR_EXIT);
X	}
X}
X
X
X#if defined(BSD)
Xvoid
Xbe_different()
X{
X	/* release the control terminal:
X	 *  get new pgrp (name after our PID)
X	 *  do an IOCTL to void tty association
X	 */
X
X	extern int	getpid(), setpgrp(), open(), ioctl(), close();
X	auto int	fd;
X
X	(void) setpgrp(0, getpid());
X
X	if ((fd = open("/dev/tty", 2)) >= 0)
X	{
X		(void) ioctl(fd, TIOCNOTTY, (char*)0);
X		(void) close(fd);
X	}
X}
X#endif /*BSD*/
X
X#if defined(ATT)
Xvoid
Xbe_different()
X{
X	/* not being a system V wiz, I don't know if this is what you have
X	 * to do to release your control terminal.  what I want to accomplish
X	 * is to keep this process from getting any signals from the tty.
X	 *
X	 * some system V person should let me know if this works... (vixie)
X	 */
X	int	setpgrp(), close(), open();
X
X	(void) 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}
X#endif /*ATT*/
X
X/* get_char(file) : like getc() but increment LINE_NUMBER on newlines
X */
Xint
Xget_char(file)
X	FILE	*file;
X{
X	int	ch;
X
X	ch = getc(file);
X	if (ch == '\n')
X		Set_LineNum(LINE_NUMBER + 1)
X	return ch;
X}
X
X
X/* unget_char(ch, file) : like ungetc but do LINE_NUMBER processing
X */
Xvoid
Xunget_char(ch, file)
X	int	ch;
X	FILE	*file;
X{
X	ungetc(ch, file);
X	if (ch == '\n')
X		Set_LineNum(LINE_NUMBER - 1)
X}
X
X
X/* get_string(str, max, file, termstr) : like fgets() but
X *		(1) has terminator string which should include \n
X *		(2) will always leave room for the null
X *		(3) uses get_char() so LINE_NUMBER will be accurate
X *		(4) returns EOF or terminating character, whichever
X */
Xint
Xget_string(string, size, file, terms)
X	char	*string;
X	int	size;
X	FILE	*file;
X	char	*terms;
X{
X	int	ch;
X	char	*index();
X
X	while (EOF != (ch = get_char(file)) && !index(terms, ch))
X		if (size > 1)
X		{
X			*string++ = (char) ch;
X			size--;
X		}
X
X	if (size > 0)
X		*string = '\0';
X
X	return ch;
X}
X
X
X/* skip_comments(file) : read past comment (if any)
X */
Xvoid
Xskip_comments(file)
X	FILE	*file;
X{
X	int	ch;
X
X	while (EOF != (ch = get_char(file)))
X	{
X		/* ch is now the first character of a line.
X		 */
X
X		while (ch == ' ' || ch == '\t')
X			ch = get_char(file);
X
X		if (ch == EOF)
X			break;
X
X		/* ch is now the first non-blank character of a line.
X		 */
X
X		if (ch != '\n' && ch != '#')
X			break;
X
X		/* ch must be a newline or comment as first non-blank
X		 * character on a line.
X		 */
X
X		while (ch != '\n' && ch != EOF)
X			ch = get_char(file);
X
X		/* ch is now the newline of a line which we're going to
X		 * ignore.
X		 */
X	}
X	unget_char(ch, file);
X}
END_OF_misc.c
if test 6692 -ne `wc -c <misc.c`; then
    echo shar: \"misc.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f user.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"user.c\"
else
echo shar: Extracting \"user.c\" \(3158 characters\)
sed "s/^X//" >user.c <<'END_OF_user.c'
X#if !defined(lint) && !defined(LINT)
Xstatic char rcsid[] = "$Header: user.c,v 1.2 87/05/02 17:34:11 paul Exp $";
X#endif
X
X/* $Source: /usr/src/local/vix/cron/user.c,v $
X * $Revision: 1.2 $
X * $Log:	user.c,v $
X * Revision 1.2  87/05/02  17:34:11  paul
X * baseline for mod.sources release
X * 
X * Revision 1.1  87/01/26  23:48:47  paul
X * Initial revision
X */
X
X/* Copyright 1987 by Vixie Enterprises
X * All rights reserved
X *
X * Distribute freely, except: don't sell it, don't remove my name from the
X * source or documentation (don't take credit for my work), mark your changes
X * (don't get me blamed for your possible bugs), don't alter or remove this
X * notice.  Commercial redistribution is negotiable; contact me for details.
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, Vixie Enterprises, 329 Noe Street, San Francisco, CA, 94114,
X * (415) 864-7013, {ucbvax!dual,ames,ucsfmis,lll-crg,sun}!ptsfa!vixie!paul.
X */
X
X
X#include "cron.h"
X#include <errno.h>
X
X
Xextern	errno;
X
X
Xvoid
Xfree_user(u)
X	user	*u;
X{
X	void	free_entry();
X	int	free();
X	entry	*e;
X	char	**env;
X
X	for (e = u->crontab;  e != NULL;  e = e->next)
X		free_entry(e);
X	for (env = u->envp;  *env;  env++)
X		(void) free(*env);
X	free((char *) u->envp);
X	(void) free((char *) u);
X}
X
X
Xuser *
Xload_user(name, uid, gid, dir, shell)
X	char	*name;
X	int	uid;
X	int	gid;
X	char	*dir;
X	char	*shell;
X{
X	char	*malloc(), *savestr(), *sprintf(),
X		**env_init(), **env_set();
X	int	load_env();
X	entry	*load_entry();
X
X	char	filename[MAX_FNAME], envstr[MAX_TEMPSTR];
X	FILE	*file;
X	user	*u;
X	entry	*e;
X	int	status;
X
X	sprintf(filename, SPOOLDIR, name);
X	if (!(file = fopen(filename, "r")))
X	{
X		/* file can't be opened.  if it's because the file doesn't
X		 * exist, it isn't critical -- it means that the user doesn't
X		 * have a crontab file.  just return NULL, and let our caller
X		 * worry about it, or not.
X		 *
X		 * if it isn't ENOENT, we have a problem that the caller
X		 * probably can't handle; print the error before returning.
X		 */
X		if (errno != ENOENT)
X			perror(filename);
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->uid   = uid;
X	u->gid   = gid;
X	u->envp  = env_init();
X	u->crontab = NULL;
X
X	/*
X	 * do auto env settings that the user could reset in the cron tab
X	 */
X	sprintf(envstr, "SHELL=%s", shell);
X	u->envp = env_set(u->envp, envstr);
X
X	sprintf(envstr, "HOME=%s", dir);
X	u->envp = env_set(u->envp, envstr);
X
X	while (ERR != (status = load_env(envstr, file)))
X	{
X		if (status == TRUE)
X		{
X			u->envp = env_set(u->envp, envstr);
X		}
X		else
X		{
X			if (NULL != (e = load_entry(file, NULL)))
X			{
X				e->next = u->crontab;
X				u->crontab = e;
X			}
X		}
X	}
X
X	/*
X	 * do automatic env settings that should have precedence over any
X	 * set in the cron tab.
X	 */
X	(void) sprintf(envstr, "USER=%s", name);
X	u->envp = env_set(u->envp, envstr);
X
X	/*
X	 * done. close file, return pointer to 'user' structure
X	 */
X	fclose(file);
X
X	Debug(DPARS, ("...load_user() done\n"))
X
X	return u;
X}
END_OF_user.c
if test 3158 -ne `wc -c <user.c`; then
    echo shar: \"user.c\" unpacked with wrong size!
fi
# end of overwriting check
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