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