blob: f0b475389a4dbd8c8db7d0e8290590fcb4b9e469 [file] [log] [blame]
Bernhard Reutner-Fischer2c998512006-04-12 18:09:26 +00001/* vi: set sw=4 ts=4: */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00002/*
3 * crond -d[#] -c <crondir> -f -b
4 *
5 * run as root, but NOT setuid root
6 *
7 * Copyright 1994 Matthew Dillon (dillon@apollo.west.oic.com)
Mike Frysingerf284c762006-04-16 20:38:26 +00008 * Vladimir Oleynik <dzo@simtreas.ru> (C) 2002
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00009 *
Mike Frysingerf284c762006-04-16 20:38:26 +000010 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000011 */
12
13#define VERSION "2.3.2"
14
15#undef FEATURE_DEBUG_OPT
16
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <stdarg.h>
21#include <string.h>
22#include <errno.h>
23#include <time.h>
24#include <dirent.h>
25#include <fcntl.h>
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000026#include <unistd.h>
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000027#include <syslog.h>
28#include <signal.h>
29#include <getopt.h>
30#include <sys/ioctl.h>
31#include <sys/wait.h>
32#include <sys/stat.h>
33#include <sys/resource.h>
34
35#include "busybox.h"
36
37#define arysize(ary) (sizeof(ary)/sizeof((ary)[0]))
38
39#ifndef CRONTABS
40#define CRONTABS "/var/spool/cron/crontabs"
41#endif
42#ifndef TMPDIR
43#define TMPDIR "/var/spool/cron"
44#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000045#ifndef SENDMAIL
46#define SENDMAIL "/usr/sbin/sendmail"
47#endif
48#ifndef SENDMAIL_ARGS
Eric Andersen35e643b2003-07-28 07:40:39 +000049#define SENDMAIL_ARGS "-ti", "oem"
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000050#endif
51#ifndef CRONUPDATE
52#define CRONUPDATE "cron.update"
53#endif
54#ifndef MAXLINES
Glenn L McGrath9079ad02004-02-22 04:44:21 +000055#define MAXLINES 256 /* max lines in non-root crontabs */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000056#endif
57
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000058typedef struct CronFile {
Glenn L McGrath9079ad02004-02-22 04:44:21 +000059 struct CronFile *cf_Next;
60 struct CronLine *cf_LineBase;
61 char *cf_User; /* username */
62 int cf_Ready; /* bool: one or more jobs ready */
63 int cf_Running; /* bool: one or more jobs running */
64 int cf_Deleted; /* marked for deletion, ignore */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000065} CronFile;
66
67typedef struct CronLine {
Glenn L McGrath9079ad02004-02-22 04:44:21 +000068 struct CronLine *cl_Next;
69 char *cl_Shell; /* shell command */
70 pid_t cl_Pid; /* running pid, 0, or armed (-1) */
71 int cl_MailFlag; /* running pid is for mail */
72 int cl_MailPos; /* 'empty file' size */
73 char cl_Mins[60]; /* 0-59 */
74 char cl_Hrs[24]; /* 0-23 */
75 char cl_Days[32]; /* 1-31 */
76 char cl_Mons[12]; /* 0-11 */
77 char cl_Dow[7]; /* 0-6, beginning sunday */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000078} CronLine;
79
80#define RUN_RANOUT 1
81#define RUN_RUNNING 2
82#define RUN_FAILED 3
83
84#define DaemonUid 0
85
86#ifdef FEATURE_DEBUG_OPT
87static short DebugOpt;
88#endif
89
90static short LogLevel = 8;
Glenn L McGrath9079ad02004-02-22 04:44:21 +000091static const char *LogFile;
92static const char *CDir = CRONTABS;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000093
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000094static void startlogger(void);
95
96static void CheckUpdates(void);
97static void SynchronizeDir(void);
98static int TestJobs(time_t t1, time_t t2);
99static void RunJobs(void);
100static int CheckJobs(void);
Eric Andersen35e643b2003-07-28 07:40:39 +0000101
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000102static void RunJob(const char *user, CronLine * line);
103
Eric Andersen35e643b2003-07-28 07:40:39 +0000104#ifdef CONFIG_FEATURE_CROND_CALL_SENDMAIL
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000105static void EndJob(const char *user, CronLine * line);
Eric Andersen35e643b2003-07-28 07:40:39 +0000106#else
107#define EndJob(user, line) line->cl_Pid = 0
108#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000109
110static void DeleteFile(const char *userName);
111
112static CronFile *FileBase;
113
114
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000115static void crondlog(const char *ctl, ...)
Eric Andersen35e643b2003-07-28 07:40:39 +0000116{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000117 va_list va;
118 const char *fmt;
119 int level = (int) (ctl[0] & 0xf);
120 int type = level == 20 ?
121 LOG_ERR : ((ctl[0] & 0100) ? LOG_WARNING : LOG_NOTICE);
Eric Andersen35e643b2003-07-28 07:40:39 +0000122
123
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000124 va_start(va, ctl);
125 fmt = ctl + 1;
126 if (level >= LogLevel) {
Eric Andersen35e643b2003-07-28 07:40:39 +0000127
128#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000129 if (DebugOpt) {
130 vfprintf(stderr, fmt, va);
131 } else
Eric Andersen35e643b2003-07-28 07:40:39 +0000132#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000133 if (LogFile == 0) {
134 vsyslog(type, fmt, va);
135 } else {
"Vladimir N. Oleynik"d0c41a82005-09-05 15:50:56 +0000136 int logfd = open(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000137 if (logfd >= 0) {
138 vdprintf(logfd, fmt, va);
139 close(logfd);
Eric Andersen35e643b2003-07-28 07:40:39 +0000140#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000141 } else {
142 bb_perror_msg("Can't open log file");
Eric Andersen35e643b2003-07-28 07:40:39 +0000143#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000144 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000145 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000146 }
147 va_end(va);
148 if (ctl[0] & 0200) {
149 exit(20);
150 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000151}
152
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000153int crond_main(int ac, char **av)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000154{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000155 unsigned long opt;
156 char *lopt, *Lopt, *copt;
157
Eric Andersen8876fb22003-06-20 09:01:58 +0000158#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000159 char *dopt;
160
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000161 bb_opt_complementally = "f-b:b-f:S-L:L-S:d-l";
Eric Andersen8876fb22003-06-20 09:01:58 +0000162#else
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000163 bb_opt_complementally = "f-b:b-f:S-L:L-S";
Eric Andersen8876fb22003-06-20 09:01:58 +0000164#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000165
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000166 opterr = 0; /* disable getopt 'errors' message. */
167 opt = bb_getopt_ulflags(ac, av, "l:L:fbSc:"
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000168#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000169 "d:"
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000170#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000171 , &lopt, &Lopt, &copt
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000172#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000173 , &dopt
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000174#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000175 );
176 if (opt & 1) {
177 LogLevel = atoi(lopt);
178 }
179 if (opt & 2) {
180 if (*Lopt != 0) {
181 LogFile = Lopt;
182 }
183 }
184 if (opt & 32) {
185 if (*copt != 0) {
186 CDir = copt;
187 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000188 }
Eric Andersen8876fb22003-06-20 09:01:58 +0000189#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000190 if (opt & 64) {
191 DebugOpt = atoi(dopt);
192 LogLevel = 0;
193 }
Eric Andersen8876fb22003-06-20 09:01:58 +0000194#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000195
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000196 /*
197 * change directory
198 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000199
Bernhard Reutner-Fischerd9cf7ac2006-04-12 18:39:58 +0000200 bb_xchdir(CDir);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000201 signal(SIGHUP, SIG_IGN); /* hmm.. but, if kill -HUP original
202 * version - his died. ;(
203 */
204 /*
205 * close stdin and stdout, stderr.
206 * close unused descriptors - don't need.
207 * optional detach from controlling terminal
208 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000209
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000210 if (!(opt & 4)) {
Russ Dilla1fece22003-12-15 21:57:44 +0000211#if defined(__uClinux__)
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000212 /* reexec for vfork() do continue parent */
213 vfork_daemon_rexec(1, 0, ac, av, "-f");
214#else /* uClinux */
Bernhard Reutner-Fischer2c998512006-04-12 18:09:26 +0000215 bb_xdaemon(1, 0);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000216#endif /* uClinux */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000217 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000218
219 (void) startlogger(); /* need if syslog mode selected */
220
221 /*
222 * main loop - synchronize to 1 second after the minute, minimum sleep
223 * of 1 second.
224 */
225
226 crondlog("\011%s " VERSION " dillon, started, log level %d\n",
227 bb_applet_name, LogLevel);
228
229 SynchronizeDir();
230
231 {
232 time_t t1 = time(NULL);
233 time_t t2;
234 long dt;
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000235 int rescan = 60;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000236 short sleep_time = 60;
237
238 for (;;) {
239 sleep((sleep_time + 1) - (short) (time(NULL) % sleep_time));
240
241 t2 = time(NULL);
242 dt = t2 - t1;
243
244 /*
245 * The file 'cron.update' is checked to determine new cron
246 * jobs. The directory is rescanned once an hour to deal
247 * with any screwups.
248 *
249 * check for disparity. Disparities over an hour either way
250 * result in resynchronization. A reverse-indexed disparity
251 * less then an hour causes us to effectively sleep until we
252 * match the original time (i.e. no re-execution of jobs that
253 * have just been run). A forward-indexed disparity less then
254 * an hour causes intermediate jobs to be run, but only once
255 * in the worst case.
256 *
257 * when running jobs, the inequality used is greater but not
258 * equal to t1, and less then or equal to t2.
259 */
260
261 if (--rescan == 0) {
262 rescan = 60;
263 SynchronizeDir();
264 }
265 CheckUpdates();
266#ifdef FEATURE_DEBUG_OPT
267 if (DebugOpt)
268 crondlog("\005Wakeup dt=%d\n", dt);
269#endif
270 if (dt < -60 * 60 || dt > 60 * 60) {
271 t1 = t2;
272 crondlog("\111time disparity of %d minutes detected\n", dt / 60);
273 } else if (dt > 0) {
274 TestJobs(t1, t2);
275 RunJobs();
276 sleep(5);
277 if (CheckJobs() > 0) {
278 sleep_time = 10;
279 } else {
280 sleep_time = 60;
281 }
282 t1 = t2;
283 }
284 }
285 }
286 /* not reached */
Glenn L McGrathb89fcd42003-12-23 07:21:33 +0000287}
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000288
Eric Andersen35e643b2003-07-28 07:40:39 +0000289#if defined(FEATURE_DEBUG_OPT) || defined(CONFIG_FEATURE_CROND_CALL_SENDMAIL)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000290/*
Eric Andersen35e643b2003-07-28 07:40:39 +0000291 write to temp file..
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000292*/
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000293static void fdprintf(int fd, const char *ctl, ...)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000294{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000295 va_list va;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000296
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000297 va_start(va, ctl);
298 vdprintf(fd, ctl, va);
299 va_end(va);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000300}
Eric Andersen35e643b2003-07-28 07:40:39 +0000301#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000302
303
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000304static int ChangeUser(const char *user)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000305{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000306 struct passwd *pas;
307 const char *err_msg;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000308
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000309 /*
Eric Andersenaff114c2004-04-14 17:51:38 +0000310 * Obtain password entry and change privileges
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000311 */
312 pas = getpwnam(user);
313 if (pas == 0) {
314 crondlog("\011failed to get uid for %s", user);
315 return (-1);
316 }
317 setenv("USER", pas->pw_name, 1);
318 setenv("HOME", pas->pw_dir, 1);
319 setenv("SHELL", DEFAULT_SHELL, 1);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000320
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000321 /*
322 * Change running state to the user in question
323 */
324 err_msg = change_identity_e2str(pas);
325 if (err_msg) {
326 crondlog("\011%s for user %s", err_msg, user);
327 return (-1);
328 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000329 if (chdir(pas->pw_dir) < 0) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000330 crondlog("\011chdir failed: %s: %m", pas->pw_dir);
331 if (chdir(TMPDIR) < 0) {
332 crondlog("\011chdir failed: %s: %m", TMPDIR);
333 return (-1);
334 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000335 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000336 return (pas->pw_uid);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000337}
338
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000339static void startlogger(void)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000340{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000341 if (LogFile == 0) {
342 openlog(bb_applet_name, LOG_CONS | LOG_PID, LOG_CRON);
343 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000344#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000345 else { /* test logfile */
346 int logfd;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000347
"Vladimir N. Oleynik"d0c41a82005-09-05 15:50:56 +0000348 if ((logfd = open(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600)) >= 0) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000349 close(logfd);
350 } else {
351 bb_perror_msg("Failed to open log file '%s' reason", LogFile);
352 }
353 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000354#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000355}
356
357
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000358static const char *const DowAry[] = {
359 "sun",
360 "mon",
361 "tue",
362 "wed",
363 "thu",
364 "fri",
365 "sat",
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000366
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000367 "Sun",
368 "Mon",
369 "Tue",
370 "Wed",
371 "Thu",
372 "Fri",
373 "Sat",
374 NULL
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000375};
376
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000377static const char *const MonAry[] = {
378 "jan",
379 "feb",
380 "mar",
381 "apr",
382 "may",
383 "jun",
384 "jul",
385 "aug",
386 "sep",
387 "oct",
388 "nov",
389 "dec",
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000390
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000391 "Jan",
392 "Feb",
393 "Mar",
394 "Apr",
395 "May",
396 "Jun",
397 "Jul",
398 "Aug",
399 "Sep",
400 "Oct",
401 "Nov",
402 "Dec",
403 NULL
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000404};
405
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000406static char *ParseField(char *user, char *ary, int modvalue, int off,
407 const char *const *names, char *ptr)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000408{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000409 char *base = ptr;
410 int n1 = -1;
411 int n2 = -1;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000412
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000413 if (base == NULL) {
414 return (NULL);
415 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000416
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000417 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
418 int skip = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000419
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000420 /* Handle numeric digit or symbol or '*' */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000421
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000422 if (*ptr == '*') {
423 n1 = 0; /* everything will be filled */
424 n2 = modvalue - 1;
425 skip = 1;
426 ++ptr;
427 } else if (*ptr >= '0' && *ptr <= '9') {
428 if (n1 < 0) {
429 n1 = strtol(ptr, &ptr, 10) + off;
430 } else {
431 n2 = strtol(ptr, &ptr, 10) + off;
432 }
433 skip = 1;
434 } else if (names) {
435 int i;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000436
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000437 for (i = 0; names[i]; ++i) {
438 if (strncmp(ptr, names[i], strlen(names[i])) == 0) {
439 break;
440 }
441 }
442 if (names[i]) {
443 ptr += strlen(names[i]);
444 if (n1 < 0) {
445 n1 = i;
446 } else {
447 n2 = i;
448 }
449 skip = 1;
450 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000451 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000452
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000453 /* handle optional range '-' */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000454
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000455 if (skip == 0) {
456 crondlog("\111failed user %s parsing %s\n", user, base);
457 return (NULL);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000458 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000459 if (*ptr == '-' && n2 < 0) {
460 ++ptr;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000461 continue;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000462 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000463
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000464 /*
465 * collapse single-value ranges, handle skipmark, and fill
466 * in the character array appropriately.
467 */
468
469 if (n2 < 0) {
470 n2 = n1;
471 }
472 if (*ptr == '/') {
473 skip = strtol(ptr + 1, &ptr, 10);
474 }
475 /*
476 * fill array, using a failsafe is the easiest way to prevent
477 * an endless loop
478 */
479
480 {
481 int s0 = 1;
482 int failsafe = 1024;
483
484 --n1;
485 do {
486 n1 = (n1 + 1) % modvalue;
487
488 if (--s0 == 0) {
489 ary[n1 % modvalue] = 1;
490 s0 = skip;
491 }
492 }
493 while (n1 != n2 && --failsafe);
494
495 if (failsafe == 0) {
496 crondlog("\111failed user %s parsing %s\n", user, base);
497 return (NULL);
498 }
499 }
500 if (*ptr != ',') {
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000501 break;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000502 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000503 ++ptr;
504 n1 = -1;
505 n2 = -1;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000506 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000507
508 if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
509 crondlog("\111failed user %s parsing %s\n", user, base);
510 return (NULL);
511 }
512
513 while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') {
514 ++ptr;
515 }
516#ifdef FEATURE_DEBUG_OPT
517 if (DebugOpt) {
518 int i;
519
520 for (i = 0; i < modvalue; ++i) {
521 crondlog("\005%d", ary[i]);
522 }
523 crondlog("\005\n");
524 }
525#endif
526
527 return (ptr);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000528}
529
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000530static void FixDayDow(CronLine * line)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000531{
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000532 int i;
533 int weekUsed = 0;
534 int daysUsed = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000535
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000536 for (i = 0; i < (int)(arysize(line->cl_Dow)); ++i) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000537 if (line->cl_Dow[i] == 0) {
538 weekUsed = 1;
539 break;
540 }
541 }
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000542 for (i = 0; i < (int)(arysize(line->cl_Days)); ++i) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000543 if (line->cl_Days[i] == 0) {
544 daysUsed = 1;
545 break;
546 }
547 }
548 if (weekUsed && !daysUsed) {
549 memset(line->cl_Days, 0, sizeof(line->cl_Days));
550 }
551 if (daysUsed && !weekUsed) {
552 memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
553 }
554}
555
556
557
558static void SynchronizeFile(const char *fileName)
559{
560 int maxEntries = MAXLINES;
561 int maxLines;
562 char buf[1024];
563
564 if (strcmp(fileName, "root") == 0) {
565 maxEntries = 65535;
566 }
567 maxLines = maxEntries * 10;
568
569 if (fileName) {
570 FILE *fi;
571
572 DeleteFile(fileName);
573
574 fi = fopen(fileName, "r");
575 if (fi != NULL) {
576 struct stat sbuf;
577
578 if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) {
579 CronFile *file = calloc(1, sizeof(CronFile));
580 CronLine **pline;
581
582 file->cf_User = strdup(fileName);
583 pline = &file->cf_LineBase;
584
585 while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) {
586 CronLine line;
587 char *ptr;
588
Rob Landley828548a2005-09-01 10:23:57 +0000589 trim(buf);
590 if (buf[0] == 0 || buf[0] == '#') {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000591 continue;
592 }
593 if (--maxEntries == 0) {
594 break;
595 }
596 memset(&line, 0, sizeof(line));
597
598#ifdef FEATURE_DEBUG_OPT
599 if (DebugOpt) {
600 crondlog("\111User %s Entry %s\n", fileName, buf);
601 }
602#endif
603
604 /* parse date ranges */
605 ptr = ParseField(file->cf_User, line.cl_Mins, 60, 0, NULL, buf);
606 ptr = ParseField(file->cf_User, line.cl_Hrs, 24, 0, NULL, ptr);
607 ptr = ParseField(file->cf_User, line.cl_Days, 32, 0, NULL, ptr);
608 ptr = ParseField(file->cf_User, line.cl_Mons, 12, -1, MonAry, ptr);
609 ptr = ParseField(file->cf_User, line.cl_Dow, 7, 0, DowAry, ptr);
610
611 /* check failure */
612 if (ptr == NULL) {
613 continue;
614 }
615
616 /*
617 * fix days and dow - if one is not * and the other
618 * is *, the other is set to 0, and vise-versa
619 */
620
621 FixDayDow(&line);
622
623 *pline = calloc(1, sizeof(CronLine));
624 **pline = line;
625
626 /* copy command */
627 (*pline)->cl_Shell = strdup(ptr);
628
629#ifdef FEATURE_DEBUG_OPT
630 if (DebugOpt) {
631 crondlog("\111 Command %s\n", ptr);
632 }
633#endif
634
635 pline = &((*pline)->cl_Next);
636 }
637 *pline = NULL;
638
639 file->cf_Next = FileBase;
640 FileBase = file;
641
642 if (maxLines == 0 || maxEntries == 0) {
643 crondlog("\111Maximum number of lines reached for user %s\n", fileName);
644 }
645 }
646 fclose(fi);
647 }
648 }
649}
650
651static void CheckUpdates(void)
652{
653 FILE *fi;
654 char buf[256];
655
656 fi = fopen(CRONUPDATE, "r");
657 if (fi != NULL) {
658 remove(CRONUPDATE);
659 while (fgets(buf, sizeof(buf), fi) != NULL) {
660 SynchronizeFile(strtok(buf, " \t\r\n"));
661 }
662 fclose(fi);
663 }
664}
665
666static void SynchronizeDir(void)
667{
668 /* Attempt to delete the database. */
669
670 for (;;) {
671 CronFile *file;
672
673 for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next);
674 if (file == NULL) {
675 break;
676 }
677 DeleteFile(file->cf_User);
678 }
679
680 /*
681 * Remove cron update file
682 *
683 * Re-chdir, in case directory was renamed & deleted, or otherwise
684 * screwed up.
685 *
686 * scan directory and add associated users
687 */
688
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000689 remove(CRONUPDATE);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000690 if (chdir(CDir) < 0) {
691 crondlog("\311unable to find %s\n", CDir);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000692 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000693 {
694 DIR *dir = opendir(".");
695 struct dirent *den;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000696
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000697 if (dir) {
698 while ((den = readdir(dir))) {
699 if (strchr(den->d_name, '.') != NULL) {
700 continue;
701 }
702 if (getpwnam(den->d_name)) {
703 SynchronizeFile(den->d_name);
704 } else {
705 crondlog("\007ignoring %s\n", den->d_name);
706 }
707 }
708 closedir(dir);
709 } else {
710 crondlog("\311Unable to open current dir!\n");
711 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000712 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000713}
714
715
716/*
717 * DeleteFile() - delete user database
718 *
719 * Note: multiple entries for same user may exist if we were unable to
720 * completely delete a database due to running processes.
721 */
722
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000723static void DeleteFile(const char *userName)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000724{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000725 CronFile **pfile = &FileBase;
726 CronFile *file;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000727
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000728 while ((file = *pfile) != NULL) {
729 if (strcmp(userName, file->cf_User) == 0) {
730 CronLine **pline = &file->cf_LineBase;
731 CronLine *line;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000732
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000733 file->cf_Running = 0;
734 file->cf_Deleted = 1;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000735
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000736 while ((line = *pline) != NULL) {
737 if (line->cl_Pid > 0) {
738 file->cf_Running = 1;
739 pline = &line->cl_Next;
740 } else {
741 *pline = line->cl_Next;
742 free(line->cl_Shell);
743 free(line);
744 }
745 }
746 if (file->cf_Running == 0) {
747 *pfile = file->cf_Next;
748 free(file->cf_User);
749 free(file);
750 } else {
751 pfile = &file->cf_Next;
752 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000753 } else {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000754 pfile = &file->cf_Next;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000755 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000756 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000757}
758
759/*
760 * TestJobs()
761 *
762 * determine which jobs need to be run. Under normal conditions, the
763 * period is about a minute (one scan). Worst case it will be one
764 * hour (60 scans).
765 */
766
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000767static int TestJobs(time_t t1, time_t t2)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000768{
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000769 int nJobs = 0;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000770 time_t t;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000771
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000772 /* Find jobs > t1 and <= t2 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000773
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000774 for (t = t1 - t1 % 60; t <= t2; t += 60) {
775 if (t > t1) {
776 struct tm *tp = localtime(&t);
777 CronFile *file;
778 CronLine *line;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000779
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000780 for (file = FileBase; file; file = file->cf_Next) {
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000781#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000782 if (DebugOpt)
783 crondlog("\005FILE %s:\n", file->cf_User);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000784#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000785 if (file->cf_Deleted)
786 continue;
787 for (line = file->cf_LineBase; line; line = line->cl_Next) {
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000788#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000789 if (DebugOpt)
790 crondlog("\005 LINE %s\n", line->cl_Shell);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000791#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000792 if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour] &&
793 (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday])
794 && line->cl_Mons[tp->tm_mon]) {
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000795#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000796 if (DebugOpt) {
797 crondlog("\005 JobToDo: %d %s\n",
798 line->cl_Pid, line->cl_Shell);
799 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000800#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000801 if (line->cl_Pid > 0) {
802 crondlog("\010 process already running: %s %s\n",
803 file->cf_User, line->cl_Shell);
804 } else if (line->cl_Pid == 0) {
805 line->cl_Pid = -1;
806 file->cf_Ready = 1;
807 ++nJobs;
808 }
809 }
810 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000811 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000812 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000813 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000814 return (nJobs);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000815}
816
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000817static void RunJobs(void)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000818{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000819 CronFile *file;
820 CronLine *line;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000821
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000822 for (file = FileBase; file; file = file->cf_Next) {
823 if (file->cf_Ready) {
824 file->cf_Ready = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000825
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000826 for (line = file->cf_LineBase; line; line = line->cl_Next) {
827 if (line->cl_Pid < 0) {
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000828
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000829 RunJob(file->cf_User, line);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000830
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000831 crondlog("\010USER %s pid %3d cmd %s\n",
832 file->cf_User, line->cl_Pid, line->cl_Shell);
833 if (line->cl_Pid < 0) {
834 file->cf_Ready = 1;
835 }
836 else if (line->cl_Pid > 0) {
837 file->cf_Running = 1;
838 }
839 }
840 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000841 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000842 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000843}
844
845/*
846 * CheckJobs() - check for job completion
847 *
848 * Check for job completion, return number of jobs still running after
849 * all done.
850 */
851
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000852static int CheckJobs(void)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000853{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000854 CronFile *file;
855 CronLine *line;
856 int nStillRunning = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000857
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000858 for (file = FileBase; file; file = file->cf_Next) {
859 if (file->cf_Running) {
860 file->cf_Running = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000861
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000862 for (line = file->cf_LineBase; line; line = line->cl_Next) {
863 if (line->cl_Pid > 0) {
864 int status;
865 int r = wait4(line->cl_Pid, &status, WNOHANG, NULL);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000866
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000867 if (r < 0 || r == line->cl_Pid) {
868 EndJob(file->cf_User, line);
869 if (line->cl_Pid) {
870 file->cf_Running = 1;
871 }
872 } else if (r == 0) {
873 file->cf_Running = 1;
874 }
875 }
876 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000877 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000878 nStillRunning += file->cf_Running;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000879 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000880 return (nStillRunning);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000881}
882
883
Eric Andersen35e643b2003-07-28 07:40:39 +0000884#ifdef CONFIG_FEATURE_CROND_CALL_SENDMAIL
885static void
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000886ForkJob(const char *user, CronLine * line, int mailFd,
887 const char *prog, const char *cmd, const char *arg, const char *mailf)
Eric Andersen35e643b2003-07-28 07:40:39 +0000888{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000889 /* Fork as the user in question and run program */
890 pid_t pid = fork();
Eric Andersen35e643b2003-07-28 07:40:39 +0000891
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000892 line->cl_Pid = pid;
893 if (pid == 0) {
894 /* CHILD */
Eric Andersen35e643b2003-07-28 07:40:39 +0000895
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000896 /* Change running state to the user in question */
Eric Andersen35e643b2003-07-28 07:40:39 +0000897
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000898 if (ChangeUser(user) < 0) {
899 exit(0);
900 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000901#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000902 if (DebugOpt) {
903 crondlog("\005Child Running %s\n", prog);
904 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000905#endif
906
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000907 if (mailFd >= 0) {
908 dup2(mailFd, mailf != NULL);
909 dup2((mailf ? mailFd : 1), 2);
910 close(mailFd);
911 }
912 execl(prog, prog, cmd, arg, NULL);
913 crondlog("\024unable to exec, user %s cmd %s %s %s\n", user, prog, cmd, arg);
914 if (mailf) {
915 fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
916 }
917 exit(0);
918 } else if (pid < 0) {
919 /* FORK FAILED */
920 crondlog("\024couldn't fork, user %s\n", user);
921 line->cl_Pid = 0;
922 if (mailf) {
923 remove(mailf);
924 }
925 } else if (mailf) {
926 /* PARENT, FORK SUCCESS
927 * rename mail-file based on pid of process
928 */
929 char mailFile2[128];
930
931 snprintf(mailFile2, sizeof(mailFile2), TMPDIR "/cron.%s.%d", user, pid);
932 rename(mailf, mailFile2);
Eric Andersen35e643b2003-07-28 07:40:39 +0000933 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000934 /*
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000935 * Close the mail file descriptor.. we can't just leave it open in
936 * a structure, closing it later, because we might run out of descriptors
Eric Andersen35e643b2003-07-28 07:40:39 +0000937 */
Eric Andersen35e643b2003-07-28 07:40:39 +0000938
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000939 if (mailFd >= 0) {
940 close(mailFd);
941 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000942}
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000943
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000944static void RunJob(const char *user, CronLine * line)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000945{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000946 char mailFile[128];
947 int mailFd;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000948
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000949 line->cl_Pid = 0;
950 line->cl_MailFlag = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000951
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000952 /* open mail file - owner root so nobody can screw with it. */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000953
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000954 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, getpid());
955 mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000956
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000957 if (mailFd >= 0) {
958 line->cl_MailFlag = 1;
959 fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user,
960 line->cl_Shell);
961 line->cl_MailPos = lseek(mailFd, 0, 1);
962 } else {
963 crondlog("\024unable to create mail file user %s file %s, output to /dev/null\n", user, mailFile);
964 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000965
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000966 ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000967}
968
969/*
970 * EndJob - called when job terminates and when mail terminates
971 */
972
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000973static void EndJob(const char *user, CronLine * line)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000974{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000975 int mailFd;
976 char mailFile[128];
977 struct stat sbuf;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000978
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000979 /* No job */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000980
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000981 if (line->cl_Pid <= 0) {
982 line->cl_Pid = 0;
983 return;
984 }
985
986 /*
987 * End of job and no mail file
988 * End of sendmail job
989 */
990
991 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, line->cl_Pid);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000992 line->cl_Pid = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000993
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000994 if (line->cl_MailFlag != 1) {
995 return;
996 }
997 line->cl_MailFlag = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000998
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000999 /*
1000 * End of primary job - check for mail file. If size has increased and
1001 * the file is still valid, we sendmail it.
1002 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001003
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001004 mailFd = open(mailFile, O_RDONLY);
1005 remove(mailFile);
1006 if (mailFd < 0) {
1007 return;
1008 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001009
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001010 if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid || sbuf.st_nlink != 0 ||
1011 sbuf.st_size == line->cl_MailPos || !S_ISREG(sbuf.st_mode)) {
1012 close(mailFd);
1013 return;
1014 }
1015 ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL);
Eric Andersen35e643b2003-07-28 07:40:39 +00001016}
1017#else
Eric Andersenaff114c2004-04-14 17:51:38 +00001018/* crond without sendmail */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001019
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001020static void RunJob(const char *user, CronLine * line)
Eric Andersen35e643b2003-07-28 07:40:39 +00001021{
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001022 /* Fork as the user in question and run program */
1023 pid_t pid = fork();
Eric Andersen35e643b2003-07-28 07:40:39 +00001024
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001025 if (pid == 0) {
1026 /* CHILD */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001027
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001028 /* Change running state to the user in question */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001029
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001030 if (ChangeUser(user) < 0) {
1031 exit(0);
1032 }
Eric Andersen35e643b2003-07-28 07:40:39 +00001033#ifdef FEATURE_DEBUG_OPT
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001034 if (DebugOpt) {
1035 crondlog("\005Child Running %s\n", DEFAULT_SHELL);
1036 }
Eric Andersen35e643b2003-07-28 07:40:39 +00001037#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001038
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001039 execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL);
1040 crondlog("\024unable to exec, user %s cmd %s -c %s\n", user,
1041 DEFAULT_SHELL, line->cl_Shell);
1042 exit(0);
1043 } else if (pid < 0) {
1044 /* FORK FAILED */
1045 crondlog("\024couldn't fork, user %s\n", user);
1046 pid = 0;
1047 }
1048 line->cl_Pid = pid;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001049}
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001050#endif /* CONFIG_FEATURE_CROND_CALL_SENDMAIL */