1: /* Copyright 1988,1990,1993,1994 by Paul Vixie
   2:  * All rights reserved
   3:  *
   4:  * Distribute freely, except: don't remove my name from the source or
   5:  * documentation (don't take credit for my work), mark your changes (don't
   6:  * get me blamed for your possible bugs), don't alter or remove this
   7:  * notice.  May be sold if buildable source is provided to buyer.  No
   8:  * warrantee of any kind, express or implied, is included with this
   9:  * software; use at your own risk, responsibility for damages (if any) to
  10:  * anyone resulting from the use of this software rests entirely with the
  11:  * user.
  12:  *
  13:  * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  14:  * I'll try to keep a version up to date.  I can be reached as follows:
  15:  * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
  16:  */
  17: 
  18: #if !defined(lint) && !defined(LINT)
  19: static char rcsid[] = "$Id: database.c,v 2.8 1994/01/15 20:43:43 vixie Exp $";
  20: #endif
  21: 
  22: /* vix 26jan87 [RCS has the log]
  23:  */
  24: 
  25: 
  26: #include "cron.h"
  27: #include <fcntl.h>
  28: #include <sys/stat.h>
  29: #include <sys/file.h>
  30: 
  31: 
  32: #define TMAX(a,b) ((a)>(b)?(a):(b))
  33: 
  34: 
  35: static  void        process_crontab __P((char *, char *, char *,
  36:                          struct stat *,
  37:                          cron_db *, cron_db *));
  38: 
  39: 
  40: void
  41: load_database(old_db)
  42:     cron_db     *old_db;
  43: {
  44:     DIR     *dir;
  45:     struct stat statbuf;
  46:     struct stat syscron_stat;
  47:     register DIR_T   *dp;
  48:     cron_db     new_db;
  49:     user        *u, *nu;
  50: 
  51:     Debug(DLOAD, ("[%d] load_database()\n", getpid()))
  52: 
  53:     /* before we start loading any data, do a stat on SPOOL_DIR
  54: 	 * so that if anything changes as of this moment (i.e., before we've
  55: 	 * cached any of the database), we'll see the changes next time.
  56: 	 */
  57:     if (stat(SPOOL_DIR, &statbuf) < OK) {
  58:         log_it("CRON", getpid(), "STAT FAILED", SPOOL_DIR);
  59:         (void) exit(ERROR_EXIT);
  60:     }
  61: 
  62:     /* track system crontab file
  63: 	 */
  64:     if (stat(SYSCRONTAB, &syscron_stat) < OK)
  65:         syscron_stat.st_mtime = 0;
  66: 
  67:     /* if spooldir's mtime has not changed, we don't need to fiddle with
  68: 	 * the database.
  69: 	 *
  70: 	 * Note that old_db->mtime is initialized to 0 in main(), and
  71: 	 * so is guaranteed to be different than the stat() mtime the first
  72: 	 * time this function is called.
  73: 	 */
  74:     if (old_db->mtime == TMAX(statbuf.st_mtime, syscron_stat.st_mtime)) {
  75:         Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n",
  76:                   getpid()))
  77:         return;
  78:     }
  79: 
  80:     /* something's different.  make a new database, moving unchanged
  81: 	 * elements from the old database, reloading elements that have
  82: 	 * actually changed.  Whatever is left in the old database when
  83: 	 * we're done is chaff -- crontabs that disappeared.
  84: 	 */
  85:     new_db.mtime = TMAX(statbuf.st_mtime, syscron_stat.st_mtime);
  86:     new_db.head = new_db.tail = NULL;
  87: 
  88:     if (syscron_stat.st_mtime) {
  89:         process_crontab("root", "*system*",
  90:                 SYSCRONTAB, &syscron_stat,
  91:                 &new_db, old_db);
  92:     }
  93: 
  94:     /* we used to keep this dir open all the time, for the sake of
  95: 	 * efficiency.  however, we need to close it in every fork, and
  96: 	 * we fork a lot more often than the mtime of the dir changes.
  97: 	 */
  98:     if (!(dir = opendir(SPOOL_DIR))) {
  99:         log_it("CRON", getpid(), "OPENDIR FAILED", SPOOL_DIR);
 100:         (void) exit(ERROR_EXIT);
 101:     }
 102: 
 103:     while (NULL != (dp = readdir(dir))) {
 104:         char    fname[MAXNAMLEN+1],
 105:             tabname[MAXNAMLEN+1];
 106: 
 107:         /* avoid file names beginning with ".".  this is good
 108: 		 * because we would otherwise waste two guaranteed calls
 109: 		 * to getpwnam() for . and .., and also because user names
 110: 		 * starting with a period are just too nasty to consider.
 111: 		 */
 112:         if (dp->d_name[0] == '.')
 113:             continue;
 114: 
 115:         (void) strcpy(fname, dp->d_name);
 116:         sprintf(tabname, CRON_TAB(fname));
 117: 
 118:         process_crontab(fname, fname, tabname,
 119:                 &statbuf, &new_db, old_db);
 120:     }
 121:     closedir(dir);
 122: 
 123:     /* if we don't do this, then when our children eventually call
 124: 	 * getpwnam() in do_command.c's child_process to verify MAILTO=,
 125: 	 * they will screw us up (and v-v).
 126: 	 */
 127:     endpwent();
 128: 
 129:     /* whatever's left in the old database is now junk.
 130: 	 */
 131:     Debug(DLOAD, ("unlinking old database:\n"))
 132:     for (u = old_db->head;  u != NULL;  u = nu) {
 133:         Debug(DLOAD, ("\t%s\n", u->name))
 134:         nu = u->next;
 135:         unlink_user(old_db, u);
 136:         free_user(u);
 137:     }
 138: 
 139:     /* overwrite the database control block with the new one.
 140: 	 */
 141:     *old_db = new_db;
 142:     Debug(DLOAD, ("load_database is done\n"))
 143: }
 144: 
 145: 
 146: void
 147: link_user(db, u)
 148:     register cron_db    *db;
 149:     register user   *u;
 150: {
 151:     if (db->head == NULL)
 152:         db->head = u;
 153:     if (db->tail)
 154:         db->tail->next = u;
 155:     u->prev = db->tail;
 156:     u->next = NULL;
 157:     db->tail = u;
 158: }
 159: 
 160: 
 161: void
 162: unlink_user(db, u)
 163:     register cron_db    *db;
 164:     register user   *u;
 165: {
 166:     if (u->prev == NULL)
 167:         db->head = u->next;
 168:     else
 169:         u->prev->next = u->next;
 170: 
 171:     if (u->next == NULL)
 172:         db->tail = u->prev;
 173:     else
 174:         u->next->prev = u->prev;
 175: }
 176: 
 177: 
 178: user *
 179: find_user(db, name)
 180:     cron_db *db;
 181:     register char   *name;
 182: {
 183:     char    *env_get();
 184:     register user   *u;
 185: 
 186:     for (u = db->head;  u != NULL;  u = u->next)
 187:         if (!strcmp(u->name, name))
 188:             break;
 189:     return u;
 190: }
 191: 
 192: 
 193: static void
 194: process_crontab(uname, fname, tabname, statbuf, new_db, old_db)
 195:     char        *uname;
 196:     char        *fname;
 197:     char        *tabname;
 198:     struct stat *statbuf;
 199:     cron_db     *new_db;
 200:     cron_db     *old_db;
 201: {
 202:     struct passwd   *pw = NULL;
 203:     int     crontab_fd = OK - 1;
 204:     register user       *u;
 205: 
 206:     if (strcmp(fname, "*system*") && !(pw = getpwnam(uname))) {
 207:         /* file doesn't have a user in passwd file.
 208: 		 */
 209:         log_it(fname, getpid(), "ORPHAN", "no passwd entry");
 210:         goto next_crontab;
 211:     }
 212: 
 213:     if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
 214:         /* crontab not accessible?
 215: 		 */
 216:         log_it(fname, getpid(), "CAN'T OPEN", tabname);
 217:         goto next_crontab;
 218:     }
 219: 
 220:     if (fstat(crontab_fd, statbuf) < OK) {
 221:         log_it(fname, getpid(), "FSTAT FAILED", tabname);
 222:         goto next_crontab;
 223:     }
 224: 
 225:     Debug(DLOAD, ("\t%s:", fname))
 226:     u = find_user(old_db, fname);
 227:     if (u != NULL) {
 228:         /* if crontab has not changed since we last read it
 229: 		 * in, then we can just use our existing entry.
 230: 		 */
 231:         if (u->mtime == statbuf->st_mtime) {
 232:             Debug(DLOAD, (" [no change, using old data]"))
 233:             unlink_user(old_db, u);
 234:             link_user(new_db, u);
 235:             goto next_crontab;
 236:         }
 237: 
 238:         /* before we fall through to the code that will reload
 239: 		 * the user, let's deallocate and unlink the user in
 240: 		 * the old database.  This is more a point of memory
 241: 		 * efficiency than anything else, since all leftover
 242: 		 * users will be deleted from the old database when
 243: 		 * we finish with the crontab...
 244: 		 */
 245:         Debug(DLOAD, (" [delete old data]"))
 246:         unlink_user(old_db, u);
 247:         free_user(u);
 248:         log_it(fname, getpid(), "RELOAD", tabname);
 249:     }
 250:     u = load_user(crontab_fd, pw, fname);
 251:     if (u != NULL) {
 252:         u->mtime = statbuf->st_mtime;
 253:         link_user(new_db, u);
 254:     }
 255: 
 256: next_crontab:
 257:     if (crontab_fd >= OK) {
 258:         Debug(DLOAD, (" [done]\n"))
 259:         close(crontab_fd);
 260:     }
 261: }

Defined functions

find_user defined in line 178; used 1 times
link_user defined in line 146; used 2 times
load_database defined in line 40; never used
process_crontab defined in line 193; used 2 times
unlink_user defined in line 161; used 3 times

Defined variables

rcsid defined in line 19; never used

Defined macros

TMAX defined in line 32; used 2 times
Last modified: 1999-06-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3591
Valid CSS Valid XHTML 1.0 Strict