ftp.nice.ch/pub/next/unix/admin/cron-vixie.2.1.N.bs.tar.gz#/cron-vixie-2.1-next/crontab.c

This is crontab.c in view mode; [Download] [Up]

#if !defined(lint) && !defined(LINT)
static char rcsid[] = "$Header: /private/Net/beauty/src/vixie-cron-2.1/RCS/crontab.c,v 2.2 90/07/18 00:23:56 vixie Exp Locker: irving $";
#endif

/* Revision 1.5  87/05/02  17:33:22  paul
 * pokecron?  (RCS file has the rest of the log)
 * 
 * Revision 1.5  87/05/02  17:33:22  paul
 * baseline for mod.sources release
 * 
 * Revision 1.4  87/03/31  13:11:48  paul
 * I won't say that rs@mirror gave me this idea but crontab uses getopt() now
 * 
 * Revision 1.3  87/03/30  23:43:48  paul
 * another suggestion from rs@mirror:
 *   use getpwuid(getuid)->pw_name instead of getenv("USER")
 *   this is a boost to security...
 * 
 * Revision 1.2  87/02/11  17:40:12  paul
 * changed command syntax to allow append and replace instead of append as
 * default and no replace at all.
 * 
 * Revision 1.1  87/01/26  23:49:06  paul
 * Initial revision
 */

/* Copyright 1988,1990 by Paul Vixie
 * All rights reserved
 *
 * Distribute freely, except: don't remove my name from the source or
 * documentation (don't take credit for my work), mark your changes (don't
 * get me blamed for your possible bugs), don't alter or remove this
 * notice.  May be sold if buildable source is provided to buyer.  No
 * warrantee of any kind, express or implied, is included with this
 * software; use at your own risk, responsibility for damages (if any) to
 * anyone resulting from the use of this software rests entirely with the
 * user.
 *
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
 * I'll try to keep a version up to date.  I can be reached as follows:
 * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
 * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
 */


#define	MAIN_PROGRAM


#include "cron.h"
#include <pwd.h>
#include <errno.h>
#include <sys/file.h>
#if defined(BSD)
# include <sys/time.h>
#endif  /*BSD*/

extern	char	*sprintf();


static int	Pid;
static char	User[MAX_UNAME], RealUser[MAX_UNAME];
static char	Filename[MAX_FNAME];
static FILE	*NewCrontab;
static int	CheckErrorCount;
static enum	{opt_unknown, opt_list, opt_delete, opt_replace}
		Option;

extern void	log_it();

#if DEBUGGING
static char	*Options[] = {"???", "list", "delete", "replace"};
#endif

static void
usage()
{
	fprintf(stderr, "usage:  %s [-u user] ...\n", ProgramName);
	fprintf(stderr, " ... -l         (list user's crontab)\n");
	fprintf(stderr, " ... -d         (delete user's crontab)\n");
	fprintf(stderr, " ... -r file    (replace user's crontab)\n");
	exit(ERROR_EXIT);
}


main(argc, argv)
	int	argc;
	char	*argv[];
{
	static void	parse_args(), set_cron_uid(), set_cron_cwd(),
		list_cmd(), delete_cmd(), replace_cmd();

	Pid = getpid();
	ProgramName = argv[0];
#if defined(BSD)
	setlinebuf(stderr);
#endif
	parse_args(argc, argv);		/* sets many globals, opens a file */
	set_cron_uid();
	set_cron_cwd();
	if (!allowed(User)) {
		fprintf(stderr,
			"You (%s) are not allowed to use this program (%s)\n",
			User, ProgramName);
		fprintf(stderr, "See crontab(1) for more information\n");
		log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
		exit(ERROR_EXIT);
	}
	switch (Option)
	{
	case opt_list:		list_cmd();
				break;
	case opt_delete:	delete_cmd();
				break;
	case opt_replace:	replace_cmd();
				break;
	}
}
	

static void
parse_args(argc, argv)
	int	argc;
	char	*argv[];
{
	void		usage();
	char		*getenv(), *strcpy();
	int		getuid();
	struct passwd	*getpwnam();
	extern int	getopt(), optind;
	extern char	*optarg;

	struct passwd	*pw;
	int		argch;

	if (!(pw = getpwuid(getuid())))
	{
		fprintf(stderr, "%s: your UID isn't in the passwd file.\n",
			ProgramName);
		fprintf(stderr, "bailing out.\n");
		exit(ERROR_EXIT);
	}
	strcpy(User, pw->pw_name);
	strcpy(RealUser, User);
	Filename[0] = '\0';
	Option = opt_unknown;
	while (EOF != (argch = getopt(argc, argv, "u:ldr:x:")))
	{
		switch (argch)
		{
		case 'x':
			if (!set_debug_flags(optarg))
				usage();
			break;
		case 'u':
			if (getuid() != ROOT_UID)
			{
				fprintf(stderr,
					"must be privileged to use -u\n");
				exit(ERROR_EXIT);
			}
			if ((struct passwd *)NULL == getpwnam(optarg))
			{
				fprintf(stderr, "%s:  user `%s' unknown\n",
					ProgramName, optarg);
				exit(ERROR_EXIT);
			}
			(void) strcpy(User, optarg);
			break;
		case 'l':
			if (Option != opt_unknown)
				usage();
			Option = opt_list;
			break;
		case 'd':
			if (Option != opt_unknown)
				usage();
			Option = opt_delete;
			break;
		case 'r':
			if (Option != opt_unknown)
				usage();
			Option = opt_replace;
			(void) strcpy(Filename, optarg);
			break;
		default:
			usage();
		}
	}

	endpwent();

	if (Option == opt_unknown || argv[optind] != NULL)
		usage();

	if (Option == opt_replace) {
		if (!Filename[0]) {
			/* getopt(3) says this can't be true
			 * but I'm paranoid today.
			 */
			fprintf(stderr, "filename must be given for -a or -r\n");
			usage();
		}
		/* we have to open the file here because we're going to
		 * chdir(2) into /var/cron before we get around to
		 * reading the file.
		 */
		if (!strcmp(Filename, "-")) {
			NewCrontab = stdin;
		} else {
			if (!(NewCrontab = fopen(Filename, "r"))) {
				perror(Filename);
				exit(ERROR_EXIT);
			}
		}
	}

	Debug(DMISC, ("user=%s, file=%s, option=%s\n",
					User, Filename, Options[(int)Option]))
}


