Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
     5         kx 
     5         kx /*
     5         kx  * MAIN.C
     5         kx  *
     5         kx  * crond [-s dir] [-c dir] [-t dir] [-m user@host] [-M mailer] [-S|-L [file]] [-l level] [-b|-f|-d]
     5         kx  * run as root, but NOT setuid root
     5         kx  *
     5         kx  * Copyright 1994 Matthew Dillon (dillon@apollo.backplane.com)
     5         kx  * Copyright 2009-2011 James Pryor <profjim@jimpryor.net>
     5         kx  * May be distributed under the GNU General Public License
     5         kx  */
     5         kx 
     5         kx #include "defs.h"
     5         kx 
     5         kx Prototype short DebugOpt;
     5         kx Prototype short LogLevel;
     5         kx Prototype short ForegroundOpt;
     5         kx Prototype short SyslogOpt;
     5         kx Prototype const char *CDir;
     5         kx Prototype const char *SCDir;
     5         kx Prototype const char *TSDir;
     5         kx Prototype const char *LogFile;
     5         kx Prototype const char *LogHeader;
     5         kx Prototype uid_t DaemonUid;
     5         kx Prototype pid_t DaemonPid;
     5         kx Prototype const char *SendMail;
     5         kx Prototype const char *Mailto;
     5         kx Prototype char *TempDir;
     5         kx Prototype char *TempFileFmt;
     5         kx 
     5         kx short DebugOpt = 0;
     5         kx short LogLevel = LOG_LEVEL;
     5         kx short ForegroundOpt = 0;
     5         kx short SyslogOpt = 1;
     5         kx const char  *CDir = CRONTABS;
     5         kx const char  *SCDir = SCRONTABS;
     5         kx const char *TSDir = CRONSTAMPS;
     5         kx const char *LogFile = NULL; 	/* opened with mode 0600 */
     5         kx const char *LogHeader = LOGHEADER;
     5         kx const char *SendMail = NULL;
     5         kx const char *Mailto = NULL;
     5         kx char *TempDir;
     5         kx char *TempFileFmt;
     5         kx 
     5         kx uid_t DaemonUid;
     5         kx pid_t DaemonPid;
     5         kx 
     5         kx int
     5         kx main(int ac, char **av)
     5         kx {
     5         kx 	const char *LevelAry[] = {
     5         kx 		"emerg",
     5         kx 		"alert",
     5         kx 		"crit",
     5         kx 		"err",
     5         kx 		"warning",
     5         kx 		"notice",
     5         kx 		"info",
     5         kx 		"debug",
     5         kx 		"panic",
     5         kx 		"error",
     5         kx 		"warn",
     5         kx 		NULL
     5         kx 	};
     5         kx 	int i;
     5         kx 
     5         kx 	/*
     5         kx 	 * parse options
     5         kx 	 */
     5         kx 
     5         kx 	DaemonUid = getuid();
     5         kx 
     5         kx 	opterr = 0;
     5         kx 
     5         kx 	while ((i = getopt(ac,av,"dl:L:fbSc:s:m:M:t:")) != -1) {
     5         kx 		switch (i) {
     5         kx 			case 'l':
     5         kx 				{
     5         kx 					char *ptr;
     5         kx 					int j;
     5         kx 					ptr = optarg;
     5         kx 					for (j = 0; LevelAry[j]; ++j) {
     5         kx 						if (strncmp(ptr, LevelAry[j], strlen(LevelAry[j])) == 0) {
     5         kx 							break;
     5         kx 						}
     5         kx 					}
     5         kx 					switch(j) {
     5         kx 						case 0:
     5         kx 						case 8:
     5         kx 							/* #define	LOG_EMERG	0	[* system is unusable *] */
     5         kx 							LogLevel = LOG_EMERG;
     5         kx 							break;
     5         kx 						case 1:
     5         kx 							/* #define	LOG_ALERT	1	[* action must be taken immediately *] */
     5         kx 							LogLevel = LOG_ALERT;
     5         kx 							break;
     5         kx 						case 2:
     5         kx 							/* #define	LOG_CRIT	2	[* critical conditions *] */
     5         kx 							LogLevel = LOG_CRIT;
     5         kx 							break;
     5         kx 						case 3:
     5         kx 						case 9:
     5         kx 							/* #define	LOG_ERR		3	[* error conditions *] */
     5         kx 							LogLevel = LOG_ERR;
     5         kx 							break;
     5         kx 						case 4:
     5         kx 						case 10:
     5         kx 							/* #define	LOG_WARNING	4	[* warning conditions *] */
     5         kx 							LogLevel = LOG_WARNING;
     5         kx 							break;
     5         kx 						case 5:
     5         kx 							/* #define	LOG_NOTICE	5	[* normal but significant condition *] */
     5         kx 							LogLevel = LOG_NOTICE;
     5         kx 							break;
     5         kx 						case 6:
     5         kx 							/* #define	LOG_INFO	6	[* informational *] */
     5         kx 							LogLevel = LOG_INFO;
     5         kx 							break;
     5         kx 						case 7:
     5         kx 							/* #define	LOG_DEBUG	7	[* debug-level messages *] */
     5         kx 							LogLevel = LOG_DEBUG;
     5         kx 							break;
     5         kx 						default:
     5         kx 							LogLevel = atoi(optarg);
     5         kx 					}
     5         kx 				}
     5         kx 				break;
     5         kx 			case 'd':
     5         kx 				DebugOpt = 1;
     5         kx 				LogLevel = LOG_DEBUG;
     5         kx 				/* fall through to include f too */
     5         kx 			case 'f':
     5         kx 				ForegroundOpt = 1;
     5         kx 				break;
     5         kx 			case 'b':
     5         kx 				ForegroundOpt = 0;
     5         kx 				break;
     5         kx 			case 'S':			/* log through syslog */
     5         kx 				SyslogOpt = 1;
     5         kx 				break;
     5         kx 			case 'L':			/* use internal log formatter */
     5         kx 				SyslogOpt = 0;
     5         kx 				LogFile = optarg;
     5         kx 				/* if LC_TIME is defined, we use it for logging to file instead of compiled-in TIMESTAMP_FMT */
     5         kx 				if (getenv("LC_TIME") != NULL) {
     5         kx 					LogHeader = LOCALE_LOGHEADER;
     5         kx 				}
     5         kx 				break;
     5         kx 			case 'c':
     5         kx 				if (*optarg != 0) CDir = optarg;
     5         kx 				break;
     5         kx 			case 's':
     5         kx 				if (*optarg != 0) SCDir = optarg;
     5         kx 				break;
     5         kx 			case 't':
     5         kx 				if (*optarg != 0) TSDir = optarg;
     5         kx 				break;
     5         kx 			case 'M':
     5         kx 				if (*optarg != 0) SendMail = optarg;
     5         kx 				break;
     5         kx 			case 'm':
     5         kx 				if (*optarg != 0) Mailto = optarg;
     5         kx 				break;
     5         kx 			default:
     5         kx 				/*
     5         kx 				 * check for parse error
     5         kx 				 */
     5         kx 				printf("dillon's cron daemon " VERSION "\n");
     5         kx 				printf("crond [-s dir] [-c dir] [-t dir] [-m user@host] [-M mailer] [-S|-L [file]] [-l level] [-b|-f|-d]\n");
     5         kx 				printf("-s            directory of system crontabs (defaults to %s)\n", SCRONTABS);
     5         kx 				printf("-c            directory of per-user crontabs (defaults to %s)\n", CRONTABS);
     5         kx 				printf("-t            directory of timestamps (defaults to %s)\n", CRONSTAMPS);
     5         kx 				printf("-m user@host  where should cron output be directed? (defaults to local user)\n");
     5         kx 				printf("-M mailer     (defaults to %s)\n", SENDMAIL);
     5         kx 				printf("-S            log to syslog using identity '%s' (default)\n", LOG_IDENT);
     5         kx 				printf("-L file       log to specified file instead of syslog\n");
     5         kx 				printf("-l loglevel   log events <= this level (defaults to %s (level %d))\n", LevelAry[LOG_LEVEL], LOG_LEVEL);
     5         kx 				printf("-b            run in background (default)\n");
     5         kx 				printf("-f            run in foreground\n");
     5         kx 				printf("-d            run in debugging mode\n");
     5         kx 				exit(2);
     5         kx 		}
     5         kx 	}
     5         kx 
     5         kx 	/*
     5         kx 	 * close stdin and stdout.
     5         kx 	 * close unused descriptors -  don't need.
     5         kx 	 * optional detach from controlling terminal
     5         kx 	 */
     5         kx 
     5         kx 	fclose(stdin);
     5         kx 	fclose(stdout);
     5         kx 
     5         kx 	i = open("/dev/null", O_RDWR);
     5         kx 	if (i < 0) {
     5         kx 		perror("open: /dev/null");
     5         kx 		exit(1);
     5         kx 	}
     5         kx 	dup2(i, 0);
     5         kx 	dup2(i, 1);
     5         kx 
     5         kx 	/* create tempdir with permissions 0755 for cron output */
     5         kx 	TempDir = strdup(TMPDIR "/cron.XXXXXX");
     5         kx 	if (mkdtemp(TempDir) == NULL) {
     5         kx 		perror("mkdtemp");
     5         kx 		exit(1);
     5         kx 	}
     5         kx 	if (chmod(TempDir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
     5         kx 		perror("chmod");
     5         kx 		exit(1);
     5         kx 	}
     5         kx 	if (!(TempFileFmt = concat(TempDir, "/cron.%s.%d", NULL))) {
     5         kx 		errno = ENOMEM;
     5         kx 		perror("main");
     5         kx 		exit(1);
     5         kx 	}
     5         kx 
     5         kx 	if (ForegroundOpt == 0) {
     5         kx 
     5         kx 		int fd;
     5         kx 		int pid;
     5         kx 
     5         kx 		if ((pid = fork()) < 0) {
     5         kx 			/* fork failed */
     5         kx 			perror("fork");
     5         kx 			exit(1);
     5         kx 		} else if (pid > 0) {
     5         kx 			/* parent */
     5         kx 			exit(0);
     5         kx 		}
     5         kx 		/* child continues */
     5         kx 
     5         kx 		/* become session leader, detach from terminal */
     5         kx 
     5         kx 		if (setsid() < 0)
     5         kx 			perror("setsid");
     5         kx 		if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
     5         kx 			ioctl(fd, TIOCNOTTY, 0);
     5         kx 			close(fd);
     5         kx 		}
     5         kx 
     5         kx 		/* setup logging for backgrounded daemons */
     5         kx 
     5         kx 		if (SyslogOpt) {
     5         kx 			/* start SIGHUP and SIGCHLD handling while stderr still open */
     5         kx 			initsignals();
     5         kx 			/* 2> /dev/null */
     5         kx 			fclose(stderr);
     5         kx 			dup2(1, 2);
     5         kx 
     5         kx 			/* open syslog */
     5         kx 			openlog(LOG_IDENT, LOG_CONS|LOG_PID, LOG_CRON);
     5         kx 
     5         kx 		} else {
     5         kx 			/* open logfile */
     5         kx 			if ((fd = open(LogFile, O_WRONLY|O_CREAT|O_APPEND, 0600)) >= 0) {
     5         kx 				/* start SIGHUP ignoring, SIGCHLD handling while stderr still open */
     5         kx 				initsignals();
     5         kx 				/* 2> LogFile */
     5         kx 				fclose(stderr);
     5         kx 				dup2(fd, 2);
     5         kx 			} else {
     5         kx 				int n = errno;
     5         kx 				fdprintf(2, "failed to open logfile '%s', reason: %s", LogFile, strerror(n));
     5         kx 				exit(n);
     5         kx 			}
     5         kx 		}
     5         kx 	} else {
     5         kx 		/* daemon in foreground */
     5         kx 
     5         kx 		/* stay in existing session, but start a new process group */
     5         kx 		if (setpgid(0,0)) {
     5         kx 			perror("setpgid");
     5         kx 			exit(1);
     5         kx 		}
     5         kx 
     5         kx 		/* stderr stays open, start SIGHUP ignoring, SIGCHLD handling */
     5         kx 		initsignals();
     5         kx 	}
     5         kx 
     5         kx 	/* close all other fds, including the ones we opened as /dev/null and LogFile */
     5         kx 	for (i = 3; i < MAXOPEN; ++i) {
     5         kx         close(i);
     5         kx     }
     5         kx 
     5         kx 
     5         kx 	/*
     5         kx 	 * main loop - synchronize to 1 second after the minute, minimum sleep
     5         kx 	 *             of 1 second.
     5         kx 	 */
     5         kx 
     5         kx 	printlogf(LOG_NOTICE,"%s " VERSION " dillon's cron daemon, started with loglevel %s\n", av[0], LevelAry[LogLevel]);
     5         kx 	SynchronizeDir(CDir, NULL, 1);
     5         kx 	SynchronizeDir(SCDir, "root", 1);
     5         kx 	ReadTimestamps(NULL);
     5         kx 	TestStartupJobs(); /* @startup jobs only run when crond is started, not when their crontab is loaded */
     5         kx 
     5         kx 	{
     5         kx 		time_t t1 = time(NULL);
     5         kx 		time_t t2;
     5         kx 		long dt;
     5         kx 		short rescan = 60;
     5         kx 		short stime = 60;
     5         kx 
     5         kx 		for (;;) {
     5         kx 			sleep((stime + 1) - (short)(time(NULL) % stime));
     5         kx 
     5         kx 			t2 = time(NULL);
     5         kx 			dt = t2 - t1;
     5         kx 
     5         kx 			/*
     5         kx 			 * The file 'cron.update' is checked to determine new cron
     5         kx 			 * jobs.  The directory is rescanned once an hour to deal
     5         kx 			 * with any screwups.
     5         kx 			 *
     5         kx 			 * check for disparity.  Disparities over an hour either way
     5         kx 			 * result in resynchronization.  A reverse-indexed disparity
     5         kx 			 * less then an hour causes us to effectively sleep until we
     5         kx 			 * match the original time (i.e. no re-execution of jobs that
     5         kx 			 * have just been run).  A forward-indexed disparity less then
     5         kx 			 * an hour causes intermediate jobs to be run, but only once
     5         kx 			 * in the worst case.
     5         kx 			 *
     5         kx 			 * when running jobs, the inequality used is greater but not
     5         kx 			 * equal to t1, and less then or equal to t2.
     5         kx 			 */
     5         kx 
     5         kx 			if (--rescan == 0) {
     5         kx 				/*
     5         kx 				 * If we resynchronize while jobs are running, we'll clobber
     5         kx 				 * the job pids, so we won't know what's already running.
     5         kx 				 */
     5         kx 				if (CheckJobs() > 0) {
     5         kx 					rescan = 1;
     5         kx 				} else {
     5         kx 					rescan = 60;
     5         kx 					SynchronizeDir(CDir, NULL, 0);
     5         kx 					SynchronizeDir(SCDir, "root", 0);
     5         kx 					ReadTimestamps(NULL);
     5         kx 				}
     5         kx 			}
     5         kx 			if (rescan < 60) {
     5         kx 				CheckUpdates(CDir, NULL, t1, t2);
     5         kx 				CheckUpdates(SCDir, "root", t1, t2);
     5         kx 			}
     5         kx 			if (DebugOpt)
     5         kx 				printlogf(LOG_DEBUG, "Wakeup dt=%d\n", dt);
     5         kx 			if (dt < -60*60 || dt > 60*60) {
     5         kx 				t1 = t2;
     5         kx 				printlogf(LOG_NOTICE,"time disparity of %d minutes detected\n", dt / 60);
     5         kx 			} else if (dt > 0) {
     5         kx 				TestJobs(t1, t2);
     5         kx 				RunJobs();
     5         kx 				sleep(5);
     5         kx 				if (CheckJobs() > 0)
     5         kx 					stime = 10;
     5         kx 				else
     5         kx 					stime = 60;
     5         kx 				t1 = t2;
     5         kx 			}
     5         kx 		}
     5         kx 	}
     5         kx 	/* not reached */
     5         kx }
     5         kx