|
|
1.1 ! root 1: #include <stdio.h> ! 2: #include <ctype.h> ! 3: #include "string.h" ! 4: #include "smtp.h" ! 5: #include "mail.h" ! 6: #include <sys/stat.h> ! 7: #include <time.h> ! 8: ! 9: char spoolsubdir[1026]; ! 10: extern char *UPASROOT; ! 11: ! 12: /* ! 13: * A lock is considered stale if it contains the id of a ! 14: * nonexistent process or if it was created more than `lockwait' ! 15: * seconds ago. lockwait should be larger than the maximum expected ! 16: * time skew among systems that might share a single spool directory ! 17: */ ! 18: static int lockwait = 3600; ! 19: ! 20: /* ! 21: * copy the directory component of `file' into lf. return ! 22: * a pointer to the base name of `file' ! 23: */ ! 24: static char * ! 25: copydir(lf, file) ! 26: string *lf; ! 27: char *file; ! 28: { ! 29: char *base; ! 30: ! 31: base = strrchr(file, '/'); ! 32: if (base){ ! 33: *base = 0; ! 34: s_append(lf, file); ! 35: s_append(lf, "/"); ! 36: *base++ = '/'; ! 37: } else ! 38: base = file; ! 39: return base; ! 40: } ! 41: ! 42: /* ! 43: * convert the control file name into a file name of the ! 44: * type specified. ! 45: */ ! 46: char * ! 47: fileoftype(type, ctl) ! 48: char type; ! 49: char *ctl; ! 50: { ! 51: static string *x; ! 52: char *cp; ! 53: ! 54: x = s_reset(x); ! 55: s_append(x, ctl); ! 56: cp = strrchr(s_to_c(x), '/'); ! 57: if(cp) ! 58: cp++; ! 59: else ! 60: cp = s_to_c(x); ! 61: *cp = type; ! 62: return s_to_c(x); ! 63: } ! 64: ! 65: /* ! 66: * creates a file with a unique name ! 67: * based on `template'. Any trailing string of x's in the ! 68: * template are converted to pppppsssssvv, where ppppp is the ! 69: * process id, sssss is the last 16 bits of the time, vv is enough ! 70: * to make the name unique. If there aren't enough x's to fit all ! 71: * of pppppsssssvv, only as much as will fit (starting right to left) ! 72: * will be substituted for the x's. ! 73: * ! 74: * returns an open fd or -1 if the file couldn't be created. ! 75: * the new name is put into template. ! 76: */ ! 77: mkdatafile(template) ! 78: char *template; ! 79: { ! 80: struct stat s; ! 81: int i, len, pid, fd; ! 82: long seed; ! 83: char hash[14]; ! 84: char *xp; ! 85: ! 86: /* ! 87: * find the number of x's ! 88: */ ! 89: if((len = strlen(template))==0) ! 90: return -1; ! 91: for(xp = template+len-1; xp>=template; xp--) ! 92: if(*xp!='x') ! 93: break; ! 94: xp++; ! 95: len = len-(xp-template); ! 96: ! 97: /* ! 98: * make sure it's <= 12 ! 99: */ ! 100: if(len>12) ! 101: len = 12; ! 102: pid = getpid(); ! 103: seed = (time((long *)0)%100000)*100; ! 104: ! 105: /* ! 106: * try 100 different file names ! 107: */ ! 108: for(i=0; i<100; i++){ ! 109: sprintf(hash, "%05d%07d", pid, seed+i); ! 110: strncpy(xp, hash+(12-len), len); ! 111: if(stat(template, &s)>=0) ! 112: continue; ! 113: if((fd = creat(template, 0660))<0) ! 114: return -1; ! 115: return fd; ! 116: } ! 117: return -1; ! 118: } ! 119: ! 120: /* ! 121: * creates a control file to go with the data file. ! 122: * the control file name is the same as the data file ! 123: * with the first character replaced by 'C'. ! 124: */ ! 125: int ! 126: mkctlfile(letter, dataname, contents) ! 127: char letter; ! 128: char *dataname; ! 129: char *contents; ! 130: { ! 131: int fd; ! 132: static string *cf; ! 133: static string *tf; ! 134: ! 135: /* ! 136: * make the file names ! 137: */ ! 138: cf = s_reset(cf); ! 139: s_append(cf, fileoftype(letter, dataname)); ! 140: tf = s_reset(tf); ! 141: s_append(tf, fileoftype('T', dataname)); ! 142: ! 143: /* ! 144: * create the control file with a temporary (non-control) name ! 145: */ ! 146: fd = creat(s_to_c(tf), 0660); ! 147: if (fd<0) ! 148: return -1; ! 149: if(write(fd, contents, strlen(contents))!=strlen(contents)){ ! 150: close(fd); ! 151: unlink(s_to_c(tf)); ! 152: return -1; ! 153: } ! 154: if(close(fd)<0){ ! 155: unlink(s_to_c(tf)); ! 156: return -1; ! 157: } ! 158: ! 159: /* ! 160: * change it's name so that it looks like a control file ! 161: */ ! 162: if(link(s_to_c(tf), s_to_c(cf))<0){ ! 163: unlink(s_to_c(tf)); ! 164: return -1; ! 165: } ! 166: unlink(s_to_c(tf)); ! 167: return 0; ! 168: } ! 169: ! 170: /* ! 171: * Fill name with the lock name for file. The lockname is ! 172: * dir/L.xxx where dir is the directory containing the file ! 173: * being locked and xxx is the first 12 characters of that file's ! 174: * name. ! 175: */ ! 176: static ! 177: setlname(lf, file) ! 178: string *lf; ! 179: char *file; ! 180: { ! 181: char *base; ! 182: ! 183: /* ! 184: * copy over directory portion ! 185: */ ! 186: base = copydir(lf, file); ! 187: ! 188: /* ! 189: * copy in the rest ! 190: */ ! 191: s_append(lf, "L."); ! 192: s_append(lf, base); ! 193: ! 194: /* ! 195: * make sure we didn't get too long ! 196: */ ! 197: base = strrchr(s_to_c(lf), '/'); ! 198: if(base) ! 199: base++; ! 200: else ! 201: base = s_to_c(lf); ! 202: if(strlen(base)>14) ! 203: base[14] = 0; ! 204: } ! 205: ! 206: /* ! 207: * Return true if file has been locked by us or another program using the same ! 208: * lock name scheme. ! 209: * ! 210: * Remove the lock file if the locking process has gone away. ! 211: */ ! 212: int ! 213: islocked(file) ! 214: char *file; ! 215: { ! 216: struct stat stbuf; ! 217: static string *ln; ! 218: int pid; ! 219: FILE *fp; ! 220: ! 221: ln = s_reset(ln); ! 222: if(setlname(ln, file)<0) ! 223: return 1; ! 224: if(stat(s_to_c(ln), &stbuf)==0) { ! 225: fp = fopen(s_to_c(ln), "r"); ! 226: if (fp == 0 || fscanf(fp, "%d", &pid)!=1) { ! 227: /* ! 228: * if the file is less than `lockwait' old, ! 229: * assume it's still current even though ! 230: * there's no pid there ! 231: */ ! 232: time_t now = time((time_t*) 0); ! 233: if (now < stbuf.st_mtime + lockwait) { ! 234: if (fp) ! 235: fclose(fp); ! 236: return 1; ! 237: } ! 238: ! 239: /* ! 240: * either we made the lock wrong ! 241: * or it just went away (race) ! 242: */ ! 243: fprintf(stderr, "can't read pid: breaking lock %s\n", ! 244: s_to_c(ln)); ! 245: if(fp) ! 246: fclose(fp); ! 247: unlink(s_to_c(ln)); ! 248: return 0; ! 249: } ! 250: if(fp) ! 251: fclose(fp); ! 252: if (kill(pid, 0) == 0) ! 253: return 1; ! 254: ! 255: /* ! 256: * locker has gone away. We are tired of this message. ! 257: */ ! 258: fprintf(stderr, "breaking stale lock %s\n", s_to_c(ln));/**/ ! 259: unlink(s_to_c(ln)); ! 260: } ! 261: return 0; ! 262: } ! 263: ! 264: /* ! 265: * lock a file being processed. see setlname (above) for the name of the lock. ! 266: * the lock file is in the same directory. ! 267: * ! 268: * returns 0 if the lock was granted, -1 otherwise. this is a none ! 269: * blocking routine. ! 270: */ ! 271: lock(file) ! 272: char *file; ! 273: { ! 274: int fd; ! 275: char *sp; ! 276: char pidbuf[20]; ! 277: static string *tn; ! 278: static string *ln; ! 279: ! 280: /* ! 281: * create a temporary file (in same directory) ! 282: */ ! 283: tn = s_reset(tn); ! 284: copydir(tn, file); ! 285: s_append(tn, "T.xxxxxxxxxxxx"); ! 286: fd = mkdatafile(s_to_c(tn)); ! 287: if(fd<0) ! 288: return -1; ! 289: sprintf(pidbuf, "%d lock", getpid()); ! 290: write(fd, pidbuf, strlen(pidbuf)); ! 291: close(fd); ! 292: ! 293: /* ! 294: * Make a link to it with the lock file name. This will fail only ! 295: * if it already exists. ! 296: */ ! 297: ln = s_reset(ln); ! 298: setlname(ln, file); ! 299: while(link(s_to_c(tn), s_to_c(ln)) < 0) { ! 300: /* ! 301: * might be a stale lock ! 302: */ ! 303: if(islocked(file)){ ! 304: unlink(s_to_c(tn)); ! 305: return -1; ! 306: } ! 307: } ! 308: unlink(s_to_c(tn)); ! 309: return 0; ! 310: } ! 311: ! 312: /* ! 313: * unlock a file ! 314: */ ! 315: unlock(file) ! 316: char *file; ! 317: { ! 318: static string *ln; ! 319: ! 320: ln = s_reset(ln); ! 321: setlname(ln, file); ! 322: unlink(s_to_c(ln)); ! 323: } ! 324: ! 325: /* ! 326: * make a spool directory and cd into it. the spool directory is in ! 327: * /usr/spool/smtpq and it's name is the 2 most significant elements of ! 328: * the domain name, `target'. ! 329: */ ! 330: #define WEIRD "weird.domain" ! 331: gotodir(target) ! 332: char *target; ! 333: { ! 334: register char *bp, *lp, *last; ! 335: char t[256]; ! 336: int elems; ! 337: ! 338: if(chdir(SMTPQROOT)<0){ ! 339: mkdir(SMTPQROOT, 0775); ! 340: if(chdir(SMTPQROOT)<0) { ! 341: Syslog(LOG_WARNING, "Could not create %s", SMTPQROOT); ! 342: return -1; ! 343: } ! 344: } ! 345: ! 346: for (bp=target, lp=t; *bp; bp++, lp++) { ! 347: if (*bp == '/') ! 348: *lp = '.'; ! 349: else if (isupper(*bp)) ! 350: *lp = tolower(*bp); ! 351: else ! 352: *lp = *bp; ! 353: } ! 354: *lp = '\0'; ! 355: ! 356: if (strncmp(t, "dk!", 3) == 0) ! 357: bp = t + 3; ! 358: else if (strncmp(t, "tcp!", 4) == 0) ! 359: bp = t + 4; ! 360: else ! 361: bp = t; ! 362: ! 363: if ((lp=strchr(bp, '!')) != NULL) /*ignore trailing service*/ ! 364: *lp-- = '\0'; ! 365: else ! 366: lp = bp + strlen(bp); ! 367: last = lp; ! 368: ! 369: for(elems=0; lp>bp && last-(--lp)<MAXPATHLEN; ){ ! 370: if(*lp=='.') ! 371: if(++elems==6){ ! 372: lp++; ! 373: break; ! 374: } ! 375: } ! 376: bp = lp; ! 377: while ((*bp != '\0') && (*bp == '.')) ! 378: bp++; ! 379: ! 380: if (*bp == '\0') ! 381: strcpy(spoolsubdir, WEIRD); ! 382: else ! 383: strcpy(spoolsubdir, bp); ! 384: ! 385: if(chdir(spoolsubdir)<0){ ! 386: mkdir(spoolsubdir, 0775); ! 387: if(chdir(spoolsubdir)<0) { ! 388: Syslog(LOG_WARNING, "Could not chdir to %s", spoolsubdir); ! 389: return -1; ! 390: } ! 391: } ! 392: ! 393: return 0; ! 394: } ! 395: ! 396: /* ! 397: * start the scheduler ! 398: */ ! 399: smtpsched(av0, target) ! 400: char *av0; ! 401: char *target; ! 402: { ! 403: int status; ! 404: static string *cmd; ! 405: ! 406: switch(fork()){ ! 407: case -1: ! 408: break; ! 409: case 0: ! 410: /* ! 411: * exec the sched process ! 412: */ ! 413: cmd = s_reset(cmd); ! 414: s_append(cmd, UPASROOT); ! 415: s_append(cmd, "/smtpsched"); ! 416: execl(s_to_c(cmd), av0, target, 0); ! 417: exit(1); ! 418: default: ! 419: /* ! 420: * wait for any sub processes to finish ! 421: */ ! 422: while(wait(&status)>=0) ! 423: ; ! 424: break; ! 425: } ! 426: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.