home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * DATABASE.C
- *
- * Copyright 1994 Matthew Dillon (dillon@apollo.west.oic.com)
- * May be distributed under the GNU General Public License
- */
-
- #include "defs.h"
-
- Prototype void CheckUpdates(void);
- Prototype void SynchronizeDir(const char *dirName);
- Prototype int TestJobs(time_t t1, time_t t2);
- Prototype void RunJobs(void);
- Prototype int CheckJobs(void);
-
- void SynchronizeFile(const char *fileName);
- void DeleteFile(const char *userName);
- char *ParseField(char *userName, char *ary, int modvalue, int off, const char **names, char *ptr);
- void FixDayDow(CronLine *line);
-
- CronFile *FileBase;
-
- const char *DowAry[] = {
- "sun",
- "mon",
- "tue",
- "wed",
- "thu",
- "fri",
- "sat",
-
- "Sun",
- "Mon",
- "Tue",
- "Wed",
- "Thu",
- "Fri",
- "Sat",
- NULL
- };
-
- const char *MonAry[] = {
- "jan",
- "feb",
- "mar",
- "apr",
- "may",
- "jun",
- "jul",
- "aug",
- "sep",
- "oct",
- "nov",
- "dec",
-
- "Jan",
- "Feb",
- "Mar",
- "Apr",
- "May",
- "Jun",
- "Jul",
- "Aug",
- "Sep",
- "Oct",
- "Nov",
- "Dec",
- NULL
- };
-
- void
- CheckUpdates(void)
- {
- FILE *fi;
- char buf[256];
-
- if ((fi = fopen(CRONUPDATE, "r")) != NULL) {
- remove(CRONUPDATE);
- while (fgets(buf, sizeof(buf), fi) != NULL) {
- SynchronizeFile(strtok(buf, " \t\r\n"));
- }
- fclose(fi);
- }
- }
-
- void
- SynchronizeDir(const char *dirName)
- {
- /*
- * Attempt to delete the database. Note that we have to make a copy
- * of the string
- */
-
- for (;;) {
- CronFile *file;
- char *user;
-
- for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next)
- ;
- if (file == NULL)
- break;
- user = strdup(file->cf_User);
- DeleteFile(user);
- free(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) {
- log9("unable to find %s\n", CDir);
- exit(20);
- }
- {
- DIR *dir;
- struct dirent *den;
-
- if ((dir = opendir("."))) {
- while ((den = readdir(dir))) {
- if (strchr(den->d_name, '.') != NULL)
- continue;
- if (getpwnam(den->d_name))
- SynchronizeFile(den->d_name);
- else
- log(7, "ignoring %s\n", den->d_name);
- }
- closedir(dir);
- } else {
- log9("Unable to open current dir!\n");
- exit(20);
- }
- }
- }
-
- 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);
-
- if ((fi = fopen(fileName, "r")) != 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;
-
- if (buf[0])
- buf[strlen(buf)-1] = 0;
-
- if (buf[0] == 0 || buf[0] == '#' || buf[0] == ' ' || buf[0] == '\t')
- continue;
-
- if (--maxEntries == 0)
- break;
-
- bzero(&line, sizeof(line));
-
- if (DebugOpt)
- log9("User %s Entry %s\n", fileName, buf);
-
- /*
- * 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);
-
- if (DebugOpt) {
- log9(" Command %s\n", ptr);
- }
-
- pline = &((*pline)->cl_Next);
- }
- *pline = NULL;
-
- file->cf_Next = FileBase;
- FileBase = file;
-
- if (maxLines == 0 || maxEntries == 0)
- log9("Maximum number of lines reached for user %s\n", fileName);
- }
- fclose(fi);
- }
- }
- }
-
- char *
- ParseField(char *user, char *ary, int modvalue, int off, const char **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) {
- log9("failed 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) {
- log9("failed user %s parsing %s\n", user, base);
- return(NULL);
- }
- }
- if (*ptr != ',')
- break;
- ++ptr;
- n1 = -1;
- n2 = -1;
- }
-
- if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
- log9("failed user %s parsing %s\n", user, base);
- return(NULL);
- }
-
- while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
- ++ptr;
-
- if (DebugOpt) {
- int i;
-
- for (i = 0; i < modvalue; ++i)
- log(5, "%d", ary[i]);
- log(5, "\n");
- }
-
- return(ptr);
- }
-
- void
- FixDayDow(CronLine *line)
- {
- short i;
- short weekUsed = 0;
- short daysUsed = 0;
-
- for (i = 0; i < arysize(line->cl_Dow); ++i) {
- if (line->cl_Dow[i] == 0) {
- weekUsed = 1;
- break;
- }
- }
- for (i = 0; i < arysize(line->cl_Days); ++i) {
- if (line->cl_Days[i] == 0) {
- daysUsed = 1;
- break;
- }
- }
- if (weekUsed && !daysUsed) {
- memset(line->cl_Days, 0, sizeof(line->cl_Days));
- }
- if (daysUsed && !weekUsed) {
- memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
- }
- }
-
- /*
- * DeleteFile() - delete user database
- *
- * Note: multiple entries for same user may exist if we were unable to
- * completely delete a database due to running processes.
- */
-
- void
- DeleteFile(const char *userName)
- {
- CronFile **pfile = &FileBase;
- CronFile *file;
-
- while ((file = *pfile) != NULL) {
- if (strcmp(userName, file->cf_User) == 0) {
- CronLine **pline = &file->cf_LineBase;
- CronLine *line;
-
- file->cf_Running = 0;
- file->cf_Deleted = 1;
-
- while ((line = *pline) != NULL) {
- if (line->cl_Pid > 0) {
- file->cf_Running = 1;
- pline = &line->cl_Next;
- } else {
- *pline = line->cl_Next;
- free(line->cl_Shell);
- free(line);
- }
- }
- if (file->cf_Running == 0) {
- *pfile = file->cf_Next;
- free(file->cf_User);
- free(file);
- } else {
- pfile = &file->cf_Next;
- }
- } else {
- pfile = &file->cf_Next;
- }
- }
- }
-
- /*
- * 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).
- */
-
- 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) {
- if (DebugOpt)
- log(5, "FILE %s:\n", file->cf_User);
- if (file->cf_Deleted)
- continue;
- for (line = file->cf_LineBase; line; line = line->cl_Next) {
- if (DebugOpt)
- log(5, " LINE %s\n", 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)
- log(5, " JobToDo: %d %s\n", line->cl_Pid, line->cl_Shell);
- if (line->cl_Pid > 0) {
- log(8, " 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);
- }
-
- 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, line);
-
- log(8, "USER %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;
- }
- }
- }
- }
- }
-
- /*
- * CheckJobs() - check for job completion
- *
- * Check for job completion, return number of jobs still running after
- * all done.
- */
-
- int
- CheckJobs(void)
- {
- CronFile *file;
- CronLine *line;
- int nStillRunning = 0;
-
- for (file = FileBase; file; file = file->cf_Next) {
- if (file->cf_Running) {
- file->cf_Running = 0;
-
- for (line = file->cf_LineBase; line; line = line->cl_Next) {
- if (line->cl_Pid > 0) {
- int status;
- int r = wait4(line->cl_Pid, &status, WNOHANG, NULL);
-
- if (r < 0 || r == line->cl_Pid) {
- EndJob(file, line);
- if (line->cl_Pid)
- file->cf_Running = 1;
- } else if (r == 0) {
- file->cf_Running = 1;
- }
- }
- }
- }
- nStillRunning += file->cf_Running;
- }
- return(nStillRunning);
- }
-
-