aboutsummaryrefslogtreecommitdiff
path: root/miscutils/crond.c
diff options
context:
space:
mode:
authorGlenn L McGrath <bug1@ihug.co.nz>2004-02-22 04:44:21 +0000
committerGlenn L McGrath <bug1@ihug.co.nz>2004-02-22 04:44:21 +0000
commit9079ad0cab687a60e7ea179beb9875ba1e739318 (patch)
tree41bb38e3f7b44fd8ebc470ee9a850d4315794865 /miscutils/crond.c
parente7f2b2bf315a71fc245a3c7f885444ca1be31d98 (diff)
downloadbusybox-w32-9079ad0cab687a60e7ea179beb9875ba1e739318.tar.gz
busybox-w32-9079ad0cab687a60e7ea179beb9875ba1e739318.tar.bz2
busybox-w32-9079ad0cab687a60e7ea179beb9875ba1e739318.zip
Fixup braces (patch from Thomas Geulig), run through indent and manually
adjust.
Diffstat (limited to 'miscutils/crond.c')
-rw-r--r--miscutils/crond.c1522
1 files changed, 744 insertions, 778 deletions
diff --git a/miscutils/crond.c b/miscutils/crond.c
index a32751d47..e32bac67a 100644
--- a/miscutils/crond.c
+++ b/miscutils/crond.c
@@ -51,29 +51,29 @@
51#define CRONUPDATE "cron.update" 51#define CRONUPDATE "cron.update"
52#endif 52#endif
53#ifndef MAXLINES 53#ifndef MAXLINES
54#define MAXLINES 256 /* max lines in non-root crontabs */ 54#define MAXLINES 256 /* max lines in non-root crontabs */
55#endif 55#endif
56 56
57typedef struct CronFile { 57typedef struct CronFile {
58 struct CronFile *cf_Next; 58 struct CronFile *cf_Next;
59 struct CronLine *cf_LineBase; 59 struct CronLine *cf_LineBase;
60 char *cf_User; /* username */ 60 char *cf_User; /* username */
61 int cf_Ready; /* bool: one or more jobs ready */ 61 int cf_Ready; /* bool: one or more jobs ready */
62 int cf_Running; /* bool: one or more jobs running */ 62 int cf_Running; /* bool: one or more jobs running */
63 int cf_Deleted; /* marked for deletion, ignore */ 63 int cf_Deleted; /* marked for deletion, ignore */
64} CronFile; 64} CronFile;
65 65
66typedef struct CronLine { 66typedef struct CronLine {
67 struct CronLine *cl_Next; 67 struct CronLine *cl_Next;
68 char *cl_Shell; /* shell command */ 68 char *cl_Shell; /* shell command */
69 pid_t cl_Pid; /* running pid, 0, or armed (-1) */ 69 pid_t cl_Pid; /* running pid, 0, or armed (-1) */
70 int cl_MailFlag; /* running pid is for mail */ 70 int cl_MailFlag; /* running pid is for mail */
71 int cl_MailPos; /* 'empty file' size */ 71 int cl_MailPos; /* 'empty file' size */
72 char cl_Mins[60]; /* 0-59 */ 72 char cl_Mins[60]; /* 0-59 */
73 char cl_Hrs[24]; /* 0-23 */ 73 char cl_Hrs[24]; /* 0-23 */
74 char cl_Days[32]; /* 1-31 */ 74 char cl_Days[32]; /* 1-31 */
75 char cl_Mons[12]; /* 0-11 */ 75 char cl_Mons[12]; /* 0-11 */
76 char cl_Dow[7]; /* 0-6, beginning sunday */ 76 char cl_Dow[7]; /* 0-6, beginning sunday */
77} CronLine; 77} CronLine;
78 78
79#define RUN_RANOUT 1 79#define RUN_RANOUT 1
@@ -87,8 +87,8 @@ static short DebugOpt;
87#endif 87#endif
88 88
89static short LogLevel = 8; 89static short LogLevel = 8;
90static const char *LogFile; 90static const char *LogFile;
91static const char *CDir = CRONTABS; 91static const char *CDir = CRONTABS;
92 92
93static void startlogger(void); 93static void startlogger(void);
94 94
@@ -98,9 +98,10 @@ static int TestJobs(time_t t1, time_t t2);
98static void RunJobs(void); 98static void RunJobs(void);
99static int CheckJobs(void); 99static int CheckJobs(void);
100 100
101static void RunJob(const char *user, CronLine *line); 101static void RunJob(const char *user, CronLine * line);
102
102#ifdef CONFIG_FEATURE_CROND_CALL_SENDMAIL 103#ifdef CONFIG_FEATURE_CROND_CALL_SENDMAIL
103static void EndJob(const char *user, CronLine *line); 104static void EndJob(const char *user, CronLine * line);
104#else 105#else
105#define EndJob(user, line) line->cl_Pid = 0 106#define EndJob(user, line) line->cl_Pid = 0
106#endif 107#endif
@@ -110,608 +111,610 @@ static void DeleteFile(const char *userName);
110static CronFile *FileBase; 111static CronFile *FileBase;
111 112
112 113
113static void 114static void crondlog(const char *ctl, ...)
114crondlog(const char *ctl, ...)
115{ 115{
116 va_list va; 116 va_list va;
117 const char *fmt; 117 const char *fmt;
118 int level = (int)(ctl[0] & 0xf); 118 int level = (int) (ctl[0] & 0xf);
119 int type = level == 20 ? 119 int type = level == 20 ?
120 LOG_ERR : ((ctl[0] & 0100) ? LOG_WARNING : LOG_NOTICE); 120 LOG_ERR : ((ctl[0] & 0100) ? LOG_WARNING : LOG_NOTICE);
121 121
122 122
123 va_start(va, ctl); 123 va_start(va, ctl);
124 fmt = ctl+1; 124 fmt = ctl + 1;
125 if (level >= LogLevel) { 125 if (level >= LogLevel) {
126 126
127#ifdef FEATURE_DEBUG_OPT 127#ifdef FEATURE_DEBUG_OPT
128 if (DebugOpt) vfprintf(stderr, fmt, va); 128 if (DebugOpt) {
129 else 129 vfprintf(stderr, fmt, va);
130 } else
130#endif 131#endif
131 if (LogFile == 0) vsyslog(type, fmt, va); 132 if (LogFile == 0) {
132 else { 133 vsyslog(type, fmt, va);
133 int logfd; 134 } else {
134 135 int logfd = open(LogFile, O_WRONLY | O_CREAT | O_APPEND, 600);
135 if ((logfd = open(LogFile, O_WRONLY|O_CREAT|O_APPEND, 600)) >= 0) { 136 if (logfd >= 0) {
136 vdprintf(logfd, fmt, va); 137 vdprintf(logfd, fmt, va);
137 close(logfd); 138 close(logfd);
138#ifdef FEATURE_DEBUG_OPT 139#ifdef FEATURE_DEBUG_OPT
139 } else { 140 } else {
140 bb_perror_msg("Can't open log file"); 141 bb_perror_msg("Can't open log file");
141#endif 142#endif
143 }
142 } 144 }
143 } 145 }
144 } 146 va_end(va);
145 va_end(va); 147 if (ctl[0] & 0200) {
146 if(ctl[0] & 0200) 148 exit(20);
147 exit(20); 149 }
148} 150}
149 151
150int 152int crond_main(int ac, char **av)
151crond_main(int ac, char **av)
152{ 153{
153 unsigned long opt; 154 unsigned long opt;
154 char *lopt, *Lopt, *copt; 155 char *lopt, *Lopt, *copt;
156
155#ifdef FEATURE_DEBUG_OPT 157#ifdef FEATURE_DEBUG_OPT
156 char *dopt; 158 char *dopt;
157 bb_opt_complementaly = "f-b:b-f:S-L:L-S:d-l"; 159
160 bb_opt_complementaly = "f-b:b-f:S-L:L-S:d-l";
158#else 161#else
159 bb_opt_complementaly = "f-b:b-f:S-L:L-S"; 162 bb_opt_complementaly = "f-b:b-f:S-L:L-S";
160#endif 163#endif
161 164
162 opterr = 0; /* disable getopt 'errors' message.*/ 165 opterr = 0; /* disable getopt 'errors' message. */
163 opt = bb_getopt_ulflags(ac, av, "l:L:fbSc:" 166 opt = bb_getopt_ulflags(ac, av, "l:L:fbSc:"
164#ifdef FEATURE_DEBUG_OPT 167#ifdef FEATURE_DEBUG_OPT
165 "d:" 168 "d:"
166#endif 169#endif
167 , &lopt, &Lopt, &copt 170 , &lopt, &Lopt, &copt
168#ifdef FEATURE_DEBUG_OPT 171#ifdef FEATURE_DEBUG_OPT
169 , &dopt 172 , &dopt
170#endif 173#endif
171 ); 174 );
172 if(opt & 1) 175 if (opt & 1) {
173 LogLevel = atoi(lopt); 176 LogLevel = atoi(lopt);
174 if(opt & 2) 177 }
175 if (*Lopt != 0) LogFile = Lopt; 178 if (opt & 2) {
176 if(opt & 32) { 179 if (*Lopt != 0) {
177 if (*copt != 0) CDir = copt; 180 LogFile = Lopt;
181 }
182 }
183 if (opt & 32) {
184 if (*copt != 0) {
185 CDir = copt;
186 }
178 } 187 }
179#ifdef FEATURE_DEBUG_OPT 188#ifdef FEATURE_DEBUG_OPT
180 if(opt & 64) { 189 if (opt & 64) {
181 DebugOpt = atoi(dopt); 190 DebugOpt = atoi(dopt);
182 LogLevel = 0; 191 LogLevel = 0;
183 } 192 }
184#endif 193#endif
185 194
186 /* 195 /*
187 * change directory 196 * change directory
188 */ 197 */
189
190 if (chdir(CDir) != 0)
191 bb_perror_msg_and_die("%s", CDir);
192 198
193 signal(SIGHUP,SIG_IGN); /* hmm.. but, if kill -HUP original 199 if (chdir(CDir) != 0) {
194 * version - his died. ;( 200 bb_perror_msg_and_die("%s", CDir);
195 */ 201 }
196 /* 202 signal(SIGHUP, SIG_IGN); /* hmm.. but, if kill -HUP original
197 * close stdin and stdout, stderr. 203 * version - his died. ;(
198 * close unused descriptors - don't need. 204 */
199 * optional detach from controlling terminal 205 /*
200 */ 206 * close stdin and stdout, stderr.
207 * close unused descriptors - don't need.
208 * optional detach from controlling terminal
209 */
201 210
202 if (!(opt & 4)) { 211 if (!(opt & 4)) {
203#if defined(__uClinux__) 212#if defined(__uClinux__)
204 /* reexec for vfork() do continue parent */ 213 /* reexec for vfork() do continue parent */
205 vfork_daemon_rexec(1, 0, ac, av, "-f"); 214 vfork_daemon_rexec(1, 0, ac, av, "-f");
206#else /* uClinux */ 215#else /* uClinux */
207 if(daemon(1, 0) < 0) { 216 if (daemon(1, 0) < 0) {
208 bb_perror_msg_and_die("daemon"); 217 bb_perror_msg_and_die("daemon");
209#endif /* uClinux */ 218 }
210 } 219#endif /* uClinux */
211 220 }
212 (void)startlogger(); /* need if syslog mode selected */
213 221
214 /* 222 (void) startlogger(); /* need if syslog mode selected */
215 * main loop - synchronize to 1 second after the minute, minimum sleep
216 * of 1 second.
217 */
218 223
219 crondlog("\011%s " VERSION " dillon, started, log level %d\n", bb_applet_name, 224 /*
220 LogLevel); 225 * main loop - synchronize to 1 second after the minute, minimum sleep
226 * of 1 second.
227 */
221 228
222 SynchronizeDir(); 229 crondlog("\011%s " VERSION " dillon, started, log level %d\n",
230 bb_applet_name, LogLevel);
223 231
224 { 232 SynchronizeDir();
225 time_t t1 = time(NULL);
226 time_t t2;
227 long dt;
228 short rescan = 60;
229 short sleep_time = 60;
230 233
231 for (;;) { 234 {
232 sleep((sleep_time + 1) - (short)(time(NULL) % sleep_time)); 235 time_t t1 = time(NULL);
233 236 time_t t2;
234 t2 = time(NULL); 237 long dt;
235 dt = t2 - t1; 238 short rescan = 60;
236 239 short sleep_time = 60;
237 /* 240
238 * The file 'cron.update' is checked to determine new cron 241 for (;;) {
239 * jobs. The directory is rescanned once an hour to deal 242 sleep((sleep_time + 1) - (short) (time(NULL) % sleep_time));
240 * with any screwups. 243
241 * 244 t2 = time(NULL);
242 * check for disparity. Disparities over an hour either way 245 dt = t2 - t1;
243 * result in resynchronization. A reverse-indexed disparity 246
244 * less then an hour causes us to effectively sleep until we 247 /*
245 * match the original time (i.e. no re-execution of jobs that 248 * The file 'cron.update' is checked to determine new cron
246 * have just been run). A forward-indexed disparity less then 249 * jobs. The directory is rescanned once an hour to deal
247 * an hour causes intermediate jobs to be run, but only once 250 * with any screwups.
248 * in the worst case. 251 *
249 * 252 * check for disparity. Disparities over an hour either way
250 * when running jobs, the inequality used is greater but not 253 * result in resynchronization. A reverse-indexed disparity
251 * equal to t1, and less then or equal to t2. 254 * less then an hour causes us to effectively sleep until we
252 */ 255 * match the original time (i.e. no re-execution of jobs that
253 256 * have just been run). A forward-indexed disparity less then
254 if (--rescan == 0) { 257 * an hour causes intermediate jobs to be run, but only once
255 rescan = 60; 258 * in the worst case.
256 SynchronizeDir(); 259 *
257 } 260 * when running jobs, the inequality used is greater but not
258 CheckUpdates(); 261 * equal to t1, and less then or equal to t2.
262 */
263
264 if (--rescan == 0) {
265 rescan = 60;
266 SynchronizeDir();
267 }
268 CheckUpdates();
259#ifdef FEATURE_DEBUG_OPT 269#ifdef FEATURE_DEBUG_OPT
260 if (DebugOpt) 270 if (DebugOpt)
261 crondlog("\005Wakeup dt=%d\n", dt); 271 crondlog("\005Wakeup dt=%d\n", dt);
262#endif 272#endif
263 if (dt < -60*60 || dt > 60*60) { 273 if (dt < -60 * 60 || dt > 60 * 60) {
264 t1 = t2; 274 t1 = t2;
265 crondlog("\111time disparity of %d minutes detected\n", dt / 60); 275 crondlog("\111time disparity of %d minutes detected\n", dt / 60);
266 } else if (dt > 0) { 276 } else if (dt > 0) {
267 TestJobs(t1, t2); 277 TestJobs(t1, t2);
268 RunJobs(); 278 RunJobs();
269 sleep(5); 279 sleep(5);
270 if (CheckJobs() > 0) 280 if (CheckJobs() > 0) {
271 sleep_time = 10; 281 sleep_time = 10;
272 else 282 } else {
273 sleep_time = 60; 283 sleep_time = 60;
274 t1 = t2; 284 }
275 } 285 t1 = t2;
286 }
287 }
276 } 288 }
277 } 289 /* not reached */
278 /* not reached */
279}
280} 290}
281 291
282#if defined(FEATURE_DEBUG_OPT) || defined(CONFIG_FEATURE_CROND_CALL_SENDMAIL) 292#if defined(FEATURE_DEBUG_OPT) || defined(CONFIG_FEATURE_CROND_CALL_SENDMAIL)
283/* 293/*
284 write to temp file.. 294 write to temp file..
285*/ 295*/
286static void 296static void fdprintf(int fd, const char *ctl, ...)
287fdprintf(int fd, const char *ctl, ...)
288{ 297{
289 va_list va; 298 va_list va;
290 299
291 va_start(va, ctl); 300 va_start(va, ctl);
292 vdprintf(fd, ctl, va); 301 vdprintf(fd, ctl, va);
293 va_end(va); 302 va_end(va);
294} 303}
295#endif 304#endif
296 305
297 306
298static int 307static int ChangeUser(const char *user)
299ChangeUser(const char *user)
300{ 308{
301 struct passwd *pas; 309 struct passwd *pas;
302 const char *err_msg; 310 const char *err_msg;
303 311
304 /* 312 /*
305 * Obtain password entry and change privilages 313 * Obtain password entry and change privilages
306 */ 314 */
307 315 pas = getpwnam(user);
308 if ((pas = getpwnam(user)) == 0) { 316 if (pas == 0) {
309 crondlog("\011failed to get uid for %s", user); 317 crondlog("\011failed to get uid for %s", user);
310 return(-1); 318 return (-1);
311 } 319 }
312 setenv("USER", pas->pw_name, 1); 320 setenv("USER", pas->pw_name, 1);
313 setenv("HOME", pas->pw_dir, 1); 321 setenv("HOME", pas->pw_dir, 1);
314 setenv("SHELL", DEFAULT_SHELL, 1); 322 setenv("SHELL", DEFAULT_SHELL, 1);
315 323
316 /* 324 /*
317 * Change running state to the user in question 325 * Change running state to the user in question
318 */ 326 */
319 err_msg = change_identity_e2str(pas); 327 err_msg = change_identity_e2str(pas);
320 if (err_msg) { 328 if (err_msg) {
321 crondlog("\011%s for user %s", err_msg, user); 329 crondlog("\011%s for user %s", err_msg, user);
322 return(-1); 330 return (-1);
323 } 331 }
324 if (chdir(pas->pw_dir) < 0) { 332 if (chdir(pas->pw_dir) < 0) {
325 crondlog("\011chdir failed: %s: %m", pas->pw_dir); 333 crondlog("\011chdir failed: %s: %m", pas->pw_dir);
326 if (chdir(TMPDIR) < 0) { 334 if (chdir(TMPDIR) < 0) {
327 crondlog("\011chdir failed: %s: %m", TMPDIR); 335 crondlog("\011chdir failed: %s: %m", TMPDIR);
328 return(-1); 336 return (-1);
329 } 337 }
330 } 338 }
331 return(pas->pw_uid); 339 return (pas->pw_uid);
332} 340}
333 341
334static void 342static void startlogger(void)
335startlogger(void)
336{ 343{
337 if (LogFile == 0) 344 if (LogFile == 0) {
338 openlog(bb_applet_name, LOG_CONS|LOG_PID, LOG_CRON); 345 openlog(bb_applet_name, LOG_CONS | LOG_PID, LOG_CRON);
346 }
339#ifdef FEATURE_DEBUG_OPT 347#ifdef FEATURE_DEBUG_OPT
340 else { /* test logfile */ 348 else { /* test logfile */
341 int logfd; 349 int logfd;
342 350
343 if ((logfd = open(LogFile, O_WRONLY|O_CREAT|O_APPEND, 600)) >= 0) 351 if ((logfd = open(LogFile, O_WRONLY | O_CREAT | O_APPEND, 600)) >= 0) {
344 close(logfd); 352 close(logfd);
345 else 353 } else {
346 bb_perror_msg("Failed to open log file '%s' reason", LogFile); 354 bb_perror_msg("Failed to open log file '%s' reason", LogFile);
347 } 355 }
356 }
348#endif 357#endif
349} 358}
350 359
351 360
352static const char * const DowAry[] = { 361static const char *const DowAry[] = {
353 "sun", 362 "sun",
354 "mon", 363 "mon",
355 "tue", 364 "tue",
356 "wed", 365 "wed",
357 "thu", 366 "thu",
358 "fri", 367 "fri",
359 "sat", 368 "sat",
360 369
361 "Sun", 370 "Sun",
362 "Mon", 371 "Mon",
363 "Tue", 372 "Tue",
364 "Wed", 373 "Wed",
365 "Thu", 374 "Thu",
366 "Fri", 375 "Fri",
367 "Sat", 376 "Sat",
368 NULL 377 NULL
369}; 378};
370 379
371static const char * const MonAry[] = { 380static const char *const MonAry[] = {
372 "jan", 381 "jan",
373 "feb", 382 "feb",
374 "mar", 383 "mar",
375 "apr", 384 "apr",
376 "may", 385 "may",
377 "jun", 386 "jun",
378 "jul", 387 "jul",
379 "aug", 388 "aug",
380 "sep", 389 "sep",
381 "oct", 390 "oct",
382 "nov", 391 "nov",
383 "dec", 392 "dec",
384 393
385 "Jan", 394 "Jan",
386 "Feb", 395 "Feb",
387 "Mar", 396 "Mar",
388 "Apr", 397 "Apr",
389 "May", 398 "May",
390 "Jun", 399 "Jun",
391 "Jul", 400 "Jul",
392 "Aug", 401 "Aug",
393 "Sep", 402 "Sep",
394 "Oct", 403 "Oct",
395 "Nov", 404 "Nov",
396 "Dec", 405 "Dec",
397 NULL 406 NULL
398}; 407};
399 408
400static char * 409static char *ParseField(char *user, char *ary, int modvalue, int off,
401ParseField(char *user, char *ary, int modvalue, int off, 410 const char *const *names, char *ptr)
402 const char * const *names, char *ptr)
403{ 411{
404 char *base = ptr; 412 char *base = ptr;
405 int n1 = -1; 413 int n1 = -1;
406 int n2 = -1; 414 int n2 = -1;
407
408 if (base == NULL)
409 return(NULL);
410
411 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
412 int skip = 0;
413 415
414 /* 416 if (base == NULL) {
415 * Handle numeric digit or symbol or '*' 417 return (NULL);
416 */
417
418 if (*ptr == '*') {
419 n1 = 0; /* everything will be filled */
420 n2 = modvalue - 1;
421 skip = 1;
422 ++ptr;
423 } else if (*ptr >= '0' && *ptr <= '9') {
424 if (n1 < 0)
425 n1 = strtol(ptr, &ptr, 10) + off;
426 else
427 n2 = strtol(ptr, &ptr, 10) + off;
428 skip = 1;
429 } else if (names) {
430 int i;
431
432 for (i = 0; names[i]; ++i) {
433 if (strncmp(ptr, names[i], strlen(names[i])) == 0) {
434 break;
435 }
436 }
437 if (names[i]) {
438 ptr += strlen(names[i]);
439 if (n1 < 0)
440 n1 = i;
441 else
442 n2 = i;
443 skip = 1;
444 }
445 } 418 }
446 419
447 /* 420 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
448 * handle optional range '-' 421 int skip = 0;
449 */ 422
450 423 /* Handle numeric digit or symbol or '*' */
451 if (skip == 0) { 424
452 crondlog("\111failed user %s parsing %s\n", user, base); 425 if (*ptr == '*') {
453 return(NULL); 426 n1 = 0; /* everything will be filled */
454 } 427 n2 = modvalue - 1;
455 if (*ptr == '-' && n2 < 0) { 428 skip = 1;
456 ++ptr; 429 ++ptr;
457 continue; 430 } else if (*ptr >= '0' && *ptr <= '9') {
458 } 431 if (n1 < 0) {
459 432 n1 = strtol(ptr, &ptr, 10) + off;
460 /* 433 } else {
461 * collapse single-value ranges, handle skipmark, and fill 434 n2 = strtol(ptr, &ptr, 10) + off;
462 * in the character array appropriately. 435 }
463 */ 436 skip = 1;
464 437 } else if (names) {
465 if (n2 < 0) 438 int i;
466 n2 = n1; 439
440 for (i = 0; names[i]; ++i) {
441 if (strncmp(ptr, names[i], strlen(names[i])) == 0) {
442 break;
443 }
444 }
445 if (names[i]) {
446 ptr += strlen(names[i]);
447 if (n1 < 0) {
448 n1 = i;
449 } else {
450 n2 = i;
451 }
452 skip = 1;
453 }
454 }
467 455
468 if (*ptr == '/') 456 /* handle optional range '-' */
469 skip = strtol(ptr + 1, &ptr, 10);
470 457
471 /* 458 if (skip == 0) {
472 * fill array, using a failsafe is the easiest way to prevent 459 crondlog("\111failed user %s parsing %s\n", user, base);
473 * an endless loop 460 return (NULL);
474 */ 461 }
462 if (*ptr == '-' && n2 < 0) {
463 ++ptr;
464 continue;
465 }
475 466
476 { 467 /*
477 int s0 = 1; 468 * collapse single-value ranges, handle skipmark, and fill
478 int failsafe = 1024; 469 * in the character array appropriately.
470 */
479 471
480 --n1; 472 if (n2 < 0) {
481 do { 473 n2 = n1;
482 n1 = (n1 + 1) % modvalue; 474 }
475 if (*ptr == '/') {
476 skip = strtol(ptr + 1, &ptr, 10);
477 }
478 /*
479 * fill array, using a failsafe is the easiest way to prevent
480 * an endless loop
481 */
482
483 {
484 int s0 = 1;
485 int failsafe = 1024;
486
487 --n1;
488 do {
489 n1 = (n1 + 1) % modvalue;
490
491 if (--s0 == 0) {
492 ary[n1 % modvalue] = 1;
493 s0 = skip;
494 }
495 }
496 while (n1 != n2 && --failsafe);
483 497
484 if (--s0 == 0) { 498 if (failsafe == 0) {
485 ary[n1 % modvalue] = 1; 499 crondlog("\111failed user %s parsing %s\n", user, base);
486 s0 = skip; 500 return (NULL);
501 }
502 }
503 if (*ptr != ',') {
504 break;
487 } 505 }
488 } while (n1 != n2 && --failsafe); 506 ++ptr;
507 n1 = -1;
508 n2 = -1;
509 }
489 510
490 if (failsafe == 0) { 511 if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
491 crondlog("\111failed user %s parsing %s\n", user, base); 512 crondlog("\111failed user %s parsing %s\n", user, base);
492 return(NULL); 513 return (NULL);
493 }
494 } 514 }
495 if (*ptr != ',')
496 break;
497 ++ptr;
498 n1 = -1;
499 n2 = -1;
500 }
501
502 if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
503 crondlog("\111failed user %s parsing %s\n", user, base);
504 return(NULL);
505 }
506
507 while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
508 ++ptr;
509 515
516 while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') {
517 ++ptr;
518 }
510#ifdef FEATURE_DEBUG_OPT 519#ifdef FEATURE_DEBUG_OPT
511 if (DebugOpt) { 520 if (DebugOpt) {
512 int i; 521 int i;
513 522
514 for (i = 0; i < modvalue; ++i) 523 for (i = 0; i < modvalue; ++i) {
515 crondlog("\005%d", ary[i]); 524 crondlog("\005%d", ary[i]);
516 crondlog("\005\n"); 525 }
517 } 526 crondlog("\005\n");
527 }
518#endif 528#endif
519 529
520 return(ptr); 530 return (ptr);
521} 531}
522 532
523static void 533static void FixDayDow(CronLine * line)
524FixDayDow(CronLine *line)
525{ 534{
526 short i; 535 short i;
527 short weekUsed = 0; 536 short weekUsed = 0;
528 short daysUsed = 0; 537 short daysUsed = 0;
529 538
530 for (i = 0; i < arysize(line->cl_Dow); ++i) { 539 for (i = 0; i < arysize(line->cl_Dow); ++i) {
531 if (line->cl_Dow[i] == 0) { 540 if (line->cl_Dow[i] == 0) {
532 weekUsed = 1; 541 weekUsed = 1;
533 break; 542 break;
543 }
534 } 544 }
535 } 545 for (i = 0; i < arysize(line->cl_Days); ++i) {
536 for (i = 0; i < arysize(line->cl_Days); ++i) { 546 if (line->cl_Days[i] == 0) {
537 if (line->cl_Days[i] == 0) { 547 daysUsed = 1;
538 daysUsed = 1; 548 break;
539 break; 549 }
550 }
551 if (weekUsed && !daysUsed) {
552 memset(line->cl_Days, 0, sizeof(line->cl_Days));
553 }
554 if (daysUsed && !weekUsed) {
555 memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
540 } 556 }
541 }
542 if (weekUsed && !daysUsed) {
543 memset(line->cl_Days, 0, sizeof(line->cl_Days));
544 }
545 if (daysUsed && !weekUsed) {
546 memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
547 }
548} 557}
549 558
550 559
551 560
552static void 561static void SynchronizeFile(const char *fileName)
553SynchronizeFile(const char *fileName)
554{ 562{
555 int maxEntries = MAXLINES; 563 int maxEntries = MAXLINES;
556 int maxLines; 564 int maxLines;
557 char buf[1024]; 565 char buf[1024];
558
559 if (strcmp(fileName, "root") == 0)
560 maxEntries = 65535;
561 maxLines = maxEntries * 10;
562 566
563 if (fileName) { 567 if (strcmp(fileName, "root") == 0) {
564 FILE *fi; 568 maxEntries = 65535;
565 569 }
566 DeleteFile(fileName); 570 maxLines = maxEntries * 10;
567
568 if ((fi = fopen(fileName, "r")) != NULL) {
569 struct stat sbuf;
570 571
571 if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) { 572 if (fileName) {
572 CronFile *file = calloc(1, sizeof(CronFile)); 573 FILE *fi;
573 CronLine **pline;
574 574
575 file->cf_User = strdup(fileName); 575 DeleteFile(fileName);
576 pline = &file->cf_LineBase;
577 576
578 while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) { 577 fi = fopen(fileName, "r");
579 CronLine line; 578 if (fi != NULL) {
580 char *ptr; 579 struct stat sbuf;
581 580
582 if (buf[0]) 581 if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) {
583 buf[strlen(buf)-1] = 0; 582 CronFile *file = calloc(1, sizeof(CronFile));
583 CronLine **pline;
584 584
585 if (buf[0] == 0 || buf[0] == '#' || buf[0] == ' ' || buf[0] == '\t') 585 file->cf_User = strdup(fileName);
586 continue; 586 pline = &file->cf_LineBase;
587 587
588 if (--maxEntries == 0) 588 while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) {
589 break; 589 CronLine line;
590 char *ptr;
590 591
591 memset(&line, 0, sizeof(line)); 592 if (buf[0]) {
593 buf[strlen(buf) - 1] = 0;
594 }
595 if (buf[0] == 0 || buf[0] == '#' || buf[0] == ' ' || buf[0] == '\t') {
596 continue;
597 }
598 if (--maxEntries == 0) {
599 break;
600 }
601 memset(&line, 0, sizeof(line));
592 602
593#ifdef FEATURE_DEBUG_OPT 603#ifdef FEATURE_DEBUG_OPT
594 if (DebugOpt) 604 if (DebugOpt) {
595 crondlog("\111User %s Entry %s\n", fileName, buf); 605 crondlog("\111User %s Entry %s\n", fileName, buf);
606 }
596#endif 607#endif
597 608
598 /* 609 /* parse date ranges */
599 * parse date ranges 610 ptr = ParseField(file->cf_User, line.cl_Mins, 60, 0, NULL, buf);
600 */ 611 ptr = ParseField(file->cf_User, line.cl_Hrs, 24, 0, NULL, ptr);
612 ptr = ParseField(file->cf_User, line.cl_Days, 32, 0, NULL, ptr);
613 ptr = ParseField(file->cf_User, line.cl_Mons, 12, -1, MonAry, ptr);
614 ptr = ParseField(file->cf_User, line.cl_Dow, 7, 0, DowAry, ptr);
601 615
602 ptr = ParseField(file->cf_User, line.cl_Mins, 60, 0, NULL, buf); 616 /* check failure */
603 ptr = ParseField(file->cf_User, line.cl_Hrs, 24, 0, NULL, ptr); 617 if (ptr == NULL) {
604 ptr = ParseField(file->cf_User, line.cl_Days, 32, 0, NULL, ptr); 618 continue;
605 ptr = ParseField(file->cf_User, line.cl_Mons, 12, -1, MonAry, ptr); 619 }
606 ptr = ParseField(file->cf_User, line.cl_Dow, 7, 0, DowAry, ptr);
607 620
608 /* 621 /*
609 * check failure 622 * fix days and dow - if one is not * and the other
610 */ 623 * is *, the other is set to 0, and vise-versa
624 */
611 625
612 if (ptr == NULL) 626 FixDayDow(&line);
613 continue;
614
615 /*
616 * fix days and dow - if one is not * and the other
617 * is *, the other is set to 0, and vise-versa
618 */
619
620 FixDayDow(&line);
621
622 *pline = calloc(1, sizeof(CronLine));
623 **pline = line;
624 627
625 /* 628 *pline = calloc(1, sizeof(CronLine));
626 * copy command 629 **pline = line;
627 */
628 630
629 (*pline)->cl_Shell = strdup(ptr); 631 /* copy command */
632 (*pline)->cl_Shell = strdup(ptr);
630 633
631#ifdef FEATURE_DEBUG_OPT 634#ifdef FEATURE_DEBUG_OPT
632 if (DebugOpt) { 635 if (DebugOpt) {
633 crondlog("\111 Command %s\n", ptr); 636 crondlog("\111 Command %s\n", ptr);
634 } 637 }
635#endif 638#endif
636 639
637 pline = &((*pline)->cl_Next); 640 pline = &((*pline)->cl_Next);
638 } 641 }
639 *pline = NULL; 642 *pline = NULL;
640 643
641 file->cf_Next = FileBase; 644 file->cf_Next = FileBase;
642 FileBase = file; 645 FileBase = file;
643 646
644 if (maxLines == 0 || maxEntries == 0) 647 if (maxLines == 0 || maxEntries == 0) {
645 crondlog("\111Maximum number of lines reached for user %s\n", fileName); 648 crondlog("\111Maximum number of lines reached for user %s\n", fileName);
646 } 649 }
647 fclose(fi); 650 }
651 fclose(fi);
652 }
648 } 653 }
649 }
650} 654}
651 655
652static void 656static void CheckUpdates(void)
653CheckUpdates(void)
654{ 657{
655 FILE *fi; 658 FILE *fi;
656 char buf[256]; 659 char buf[256];
657 660
658 if ((fi = fopen(CRONUPDATE, "r")) != NULL) { 661 fi = fopen(CRONUPDATE, "r");
659 remove(CRONUPDATE); 662 if (fi != NULL) {
660 while (fgets(buf, sizeof(buf), fi) != NULL) { 663 remove(CRONUPDATE);
661 SynchronizeFile(strtok(buf, " \t\r\n")); 664 while (fgets(buf, sizeof(buf), fi) != NULL) {
665 SynchronizeFile(strtok(buf, " \t\r\n"));
666 }
667 fclose(fi);
662 } 668 }
663 fclose(fi);
664 }
665} 669}
666 670
667static void 671static void SynchronizeDir(void)
668SynchronizeDir(void)
669{ 672{
670 /* 673 /* Attempt to delete the database. */
671 * Attempt to delete the database.
672 */
673 674
674 for (;;) { 675 for (;;) {
675 CronFile *file; 676 CronFile *file;
676 677
677 for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next) 678 for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next);
678 ; 679 if (file == NULL) {
679 if (file == NULL) 680 break;
680 break; 681 }
681 DeleteFile(file->cf_User); 682 DeleteFile(file->cf_User);
682 } 683 }
683 684
684 /* 685 /*
685 * Remove cron update file 686 * Remove cron update file
686 * 687 *
687 * Re-chdir, in case directory was renamed & deleted, or otherwise 688 * Re-chdir, in case directory was renamed & deleted, or otherwise
688 * screwed up. 689 * screwed up.
689 * 690 *
690 * scan directory and add associated users 691 * scan directory and add associated users
691 */ 692 */
692 693
693 remove(CRONUPDATE); 694 remove(CRONUPDATE);
694 if (chdir(CDir) < 0) { 695 if (chdir(CDir) < 0) {
695 crondlog("\311unable to find %s\n", CDir); 696 crondlog("\311unable to find %s\n", CDir);
696 } 697 }
697 { 698 {
698 DIR *dir; 699 DIR *dir = opendir(".");
699 struct dirent *den; 700 struct dirent *den;
700 701
701 if ((dir = opendir("."))) { 702 if (dir) {
702 while ((den = readdir(dir))) { 703 while ((den = readdir(dir))) {
703 if (strchr(den->d_name, '.') != NULL) 704 if (strchr(den->d_name, '.') != NULL) {
704 continue; 705 continue;
705 if (getpwnam(den->d_name)) 706 }
706 SynchronizeFile(den->d_name); 707 if (getpwnam(den->d_name)) {
707 else 708 SynchronizeFile(den->d_name);
708 crondlog("\007ignoring %s\n", den->d_name); 709 } else {
709 } 710 crondlog("\007ignoring %s\n", den->d_name);
710 closedir(dir); 711 }
711 } else { 712 }
712 crondlog("\311Unable to open current dir!\n"); 713 closedir(dir);
714 } else {
715 crondlog("\311Unable to open current dir!\n");
716 }
713 } 717 }
714 }
715} 718}
716 719
717 720
@@ -722,41 +725,40 @@ SynchronizeDir(void)
722 * completely delete a database due to running processes. 725 * completely delete a database due to running processes.
723 */ 726 */
724 727
725static void 728static void DeleteFile(const char *userName)
726DeleteFile(const char *userName)
727{ 729{
728 CronFile **pfile = &FileBase; 730 CronFile **pfile = &FileBase;
729 CronFile *file; 731 CronFile *file;
730
731 while ((file = *pfile) != NULL) {
732 if (strcmp(userName, file->cf_User) == 0) {
733 CronLine **pline = &file->cf_LineBase;
734 CronLine *line;
735
736 file->cf_Running = 0;
737 file->cf_Deleted = 1;
738 732
739 while ((line = *pline) != NULL) { 733 while ((file = *pfile) != NULL) {
740 if (line->cl_Pid > 0) { 734 if (strcmp(userName, file->cf_User) == 0) {
741 file->cf_Running = 1; 735 CronLine **pline = &file->cf_LineBase;
742 pline = &line->cl_Next; 736 CronLine *line;
737
738 file->cf_Running = 0;
739 file->cf_Deleted = 1;
740
741 while ((line = *pline) != NULL) {
742 if (line->cl_Pid > 0) {
743 file->cf_Running = 1;
744 pline = &line->cl_Next;
745 } else {
746 *pline = line->cl_Next;
747 free(line->cl_Shell);
748 free(line);
749 }
750 }
751 if (file->cf_Running == 0) {
752 *pfile = file->cf_Next;
753 free(file->cf_User);
754 free(file);
755 } else {
756 pfile = &file->cf_Next;
757 }
743 } else { 758 } else {
744 *pline = line->cl_Next; 759 pfile = &file->cf_Next;
745 free(line->cl_Shell);
746 free(line);
747 } 760 }
748 }
749 if (file->cf_Running == 0) {
750 *pfile = file->cf_Next;
751 free(file->cf_User);
752 free(file);
753 } else {
754 pfile = &file->cf_Next;
755 }
756 } else {
757 pfile = &file->cf_Next;
758 } 761 }
759 }
760} 762}
761 763
762/* 764/*
@@ -767,89 +769,82 @@ DeleteFile(const char *userName)
767 * hour (60 scans). 769 * hour (60 scans).
768 */ 770 */
769 771
770static int 772static int TestJobs(time_t t1, time_t t2)
771TestJobs(time_t t1, time_t t2)
772{ 773{
773 short nJobs = 0; 774 short nJobs = 0;
774 time_t t; 775 time_t t;
775 776
776 /* 777 /* Find jobs > t1 and <= t2 */
777 * Find jobs > t1 and <= t2
778 */
779 778
780 for (t = t1 - t1 % 60; t <= t2; t += 60) { 779 for (t = t1 - t1 % 60; t <= t2; t += 60) {
781 if (t > t1) { 780 if (t > t1) {
782 struct tm *tp = localtime(&t); 781 struct tm *tp = localtime(&t);
783 CronFile *file; 782 CronFile *file;
784 CronLine *line; 783 CronLine *line;
785 784
786 for (file = FileBase; file; file = file->cf_Next) { 785 for (file = FileBase; file; file = file->cf_Next) {
787#ifdef FEATURE_DEBUG_OPT 786#ifdef FEATURE_DEBUG_OPT
788 if (DebugOpt) 787 if (DebugOpt)
789 crondlog("\005FILE %s:\n", file->cf_User); 788 crondlog("\005FILE %s:\n", file->cf_User);
790#endif 789#endif
791 if (file->cf_Deleted) 790 if (file->cf_Deleted)
792 continue; 791 continue;
793 for (line = file->cf_LineBase; line; line = line->cl_Next) { 792 for (line = file->cf_LineBase; line; line = line->cl_Next) {
794#ifdef FEATURE_DEBUG_OPT 793#ifdef FEATURE_DEBUG_OPT
795 if (DebugOpt) 794 if (DebugOpt)
796 crondlog("\005 LINE %s\n", line->cl_Shell); 795 crondlog("\005 LINE %s\n", line->cl_Shell);
797#endif 796#endif
798 if (line->cl_Mins[tp->tm_min] && 797 if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour] &&
799 line->cl_Hrs[tp->tm_hour] && 798 (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday])
800 (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday]) && 799 && line->cl_Mons[tp->tm_mon]) {
801 line->cl_Mons[tp->tm_mon]
802 ) {
803#ifdef FEATURE_DEBUG_OPT 800#ifdef FEATURE_DEBUG_OPT
804 if (DebugOpt) 801 if (DebugOpt) {
805 crondlog("\005 JobToDo: %d %s\n", line->cl_Pid, line->cl_Shell); 802 crondlog("\005 JobToDo: %d %s\n",
803 line->cl_Pid, line->cl_Shell);
804 }
806#endif 805#endif
807 if (line->cl_Pid > 0) { 806 if (line->cl_Pid > 0) {
808 crondlog("\010 process already running: %s %s\n", 807 crondlog("\010 process already running: %s %s\n",
809 file->cf_User, 808 file->cf_User, line->cl_Shell);
810 line->cl_Shell 809 } else if (line->cl_Pid == 0) {
811 ); 810 line->cl_Pid = -1;
812 } else if (line->cl_Pid == 0) { 811 file->cf_Ready = 1;
813 line->cl_Pid = -1; 812 ++nJobs;
814 file->cf_Ready = 1; 813 }
815 ++nJobs; 814 }
815 }
816 } 816 }
817 }
818 } 817 }
819 }
820 } 818 }
821 } 819 return (nJobs);
822 return(nJobs);
823} 820}
824 821
825static void 822static void RunJobs(void)
826RunJobs(void)
827{ 823{
828 CronFile *file; 824 CronFile *file;
829 CronLine *line; 825 CronLine *line;
830 826
831 for (file = FileBase; file; file = file->cf_Next) { 827 for (file = FileBase; file; file = file->cf_Next) {
832 if (file->cf_Ready) { 828 if (file->cf_Ready) {
833 file->cf_Ready = 0; 829 file->cf_Ready = 0;
834 830
835 for (line = file->cf_LineBase; line; line = line->cl_Next) { 831 for (line = file->cf_LineBase; line; line = line->cl_Next) {
836 if (line->cl_Pid < 0) { 832 if (line->cl_Pid < 0) {
837 833
838 RunJob(file->cf_User, line); 834 RunJob(file->cf_User, line);
839 835
840 crondlog("\010USER %s pid %3d cmd %s\n", 836 crondlog("\010USER %s pid %3d cmd %s\n",
841 file->cf_User, 837 file->cf_User, line->cl_Pid, line->cl_Shell);
842 line->cl_Pid, 838 if (line->cl_Pid < 0) {
843 line->cl_Shell 839 file->cf_Ready = 1;
844 ); 840 }
845 if (line->cl_Pid < 0) 841 else if (line->cl_Pid > 0) {
846 file->cf_Ready = 1; 842 file->cf_Running = 1;
847 else if (line->cl_Pid > 0) 843 }
848 file->cf_Running = 1; 844 }
845 }
849 } 846 }
850 }
851 } 847 }
852 }
853} 848}
854 849
855/* 850/*
@@ -859,231 +854,202 @@ RunJobs(void)
859 * all done. 854 * all done.
860 */ 855 */
861 856
862static int 857static int CheckJobs(void)
863CheckJobs(void)
864{ 858{
865 CronFile *file; 859 CronFile *file;
866 CronLine *line; 860 CronLine *line;
867 int nStillRunning = 0; 861 int nStillRunning = 0;
868 862
869 for (file = FileBase; file; file = file->cf_Next) { 863 for (file = FileBase; file; file = file->cf_Next) {
870 if (file->cf_Running) { 864 if (file->cf_Running) {
871 file->cf_Running = 0; 865 file->cf_Running = 0;
872 866
873 for (line = file->cf_LineBase; line; line = line->cl_Next) { 867 for (line = file->cf_LineBase; line; line = line->cl_Next) {
874 if (line->cl_Pid > 0) { 868 if (line->cl_Pid > 0) {
875 int status; 869 int status;
876 int r = wait4(line->cl_Pid, &status, WNOHANG, NULL); 870 int r = wait4(line->cl_Pid, &status, WNOHANG, NULL);
877 871
878 if (r < 0 || r == line->cl_Pid) { 872 if (r < 0 || r == line->cl_Pid) {
879 EndJob(file->cf_User, line); 873 EndJob(file->cf_User, line);
880 if (line->cl_Pid) 874 if (line->cl_Pid) {
881 file->cf_Running = 1; 875 file->cf_Running = 1;
882 } else if (r == 0) { 876 }
883 file->cf_Running = 1; 877 } else if (r == 0) {
884 } 878 file->cf_Running = 1;
879 }
880 }
881 }
885 } 882 }
886 } 883 nStillRunning += file->cf_Running;
887 } 884 }
888 nStillRunning += file->cf_Running; 885 return (nStillRunning);
889 }
890 return(nStillRunning);
891} 886}
892 887
893 888
894#ifdef CONFIG_FEATURE_CROND_CALL_SENDMAIL 889#ifdef CONFIG_FEATURE_CROND_CALL_SENDMAIL
895static void 890static void
896ForkJob(const char *user, CronLine *line, int mailFd, 891ForkJob(const char *user, CronLine * line, int mailFd,
897 const char *prog, const char *cmd, const char *arg, const char *mailf) 892 const char *prog, const char *cmd, const char *arg, const char *mailf)
898{ 893{
899 /* 894 /* Fork as the user in question and run program */
900 * Fork as the user in question and run program 895 pid_t pid = fork();
901 */
902 pid_t pid = fork();
903
904 line->cl_Pid = pid;
905 if (pid == 0) {
906 /*
907 * CHILD
908 */
909 896
910 /* 897 line->cl_Pid = pid;
911 * Change running state to the user in question 898 if (pid == 0) {
912 */ 899 /* CHILD */
913 900
914 if (ChangeUser(user) < 0) 901 /* Change running state to the user in question */
915 exit(0);
916 902
903 if (ChangeUser(user) < 0) {
904 exit(0);
905 }
917#ifdef FEATURE_DEBUG_OPT 906#ifdef FEATURE_DEBUG_OPT
918 if (DebugOpt) 907 if (DebugOpt) {
919 crondlog("\005Child Running %s\n", prog); 908 crondlog("\005Child Running %s\n", prog);
909 }
920#endif 910#endif
921 911
922 if (mailFd >= 0) { 912 if (mailFd >= 0) {
923 dup2(mailFd, mailf != NULL); 913 dup2(mailFd, mailf != NULL);
924 dup2((mailf ? mailFd : 1), 2); 914 dup2((mailf ? mailFd : 1), 2);
925 close(mailFd); 915 close(mailFd);
916 }
917 execl(prog, prog, cmd, arg, NULL);
918 crondlog("\024unable to exec, user %s cmd %s %s %s\n", user, prog, cmd, arg);
919 if (mailf) {
920 fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
921 }
922 exit(0);
923 } else if (pid < 0) {
924 /* FORK FAILED */
925 crondlog("\024couldn't fork, user %s\n", user);
926 line->cl_Pid = 0;
927 if (mailf) {
928 remove(mailf);
929 }
930 } else if (mailf) {
931 /* PARENT, FORK SUCCESS
932 * rename mail-file based on pid of process
933 */
934 char mailFile2[128];
935
936 snprintf(mailFile2, sizeof(mailFile2), TMPDIR "/cron.%s.%d", user, pid);
937 rename(mailf, mailFile2);
926 } 938 }
927 execl(prog, prog, cmd, arg, NULL);
928 crondlog("\024unable to exec, user %s cmd %s %s %s\n", user,
929 prog, cmd, arg);
930 if(mailf)
931 fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
932 exit(0);
933 } else if (pid < 0) {
934 /* 939 /*
935 * FORK FAILED 940 * Close the mail file descriptor.. we can't just leave it open in
941 * a structure, closing it later, because we might run out of descriptors
936 */ 942 */
937 crondlog("\024couldn't fork, user %s\n", user); 943
938 line->cl_Pid = 0; 944 if (mailFd >= 0) {
939 if(mailf) 945 close(mailFd);
940 remove(mailf); 946 }
941 } else if(mailf) {
942 /*
943 * PARENT, FORK SUCCESS
944 *
945 * rename mail-file based on pid of process
946 */
947 char mailFile2[128];
948
949 snprintf(mailFile2, sizeof(mailFile2), TMPDIR "/cron.%s.%d",
950 user, pid);
951 rename(mailf, mailFile2);
952 }
953 /*
954 * Close the mail file descriptor.. we can't just leave it open in
955 * a structure, closing it later, because we might run out of descriptors
956 */
957
958 if (mailFd >= 0)
959 close(mailFd);
960} 947}
961 948
962static void 949static void RunJob(const char *user, CronLine * line)
963RunJob(const char *user, CronLine *line)
964{ 950{
965 char mailFile[128]; 951 char mailFile[128];
966 int mailFd; 952 int mailFd;
967 953
968 line->cl_Pid = 0; 954 line->cl_Pid = 0;
969 line->cl_MailFlag = 0; 955 line->cl_MailFlag = 0;
970 956
971 /* 957 /* open mail file - owner root so nobody can screw with it. */
972 * open mail file - owner root so nobody can screw with it. 958
973 */ 959 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, getpid());
974 960 mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600);
975 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", 961
976 user, getpid()); 962 if (mailFd >= 0) {
977 mailFd = open(mailFile, O_CREAT|O_TRUNC|O_WRONLY|O_EXCL|O_APPEND, 0600); 963 line->cl_MailFlag = 1;
978 964 fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user,
979 if (mailFd >= 0) { 965 line->cl_Shell);
980 line->cl_MailFlag = 1; 966 line->cl_MailPos = lseek(mailFd, 0, 1);
981 fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user, 967 } else {
982 line->cl_Shell); 968 crondlog("\024unable to create mail file user %s file %s, output to /dev/null\n", user, mailFile);
983 line->cl_MailPos = lseek(mailFd, 0, 1); 969 }
984 } else { 970
985 crondlog("\024unable to create mail file user %s file %s, output to /dev/null\n", 971 ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile);
986 user, mailFile);
987 }
988
989 ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile);
990} 972}
991 973
992/* 974/*
993 * EndJob - called when job terminates and when mail terminates 975 * EndJob - called when job terminates and when mail terminates
994 */ 976 */
995 977
996static void 978static void EndJob(const char *user, CronLine * line)
997EndJob(const char *user, CronLine *line)
998{ 979{
999 int mailFd; 980 int mailFd;
1000 char mailFile[128]; 981 char mailFile[128];
1001 struct stat sbuf; 982 struct stat sbuf;
1002 983
1003 /* 984 /* No job */
1004 * No job
1005 */
1006 985
1007 if (line->cl_Pid <= 0) { 986 if (line->cl_Pid <= 0) {
1008 line->cl_Pid = 0; 987 line->cl_Pid = 0;
1009 return; 988 return;
1010 } 989 }
1011
1012 /*
1013 * End of job and no mail file
1014 * End of sendmail job
1015 */
1016
1017 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d",
1018 user, line->cl_Pid);
1019 line->cl_Pid = 0;
1020
1021 if (line->cl_MailFlag != 1)
1022 return;
1023
1024 line->cl_MailFlag = 0;
1025
1026 /*
1027 * End of primary job - check for mail file. If size has increased and
1028 * the file is still valid, we sendmail it.
1029 */
1030
1031 mailFd = open(mailFile, O_RDONLY);
1032 remove(mailFile);
1033 if (mailFd < 0) {
1034 return;
1035 }
1036
1037 if (fstat(mailFd, &sbuf) < 0 ||
1038 sbuf.st_uid != DaemonUid ||
1039 sbuf.st_nlink != 0 ||
1040 sbuf.st_size == line->cl_MailPos ||
1041 !S_ISREG(sbuf.st_mode)
1042 ) {
1043 close(mailFd);
1044 return;
1045 }
1046 ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL);
1047}
1048#else
1049/* crond whithout sendmail */
1050 990
1051static void
1052RunJob(const char *user, CronLine *line)
1053{
1054 /* 991 /*
1055 * Fork as the user in question and run program 992 * End of job and no mail file
993 * End of sendmail job
1056 */ 994 */
1057 pid_t pid = fork();
1058 995
1059 if (pid == 0) { 996 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, line->cl_Pid);
1060 /* 997 line->cl_Pid = 0;
1061 * CHILD 998
1062 */ 999 if (line->cl_MailFlag != 1) {
1000 return;
1001 }
1002 line->cl_MailFlag = 0;
1063 1003
1064 /* 1004 /*
1065 * Change running state to the user in question 1005 * End of primary job - check for mail file. If size has increased and
1006 * the file is still valid, we sendmail it.
1066 */ 1007 */
1067 1008
1068 if (ChangeUser(user) < 0) 1009 mailFd = open(mailFile, O_RDONLY);
1069 exit(0); 1010 remove(mailFile);
1011 if (mailFd < 0) {
1012 return;
1013 }
1070 1014
1015 if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid || sbuf.st_nlink != 0 ||
1016 sbuf.st_size == line->cl_MailPos || !S_ISREG(sbuf.st_mode)) {
1017 close(mailFd);
1018 return;
1019 }
1020 ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL);
1021}
1022#else
1023/* crond whithout sendmail */
1024
1025static void RunJob(const char *user, CronLine * line)
1026{
1027 /* Fork as the user in question and run program */
1028 pid_t pid = fork();
1029
1030 if (pid == 0) {
1031 /* CHILD */
1032
1033 /* Change running state to the user in question */
1034
1035 if (ChangeUser(user) < 0) {
1036 exit(0);
1037 }
1071#ifdef FEATURE_DEBUG_OPT 1038#ifdef FEATURE_DEBUG_OPT
1072 if (DebugOpt) 1039 if (DebugOpt) {
1073 crondlog("\005Child Running %s\n", DEFAULT_SHELL); 1040 crondlog("\005Child Running %s\n", DEFAULT_SHELL);
1041 }
1074#endif 1042#endif
1075 1043
1076 execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL); 1044 execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL);
1077 crondlog("\024unable to exec, user %s cmd %s -c %s\n", user, 1045 crondlog("\024unable to exec, user %s cmd %s -c %s\n", user,
1078 DEFAULT_SHELL, line->cl_Shell); 1046 DEFAULT_SHELL, line->cl_Shell);
1079 exit(0); 1047 exit(0);
1080 } else if (pid < 0) { 1048 } else if (pid < 0) {
1081 /* 1049 /* FORK FAILED */
1082 * FORK FAILED 1050 crondlog("\024couldn't fork, user %s\n", user);
1083 */ 1051 pid = 0;
1084 crondlog("\024couldn't fork, user %s\n", user); 1052 }
1085 pid = 0; 1053 line->cl_Pid = pid;
1086 }
1087 line->cl_Pid = pid;
1088} 1054}
1089#endif /* CONFIG_FEATURE_CROND_CALL_SENDMAIL */ 1055#endif /* CONFIG_FEATURE_CROND_CALL_SENDMAIL */