static void
list_cmd()
{
	extern	errno;
	char	n[MAX_FNAME];
	FILE	*f;
	int	ch;

	log_it(RealUser, Pid, "LIST", User);
	(void) sprintf(n, CRON_TAB(User));
	if (!(f = fopen(n, "r")))
	{
		if (errno == ENOENT)
			fprintf(stderr, "no crontab for %s\n", User);
		else
			perror(n);
		exit(ERROR_EXIT);
	}

	/* file is open. copy to stdout, close.
	 */
	Set_LineNum(1)
	while (EOF != (ch = get_char(f)))
		putchar(ch);
	fclose(f);
}


static void
delete_cmd()
{
	extern	errno;
	int	unlink();
	static void	poke_daemon();
	char	n[MAX_FNAME];

	log_it(RealUser, Pid, "DELETE", User);
	(void) sprintf(n, CRON_TAB(User));
	if (unlink(n))
	{
		if (errno == ENOENT)
			fprintf(stderr, "no crontab for %s\n", User);
		else
			perror(n);
		exit(ERROR_EXIT);
	}
	poke_daemon();
}


static void
check_error(msg)
	char	*msg;
{
	CheckErrorCount += 1;
	fprintf(stderr, "\"%s\", line %d: %s\n", Filename, LineNumber, msg);
}


static void
replace_cmd()
{
	char	*sprintf();
	entry	*load_entry();
	int	load_env();
	int	unlink();
	void	free_entry();
	void	check_error();
	static void	poke_daemon();
	extern	errno;

	char	n[MAX_FNAME], envstr[MAX_ENVSTR], tn[MAX_FNAME];
	FILE	*tmp;
	int	ch;
	entry	*e;
	int	status;
	time_t	now = time(NULL);

	(void) sprintf(n, "tmp.%d", Pid);
	(void) sprintf(tn, CRON_TAB(n));
	if (!(tmp = fopen(tn, "w"))) {
		perror(tn);
		exit(ERROR_EXIT);
	}

	/* write a signature at the top of the file.  for brian.
	 */
	fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
	fprintf(tmp, "# (Cron version -- %s)\n", rcsid);

	/* copy the crontab to the tmp
	 */
	Set_LineNum(1)
	while (EOF != (ch = get_char(NewCrontab)))
		putc(ch, tmp);
	fclose(NewCrontab);
	fflush(tmp);  rewind(tmp);

	if (ferror(tmp)) {
		fprintf("%s: error while writing new crontab to %s\n",
			ProgramName, tn);
		fclose(tmp);  unlink(tn);
		exit(ERROR_EXIT);
	}

	/* check the syntax of the file being installed.
	 */

	/* BUG: was reporting errors after the EOF if there were any errors
	 * in the file proper -- kludged it by stopping after first error.
	 *		vix 31mar87
	 */
	CheckErrorCount = 0;
	while (!CheckErrorCount && (status = load_env(envstr, tmp)) >= OK)
	{
		if (status == FALSE)
		{
			if (NULL != (e = load_entry(NewCrontab, check_error)))
				free((char *) e);
		}
	}

	if (CheckErrorCount != 0)
	{
		fprintf(stderr, "errors in crontab file, can't install.\n");
		fclose(tmp);  unlink(tn);
		exit(ERROR_EXIT);
	}

	if (fchown(fileno(tmp), ROOT_UID, -1) < OK)
	{
		perror("chown");
		fclose(tmp);  unlink(tn);
		exit(ERROR_EXIT);
	}

	if (fchmod(fileno(tmp), 0600) < OK)
	{
		perror("chown");
		fclose(tmp);  unlink(tn);
		exit(ERROR_EXIT);
	}

	if (fclose(tmp) == EOF) {
		perror("fclose");
		unlink(tn);
		exit(ERROR_EXIT);
	}

	(void) sprintf(n, CRON_TAB(User));
	if (rename(tn, n))
	{
		fprintf(stderr, "%s: error renaming %s to %s\n",
			ProgramName, tn, n);
		perror("rename");
		unlink(tn);
		exit(ERROR_EXIT);
	}
	log_it(RealUser, Pid, "REPLACE", User);

	poke_daemon();
}


static void
poke_daemon()
{
#if defined(BSD)
	struct timeval tvs[2];
	struct timezone tz;

	(void) gettimeofday(&tvs[0], &tz);
	tvs[1] = tvs[0];
	if (utimes(SPOOL_DIR, tvs) < OK)
	{
		fprintf(stderr, "crontab: can't update mtime on spooldir\n");
		perror(SPOOL_DIR);
		return;
	}
#endif  /*BSD*/
#if defined(ATT)
	if (utime(SPOOL_DIR, NULL) < OK)
	{
		fprintf(stderr, "crontab: can't update mtime on spooldir\n");
		perror(SPOOL_DIR);
		return;
	}
#endif  /*ATT*/
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.