static int ChangeUser(const char *user) { struct passwd *pas; const char *err_msg; /* * Obtain password entry and change privileges */ pas = getpwnam(user); if (pas == 0) { crondlog("\011failed to get uid for %s", user); return (-1); } setenv("USER", pas->pw_name, 1); setenv("HOME", pas->pw_dir, 1); setenv("SHELL", DEFAULT_SHELL, 1); /* * Change running state to the user in question */ err_msg = change_identity_e2str(pas); if (err_msg) { crondlog("\011%s for user %s", err_msg, user); return (-1); } if (chdir(pas->pw_dir) < 0) { crondlog("\011chdir failed: %s: %m", pas->pw_dir); if (chdir(TMPDIR) < 0) { crondlog("\011chdir failed: %s: %m", TMPDIR); return (-1); } } return (pas->pw_uid); }
static void RunJob(const char *user, CronLine *line) { struct passwd *pas; pid_t pid; /* prepare things before vfork */ pas = getpwnam(user); if (!pas) { crondlog(LVL9 "can't get uid for %s", user); goto err; } SetEnv(pas); /* fork as the user in question and run program */ pid = vfork(); if (pid == 0) { /* CHILD */ /* change running state to the user in question */ ChangeUser(pas); if (DebugOpt) { crondlog(LVL5 "child running %s", DEFAULT_SHELL); } execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL); crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, DEFAULT_SHELL, "-c", line->cl_Shell); _exit(EXIT_SUCCESS); } if (pid < 0) { /* FORK FAILED */ crondlog(ERR20 "can't vfork"); err: pid = 0; } line->cl_Pid = pid; }
static void RunJob(const char *user, CronLine * line) { /* Fork as the user in question and run program */ pid_t pid = fork(); if (pid == 0) { /* CHILD */ /* Change running state to the user in question */ if (ChangeUser(user) < 0) { exit(0); } #ifdef FEATURE_DEBUG_OPT if (DebugOpt) { crondlog("\005Child Running %s\n", DEFAULT_SHELL); } #endif execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL); crondlog("\024unable to exec, user %s cmd %s -c %s\n", user, DEFAULT_SHELL, line->cl_Shell); exit(0); } else if (pid < 0) { /* FORK FAILED */ crondlog("\024couldn't fork, user %s\n", user); pid = 0; } line->cl_Pid = pid; }
static void ForkJob(const char *user, CronLine * line, int mailFd, const char *prog, const char *cmd, const char *arg, const char *mailf) { /* Fork as the user in question and run program */ pid_t pid = fork(); line->cl_Pid = pid; if (pid == 0) { /* CHILD */ /* Change running state to the user in question */ if (ChangeUser(user) < 0) { exit(0); } #ifdef FEATURE_DEBUG_OPT if (DebugOpt) { crondlog("\005Child Running %s\n", prog); } #endif if (mailFd >= 0) { dup2(mailFd, mailf != NULL); dup2((mailf ? mailFd : 1), 2); close(mailFd); } execl(prog, prog, cmd, arg, NULL); crondlog("\024unable to exec, user %s cmd %s %s %s\n", user, prog, cmd, arg); if (mailf) { fdprintf(1, "Exec failed: %s -c %s\n", prog, arg); } exit(0); } else if (pid < 0) { /* FORK FAILED */ crondlog("\024couldn't fork, user %s\n", user); line->cl_Pid = 0; if (mailf) { remove(mailf); } } else if (mailf) { /* PARENT, FORK SUCCESS * rename mail-file based on pid of process */ char mailFile2[128]; snprintf(mailFile2, sizeof(mailFile2), TMPDIR "/cron.%s.%d", user, pid); rename(mailf, mailFile2); } /* * Close the mail file descriptor.. we can't just leave it open in * a structure, closing it later, because we might run out of descriptors */ if (mailFd >= 0) { close(mailFd); } }
static void ChangeUser(struct passwd *pas) { /* careful: we're after vfork! */ change_identity(pas); /* - initgroups, setgid, setuid */ if (chdir(pas->pw_dir) < 0) { crondlog(LVL9 "can't chdir(%s)", pas->pw_dir); if (chdir(TMPDIR) < 0) { crondlog(DIE9 "can't chdir(%s)", TMPDIR); /* exits */ } } }
static int TestJobs(time_t t1, time_t t2) { short nJobs = 0; time_t t; /* Find jobs > t1 and <= t2 */ for (t = t1 - t1 % 60; t <= t2; t += 60) { if (t > t1) { struct tm *tp = localtime(&t); CronFile *file; CronLine *line; for (file = FileBase; file; file = file->cf_Next) { #ifdef FEATURE_DEBUG_OPT if (DebugOpt) crondlog("\005FILE %s:\n", file->cf_User); #endif if (file->cf_Deleted) continue; for (line = file->cf_LineBase; line; line = line->cl_Next) { #ifdef FEATURE_DEBUG_OPT if (DebugOpt) crondlog("\005 LINE %s\n", line->cl_Shell); #endif if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour] && (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday]) && line->cl_Mons[tp->tm_mon]) { #ifdef FEATURE_DEBUG_OPT if (DebugOpt) { crondlog("\005 JobToDo: %d %s\n", line->cl_Pid, line->cl_Shell); } #endif if (line->cl_Pid > 0) { crondlog("\010 process already running: %s %s\n", file->cf_User, line->cl_Shell); } else if (line->cl_Pid == 0) { line->cl_Pid = -1; file->cf_Ready = 1; ++nJobs; } } } } } } return (nJobs); }
static void SynchronizeDir(void) { /* Attempt to delete the database. */ for (;;) { CronFile *file; for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next); if (file == NULL) { break; } DeleteFile(file->cf_User); } /* * Remove cron update file * * Re-chdir, in case directory was renamed & deleted, or otherwise * screwed up. * * scan directory and add associated users */ remove(CRONUPDATE); if (chdir(CDir) < 0) { crondlog("\311unable to find %s\n", CDir); } { DIR *dir = opendir("."); struct dirent *den; if (dir) { while ((den = readdir(dir))) { if (strchr(den->d_name, '.') != NULL) { continue; } if (getpwnam(den->d_name)) { SynchronizeFile(den->d_name); } else { crondlog("\007ignoring %s\n", den->d_name); } } closedir(dir); } else { crondlog("\311Unable to open current dir!\n"); } } }
static void RunJob(const char *user, CronLine *line) { char mailFile[128]; int mailFd = -1; line->cl_Pid = 0; line->cl_MailFlag = 0; if (line->cl_MailTo) { /* open mail file - owner root so nobody can screw with it. */ snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, getpid()); mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); if (mailFd >= 0) { line->cl_MailFlag = 1; fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user, line->cl_Shell); line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR); } else { crondlog(ERR20 "cannot create mail file %s for user %s, " "discarding output", mailFile, user); } } ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile); }
static void RunJobs(void) { CronFile *file; CronLine *line; for (file = FileBase; file; file = file->cf_Next) { if (!file->cf_Ready) continue; file->cf_Ready = 0; for (line = file->cf_LineBase; line; line = line->cl_Next) { if (line->cl_Pid >= 0) continue; RunJob(file->cf_User, line); crondlog(LVL8 "USER %s pid %3d cmd %s", file->cf_User, (int)line->cl_Pid, line->cl_Shell); if (line->cl_Pid < 0) { file->cf_Ready = 1; } else if (line->cl_Pid > 0) { file->cf_Running = 1; } } } }
static void log8(const char *msg, ...) { va_list va; va_start(va, msg); crondlog(8, msg, va); va_end(va); }
static void RunJobs(void) { CronFile *file; CronLine *line; for (file = FileBase; file; file = file->cf_Next) { if (file->cf_Ready) { file->cf_Ready = 0; for (line = file->cf_LineBase; line; line = line->cl_Next) { if (line->cl_Pid < 0) { RunJob(file->cf_User, line); crondlog("\010USER %s pid %3d cmd %s\n", file->cf_User, line->cl_Pid, line->cl_Shell); if (line->cl_Pid < 0) { file->cf_Ready = 1; } else if (line->cl_Pid > 0) { file->cf_Running = 1; } } } } } }
/* * TestJobs() * * determine which jobs need to be run. Under normal conditions, the * period is about a minute (one scan). Worst case it will be one * hour (60 scans). */ static int TestJobs(time_t t1, time_t t2) { int nJobs = 0; time_t t; /* Find jobs > t1 and <= t2 */ for (t = t1 - t1 % 60; t <= t2; t += 60) { struct tm *tp; CronFile *file; CronLine *line; if (t <= t1) continue; tp = localtime(&t); for (file = FileBase; file; file = file->cf_Next) { if (DebugOpt) crondlog(LVL5 "file %s:", file->cf_User); if (file->cf_Deleted) continue; for (line = file->cf_LineBase; line; line = line->cl_Next) { if (DebugOpt) crondlog(LVL5 " line %s", line->cl_Shell); if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour] && (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday]) && line->cl_Mons[tp->tm_mon] ) { if (DebugOpt) { crondlog(LVL5 " job: %d %s", (int)line->cl_Pid, line->cl_Shell); } if (line->cl_Pid > 0) { crondlog(LVL8 "user %s: process already running: %s", file->cf_User, line->cl_Shell); } else if (line->cl_Pid == 0) { line->cl_Pid = -1; file->cf_Ready = 1; ++nJobs; } } } } } return nJobs; }
static void SynchronizeDir(void) { CronFile *file; /* Attempt to delete the database. */ again: for (file = FileBase; file; file = file->cf_Next) { if (!file->cf_Deleted) { DeleteFile(file->cf_User); goto again; } } /* * Remove cron update file * * Re-chdir, in case directory was renamed & deleted, or otherwise * screwed up. * * scan directory and add associated users */ unlink(CRONUPDATE); if (chdir(CDir) < 0) { crondlog(DIE9 "can't chdir(%s)", CDir); } { DIR *dir = opendir("."); struct dirent *den; if (!dir) crondlog(DIE9 "can't chdir(%s)", "."); /* exits */ while ((den = readdir(dir)) != NULL) { if (strchr(den->d_name, '.') != NULL) { continue; } if (getpwnam(den->d_name)) { SynchronizeFile(den->d_name); } else { crondlog(LVL7 "ignoring %s", den->d_name); } } closedir(dir); } }
static void RunJob(const char *user, CronLine * line) { char mailFile[128]; int mailFd; line->cl_Pid = 0; line->cl_MailFlag = 0; /* open mail file - owner root so nobody can screw with it. */ snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, getpid()); mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); if (mailFd >= 0) { line->cl_MailFlag = 1; fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user, line->cl_Shell); line->cl_MailPos = lseek(mailFd, 0, 1); } else { crondlog("\024unable to create mail file user %s file %s, output to /dev/null\n", user, mailFile); } ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile); }
int crond_main(int argc ATTRIBUTE_UNUSED, char **argv) { unsigned opt; INIT_G(); /* "-b after -f is ignored", and so on for every pair a-b */ opt_complementary = "f-b:b-f:S-L:L-S" USE_DEBUG_CROND_OPTION(":d-l") ":l+:d+"; /* -l and -d have numeric param */ opt = getopt32(argv, "l:L:fbSc:" USE_DEBUG_CROND_OPTION("d:"), &LogLevel, &LogFile, &CDir USE_DEBUG_CROND_OPTION(,&LogLevel)); /* both -d N and -l N set the same variable: LogLevel */ if (!(opt & OPT_f)) { /* close stdin, stdout, stderr. * close unused descriptors - don't need them. */ bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); } if (!DebugOpt && LogFile == NULL) { /* logging to syslog */ openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); logmode = LOGMODE_SYSLOG; } xchdir(CDir); //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ setenv("SHELL", DEFAULT_SHELL, 1); /* once, for all future children */ crondlog(LVL9 "crond (busybox "BB_VER") started, log level %d", LogLevel); SynchronizeDir(); /* main loop - synchronize to 1 second after the minute, minimum sleep * of 1 second. */ { time_t t1 = time(NULL); time_t t2; long dt; int rescan = 60; int sleep_time = 60; write_pidfile("/var/run/crond.pid"); for (;;) { sleep((sleep_time + 1) - (time(NULL) % sleep_time)); t2 = time(NULL); dt = (long)t2 - (long)t1; /* * The file 'cron.update' is checked to determine new cron * jobs. The directory is rescanned once an hour to deal * with any screwups. * * check for disparity. Disparities over an hour either way * result in resynchronization. A reverse-indexed disparity * less then an hour causes us to effectively sleep until we * match the original time (i.e. no re-execution of jobs that * have just been run). A forward-indexed disparity less then * an hour causes intermediate jobs to be run, but only once * in the worst case. * * when running jobs, the inequality used is greater but not * equal to t1, and less then or equal to t2. */ if (--rescan == 0) { rescan = 60; SynchronizeDir(); } CheckUpdates(); if (DebugOpt) crondlog(LVL5 "wakeup dt=%ld", dt); if (dt < -60 * 60 || dt > 60 * 60) { crondlog(WARN9 "time disparity of %d minutes detected", dt / 60); } else if (dt > 0) { TestJobs(t1, t2); RunJobs(); sleep(5); if (CheckJobs() > 0) { sleep_time = 10; } else { sleep_time = 60; } } t1 = t2; } } return 0; /* not reached */ }
int eooqd_main(int argc, char *argv[]) { int r; char *pid_file_name, *instance_id_str; char *check; struct event *checkQueueEvent, *rePostEvent; struct timeval tv; struct rlimit limit; atlas_id= NULL; instance_id_str= NULL; pid_file_name= NULL; queue_id= ""; (void)getopt32(argv, "A:i:P:q:", &atlas_id, &instance_id_str, &pid_file_name, &queue_id); if (argc != optind+1) { bb_show_usage(); return 1; } instance_id= 0; if (instance_id_str) { instance_id= strtoul(instance_id_str, &check, 0); if (check[0] != '\0') { report("unable to parse instance id '%s'", instance_id_str); return 1; } } if(pid_file_name) { write_pidfile(pid_file_name); } state = xzalloc(sizeof(*state)); state->atlas_id= atlas_id; state->queue_file= argv[optind]; state->max_busy= 10; state->slots= xzalloc(sizeof(*state->slots) * state->max_busy); if (strlen(state->queue_file) + strlen(SUFFIX) + 1 > sizeof(state->curr_qfile)) { report("filename too long ('%s')", state->queue_file); return 1; } strlcpy(state->curr_qfile, state->queue_file, sizeof(state->curr_qfile)); strlcat(state->curr_qfile, SUFFIX, sizeof(state->curr_qfile)); signal(SIGQUIT, SIG_DFL); limit.rlim_cur= RLIM_INFINITY; limit.rlim_max= RLIM_INFINITY; setrlimit(RLIMIT_CORE, &limit); /* Create libevent event base */ EventBase= event_base_new(); if (!EventBase) { crondlog(DIE9 "event_base_new failed"); /* exits */ } DnsBase= evdns_base_new(EventBase, 1 /*initialize*/); if (!DnsBase) { event_base_free(EventBase); crondlog(DIE9 "evdns_base_new failed"); /* exits */ } checkQueueEvent= event_new(EventBase, -1, EV_TIMEOUT|EV_PERSIST, checkQueue, NULL); if (!checkQueueEvent) crondlog(DIE9 "event_new failed"); /* exits */ tv.tv_sec= 1; tv.tv_usec= 0; event_add(checkQueueEvent, &tv); rePostEvent= event_new(EventBase, -1, EV_TIMEOUT|EV_PERSIST, re_post, NULL); if (!rePostEvent) crondlog(DIE9 "event_new failed"); /* exits */ tv.tv_sec= 60; tv.tv_usec= 0; event_add(rePostEvent, &tv); r= event_base_loop(EventBase, 0); if (r != 0) crondlog(LVL9 "event_base_loop failed"); return 0; }
static char *ParseField(char *user, char *ary, int modvalue, int off, const char *names, char *ptr) /* 'names' is a pointer to a set of 3-char abbreviations */ { char *base = ptr; int n1 = -1; int n2 = -1; if (base == NULL) { return NULL; } while (!isspace(*ptr)) { int skip = 0; /* Handle numeric digit or symbol or '*' */ if (*ptr == '*') { n1 = 0; /* everything will be filled */ n2 = modvalue - 1; skip = 1; ++ptr; } else if (isdigit(*ptr)) { if (n1 < 0) { n1 = strtol(ptr, &ptr, 10) + off; } else { n2 = strtol(ptr, &ptr, 10) + off; } skip = 1; } else if (names) { int i; for (i = 0; names[i]; i += 3) { /* was using strncmp before... */ if (strncasecmp(ptr, &names[i], 3) == 0) { ptr += 3; if (n1 < 0) { n1 = i / 3; } else { n2 = i / 3; } skip = 1; break; } } } /* handle optional range '-' */ if (skip == 0) { crondlog(WARN9 "user %s: parse error at %s", user, base); return NULL; } if (*ptr == '-' && n2 < 0) { ++ptr; continue; } /* * collapse single-value ranges, handle skipmark, and fill * in the character array appropriately. */ if (n2 < 0) { n2 = n1; } if (*ptr == '/') { skip = strtol(ptr + 1, &ptr, 10); } /* * fill array, using a failsafe is the easiest way to prevent * an endless loop */ { int s0 = 1; int failsafe = 1024; --n1; do { n1 = (n1 + 1) % modvalue; if (--s0 == 0) { ary[n1 % modvalue] = 1; s0 = skip; } if (--failsafe == 0) { crondlog(WARN9 "user %s: parse error at %s", user, base); return NULL; } } while (n1 != n2); } if (*ptr != ',') { break; } ++ptr; n1 = -1; n2 = -1; } if (!isspace(*ptr)) { crondlog(WARN9 "user %s: parse error at %s", user, base); return NULL; } if (DebugOpt && (LogLevel <= 5)) { /* like LVL5 */ /* can't use crondlog, it inserts '\n' */ int i; for (i = 0; i < modvalue; ++i) fprintf(stderr, "%d", (unsigned char)ary[i]); fputc('\n', stderr); } return skip_whitespace(ptr); }
static void SynchronizeFile(const char *fileName) { FILE *fi; struct stat sbuf; int maxEntries; int maxLines; char buf[1024]; #if ENABLE_FEATURE_CROND_CALL_SENDMAIL char *mailTo = NULL; #endif if (!fileName) return; DeleteFile(fileName); fi = fopen(fileName, "r"); if (!fi) return; maxEntries = MAXLINES; if (strcmp(fileName, "root") == 0) { maxEntries = 65535; } maxLines = maxEntries * 10; if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) { CronFile *file = xzalloc(sizeof(CronFile)); CronLine **pline; file->cf_User = xstrdup(fileName); pline = &file->cf_LineBase; while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) { CronLine *line; char *ptr; trim(buf); if (buf[0] == '\0' || buf[0] == '#') { continue; } if (--maxEntries == 0) { break; } if (DebugOpt) { crondlog(LVL5 "user:%s entry:%s", fileName, buf); } /* check if line is setting MAILTO= */ if (0 == strncmp("MAILTO=", buf, 7)) { #if ENABLE_FEATURE_CROND_CALL_SENDMAIL free(mailTo); mailTo = (buf[7]) ? xstrdup(buf+7) : NULL; #endif /* otherwise just ignore such lines */ continue; } *pline = line = xzalloc(sizeof(CronLine)); /* parse date ranges */ ptr = ParseField(file->cf_User, line->cl_Mins, 60, 0, NULL, buf); ptr = ParseField(file->cf_User, line->cl_Hrs, 24, 0, NULL, ptr); ptr = ParseField(file->cf_User, line->cl_Days, 32, 0, NULL, ptr); ptr = ParseField(file->cf_User, line->cl_Mons, 12, -1, MonAry, ptr); ptr = ParseField(file->cf_User, line->cl_Dow, 7, 0, DowAry, ptr); /* check failure */ if (ptr == NULL) { free(line); continue; } /* * fix days and dow - if one is not "*" and the other * is "*", the other is set to 0, and vise-versa */ FixDayDow(line); #if ENABLE_FEATURE_CROND_CALL_SENDMAIL /* copy mailto (can be NULL) */ line->cl_MailTo = xstrdup(mailTo); #endif /* copy command */ line->cl_Shell = xstrdup(ptr); if (DebugOpt) { crondlog(LVL5 " command:%s", ptr); } pline = &line->cl_Next; } *pline = NULL; file->cf_Next = FileBase; FileBase = file; if (maxLines == 0 || maxEntries == 0) { crondlog(WARN9 "user %s: too many lines", fileName); } } fclose(fi); }
static void SynchronizeFile(const char *fileName) { int maxEntries = MAXLINES; int maxLines; char buf[1024]; if (strcmp(fileName, "root") == 0) { maxEntries = 65535; } maxLines = maxEntries * 10; if (fileName) { FILE *fi; DeleteFile(fileName); fi = fopen(fileName, "r"); if (fi != NULL) { struct stat sbuf; if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) { CronFile *file = calloc(1, sizeof(CronFile)); CronLine **pline; file->cf_User = strdup(fileName); pline = &file->cf_LineBase; while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) { CronLine line; char *ptr; trim(buf); if (buf[0] == 0 || buf[0] == '#') { continue; } if (--maxEntries == 0) { break; } memset(&line, 0, sizeof(line)); #ifdef FEATURE_DEBUG_OPT if (DebugOpt) { crondlog("\111User %s Entry %s\n", fileName, buf); } #endif /* parse date ranges */ ptr = ParseField(file->cf_User, line.cl_Mins, 60, 0, NULL, buf); ptr = ParseField(file->cf_User, line.cl_Hrs, 24, 0, NULL, ptr); ptr = ParseField(file->cf_User, line.cl_Days, 32, 0, NULL, ptr); ptr = ParseField(file->cf_User, line.cl_Mons, 12, -1, MonAry, ptr); ptr = ParseField(file->cf_User, line.cl_Dow, 7, 0, DowAry, ptr); /* check failure */ if (ptr == NULL) { continue; } /* * fix days and dow - if one is not * and the other * is *, the other is set to 0, and vise-versa */ FixDayDow(&line); *pline = calloc(1, sizeof(CronLine)); **pline = line; /* copy command */ (*pline)->cl_Shell = strdup(ptr); #ifdef FEATURE_DEBUG_OPT if (DebugOpt) { crondlog("\111 Command %s\n", ptr); } #endif pline = &((*pline)->cl_Next); } *pline = NULL; file->cf_Next = FileBase; FileBase = file; if (maxLines == 0 || maxEntries == 0) { crondlog("\111Maximum number of lines reached for user %s\n", fileName); } } fclose(fi); } } }
static char *ParseField(char *user, char *ary, int modvalue, int off, const char *const *names, char *ptr) { char *base = ptr; int n1 = -1; int n2 = -1; if (base == NULL) { return (NULL); } while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') { int skip = 0; /* Handle numeric digit or symbol or '*' */ if (*ptr == '*') { n1 = 0; /* everything will be filled */ n2 = modvalue - 1; skip = 1; ++ptr; } else if (*ptr >= '0' && *ptr <= '9') { if (n1 < 0) { n1 = strtol(ptr, &ptr, 10) + off; } else { n2 = strtol(ptr, &ptr, 10) + off; } skip = 1; } else if (names) { int i; for (i = 0; names[i]; ++i) { if (strncmp(ptr, names[i], strlen(names[i])) == 0) { break; } } if (names[i]) { ptr += strlen(names[i]); if (n1 < 0) { n1 = i; } else { n2 = i; } skip = 1; } } /* handle optional range '-' */ if (skip == 0) { crondlog("\111failed user %s parsing %s\n", user, base); return (NULL); } if (*ptr == '-' && n2 < 0) { ++ptr; continue; } /* * collapse single-value ranges, handle skipmark, and fill * in the character array appropriately. */ if (n2 < 0) { n2 = n1; } if (*ptr == '/') { skip = strtol(ptr + 1, &ptr, 10); } /* * fill array, using a failsafe is the easiest way to prevent * an endless loop */ { int s0 = 1; int failsafe = 1024; --n1; do { n1 = (n1 + 1) % modvalue; if (--s0 == 0) { ary[n1 % modvalue] = 1; s0 = skip; } } while (n1 != n2 && --failsafe); if (failsafe == 0) { crondlog("\111failed user %s parsing %s\n", user, base); return (NULL); } } if (*ptr != ',') { break; } ++ptr; n1 = -1; n2 = -1; } if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') { crondlog("\111failed user %s parsing %s\n", user, base); return (NULL); } while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') { ++ptr; } #ifdef FEATURE_DEBUG_OPT if (DebugOpt) { int i; for (i = 0; i < modvalue; ++i) { crondlog("\005%d", ary[i]); } crondlog("\005\n"); } #endif return (ptr); }
int crond_main(int ac, char **av) { unsigned long opt; char *lopt, *Lopt, *copt; #ifdef FEATURE_DEBUG_OPT char *dopt; bb_opt_complementally = "f-b:b-f:S-L:L-S:d-l"; #else bb_opt_complementally = "f-b:b-f:S-L:L-S"; #endif opterr = 0; /* disable getopt 'errors' message. */ opt = bb_getopt_ulflags(ac, av, "l:L:fbSc:" #ifdef FEATURE_DEBUG_OPT "d:" #endif , &lopt, &Lopt, &copt #ifdef FEATURE_DEBUG_OPT , &dopt #endif ); if (opt & 1) { LogLevel = atoi(lopt); } if (opt & 2) { if (*Lopt != 0) { LogFile = Lopt; } } if (opt & 32) { if (*copt != 0) { CDir = copt; } } #ifdef FEATURE_DEBUG_OPT if (opt & 64) { DebugOpt = atoi(dopt); LogLevel = 0; } #endif /* * change directory */ if (chdir(CDir) != 0) { bb_perror_msg_and_die("%s", CDir); } signal(SIGHUP, SIG_IGN); /* hmm.. but, if kill -HUP original * version - his died. ;( */ /* * close stdin and stdout, stderr. * close unused descriptors - don't need. * optional detach from controlling terminal */ if (!(opt & 4)) { #if defined(__uClinux__) /* reexec for vfork() do continue parent */ vfork_daemon_rexec(1, 0, ac, av, "-f"); #else /* uClinux */ if (daemon(1, 0) < 0) { bb_perror_msg_and_die("daemon"); } #endif /* uClinux */ } (void) startlogger(); /* need if syslog mode selected */ /* * main loop - synchronize to 1 second after the minute, minimum sleep * of 1 second. */ crondlog("\011%s " VERSION " dillon, started, log level %d\n", bb_applet_name, LogLevel); SynchronizeDir(); { time_t t1 = time(NULL); time_t t2; long dt; short rescan = 60; short sleep_time = 60; for (;;) { sleep((sleep_time + 1) - (short) (time(NULL) % sleep_time)); t2 = time(NULL); dt = t2 - t1; /* * The file 'cron.update' is checked to determine new cron * jobs. The directory is rescanned once an hour to deal * with any screwups. * * check for disparity. Disparities over an hour either way * result in resynchronization. A reverse-indexed disparity * less then an hour causes us to effectively sleep until we * match the original time (i.e. no re-execution of jobs that * have just been run). A forward-indexed disparity less then * an hour causes intermediate jobs to be run, but only once * in the worst case. * * when running jobs, the inequality used is greater but not * equal to t1, and less then or equal to t2. */ if (--rescan == 0) { rescan = 60; SynchronizeDir(); } CheckUpdates(); #ifdef FEATURE_DEBUG_OPT if (DebugOpt) crondlog("\005Wakeup dt=%d\n", dt); #endif if (dt < -60 * 60 || dt > 60 * 60) { t1 = t2; crondlog("\111time disparity of %d minutes detected\n", dt / 60); } else if (dt > 0) { TestJobs(t1, t2); RunJobs(); sleep(5); if (CheckJobs() > 0) { sleep_time = 10; } else { sleep_time = 60; } t1 = t2; } } } /* not reached */ }
static void ForkJob(const char *user, CronLine *line, int mailFd, const char *prog, const char *cmd, const char *arg, const char *mail_filename) { struct passwd *pas; pid_t pid; /* prepare things before vfork */ pas = getpwnam(user); if (!pas) { crondlog(LVL9 "can't get uid for %s", user); goto err; } SetEnv(pas); pid = vfork(); if (pid == 0) { /* CHILD */ /* change running state to the user in question */ ChangeUser(pas); if (DebugOpt) { crondlog(LVL5 "child running %s", prog); } if (mailFd >= 0) { xmove_fd(mailFd, mail_filename ? 1 : 0); dup2(1, 2); } execl(prog, prog, cmd, arg, NULL); crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg); if (mail_filename) { fdprintf(1, "Exec failed: %s -c %s\n", prog, arg); } _exit(EXIT_SUCCESS); } line->cl_Pid = pid; if (pid < 0) { /* FORK FAILED */ crondlog(ERR20 "can't vfork"); err: line->cl_Pid = 0; if (mail_filename) { unlink(mail_filename); } } else if (mail_filename) { /* PARENT, FORK SUCCESS * rename mail-file based on pid of process */ char mailFile2[128]; snprintf(mailFile2, sizeof(mailFile2), "%s/cron.%s.%d", TMPDIR, user, pid); rename(mail_filename, mailFile2); // TODO: xrename? } /* * Close the mail file descriptor.. we can't just leave it open in * a structure, closing it later, because we might run out of descriptors */ if (mailFd >= 0) { close(mailFd); } }
int eooqd_main(int argc, char *argv[]) { int r; size_t len; char *pid_file_name, *interface_name, *instance_id_str; char *check; struct event *checkQueueEvent, *rePostEvent; struct timeval tv; struct rlimit limit; struct stat sb; atlas_id= NULL; interface_name= NULL; instance_id_str= NULL; pid_file_name= NULL; queue_id= ""; (void)getopt32(argv, "A:I:i:P:q:", &atlas_id, &interface_name, &instance_id_str, &pid_file_name, &queue_id); if (argc != optind+1) { bb_show_usage(); return 1; } instance_id= 0; if (instance_id_str) { instance_id= strtoul(instance_id_str, &check, 0); if (check[0] != '\0') { report("unable to parse instance id '%s'", instance_id_str); return 1; } } if (interface_name) { len= strlen(RESOLV_CONF) + 1 + strlen(interface_name) + 1; resolv_conf= malloc(len); snprintf(resolv_conf, len, "%s.%s", RESOLV_CONF, interface_name); /* Check if this resolv.conf exists. If it doen't, switch * to the standard one. */ if (stat(resolv_conf, &sb) == -1) { free(resolv_conf); resolv_conf= strdup(RESOLV_CONF); } } else { resolv_conf= strdup(RESOLV_CONF); } if(pid_file_name) { write_pidfile(pid_file_name); } state = xzalloc(sizeof(*state)); state->atlas_id= atlas_id; state->queue_file= argv[optind]; state->max_busy= 10; state->slots= xzalloc(sizeof(*state->slots) * state->max_busy); if (strlen(state->queue_file) + strlen(SUFFIX) + 1 > sizeof(state->curr_qfile)) { report("filename too long ('%s')", state->queue_file); return 1; } strlcpy(state->curr_qfile, state->queue_file, sizeof(state->curr_qfile)); strlcat(state->curr_qfile, SUFFIX, sizeof(state->curr_qfile)); snprintf(output_filename, sizeof(output_filename), OOQD_OUT_PREFIX "%s/ooq.out", queue_id); signal(SIGQUIT, SIG_DFL); limit.rlim_cur= RLIM_INFINITY; limit.rlim_max= RLIM_INFINITY; setrlimit(RLIMIT_CORE, &limit); /* Ignore SIGPIPE, broken TCP sessions may trigger them */ signal(SIGPIPE, SIG_IGN); /* Create libevent event base */ EventBase= event_base_new(); if (!EventBase) { crondlog(DIE9 "event_base_new failed"); /* exits */ } DnsBase= evdns_base_new(EventBase, 0 /*initialize*/); if (!DnsBase) { event_base_free(EventBase); crondlog(DIE9 "evdns_base_new failed"); /* exits */ } if (interface_name) { r= evdns_base_set_interface(DnsBase, interface_name); if (r == -1) { event_base_free(EventBase); crondlog(DIE9 "evdns_base_set_interface failed"); /* exits */ } } r = evdns_base_resolv_conf_parse(DnsBase, DNS_OPTIONS_ALL, resolv_conf); if (r == -1) { event_base_free(EventBase); crondlog(DIE9 "evdns_base_resolv_conf_parse failed"); /* exits */ } checkQueueEvent= event_new(EventBase, -1, EV_TIMEOUT|EV_PERSIST, checkQueue, NULL); if (!checkQueueEvent) crondlog(DIE9 "event_new failed"); /* exits */ tv.tv_sec= 1; tv.tv_usec= 0; event_add(checkQueueEvent, &tv); rePostEvent= event_new(EventBase, -1, EV_TIMEOUT|EV_PERSIST, re_post, NULL); if (!rePostEvent) crondlog(DIE9 "event_new failed"); /* exits */ tv.tv_sec= 60; tv.tv_usec= 0; event_add(rePostEvent, &tv); r= event_base_loop(EventBase, 0); if (r != 0) crondlog(LVL9 "event_base_loop failed"); return 0; }