blob: 4fc940b7901660256c8ca6563b3ee6db169c4e30 [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"
Rob Landleyd921b2e2006-08-03 15:41:12 +000016#include <sys/syslog.h>
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000017
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000018#define arysize(ary) (sizeof(ary)/sizeof((ary)[0]))
19
20#ifndef CRONTABS
21#define CRONTABS "/var/spool/cron/crontabs"
22#endif
23#ifndef TMPDIR
24#define TMPDIR "/var/spool/cron"
25#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000026#ifndef SENDMAIL
27#define SENDMAIL "/usr/sbin/sendmail"
28#endif
29#ifndef SENDMAIL_ARGS
Eric Andersen35e643b2003-07-28 07:40:39 +000030#define SENDMAIL_ARGS "-ti", "oem"
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000031#endif
32#ifndef CRONUPDATE
33#define CRONUPDATE "cron.update"
34#endif
35#ifndef MAXLINES
Glenn L McGrath9079ad02004-02-22 04:44:21 +000036#define MAXLINES 256 /* max lines in non-root crontabs */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000037#endif
38
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000039typedef struct CronFile {
Glenn L McGrath9079ad02004-02-22 04:44:21 +000040 struct CronFile *cf_Next;
41 struct CronLine *cf_LineBase;
42 char *cf_User; /* username */
43 int cf_Ready; /* bool: one or more jobs ready */
44 int cf_Running; /* bool: one or more jobs running */
45 int cf_Deleted; /* marked for deletion, ignore */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000046} CronFile;
47
48typedef struct CronLine {
Glenn L McGrath9079ad02004-02-22 04:44:21 +000049 struct CronLine *cl_Next;
50 char *cl_Shell; /* shell command */
51 pid_t cl_Pid; /* running pid, 0, or armed (-1) */
52 int cl_MailFlag; /* running pid is for mail */
53 int cl_MailPos; /* 'empty file' size */
54 char cl_Mins[60]; /* 0-59 */
55 char cl_Hrs[24]; /* 0-23 */
56 char cl_Days[32]; /* 1-31 */
57 char cl_Mons[12]; /* 0-11 */
58 char cl_Dow[7]; /* 0-6, beginning sunday */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000059} CronLine;
60
61#define RUN_RANOUT 1
62#define RUN_RUNNING 2
63#define RUN_FAILED 3
64
65#define DaemonUid 0
66
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +000067#if ENABLE_DEBUG_CROND_OPTION
Denis Vlasenko13858992006-10-08 12:49:22 +000068static unsigned DebugOpt;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000069#endif
70
Denis Vlasenko13858992006-10-08 12:49:22 +000071static unsigned LogLevel = 8;
Glenn L McGrath9079ad02004-02-22 04:44:21 +000072static const char *LogFile;
73static const char *CDir = CRONTABS;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000074
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000075static void startlogger(void);
76
77static void CheckUpdates(void);
78static void SynchronizeDir(void);
79static int TestJobs(time_t t1, time_t t2);
80static void RunJobs(void);
81static int CheckJobs(void);
Eric Andersen35e643b2003-07-28 07:40:39 +000082
Glenn L McGrath9079ad02004-02-22 04:44:21 +000083static void RunJob(const char *user, CronLine * line);
84
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +000085#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
Glenn L McGrath9079ad02004-02-22 04:44:21 +000086static void EndJob(const char *user, CronLine * line);
Eric Andersen35e643b2003-07-28 07:40:39 +000087#else
88#define EndJob(user, line) line->cl_Pid = 0
89#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +000090
91static void DeleteFile(const char *userName);
92
93static CronFile *FileBase;
94
95
Glenn L McGrath9079ad02004-02-22 04:44:21 +000096static void crondlog(const char *ctl, ...)
Eric Andersen35e643b2003-07-28 07:40:39 +000097{
Glenn L McGrath9079ad02004-02-22 04:44:21 +000098 va_list va;
99 const char *fmt;
100 int level = (int) (ctl[0] & 0xf);
101 int type = level == 20 ?
102 LOG_ERR : ((ctl[0] & 0100) ? LOG_WARNING : LOG_NOTICE);
Eric Andersen35e643b2003-07-28 07:40:39 +0000103
104
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000105 va_start(va, ctl);
106 fmt = ctl + 1;
107 if (level >= LogLevel) {
Eric Andersen35e643b2003-07-28 07:40:39 +0000108
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000109#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000110 if (DebugOpt) {
111 vfprintf(stderr, fmt, va);
112 } else
Eric Andersen35e643b2003-07-28 07:40:39 +0000113#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000114 if (LogFile == 0) {
115 vsyslog(type, fmt, va);
116 } else {
"Vladimir N. Oleynik"d0c41a82005-09-05 15:50:56 +0000117 int logfd = open(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000118 if (logfd >= 0) {
119 vdprintf(logfd, fmt, va);
120 close(logfd);
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000121#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000122 } else {
Denis Vlasenkoea620772006-10-14 02:23:43 +0000123 bb_perror_msg("can't open log file");
Eric Andersen35e643b2003-07-28 07:40:39 +0000124#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000125 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000126 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000127 }
128 va_end(va);
129 if (ctl[0] & 0200) {
130 exit(20);
131 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000132}
133
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000134int crond_main(int ac, char **av)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000135{
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000136 unsigned opt;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000137 char *lopt, *Lopt, *copt;
138
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000139#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000140 char *dopt;
141
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000142 opt_complementary = "f-b:b-f:S-L:L-S:d-l";
Eric Andersen8876fb22003-06-20 09:01:58 +0000143#else
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000144 opt_complementary = "f-b:b-f:S-L:L-S";
Eric Andersen8876fb22003-06-20 09:01:58 +0000145#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000146
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000147 opterr = 0; /* disable getopt 'errors' message. */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000148 opt = getopt32(ac, av, "l:L:fbSc:"
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000149#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000150 "d:"
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000151#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000152 , &lopt, &Lopt, &copt
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000153#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000154 , &dopt
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000155#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000156 );
157 if (opt & 1) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000158 LogLevel = xatou(lopt);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000159 }
160 if (opt & 2) {
161 if (*Lopt != 0) {
162 LogFile = Lopt;
163 }
164 }
165 if (opt & 32) {
166 if (*copt != 0) {
167 CDir = copt;
168 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000169 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000170#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000171 if (opt & 64) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000172 DebugOpt = xatou(dopt);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000173 LogLevel = 0;
174 }
Eric Andersen8876fb22003-06-20 09:01:58 +0000175#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000176
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000177 /*
178 * change directory
179 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000180
Rob Landleyd921b2e2006-08-03 15:41:12 +0000181 xchdir(CDir);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000182 signal(SIGHUP, SIG_IGN); /* hmm.. but, if kill -HUP original
183 * version - his died. ;(
184 */
185 /*
186 * close stdin and stdout, stderr.
187 * close unused descriptors - don't need.
188 * optional detach from controlling terminal
189 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000190
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000191 if (!(opt & 4)) {
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000192#ifdef BB_NOMMU
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000193 /* reexec for vfork() do continue parent */
194 vfork_daemon_rexec(1, 0, ac, av, "-f");
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000195#else
Rob Landleyd921b2e2006-08-03 15:41:12 +0000196 xdaemon(1, 0);
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000197#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000198 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000199
200 (void) startlogger(); /* need if syslog mode selected */
201
202 /*
203 * main loop - synchronize to 1 second after the minute, minimum sleep
204 * of 1 second.
205 */
206
207 crondlog("\011%s " VERSION " dillon, started, log level %d\n",
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000208 applet_name, LogLevel);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000209
210 SynchronizeDir();
211
212 {
213 time_t t1 = time(NULL);
214 time_t t2;
215 long dt;
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000216 int rescan = 60;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000217 short sleep_time = 60;
218
219 for (;;) {
220 sleep((sleep_time + 1) - (short) (time(NULL) % sleep_time));
221
222 t2 = time(NULL);
223 dt = t2 - t1;
224
225 /*
226 * The file 'cron.update' is checked to determine new cron
227 * jobs. The directory is rescanned once an hour to deal
228 * with any screwups.
229 *
230 * check for disparity. Disparities over an hour either way
231 * result in resynchronization. A reverse-indexed disparity
232 * less then an hour causes us to effectively sleep until we
233 * match the original time (i.e. no re-execution of jobs that
234 * have just been run). A forward-indexed disparity less then
235 * an hour causes intermediate jobs to be run, but only once
236 * in the worst case.
237 *
238 * when running jobs, the inequality used is greater but not
239 * equal to t1, and less then or equal to t2.
240 */
241
242 if (--rescan == 0) {
243 rescan = 60;
244 SynchronizeDir();
245 }
246 CheckUpdates();
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000247#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000248 if (DebugOpt)
249 crondlog("\005Wakeup dt=%d\n", dt);
250#endif
251 if (dt < -60 * 60 || dt > 60 * 60) {
252 t1 = t2;
253 crondlog("\111time disparity of %d minutes detected\n", dt / 60);
254 } else if (dt > 0) {
255 TestJobs(t1, t2);
256 RunJobs();
257 sleep(5);
258 if (CheckJobs() > 0) {
259 sleep_time = 10;
260 } else {
261 sleep_time = 60;
262 }
263 t1 = t2;
264 }
265 }
266 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000267 bb_fflush_stdout_and_exit(EXIT_SUCCESS); /* not reached */
Glenn L McGrathb89fcd42003-12-23 07:21:33 +0000268}
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000269
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000270static int ChangeUser(const char *user)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000271{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000272 struct passwd *pas;
273 const char *err_msg;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000274
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000275 /*
Eric Andersenaff114c2004-04-14 17:51:38 +0000276 * Obtain password entry and change privileges
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000277 */
278 pas = getpwnam(user);
279 if (pas == 0) {
280 crondlog("\011failed to get uid for %s", user);
281 return (-1);
282 }
283 setenv("USER", pas->pw_name, 1);
284 setenv("HOME", pas->pw_dir, 1);
285 setenv("SHELL", DEFAULT_SHELL, 1);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000286
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000287 /*
288 * Change running state to the user in question
289 */
290 err_msg = change_identity_e2str(pas);
291 if (err_msg) {
292 crondlog("\011%s for user %s", err_msg, user);
293 return (-1);
294 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000295 if (chdir(pas->pw_dir) < 0) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000296 crondlog("\011chdir failed: %s: %m", pas->pw_dir);
297 if (chdir(TMPDIR) < 0) {
298 crondlog("\011chdir failed: %s: %m", TMPDIR);
299 return (-1);
300 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000301 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000302 return (pas->pw_uid);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000303}
304
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000305static void startlogger(void)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000306{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000307 if (LogFile == 0) {
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000308 openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000309 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000310#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000311 else { /* test logfile */
312 int logfd;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000313
"Vladimir N. Oleynik"d0c41a82005-09-05 15:50:56 +0000314 if ((logfd = open(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600)) >= 0) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000315 close(logfd);
316 } else {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000317 bb_perror_msg("failed to open log file '%s': ", LogFile);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000318 }
319 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000320#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000321}
322
323
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000324static const char *const DowAry[] = {
325 "sun",
326 "mon",
327 "tue",
328 "wed",
329 "thu",
330 "fri",
331 "sat",
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000332
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000333 "Sun",
334 "Mon",
335 "Tue",
336 "Wed",
337 "Thu",
338 "Fri",
339 "Sat",
340 NULL
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000341};
342
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000343static const char *const MonAry[] = {
344 "jan",
345 "feb",
346 "mar",
347 "apr",
348 "may",
349 "jun",
350 "jul",
351 "aug",
352 "sep",
353 "oct",
354 "nov",
355 "dec",
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000356
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000357 "Jan",
358 "Feb",
359 "Mar",
360 "Apr",
361 "May",
362 "Jun",
363 "Jul",
364 "Aug",
365 "Sep",
366 "Oct",
367 "Nov",
368 "Dec",
369 NULL
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000370};
371
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000372static char *ParseField(char *user, char *ary, int modvalue, int off,
373 const char *const *names, char *ptr)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000374{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000375 char *base = ptr;
376 int n1 = -1;
377 int n2 = -1;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000378
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000379 if (base == NULL) {
380 return (NULL);
381 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000382
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000383 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
384 int skip = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000385
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000386 /* Handle numeric digit or symbol or '*' */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000387
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000388 if (*ptr == '*') {
389 n1 = 0; /* everything will be filled */
390 n2 = modvalue - 1;
391 skip = 1;
392 ++ptr;
393 } else if (*ptr >= '0' && *ptr <= '9') {
394 if (n1 < 0) {
395 n1 = strtol(ptr, &ptr, 10) + off;
396 } else {
397 n2 = strtol(ptr, &ptr, 10) + off;
398 }
399 skip = 1;
400 } else if (names) {
401 int i;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000402
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000403 for (i = 0; names[i]; ++i) {
404 if (strncmp(ptr, names[i], strlen(names[i])) == 0) {
405 break;
406 }
407 }
408 if (names[i]) {
409 ptr += strlen(names[i]);
410 if (n1 < 0) {
411 n1 = i;
412 } else {
413 n2 = i;
414 }
415 skip = 1;
416 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000417 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000418
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000419 /* handle optional range '-' */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000420
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000421 if (skip == 0) {
422 crondlog("\111failed user %s parsing %s\n", user, base);
423 return (NULL);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000424 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000425 if (*ptr == '-' && n2 < 0) {
426 ++ptr;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000427 continue;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000428 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000429
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000430 /*
431 * collapse single-value ranges, handle skipmark, and fill
432 * in the character array appropriately.
433 */
434
435 if (n2 < 0) {
436 n2 = n1;
437 }
438 if (*ptr == '/') {
439 skip = strtol(ptr + 1, &ptr, 10);
440 }
441 /*
442 * fill array, using a failsafe is the easiest way to prevent
443 * an endless loop
444 */
445
446 {
447 int s0 = 1;
448 int failsafe = 1024;
449
450 --n1;
451 do {
452 n1 = (n1 + 1) % modvalue;
453
454 if (--s0 == 0) {
455 ary[n1 % modvalue] = 1;
456 s0 = skip;
457 }
458 }
459 while (n1 != n2 && --failsafe);
460
461 if (failsafe == 0) {
462 crondlog("\111failed user %s parsing %s\n", user, base);
463 return (NULL);
464 }
465 }
466 if (*ptr != ',') {
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000467 break;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000468 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000469 ++ptr;
470 n1 = -1;
471 n2 = -1;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000472 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000473
474 if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
475 crondlog("\111failed user %s parsing %s\n", user, base);
476 return (NULL);
477 }
478
479 while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') {
480 ++ptr;
481 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000482#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000483 if (DebugOpt) {
484 int i;
485
486 for (i = 0; i < modvalue; ++i) {
487 crondlog("\005%d", ary[i]);
488 }
489 crondlog("\005\n");
490 }
491#endif
492
493 return (ptr);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000494}
495
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000496static void FixDayDow(CronLine * line)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000497{
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000498 int i;
499 int weekUsed = 0;
500 int daysUsed = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000501
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000502 for (i = 0; i < (int)(arysize(line->cl_Dow)); ++i) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000503 if (line->cl_Dow[i] == 0) {
504 weekUsed = 1;
505 break;
506 }
507 }
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000508 for (i = 0; i < (int)(arysize(line->cl_Days)); ++i) {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000509 if (line->cl_Days[i] == 0) {
510 daysUsed = 1;
511 break;
512 }
513 }
514 if (weekUsed && !daysUsed) {
515 memset(line->cl_Days, 0, sizeof(line->cl_Days));
516 }
517 if (daysUsed && !weekUsed) {
518 memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
519 }
520}
521
522
523
524static void SynchronizeFile(const char *fileName)
525{
526 int maxEntries = MAXLINES;
527 int maxLines;
528 char buf[1024];
529
530 if (strcmp(fileName, "root") == 0) {
531 maxEntries = 65535;
532 }
533 maxLines = maxEntries * 10;
534
535 if (fileName) {
536 FILE *fi;
537
538 DeleteFile(fileName);
539
540 fi = fopen(fileName, "r");
541 if (fi != NULL) {
542 struct stat sbuf;
543
544 if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) {
545 CronFile *file = calloc(1, sizeof(CronFile));
546 CronLine **pline;
547
548 file->cf_User = strdup(fileName);
549 pline = &file->cf_LineBase;
550
551 while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) {
552 CronLine line;
553 char *ptr;
554
Rob Landley828548a2005-09-01 10:23:57 +0000555 trim(buf);
556 if (buf[0] == 0 || buf[0] == '#') {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000557 continue;
558 }
559 if (--maxEntries == 0) {
560 break;
561 }
562 memset(&line, 0, sizeof(line));
563
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000564#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000565 if (DebugOpt) {
566 crondlog("\111User %s Entry %s\n", fileName, buf);
567 }
568#endif
569
570 /* parse date ranges */
571 ptr = ParseField(file->cf_User, line.cl_Mins, 60, 0, NULL, buf);
572 ptr = ParseField(file->cf_User, line.cl_Hrs, 24, 0, NULL, ptr);
573 ptr = ParseField(file->cf_User, line.cl_Days, 32, 0, NULL, ptr);
574 ptr = ParseField(file->cf_User, line.cl_Mons, 12, -1, MonAry, ptr);
575 ptr = ParseField(file->cf_User, line.cl_Dow, 7, 0, DowAry, ptr);
576
577 /* check failure */
578 if (ptr == NULL) {
579 continue;
580 }
581
582 /*
583 * fix days and dow - if one is not * and the other
584 * is *, the other is set to 0, and vise-versa
585 */
586
587 FixDayDow(&line);
588
589 *pline = calloc(1, sizeof(CronLine));
590 **pline = line;
591
592 /* copy command */
593 (*pline)->cl_Shell = strdup(ptr);
594
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000595#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000596 if (DebugOpt) {
597 crondlog("\111 Command %s\n", ptr);
598 }
599#endif
600
601 pline = &((*pline)->cl_Next);
602 }
603 *pline = NULL;
604
605 file->cf_Next = FileBase;
606 FileBase = file;
607
608 if (maxLines == 0 || maxEntries == 0) {
609 crondlog("\111Maximum number of lines reached for user %s\n", fileName);
610 }
611 }
612 fclose(fi);
613 }
614 }
615}
616
617static void CheckUpdates(void)
618{
619 FILE *fi;
620 char buf[256];
621
622 fi = fopen(CRONUPDATE, "r");
623 if (fi != NULL) {
624 remove(CRONUPDATE);
625 while (fgets(buf, sizeof(buf), fi) != NULL) {
626 SynchronizeFile(strtok(buf, " \t\r\n"));
627 }
628 fclose(fi);
629 }
630}
631
632static void SynchronizeDir(void)
633{
634 /* Attempt to delete the database. */
635
636 for (;;) {
637 CronFile *file;
638
639 for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next);
640 if (file == NULL) {
641 break;
642 }
643 DeleteFile(file->cf_User);
644 }
645
646 /*
647 * Remove cron update file
648 *
649 * Re-chdir, in case directory was renamed & deleted, or otherwise
650 * screwed up.
651 *
652 * scan directory and add associated users
653 */
654
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000655 remove(CRONUPDATE);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000656 if (chdir(CDir) < 0) {
657 crondlog("\311unable to find %s\n", CDir);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000658 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000659 {
660 DIR *dir = opendir(".");
661 struct dirent *den;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000662
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000663 if (dir) {
664 while ((den = readdir(dir))) {
665 if (strchr(den->d_name, '.') != NULL) {
666 continue;
667 }
668 if (getpwnam(den->d_name)) {
669 SynchronizeFile(den->d_name);
670 } else {
671 crondlog("\007ignoring %s\n", den->d_name);
672 }
673 }
674 closedir(dir);
675 } else {
676 crondlog("\311Unable to open current dir!\n");
677 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000678 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000679}
680
681
682/*
683 * DeleteFile() - delete user database
684 *
685 * Note: multiple entries for same user may exist if we were unable to
686 * completely delete a database due to running processes.
687 */
688
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000689static void DeleteFile(const char *userName)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000690{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000691 CronFile **pfile = &FileBase;
692 CronFile *file;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000693
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000694 while ((file = *pfile) != NULL) {
695 if (strcmp(userName, file->cf_User) == 0) {
696 CronLine **pline = &file->cf_LineBase;
697 CronLine *line;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000698
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000699 file->cf_Running = 0;
700 file->cf_Deleted = 1;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000701
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000702 while ((line = *pline) != NULL) {
703 if (line->cl_Pid > 0) {
704 file->cf_Running = 1;
705 pline = &line->cl_Next;
706 } else {
707 *pline = line->cl_Next;
708 free(line->cl_Shell);
709 free(line);
710 }
711 }
712 if (file->cf_Running == 0) {
713 *pfile = file->cf_Next;
714 free(file->cf_User);
715 free(file);
716 } else {
717 pfile = &file->cf_Next;
718 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000719 } else {
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000720 pfile = &file->cf_Next;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000721 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000722 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000723}
724
725/*
726 * TestJobs()
727 *
728 * determine which jobs need to be run. Under normal conditions, the
729 * period is about a minute (one scan). Worst case it will be one
730 * hour (60 scans).
731 */
732
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000733static int TestJobs(time_t t1, time_t t2)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000734{
"Vladimir N. Oleynik"cd5c15d2006-01-30 13:36:03 +0000735 int nJobs = 0;
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000736 time_t t;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000737
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000738 /* Find jobs > t1 and <= t2 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000739
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000740 for (t = t1 - t1 % 60; t <= t2; t += 60) {
741 if (t > t1) {
742 struct tm *tp = localtime(&t);
743 CronFile *file;
744 CronLine *line;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000745
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000746 for (file = FileBase; file; file = file->cf_Next) {
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000747#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000748 if (DebugOpt)
749 crondlog("\005FILE %s:\n", file->cf_User);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000750#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000751 if (file->cf_Deleted)
752 continue;
753 for (line = file->cf_LineBase; line; line = line->cl_Next) {
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000754#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000755 if (DebugOpt)
756 crondlog("\005 LINE %s\n", line->cl_Shell);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000757#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000758 if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour] &&
759 (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday])
760 && line->cl_Mons[tp->tm_mon]) {
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000761#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000762 if (DebugOpt) {
763 crondlog("\005 JobToDo: %d %s\n",
764 line->cl_Pid, line->cl_Shell);
765 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000766#endif
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000767 if (line->cl_Pid > 0) {
768 crondlog("\010 process already running: %s %s\n",
769 file->cf_User, line->cl_Shell);
770 } else if (line->cl_Pid == 0) {
771 line->cl_Pid = -1;
772 file->cf_Ready = 1;
773 ++nJobs;
774 }
775 }
776 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000777 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000778 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000779 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000780 return (nJobs);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000781}
782
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000783static void RunJobs(void)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000784{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000785 CronFile *file;
786 CronLine *line;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000787
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000788 for (file = FileBase; file; file = file->cf_Next) {
789 if (file->cf_Ready) {
790 file->cf_Ready = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000791
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000792 for (line = file->cf_LineBase; line; line = line->cl_Next) {
793 if (line->cl_Pid < 0) {
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000794
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000795 RunJob(file->cf_User, line);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000796
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000797 crondlog("\010USER %s pid %3d cmd %s\n",
798 file->cf_User, line->cl_Pid, line->cl_Shell);
799 if (line->cl_Pid < 0) {
800 file->cf_Ready = 1;
801 }
802 else if (line->cl_Pid > 0) {
803 file->cf_Running = 1;
804 }
805 }
806 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000807 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000808 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000809}
810
811/*
812 * CheckJobs() - check for job completion
813 *
814 * Check for job completion, return number of jobs still running after
815 * all done.
816 */
817
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000818static int CheckJobs(void)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000819{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000820 CronFile *file;
821 CronLine *line;
822 int nStillRunning = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000823
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000824 for (file = FileBase; file; file = file->cf_Next) {
825 if (file->cf_Running) {
826 file->cf_Running = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000827
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000828 for (line = file->cf_LineBase; line; line = line->cl_Next) {
829 if (line->cl_Pid > 0) {
830 int status;
831 int r = wait4(line->cl_Pid, &status, WNOHANG, NULL);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000832
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000833 if (r < 0 || r == line->cl_Pid) {
834 EndJob(file->cf_User, line);
835 if (line->cl_Pid) {
836 file->cf_Running = 1;
837 }
838 } else if (r == 0) {
839 file->cf_Running = 1;
840 }
841 }
842 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000843 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000844 nStillRunning += file->cf_Running;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000845 }
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000846 return (nStillRunning);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000847}
848
849
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000850#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
Eric Andersen35e643b2003-07-28 07:40:39 +0000851static void
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000852ForkJob(const char *user, CronLine * line, int mailFd,
853 const char *prog, const char *cmd, const char *arg, const char *mailf)
Eric Andersen35e643b2003-07-28 07:40:39 +0000854{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000855 /* Fork as the user in question and run program */
856 pid_t pid = fork();
Eric Andersen35e643b2003-07-28 07:40:39 +0000857
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000858 line->cl_Pid = pid;
859 if (pid == 0) {
860 /* CHILD */
Eric Andersen35e643b2003-07-28 07:40:39 +0000861
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000862 /* Change running state to the user in question */
Eric Andersen35e643b2003-07-28 07:40:39 +0000863
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000864 if (ChangeUser(user) < 0) {
865 exit(0);
866 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000867#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000868 if (DebugOpt) {
869 crondlog("\005Child Running %s\n", prog);
870 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000871#endif
872
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000873 if (mailFd >= 0) {
874 dup2(mailFd, mailf != NULL);
875 dup2((mailf ? mailFd : 1), 2);
876 close(mailFd);
877 }
878 execl(prog, prog, cmd, arg, NULL);
879 crondlog("\024unable to exec, user %s cmd %s %s %s\n", user, prog, cmd, arg);
880 if (mailf) {
881 fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
882 }
883 exit(0);
884 } else if (pid < 0) {
885 /* FORK FAILED */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000886 crondlog("\024cannot fork, user %s\n", user);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000887 line->cl_Pid = 0;
888 if (mailf) {
889 remove(mailf);
890 }
891 } else if (mailf) {
892 /* PARENT, FORK SUCCESS
893 * rename mail-file based on pid of process
894 */
895 char mailFile2[128];
896
897 snprintf(mailFile2, sizeof(mailFile2), TMPDIR "/cron.%s.%d", user, pid);
898 rename(mailf, mailFile2);
Eric Andersen35e643b2003-07-28 07:40:39 +0000899 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000900 /*
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000901 * Close the mail file descriptor.. we can't just leave it open in
902 * a structure, closing it later, because we might run out of descriptors
Eric Andersen35e643b2003-07-28 07:40:39 +0000903 */
Eric Andersen35e643b2003-07-28 07:40:39 +0000904
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000905 if (mailFd >= 0) {
906 close(mailFd);
907 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000908}
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000909
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000910static void RunJob(const char *user, CronLine * line)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000911{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000912 char mailFile[128];
913 int mailFd;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000914
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000915 line->cl_Pid = 0;
916 line->cl_MailFlag = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000917
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000918 /* open mail file - owner root so nobody can screw with it. */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000919
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000920 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, getpid());
921 mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000922
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000923 if (mailFd >= 0) {
924 line->cl_MailFlag = 1;
925 fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user,
926 line->cl_Shell);
Denis Vlasenkoea620772006-10-14 02:23:43 +0000927 line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR);
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000928 } else {
929 crondlog("\024unable to create mail file user %s file %s, output to /dev/null\n", user, mailFile);
930 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000931
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000932 ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000933}
934
935/*
936 * EndJob - called when job terminates and when mail terminates
937 */
938
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000939static void EndJob(const char *user, CronLine * line)
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000940{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000941 int mailFd;
942 char mailFile[128];
943 struct stat sbuf;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000944
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000945 /* No job */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000946
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000947 if (line->cl_Pid <= 0) {
948 line->cl_Pid = 0;
949 return;
950 }
951
952 /*
953 * End of job and no mail file
954 * End of sendmail job
955 */
956
957 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, line->cl_Pid);
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000958 line->cl_Pid = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000959
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000960 if (line->cl_MailFlag != 1) {
961 return;
962 }
963 line->cl_MailFlag = 0;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000964
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000965 /*
966 * End of primary job - check for mail file. If size has increased and
967 * the file is still valid, we sendmail it.
968 */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000969
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000970 mailFd = open(mailFile, O_RDONLY);
971 remove(mailFile);
972 if (mailFd < 0) {
973 return;
974 }
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000975
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000976 if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid || sbuf.st_nlink != 0 ||
977 sbuf.st_size == line->cl_MailPos || !S_ISREG(sbuf.st_mode)) {
978 close(mailFd);
979 return;
980 }
981 ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL);
Eric Andersen35e643b2003-07-28 07:40:39 +0000982}
983#else
Eric Andersenaff114c2004-04-14 17:51:38 +0000984/* crond without sendmail */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000985
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000986static void RunJob(const char *user, CronLine * line)
Eric Andersen35e643b2003-07-28 07:40:39 +0000987{
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000988 /* Fork as the user in question and run program */
989 pid_t pid = fork();
Eric Andersen35e643b2003-07-28 07:40:39 +0000990
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000991 if (pid == 0) {
992 /* CHILD */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000993
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000994 /* Change running state to the user in question */
Eric Andersenf6f7bfb2002-10-22 12:24:59 +0000995
Glenn L McGrath9079ad02004-02-22 04:44:21 +0000996 if (ChangeUser(user) < 0) {
997 exit(0);
998 }
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +0000999#if ENABLE_DEBUG_CROND_OPTION
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001000 if (DebugOpt) {
1001 crondlog("\005Child Running %s\n", DEFAULT_SHELL);
1002 }
Eric Andersen35e643b2003-07-28 07:40:39 +00001003#endif
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001004
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001005 execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL);
1006 crondlog("\024unable to exec, user %s cmd %s -c %s\n", user,
1007 DEFAULT_SHELL, line->cl_Shell);
1008 exit(0);
1009 } else if (pid < 0) {
1010 /* FORK FAILED */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00001011 crondlog("\024cannot, user %s\n", user);
Glenn L McGrath9079ad02004-02-22 04:44:21 +00001012 pid = 0;
1013 }
1014 line->cl_Pid = pid;
Eric Andersenf6f7bfb2002-10-22 12:24:59 +00001015}
Bernhard Reutner-Fischeref216292006-05-20 14:14:05 +00001016#endif /* ENABLE_FEATURE_CROND_CALL_SENDMAIL */