blob: 3f60468de48e251aff73226c152ec586de1d3732 [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
Bernhard Reutner-Fischerc89982d2006-06-03 19:49:21 +000015#include "busybox.h"
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000016#include <stdio.h>
17#include <stdlib.h>
18#include <stdarg.h>
19#include <string.h>
20#include <errno.h>
21#include <time.h>
22#include <dirent.h>
23#include <fcntl.h>
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000024#include <unistd.h>
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000025#include <syslog.h>
26#include <signal.h>
27#include <getopt.h>
28#include <sys/ioctl.h>
29#include <sys/wait.h>
30#include <sys/stat.h>
31#include <sys/resource.h>
32
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000033#define arysize(ary) (sizeof(ary)/sizeof((ary)[0]))
34
35#ifndef CRONTABS
36#define CRONTABS "/var/spool/cron/crontabs"
37#endif
38#ifndef TMPDIR
39#define TMPDIR "/var/spool/cron"
40#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000041#ifndef SENDMAIL
42#define SENDMAIL "/usr/sbin/sendmail"
43#endif
44#ifndef SENDMAIL_ARGS
Eric Andersen35e643b2003-07-28 07:40:39 +000045#define SENDMAIL_ARGS "-ti", "oem"
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000046#endif
47#ifndef CRONUPDATE
48#define CRONUPDATE "cron.update"
49#endif
50#ifndef MAXLINES
Glenn L McGrath9079ad02004-02-22 04:44:21 +000051#define MAXLINES 256 /* max lines in non-root crontabs */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000052#endif
53
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000054typedef struct CronFile {
Glenn L McGrath9079ad02004-02-22 04:44:21 +000055 struct CronFile *cf_Next;
56 struct CronLine *cf_LineBase;
57 char *cf_User; /* username */
58 int cf_Ready; /* bool: one or more jobs ready */
59 int cf_Running; /* bool: one or more jobs running */
60 int cf_Deleted; /* marked for deletion, ignore */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000061} CronFile;
62
63typedef struct CronLine {
Glenn L McGrath9079ad02004-02-22 04:44:21 +000064 struct CronLine *cl_Next;
65 char *cl_Shell; /* shell command */
66 pid_t cl_Pid; /* running pid, 0, or armed (-1) */
67 int cl_MailFlag; /* running pid is for mail */
68 int cl_MailPos; /* 'empty file' size */
69 char cl_Mins[60]; /* 0-59 */
70 char cl_Hrs[24]; /* 0-23 */
71 char cl_Days[32]; /* 1-31 */
72 char cl_Mons[12]; /* 0-11 */
73 char cl_Dow[7]; /* 0-6, beginning sunday */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000074} CronLine;
75
76#define RUN_RANOUT 1
77#define RUN_RUNNING 2
78#define RUN_FAILED 3
79
80#define DaemonUid 0
81
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +000082#if ENABLE_DEBUG_CROND_OPTION
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000083static short DebugOpt;
84#endif
85
86static short LogLevel = 8;
Glenn L McGrath9079ad02004-02-22 04:44:21 +000087static const char *LogFile;
88static const char *CDir = CRONTABS;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000089
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000090static void startlogger(void);
91
92static void CheckUpdates(void);
93static void SynchronizeDir(void);
94static int TestJobs(time_t t1, time_t t2);
95static void RunJobs(void);
96static int CheckJobs(void);
Eric Andersen35e643b2003-07-28 07:40:39 +000097
Glenn L McGrath9079ad02004-02-22 04:44:21 +000098static void RunJob(const char *user, CronLine * line);
99
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000100#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000101static void EndJob(const char *user, CronLine * line);
Eric Andersen35e643b2003-07-28 07:40:39 +0000102#else
103#define EndJob(user, line) line->cl_Pid = 0
104#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000105
106static void DeleteFile(const char *userName);
107
108static CronFile *FileBase;
109
110
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000111static void crondlog(const char *ctl, ...)
Eric Andersen35e643b2003-07-28 07:40:39 +0000112{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000113 va_list va;
114 const char *fmt;
115 int level = (int) (ctl[0] & 0xf);
116 int type = level == 20 ?
117 LOG_ERR : ((ctl[0] & 0100) ? LOG_WARNING : LOG_NOTICE);
Eric Andersen35e643b2003-07-28 07:40:39 +0000118
119
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000120 va_start(va, ctl);
121 fmt = ctl + 1;
122 if (level >= LogLevel) {
Eric Andersen35e643b2003-07-28 07:40:39 +0000123
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000124#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000125 if (DebugOpt) {
126 vfprintf(stderr, fmt, va);
127 } else
Eric Andersen35e643b2003-07-28 07:40:39 +0000128#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000129 if (LogFile == 0) {
130 vsyslog(type, fmt, va);
131 } else {
"Vladimir N. Oleynik"d0c41a82005-09-05 15:50:56 +0000132 int logfd = open(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000133 if (logfd >= 0) {
134 vdprintf(logfd, fmt, va);
135 close(logfd);
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000136#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000137 } else {
138 bb_perror_msg("Can't open log file");
Eric Andersen35e643b2003-07-28 07:40:39 +0000139#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000140 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000141 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000142 }
143 va_end(va);
144 if (ctl[0] & 0200) {
145 exit(20);
146 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000147}
148
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000149int crond_main(int ac, char **av)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000150{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000151 unsigned long opt;
152 char *lopt, *Lopt, *copt;
153
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000154#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000155 char *dopt;
156
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000157 bb_opt_complementally = "f-b:b-f:S-L:L-S:d-l";
Eric Andersen8876fb22003-06-20 09:01:58 +0000158#else
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000159 bb_opt_complementally = "f-b:b-f:S-L:L-S";
Eric Andersen8876fb22003-06-20 09:01:58 +0000160#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000161
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000162 opterr = 0; /* disable getopt 'errors' message. */
163 opt = bb_getopt_ulflags(ac, av, "l:L:fbSc:"
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000164#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000165 "d:"
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000166#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000167 , &lopt, &Lopt, &copt
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000168#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000169 , &dopt
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000170#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000171 );
172 if (opt & 1) {
173 LogLevel = atoi(lopt);
174 }
175 if (opt & 2) {
176 if (*Lopt != 0) {
177 LogFile = Lopt;
178 }
179 }
180 if (opt & 32) {
181 if (*copt != 0) {
182 CDir = copt;
183 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000184 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000185#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000186 if (opt & 64) {
187 DebugOpt = atoi(dopt);
188 LogLevel = 0;
189 }
Eric Andersen8876fb22003-06-20 09:01:58 +0000190#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000191
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000192 /*
193 * change directory
194 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000195
Bernhard Reutner-Fischerd9cf7ac2006-04-12 18:39:58 +0000196 bb_xchdir(CDir);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000197 signal(SIGHUP, SIG_IGN); /* hmm.. but, if kill -HUP original
198 * version - his died. ;(
199 */
200 /*
201 * close stdin and stdout, stderr.
202 * close unused descriptors - don't need.
203 * optional detach from controlling terminal
204 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000205
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000206 if (!(opt & 4)) {
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000207#ifdef BB_NOMMU
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000208 /* reexec for vfork() do continue parent */
209 vfork_daemon_rexec(1, 0, ac, av, "-f");
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000210#else
Bernhard Reutner-Fischer2c998512006-04-12 18:09:26 +0000211 bb_xdaemon(1, 0);
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000212#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000213 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000214
215 (void) startlogger(); /* need if syslog mode selected */
216
217 /*
218 * main loop - synchronize to 1 second after the minute, minimum sleep
219 * of 1 second.
220 */
221
222 crondlog("\011%s " VERSION " dillon, started, log level %d\n",
223 bb_applet_name, LogLevel);
224
225 SynchronizeDir();
226
227 {
228 time_t t1 = time(NULL);
229 time_t t2;
230 long dt;
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000231 int rescan = 60;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000232 short sleep_time = 60;
233
234 for (;;) {
235 sleep((sleep_time + 1) - (short) (time(NULL) % sleep_time));
236
237 t2 = time(NULL);
238 dt = t2 - t1;
239
240 /*
241 * The file 'cron.update' is checked to determine new cron
242 * jobs. The directory is rescanned once an hour to deal
243 * with any screwups.
244 *
245 * check for disparity. Disparities over an hour either way
246 * result in resynchronization. A reverse-indexed disparity
247 * less then an hour causes us to effectively sleep until we
248 * match the original time (i.e. no re-execution of jobs that
249 * have just been run). A forward-indexed disparity less then
250 * an hour causes intermediate jobs to be run, but only once
251 * in the worst case.
252 *
253 * when running jobs, the inequality used is greater but not
254 * equal to t1, and less then or equal to t2.
255 */
256
257 if (--rescan == 0) {
258 rescan = 60;
259 SynchronizeDir();
260 }
261 CheckUpdates();
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000262#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000263 if (DebugOpt)
264 crondlog("\005Wakeup dt=%d\n", dt);
265#endif
266 if (dt < -60 * 60 || dt > 60 * 60) {
267 t1 = t2;
268 crondlog("\111time disparity of %d minutes detected\n", dt / 60);
269 } else if (dt > 0) {
270 TestJobs(t1, t2);
271 RunJobs();
272 sleep(5);
273 if (CheckJobs() > 0) {
274 sleep_time = 10;
275 } else {
276 sleep_time = 60;
277 }
278 t1 = t2;
279 }
280 }
281 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000282 bb_fflush_stdout_and_exit(EXIT_SUCCESS); /* not reached */
Glenn L McGrathb89fcd42003-12-23 07:21:33 +0000283}
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000284
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000285static int ChangeUser(const char *user)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000286{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000287 struct passwd *pas;
288 const char *err_msg;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000289
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000290 /*
Eric Andersenaff114c2004-04-14 17:51:38 +0000291 * Obtain password entry and change privileges
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000292 */
293 pas = getpwnam(user);
294 if (pas == 0) {
295 crondlog("\011failed to get uid for %s", user);
296 return (-1);
297 }
298 setenv("USER", pas->pw_name, 1);
299 setenv("HOME", pas->pw_dir, 1);
300 setenv("SHELL", DEFAULT_SHELL, 1);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000301
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000302 /*
303 * Change running state to the user in question
304 */
305 err_msg = change_identity_e2str(pas);
306 if (err_msg) {
307 crondlog("\011%s for user %s", err_msg, user);
308 return (-1);
309 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000310 if (chdir(pas->pw_dir) < 0) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000311 crondlog("\011chdir failed: %s: %m", pas->pw_dir);
312 if (chdir(TMPDIR) < 0) {
313 crondlog("\011chdir failed: %s: %m", TMPDIR);
314 return (-1);
315 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000316 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000317 return (pas->pw_uid);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000318}
319
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000320static void startlogger(void)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000321{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000322 if (LogFile == 0) {
323 openlog(bb_applet_name, LOG_CONS | LOG_PID, LOG_CRON);
324 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000325#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000326 else { /* test logfile */
327 int logfd;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000328
"Vladimir N. Oleynik"d0c41a82005-09-05 15:50:56 +0000329 if ((logfd = open(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600)) >= 0) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000330 close(logfd);
331 } else {
332 bb_perror_msg("Failed to open log file '%s' reason", LogFile);
333 }
334 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000335#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000336}
337
338
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000339static const char *const DowAry[] = {
340 "sun",
341 "mon",
342 "tue",
343 "wed",
344 "thu",
345 "fri",
346 "sat",
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000347
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000348 "Sun",
349 "Mon",
350 "Tue",
351 "Wed",
352 "Thu",
353 "Fri",
354 "Sat",
355 NULL
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000356};
357
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000358static const char *const MonAry[] = {
359 "jan",
360 "feb",
361 "mar",
362 "apr",
363 "may",
364 "jun",
365 "jul",
366 "aug",
367 "sep",
368 "oct",
369 "nov",
370 "dec",
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000371
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000372 "Jan",
373 "Feb",
374 "Mar",
375 "Apr",
376 "May",
377 "Jun",
378 "Jul",
379 "Aug",
380 "Sep",
381 "Oct",
382 "Nov",
383 "Dec",
384 NULL
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000385};
386
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000387static char *ParseField(char *user, char *ary, int modvalue, int off,
388 const char *const *names, char *ptr)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000389{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000390 char *base = ptr;
391 int n1 = -1;
392 int n2 = -1;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000393
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000394 if (base == NULL) {
395 return (NULL);
396 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000397
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000398 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
399 int skip = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000400
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000401 /* Handle numeric digit or symbol or '*' */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000402
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000403 if (*ptr == '*') {
404 n1 = 0; /* everything will be filled */
405 n2 = modvalue - 1;
406 skip = 1;
407 ++ptr;
408 } else if (*ptr >= '0' && *ptr <= '9') {
409 if (n1 < 0) {
410 n1 = strtol(ptr, &ptr, 10) + off;
411 } else {
412 n2 = strtol(ptr, &ptr, 10) + off;
413 }
414 skip = 1;
415 } else if (names) {
416 int i;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000417
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000418 for (i = 0; names[i]; ++i) {
419 if (strncmp(ptr, names[i], strlen(names[i])) == 0) {
420 break;
421 }
422 }
423 if (names[i]) {
424 ptr += strlen(names[i]);
425 if (n1 < 0) {
426 n1 = i;
427 } else {
428 n2 = i;
429 }
430 skip = 1;
431 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000432 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000433
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000434 /* handle optional range '-' */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000435
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000436 if (skip == 0) {
437 crondlog("\111failed user %s parsing %s\n", user, base);
438 return (NULL);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000439 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000440 if (*ptr == '-' && n2 < 0) {
441 ++ptr;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000442 continue;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000443 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000444
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000445 /*
446 * collapse single-value ranges, handle skipmark, and fill
447 * in the character array appropriately.
448 */
449
450 if (n2 < 0) {
451 n2 = n1;
452 }
453 if (*ptr == '/') {
454 skip = strtol(ptr + 1, &ptr, 10);
455 }
456 /*
457 * fill array, using a failsafe is the easiest way to prevent
458 * an endless loop
459 */
460
461 {
462 int s0 = 1;
463 int failsafe = 1024;
464
465 --n1;
466 do {
467 n1 = (n1 + 1) % modvalue;
468
469 if (--s0 == 0) {
470 ary[n1 % modvalue] = 1;
471 s0 = skip;
472 }
473 }
474 while (n1 != n2 && --failsafe);
475
476 if (failsafe == 0) {
477 crondlog("\111failed user %s parsing %s\n", user, base);
478 return (NULL);
479 }
480 }
481 if (*ptr != ',') {
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000482 break;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000483 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000484 ++ptr;
485 n1 = -1;
486 n2 = -1;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000487 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000488
489 if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
490 crondlog("\111failed user %s parsing %s\n", user, base);
491 return (NULL);
492 }
493
494 while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') {
495 ++ptr;
496 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000497#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000498 if (DebugOpt) {
499 int i;
500
501 for (i = 0; i < modvalue; ++i) {
502 crondlog("\005%d", ary[i]);
503 }
504 crondlog("\005\n");
505 }
506#endif
507
508 return (ptr);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000509}
510
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000511static void FixDayDow(CronLine * line)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000512{
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000513 int i;
514 int weekUsed = 0;
515 int daysUsed = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000516
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000517 for (i = 0; i < (int)(arysize(line->cl_Dow)); ++i) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000518 if (line->cl_Dow[i] == 0) {
519 weekUsed = 1;
520 break;
521 }
522 }
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000523 for (i = 0; i < (int)(arysize(line->cl_Days)); ++i) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000524 if (line->cl_Days[i] == 0) {
525 daysUsed = 1;
526 break;
527 }
528 }
529 if (weekUsed && !daysUsed) {
530 memset(line->cl_Days, 0, sizeof(line->cl_Days));
531 }
532 if (daysUsed && !weekUsed) {
533 memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
534 }
535}
536
537
538
539static void SynchronizeFile(const char *fileName)
540{
541 int maxEntries = MAXLINES;
542 int maxLines;
543 char buf[1024];
544
545 if (strcmp(fileName, "root") == 0) {
546 maxEntries = 65535;
547 }
548 maxLines = maxEntries * 10;
549
550 if (fileName) {
551 FILE *fi;
552
553 DeleteFile(fileName);
554
555 fi = fopen(fileName, "r");
556 if (fi != NULL) {
557 struct stat sbuf;
558
559 if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) {
560 CronFile *file = calloc(1, sizeof(CronFile));
561 CronLine **pline;
562
563 file->cf_User = strdup(fileName);
564 pline = &file->cf_LineBase;
565
566 while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) {
567 CronLine line;
568 char *ptr;
569
Rob Landley828548a2005-09-01 10:23:57 +0000570 trim(buf);
571 if (buf[0] == 0 || buf[0] == '#') {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000572 continue;
573 }
574 if (--maxEntries == 0) {
575 break;
576 }
577 memset(&line, 0, sizeof(line));
578
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000579#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000580 if (DebugOpt) {
581 crondlog("\111User %s Entry %s\n", fileName, buf);
582 }
583#endif
584
585 /* parse date ranges */
586 ptr = ParseField(file->cf_User, line.cl_Mins, 60, 0, NULL, buf);
587 ptr = ParseField(file->cf_User, line.cl_Hrs, 24, 0, NULL, ptr);
588 ptr = ParseField(file->cf_User, line.cl_Days, 32, 0, NULL, ptr);
589 ptr = ParseField(file->cf_User, line.cl_Mons, 12, -1, MonAry, ptr);
590 ptr = ParseField(file->cf_User, line.cl_Dow, 7, 0, DowAry, ptr);
591
592 /* check failure */
593 if (ptr == NULL) {
594 continue;
595 }
596
597 /*
598 * fix days and dow - if one is not * and the other
599 * is *, the other is set to 0, and vise-versa
600 */
601
602 FixDayDow(&line);
603
604 *pline = calloc(1, sizeof(CronLine));
605 **pline = line;
606
607 /* copy command */
608 (*pline)->cl_Shell = strdup(ptr);
609
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000610#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000611 if (DebugOpt) {
612 crondlog("\111 Command %s\n", ptr);
613 }
614#endif
615
616 pline = &((*pline)->cl_Next);
617 }
618 *pline = NULL;
619
620 file->cf_Next = FileBase;
621 FileBase = file;
622
623 if (maxLines == 0 || maxEntries == 0) {
624 crondlog("\111Maximum number of lines reached for user %s\n", fileName);
625 }
626 }
627 fclose(fi);
628 }
629 }
630}
631
632static void CheckUpdates(void)
633{
634 FILE *fi;
635 char buf[256];
636
637 fi = fopen(CRONUPDATE, "r");
638 if (fi != NULL) {
639 remove(CRONUPDATE);
640 while (fgets(buf, sizeof(buf), fi) != NULL) {
641 SynchronizeFile(strtok(buf, " \t\r\n"));
642 }
643 fclose(fi);
644 }
645}
646
647static void SynchronizeDir(void)
648{
649 /* Attempt to delete the database. */
650
651 for (;;) {
652 CronFile *file;
653
654 for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next);
655 if (file == NULL) {
656 break;
657 }
658 DeleteFile(file->cf_User);
659 }
660
661 /*
662 * Remove cron update file
663 *
664 * Re-chdir, in case directory was renamed & deleted, or otherwise
665 * screwed up.
666 *
667 * scan directory and add associated users
668 */
669
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000670 remove(CRONUPDATE);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000671 if (chdir(CDir) < 0) {
672 crondlog("\311unable to find %s\n", CDir);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000673 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000674 {
675 DIR *dir = opendir(".");
676 struct dirent *den;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000677
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000678 if (dir) {
679 while ((den = readdir(dir))) {
680 if (strchr(den->d_name, '.') != NULL) {
681 continue;
682 }
683 if (getpwnam(den->d_name)) {
684 SynchronizeFile(den->d_name);
685 } else {
686 crondlog("\007ignoring %s\n", den->d_name);
687 }
688 }
689 closedir(dir);
690 } else {
691 crondlog("\311Unable to open current dir!\n");
692 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000693 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000694}
695
696
697/*
698 * DeleteFile() - delete user database
699 *
700 * Note: multiple entries for same user may exist if we were unable to
701 * completely delete a database due to running processes.
702 */
703
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000704static void DeleteFile(const char *userName)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000705{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000706 CronFile **pfile = &FileBase;
707 CronFile *file;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000708
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000709 while ((file = *pfile) != NULL) {
710 if (strcmp(userName, file->cf_User) == 0) {
711 CronLine **pline = &file->cf_LineBase;
712 CronLine *line;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000713
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000714 file->cf_Running = 0;
715 file->cf_Deleted = 1;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000716
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000717 while ((line = *pline) != NULL) {
718 if (line->cl_Pid > 0) {
719 file->cf_Running = 1;
720 pline = &line->cl_Next;
721 } else {
722 *pline = line->cl_Next;
723 free(line->cl_Shell);
724 free(line);
725 }
726 }
727 if (file->cf_Running == 0) {
728 *pfile = file->cf_Next;
729 free(file->cf_User);
730 free(file);
731 } else {
732 pfile = &file->cf_Next;
733 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000734 } else {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000735 pfile = &file->cf_Next;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000736 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000737 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000738}
739
740/*
741 * TestJobs()
742 *
743 * determine which jobs need to be run. Under normal conditions, the
744 * period is about a minute (one scan). Worst case it will be one
745 * hour (60 scans).
746 */
747
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000748static int TestJobs(time_t t1, time_t t2)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000749{
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000750 int nJobs = 0;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000751 time_t t;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000752
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000753 /* Find jobs > t1 and <= t2 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000754
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000755 for (t = t1 - t1 % 60; t <= t2; t += 60) {
756 if (t > t1) {
757 struct tm *tp = localtime(&t);
758 CronFile *file;
759 CronLine *line;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000760
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000761 for (file = FileBase; file; file = file->cf_Next) {
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000762#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000763 if (DebugOpt)
764 crondlog("\005FILE %s:\n", file->cf_User);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000765#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000766 if (file->cf_Deleted)
767 continue;
768 for (line = file->cf_LineBase; line; line = line->cl_Next) {
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000769#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000770 if (DebugOpt)
771 crondlog("\005 LINE %s\n", line->cl_Shell);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000772#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000773 if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour] &&
774 (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday])
775 && line->cl_Mons[tp->tm_mon]) {
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000776#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000777 if (DebugOpt) {
778 crondlog("\005 JobToDo: %d %s\n",
779 line->cl_Pid, line->cl_Shell);
780 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000781#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000782 if (line->cl_Pid > 0) {
783 crondlog("\010 process already running: %s %s\n",
784 file->cf_User, line->cl_Shell);
785 } else if (line->cl_Pid == 0) {
786 line->cl_Pid = -1;
787 file->cf_Ready = 1;
788 ++nJobs;
789 }
790 }
791 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000792 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000793 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000794 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000795 return (nJobs);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000796}
797
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000798static void RunJobs(void)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000799{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000800 CronFile *file;
801 CronLine *line;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000802
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000803 for (file = FileBase; file; file = file->cf_Next) {
804 if (file->cf_Ready) {
805 file->cf_Ready = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000806
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000807 for (line = file->cf_LineBase; line; line = line->cl_Next) {
808 if (line->cl_Pid < 0) {
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000809
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000810 RunJob(file->cf_User, line);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000811
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000812 crondlog("\010USER %s pid %3d cmd %s\n",
813 file->cf_User, line->cl_Pid, line->cl_Shell);
814 if (line->cl_Pid < 0) {
815 file->cf_Ready = 1;
816 }
817 else if (line->cl_Pid > 0) {
818 file->cf_Running = 1;
819 }
820 }
821 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000822 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000823 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000824}
825
826/*
827 * CheckJobs() - check for job completion
828 *
829 * Check for job completion, return number of jobs still running after
830 * all done.
831 */
832
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000833static int CheckJobs(void)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000834{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000835 CronFile *file;
836 CronLine *line;
837 int nStillRunning = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000838
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000839 for (file = FileBase; file; file = file->cf_Next) {
840 if (file->cf_Running) {
841 file->cf_Running = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000842
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000843 for (line = file->cf_LineBase; line; line = line->cl_Next) {
844 if (line->cl_Pid > 0) {
845 int status;
846 int r = wait4(line->cl_Pid, &status, WNOHANG, NULL);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000847
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000848 if (r < 0 || r == line->cl_Pid) {
849 EndJob(file->cf_User, line);
850 if (line->cl_Pid) {
851 file->cf_Running = 1;
852 }
853 } else if (r == 0) {
854 file->cf_Running = 1;
855 }
856 }
857 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000858 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000859 nStillRunning += file->cf_Running;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000860 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000861 return (nStillRunning);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000862}
863
864
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000865#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
Eric Andersen35e643b2003-07-28 07:40:39 +0000866static void
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000867ForkJob(const char *user, CronLine * line, int mailFd,
868 const char *prog, const char *cmd, const char *arg, const char *mailf)
Eric Andersen35e643b2003-07-28 07:40:39 +0000869{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000870 /* Fork as the user in question and run program */
871 pid_t pid = fork();
Eric Andersen35e643b2003-07-28 07:40:39 +0000872
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000873 line->cl_Pid = pid;
874 if (pid == 0) {
875 /* CHILD */
Eric Andersen35e643b2003-07-28 07:40:39 +0000876
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000877 /* Change running state to the user in question */
Eric Andersen35e643b2003-07-28 07:40:39 +0000878
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000879 if (ChangeUser(user) < 0) {
880 exit(0);
881 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000882#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000883 if (DebugOpt) {
884 crondlog("\005Child Running %s\n", prog);
885 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000886#endif
887
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000888 if (mailFd >= 0) {
889 dup2(mailFd, mailf != NULL);
890 dup2((mailf ? mailFd : 1), 2);
891 close(mailFd);
892 }
893 execl(prog, prog, cmd, arg, NULL);
894 crondlog("\024unable to exec, user %s cmd %s %s %s\n", user, prog, cmd, arg);
895 if (mailf) {
896 fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
897 }
898 exit(0);
899 } else if (pid < 0) {
900 /* FORK FAILED */
901 crondlog("\024couldn't fork, user %s\n", user);
902 line->cl_Pid = 0;
903 if (mailf) {
904 remove(mailf);
905 }
906 } else if (mailf) {
907 /* PARENT, FORK SUCCESS
908 * rename mail-file based on pid of process
909 */
910 char mailFile2[128];
911
912 snprintf(mailFile2, sizeof(mailFile2), TMPDIR "/cron.%s.%d", user, pid);
913 rename(mailf, mailFile2);
Eric Andersen35e643b2003-07-28 07:40:39 +0000914 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000915 /*
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000916 * Close the mail file descriptor.. we can't just leave it open in
917 * a structure, closing it later, because we might run out of descriptors
Eric Andersen35e643b2003-07-28 07:40:39 +0000918 */
Eric Andersen35e643b2003-07-28 07:40:39 +0000919
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000920 if (mailFd >= 0) {
921 close(mailFd);
922 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000923}
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000924
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000925static void RunJob(const char *user, CronLine * line)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000926{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000927 char mailFile[128];
928 int mailFd;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000929
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000930 line->cl_Pid = 0;
931 line->cl_MailFlag = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000932
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000933 /* open mail file - owner root so nobody can screw with it. */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000934
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000935 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, getpid());
936 mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000937
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000938 if (mailFd >= 0) {
939 line->cl_MailFlag = 1;
940 fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user,
941 line->cl_Shell);
942 line->cl_MailPos = lseek(mailFd, 0, 1);
943 } else {
944 crondlog("\024unable to create mail file user %s file %s, output to /dev/null\n", user, mailFile);
945 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000946
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000947 ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000948}
949
950/*
951 * EndJob - called when job terminates and when mail terminates
952 */
953
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000954static void EndJob(const char *user, CronLine * line)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000955{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000956 int mailFd;
957 char mailFile[128];
958 struct stat sbuf;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000959
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000960 /* No job */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000961
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000962 if (line->cl_Pid <= 0) {
963 line->cl_Pid = 0;
964 return;
965 }
966
967 /*
968 * End of job and no mail file
969 * End of sendmail job
970 */
971
972 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, line->cl_Pid);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000973 line->cl_Pid = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000974
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000975 if (line->cl_MailFlag != 1) {
976 return;
977 }
978 line->cl_MailFlag = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000979
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000980 /*
981 * End of primary job - check for mail file. If size has increased and
982 * the file is still valid, we sendmail it.
983 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000984
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000985 mailFd = open(mailFile, O_RDONLY);
986 remove(mailFile);
987 if (mailFd < 0) {
988 return;
989 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000990
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000991 if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid || sbuf.st_nlink != 0 ||
992 sbuf.st_size == line->cl_MailPos || !S_ISREG(sbuf.st_mode)) {
993 close(mailFd);
994 return;
995 }
996 ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL);
Eric Andersen35e643b2003-07-28 07:40:39 +0000997}
998#else
Eric Andersenaff114c2004-04-14 17:51:38 +0000999/* crond without sendmail */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001000
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001001static void RunJob(const char *user, CronLine * line)
Eric Andersen35e643b2003-07-28 07:40:39 +00001002{
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001003 /* Fork as the user in question and run program */
1004 pid_t pid = fork();
Eric Andersen35e643b2003-07-28 07:40:39 +00001005
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001006 if (pid == 0) {
1007 /* CHILD */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001008
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001009 /* Change running state to the user in question */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001010
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001011 if (ChangeUser(user) < 0) {
1012 exit(0);
1013 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +00001014#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001015 if (DebugOpt) {
1016 crondlog("\005Child Running %s\n", DEFAULT_SHELL);
1017 }
Eric Andersen35e643b2003-07-28 07:40:39 +00001018#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001019
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001020 execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL);
1021 crondlog("\024unable to exec, user %s cmd %s -c %s\n", user,
1022 DEFAULT_SHELL, line->cl_Shell);
1023 exit(0);
1024 } else if (pid < 0) {
1025 /* FORK FAILED */
1026 crondlog("\024couldn't fork, user %s\n", user);
1027 pid = 0;
1028 }
1029 line->cl_Pid = pid;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001030}
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +00001031#endif /* ENABLE_FEATURE_CROND_CALL_SENDMAIL */