Annotation of researchv10no/cmd/upas/smtp/qlib.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.