Annotation of researchv10no/cmd/upas/smtp/smtpsched.c, revision 1.1

1.1     ! root        1: #include <stdio.h>
        !             2: #include <ctype.h>
        !             3: #include <signal.h>
        !             4: #include <sysexits.h>
        !             5: #include "string.h"
        !             6: #include "smtp.h"
        !             7: #include "mail.h"
        !             8: #include <sys/stat.h>
        !             9: 
        !            10: /*
        !            11:  *  names of the limit files
        !            12:  */
        !            13: #define CON ".smtpscheds"
        !            14: #define NCON ".nsmtpscheds"
        !            15: 
        !            16: #define        OLD     1*3600L         /* old C file -> try less often */
        !            17: #define        VOLD    6*3600L         /* very old C file -> try much less often */
        !            18: #define        OLDW    1*3600L         /* wait time between tries at old files */
        !            19: #define        VOLDW   4*3600L         /* wait time between tries at very old files */
        !            20: 
        !            21: extern char *UPASROOT;
        !            22: int warn = -1;
        !            23: int removedays = -1;
        !            24: int cleanup;
        !            25: int verbose;
        !            26: int testmode;
        !            27: int Xonly;
        !            28: int Conly;
        !            29: string *replyaddr;
        !            30: string *dest;
        !            31: int mypid;
        !            32: char **getcmd();
        !            33: 
        !            34: #define        MAXDEST 50              /* # destinations remembered */
        !            35: #define        MAXTPERD 5*60           /* total time allowed before skipping dests */
        !            36: struct {
        !            37:        string  *dest;
        !            38:        time_t  time;
        !            39: } destlist[MAXDEST];           /* time consumed by unsuccessful tries at dest */
        !            40: int    ndest = 0;
        !            41: 
        !            42: int    debug;
        !            43: 
        !            44: 
        !            45: /*
        !            46:  *  actions to take when locking
        !            47:  */
        !            48: #define BLOCK 0                /* wait for 5 minutes if the directory is locked */
        !            49: #define SKIP 1         /* skip the directory if it is locked */
        !            50: #define IGNORE 2       /* don't lock the directory or care if it is */
        !            51: 
        !            52: /*
        !            53:  *  If called with arguments, those arguments are spool directories.  Descend
        !            54:  *  each one processing the control files in it (C.* and X.*).
        !            55:  *
        !            56:  *  If called without arguments, descend all spool directories.
        !            57:  *
        !            58:  *  -s #scheds  specifies a maximum number of concurrent smtpscheds.
        !            59:  *  -w #days   causes users to be warned if their mail files are older
        !            60:  *             than #days days
        !            61:  *  -r #days   causes mail older than #days days to be returned to sender
        !            62:  *  -c         cleanup empty directories
        !            63:  *  -D         debug
        !            64:  *  -L level   logging level
        !            65:  */
        !            66: usage()
        !            67: {
        !            68:        fprintf(stderr, "smtpsched [-cvtDL] [-w #days] [-r #days] [-s #scheds] [dir]\n");
        !            69:        exit(1);
        !            70: }
        !            71: 
        !            72: main(ac, av)
        !            73:        int ac;
        !            74:        char *av[];
        !            75: {
        !            76:        DIR *dirp;
        !            77:        Direct *dp;
        !            78:        int max=0;
        !            79:        int c;
        !            80:        extern int optind;
        !            81:        extern char *optarg;
        !            82: 
        !            83:        umask(2);
        !            84: 
        !            85:        mypid = getpid();
        !            86: 
        !            87:        /*
        !            88:         *  avoid annoying distractions
        !            89:         */
        !            90:        signal(SIGPIPE, SIG_IGN);
        !            91:        signal(SIGHUP, SIG_IGN);
        !            92:        Openlog("smtpsched", LOG_PID, LOG_SMTPSCHED);
        !            93:        setlogmask(LOG_UPTO(LOG_INFO));
        !            94: 
        !            95:        while ((c = getopt(ac, av, "XCDcvtr:w:s:L:")) != EOF)
        !            96:                switch (c) {
        !            97:                case 'X':       Xonly++;                break;
        !            98:                case 'C':       Conly++;                break;
        !            99:                case 't':       testmode++;             break;
        !           100:                case 'v':       verbose++;              break;
        !           101:                case 'c':       cleanup++;              break;
        !           102:                case 'r':       removedays = atoi(optarg);      break;
        !           103:                case 's':       max = atoi(optarg);     break;
        !           104:                case 'w':       warn = atoi(optarg);    break;
        !           105:                case 'L':       setloglevel(optarg);    break;
        !           106:                case 'D':       debug++;                break;
        !           107:                default:        usage();
        !           108:                }
        !           109: 
        !           110:        /*
        !           111:         *  go to top spool directory
        !           112:         */
        !           113:        if(chdir(SMTPQROOT)<0){
        !           114:                Syslog(LOG_ALERT, "can't chdir to %s\n", SMTPQROOT);
        !           115:                exit(1);
        !           116:        }
        !           117: 
        !           118:        /*
        !           119:         *  if there are too many running exit
        !           120:         */
        !           121:        if(max && toomany(max)<0)
        !           122:                exit(0);
        !           123: 
        !           124:        /*
        !           125:         *  If specific directories, do just them.  Keep running the directory till there
        !           126:         *  is no change.  
        !           127:         */
        !           128:        if(optind!=ac){
        !           129:                for(; optind<ac; optind++)
        !           130:                        while(dodir(av[optind], SKIP) && !warn && !removedays)
        !           131:                                ;
        !           132:                return 0;
        !           133:        }
        !           134: 
        !           135:        /*
        !           136:         *  walk through all directories in top directory.  the lock is
        !           137:         *  non-blocking (if neither r nor w options specified) to let
        !           138:         *  different instances of smtpsched skip over each other.
        !           139:         */
        !           140:        dirp = opendir(".");
        !           141:        if(dirp==NULL){
        !           142:                Syslog(LOG_ALERT, "couldn't read %s\n", SMTPQROOT);
        !           143:                exit(1);
        !           144:        }
        !           145:        while(dp = readdir(dirp)){
        !           146:                if(strcmp(dp->d_name, ".")!=0 && strcmp(dp->d_name, "..")!=0)
        !           147:                        dodir(dp->d_name, (warn>=0 || removedays>=0) ? IGNORE : SKIP);
        !           148:        }
        !           149:        closedir(dirp);
        !           150:        return 0;
        !           151: }
        !           152: 
        !           153: /*
        !           154:  *  do both directions in a directory
        !           155:  */
        !           156: dodir(dname, action)
        !           157:        char *dname;
        !           158: {
        !           159:        int i, err;
        !           160:        static string *ds;
        !           161:        struct stat buf;
        !           162: 
        !           163:        if ((err=stat(dname, &buf)) < 0)
        !           164:                return 0;
        !           165: 
        !           166:        if (!(buf.st_mode & S_IFDIR))
        !           167:                return 0;
        !           168: 
        !           169:        ds = s_reset(ds);
        !           170:        s_append(ds, dname);
        !           171: 
        !           172:        if (debug)
        !           173:                fprintf(stderr, "Checking %s\n", dname);
        !           174:        i = dodirdir(s_to_c(ds), action, "X.");
        !           175:        i += dodirdir(s_to_c(ds), action, "C.");
        !           176:        return i;
        !           177: }
        !           178: 
        !           179: /*
        !           180:  *  walk through all entries in this directory.  process any
        !           181:  *  not starting with '.'.  lock the directory before proceeding.
        !           182:  */
        !           183: dodirdir(dname, action, direction)
        !           184:        char *dname;
        !           185:        char *direction;
        !           186: {
        !           187:        DIR *dirp;
        !           188:        Direct *dp;
        !           189:        int i;
        !           190:        int changed=0;
        !           191:        int ents=0, files=0;
        !           192:        static string *ls;
        !           193:        extern int errno;
        !           194: 
        !           195:        ls = s_reset(ls);
        !           196:        s_append(ls, direction);
        !           197:        s_append(ls, dname);
        !           198: 
        !           199:        /*
        !           200:         *  lock the directory.  the lock is in the parent directory.
        !           201:         */
        !           202:        switch(action){
        !           203:        case BLOCK:
        !           204:                for(i=0; i<3; i++){
        !           205:                        if(lock(s_to_c(ls))==0)
        !           206:                                break;
        !           207:                        if (debug)
        !           208:                                Syslog(LOG_DEBUG, "pausing for lock");
        !           209:                        sleep(5);
        !           210:                }
        !           211:                if(i==3)
        !           212:                        return changed;
        !           213:                break;
        !           214:        case SKIP:
        !           215:                if(lock(s_to_c(ls))<0){
        !           216:                        Syslog(LOG_DEBUG, "couldn't lock %s\n", dname);
        !           217:                        return changed;
        !           218:                }
        !           219:                break;
        !           220:        case IGNORE:
        !           221:                break;
        !           222:        }
        !           223: 
        !           224:        /*
        !           225:         *  descend into the directory.  if it isn't a directory,
        !           226:         *  this will fail.
        !           227:         */
        !           228:        if(chdir(dname)<0){
        !           229:                if(action != IGNORE)
        !           230:                        unlock(s_to_c(ls));
        !           231:                return changed;
        !           232:        }
        !           233: 
        !           234:        /*
        !           235:         *  walk through the entries
        !           236:         */
        !           237:        dirp = opendir(".");
        !           238:        if(dirp==NULL){
        !           239:                Syslog(LOG_INFO, "couldn't read directory %s\n", dname);
        !           240:                if(chdir(SMTPQROOT)<0){
        !           241:                        Syslog(LOG_ALERT, "can't chdir back to SMTPQROOT\n");
        !           242:                        exit(1);
        !           243:                }
        !           244:                if(action != IGNORE)
        !           245:                        unlock(s_to_c(ls));
        !           246:                return changed;
        !           247:        }
        !           248:        while(dp = readdir(dirp)){
        !           249:                if(strcmp(dp->d_name, ".")==0 || strcmp(dp->d_name, "..")==0)
        !           250:                        continue;
        !           251:                files++;
        !           252:                if (cleanup)
        !           253:                        continue;
        !           254:                if (dp->d_name[0] == *direction) {
        !           255:                        switch(dofile(dname, dp->d_name)){
        !           256:                        case 0:
        !           257:                                /* file removed */
        !           258:                                changed = 1;
        !           259:                                break;
        !           260:                        case 1:
        !           261:                                /* file left alone */
        !           262:                                ents += 1;
        !           263:                                break;
        !           264:                        }
        !           265:                }
        !           266:        }
        !           267:        closedir(dirp);
        !           268: 
        !           269:        /*
        !           270:         *  go back up.  symbolic links could be painful!!!!
        !           271:         */
        !           272:        if(chdir(SMTPQROOT)<0){
        !           273:                Syslog(LOG_ALERT, "Can't chdir back to SMTPQROOT\n");
        !           274:                exit(1);
        !           275:        }
        !           276: 
        !           277:        /*
        !           278:         *  cleanup empty directories
        !           279:         */
        !           280:        if(cleanup && files==0){
        !           281:                Syslog(LOG_DEBUG, "%s empty\n", dname);
        !           282:                if(rmdir(dname)<0)
        !           283:                        Syslog(LOG_ALERT, "can't unlink: %d\n", errno);
        !           284:        }
        !           285: 
        !           286:        if(action != IGNORE)
        !           287:                unlock(s_to_c(ls));
        !           288:        return changed;
        !           289: }
        !           290: 
        !           291: /*
        !           292:  *  process a spool control file.  control file names start with C. or
        !           293:  *  X.  all error goes into an error file.
        !           294:  *
        !           295:  *  return 0 if file removed, 1 otherwise.
        !           296:  */
        !           297: dofile(dname, name)
        !           298:        char *dname;
        !           299:        char *name;
        !           300: {
        !           301:        int rv;
        !           302:        int fd, ofd;
        !           303:        char *ef;
        !           304:        extern char *fileoftype();
        !           305:        struct stat sb;
        !           306:        time_t now, Edate, Cdate;
        !           307: 
        !           308:        rv = -1;
        !           309: 
        !           310:        /*
        !           311:         *  if the file is inconsistent, remove it
        !           312:         */
        !           313:        if(cleanup && inconsistent(name)){
        !           314:                Syslog(LOG_NOTICE, "%s/%s inconsistent\n", dname, name);
        !           315:                unlink(name);
        !           316:                return 0;
        !           317:        }
        !           318: 
        !           319:        /*
        !           320:         *  if this is not a control file, ignore it
        !           321:         */
        !           322:        if(name[1]!='.' || (name[0]!='C' && name[0]!='X'))
        !           323:                return 1;
        !           324: 
        !           325:        /*
        !           326:         *  if file is too old, warn user and remove it.  if checking age,
        !           327:         *  don't run the control file.
        !           328:         */
        !           329:        if(warn>=0 || removedays>=0) {
        !           330:                if(checkage(name)==0) {
        !           331:                        Syslog(LOG_NOTICE, "%s/%s too old\n", dname, name);
        !           332:                        doremove(name);
        !           333:                        return 0;
        !           334:                }
        !           335:                return 1;
        !           336:        }
        !           337: 
        !           338:        /*
        !           339:         *  don't run control file when cleaning up
        !           340:         */
        !           341:        if(cleanup)
        !           342:                return 1;
        !           343: 
        !           344:        /*
        !           345:         * Backoff scheme: don't try old C files very often
        !           346:         */
        !           347:        ef = fileoftype('E', name);
        !           348:        if (name[0]=='C') {
        !           349:                now = time((time_t *)0);
        !           350:                Cdate = now;
        !           351:                Edate = now-VOLDW-1;
        !           352:                if (stat(name, &sb)==0)
        !           353:                        Cdate = sb.st_ctime;
        !           354:                if (stat(ef, &sb)==0)
        !           355:                        Edate = sb.st_mtime;
        !           356:                if (now-Cdate>VOLD && now-Edate<VOLDW
        !           357:                 || now-Cdate>OLD  && now-Edate<OLDW) {
        !           358:                        if (verbose)
        !           359:                                Syslog(LOG_DEBUG, "ignore %s/%s: not time yet\n", dname, name);
        !           360:                        if (debug==0)
        !           361:                                return 1;
        !           362:                }
        !           363:        }
        !           364: 
        !           365:        /*
        !           366:         * in test mode, just return
        !           367:         */
        !           368:        if (testmode) {
        !           369:                Syslog(LOG_DEBUG, "would process %s/%s\n", dname, name);
        !           370:                return 1;
        !           371:        }
        !           372:        /*
        !           373:         *  redirect output to an error file
        !           374:         */
        !           375:        ofd = dup(2);
        !           376:        close(2);
        !           377:        fd = open(ef, 1);
        !           378:        if(fd<0)
        !           379:                fd = creat(ef, 0666);
        !           380:        if(fd>=0){
        !           381:                lseek(fd, 0l, 2);
        !           382:        
        !           383:                /*
        !           384:                 *  process the file
        !           385:                 */
        !           386:                if(name[0]=='C') {
        !           387:                        rv = dosmtp(dname, name);
        !           388:                } else if(name[0]=='X') {
        !           389:                        rv = dormail(dname, name);
        !           390:                }
        !           391: 
        !           392:                /*
        !           393:                 *  get old error file back
        !           394:                 */
        !           395:                close(2);
        !           396:                (void) dup(ofd);
        !           397:                close(ofd);
        !           398:        }
        !           399: 
        !           400:        /*
        !           401:         *  if processing was successful, remove the spool files
        !           402:         */
        !           403:        if(rv==0) {
        !           404:                doremove(name);
        !           405:                return 0;
        !           406:        }
        !           407:        return 1;
        !           408: }
        !           409: 
        !           410: /*
        !           411:  *  remove the control file, data file, and error file
        !           412:  */
        !           413: doremove(ctl)
        !           414:        char *ctl;
        !           415: {
        !           416:        fflush(stdout);
        !           417:        unlink(fileoftype('E', ctl));
        !           418:        unlink(ctl);
        !           419:        unlink(fileoftype('D', ctl));
        !           420: }
        !           421: 
        !           422: /*
        !           423:  *  run rmail.  rmail takes care of its own errors, so if rmail fails,
        !           424:  *  just don't remove the files.
        !           425:  */
        !           426: dormail(dname, ctl)
        !           427:        char *dname;
        !           428:        char *ctl;
        !           429: {
        !           430:        char **av;
        !           431:        int rc;
        !           432: 
        !           433:        /*
        !           434:         *  fork off the command
        !           435:         */
        !           436:        if ((av = getcmd(ctl, "/bin/rmail")) == NULL) {
        !           437:                Syslog(LOG_WARNING, "Could not get rmail params for %s", ctl);
        !           438:                return -1;
        !           439:        }
        !           440: 
        !           441:        if ((rc = docmd(ctl, av)) == 0){
        !           442:                Syslog(LOG_DEBUG, "success");
        !           443:                return 0;
        !           444:        } else {
        !           445:                Syslog(LOG_DEBUG, "failed, rc = %d", rc);
        !           446:                return -1;
        !           447:        }
        !           448: }
        !           449: 
        !           450: /*
        !           451:  *  run smtp.  if an error occurs, determine its importance and send
        !           452:  *  a error mail message if it is fatal.
        !           453:  */
        !           454: dosmtp(dname, ctl)
        !           455:        char *dname;
        !           456:        char *ctl;
        !           457: {
        !           458:        static string *cmd;
        !           459:        int status, i;
        !           460:        char **av;
        !           461:        time_t t0, t1;
        !           462: 
        !           463:        /*
        !           464:         *  fork off the command
        !           465:         */
        !           466:        cmd = s_reset(cmd);
        !           467:        s_append(cmd, UPASROOT);
        !           468:        s_append(cmd, "smtp");
        !           469:        av = getcmd(ctl, s_to_c(cmd));
        !           470:        if (av==NULL) {
        !           471:                Syslog(LOG_WARNING, "Could not get smtp params for %s", ctl);
        !           472:                return -1;
        !           473:        }
        !           474:        /*
        !           475:         * Check whether unsuccessful attempts at this destination
        !           476:         * have taken too much time.  If so, pass over the file.
        !           477:         */
        !           478:        for (i=0; i<ndest; i++) {
        !           479:                if (strcmp(s_to_c(dest), s_to_c(destlist[i].dest))==0) {
        !           480:                        if (destlist[i].time > MAXTPERD) {
        !           481:                                Syslog(LOG_DEBUG, "passed %s (%d sec)\n", s_to_c(dest), destlist[i].time);
        !           482:                                fprintf(stderr, "can't contact destination\n");
        !           483:                                return -1;
        !           484:                        }
        !           485:                        break;
        !           486:                }
        !           487:        }
        !           488:        if (i==ndest) {
        !           489:                if (ndest<MAXDEST)
        !           490:                        ndest++;
        !           491:                else
        !           492:                        i = 0;          /* loses storage */
        !           493: /*
        !           494:  * the following s_copy died on a malformed `C' file.  The
        !           495:  * contents of these files should be checked more carefully. 
        !           496:  */
        !           497:                destlist[i].dest = s_copy(s_to_c(dest));
        !           498:                destlist[i].time = 0;
        !           499:        }
        !           500:        time(&t0);
        !           501:        switch(status=docmd(ctl, av)){
        !           502:        case 0:         /* it worked */
        !           503:                Syslog(LOG_DEBUG, "success\n");
        !           504:                destlist[i].time = 0;
        !           505:                return 0;
        !           506: 
        !           507:        case EX_UNAVAILABLE:    /* service unavailable */
        !           508:        case EX_NOPERM:         /* permission denied */
        !           509:        case EX_NOUSER:         /* rejected by the other side */
        !           510:        case EX_NOHOST:         /* host name unknown */
        !           511:        case EX_DATAERR:        /* data format error */
        !           512:        case EX_USAGE:          /* command line usage error */
        !           513:                Syslog(LOG_INFO, "failed with status %d\n", status);
        !           514:                returnmail(ctl, 1);             /*permanant failure*/
        !           515:                destlist[i].time = 0;
        !           516:                return 0;
        !           517: 
        !           518:        case EX_CANTCREAT:      /* can't create (user) output file */
        !           519:        case EX_IOERR:          /* input/output error */
        !           520:        case EX_OSERR:          /* system error (e.g., can't fork) */
        !           521:        case EX_OSFILE:         /* critical OS file missing */
        !           522:        case EX_SOFTWARE:       /* internal software error */
        !           523:        case EX_NOINPUT:        /* cannot open input */
        !           524:        case EX_PROTOCOL:       /* remote error in protocol */
        !           525:                /* gauss is having flakey datakit errors that confuse the
        !           526:                 * SMTP protocol.  EX_PROTOCOL is a temporary error for gauss-ches*/
        !           527:        case EX_TEMPFAIL:       /* temp failure; user is invited to retry */
        !           528:                Syslog(LOG_INFO, "temp fail with status %d\n", status);
        !           529:                time(&t1);                      /*temporary failure*/
        !           530:                destlist[i].time += t1-t0;
        !           531:                return -1;
        !           532: 
        !           533:        default:        /* possibly a temporary problem */
        !           534:                Syslog(LOG_WARNING, "unknown fail with status %d\n", status);
        !           535:                time(&t1);
        !           536:                destlist[i].time += t1-t0;
        !           537:                return -1;
        !           538:        }
        !           539: }
        !           540: 
        !           541: /*
        !           542:  *  open a control file and parse the first line.  It contains
        !           543:  *  the reply address and the destination (for returning the mail).
        !           544:  *
        !           545:  *  It leaves the control file open and returns the fp.
        !           546:  */
        !           547: FILE *
        !           548: parseline1(ctl)
        !           549:        char *ctl;
        !           550: {
        !           551:        FILE *fp;
        !           552:        static string *line;
        !           553: 
        !           554:        fp = fopen(ctl, "r");
        !           555:        if(fp==NULL)
        !           556:                return NULL;
        !           557: 
        !           558:        /*
        !           559:         *  get reply address and destination
        !           560:         */
        !           561:        line = s_reset(line);
        !           562:        if(s_read_line(fp, line)==NULL){
        !           563:                fprintf(stderr, "smtpsched: error reading ctl file %s: %s\n", ctl,
        !           564:                        s_to_c(line));
        !           565:                fclose(fp);
        !           566:                return NULL;
        !           567:        }
        !           568:        replyaddr = s_parse(s_restart(line), s_reset(replyaddr));
        !           569:        if(replyaddr==NULL){
        !           570:                fprintf(stderr, "smtpsched: error reading ctl file replyaddr %s\n",
        !           571:                        ctl);
        !           572:                fclose(fp);
        !           573:                return NULL;
        !           574:        }
        !           575:        dest = s_parse(line, s_reset(dest));
        !           576:        if(dest==NULL){
        !           577:                fprintf(stderr, "smtpsched: error reading ctl file dest %s\n",
        !           578:                        ctl);
        !           579:                fclose(fp);
        !           580:                return NULL;
        !           581:        }
        !           582:        return fp;
        !           583: }
        !           584: 
        !           585: /*
        !           586:  * Read control file to get arguments for command.  Leave dest and replyaddr
        !           587:  * available.  The control file has two lines.  The first is reply address
        !           588:  * and recipients.  the second is the arguments for the command.
        !           589:  */
        !           590: char **
        !           591: getcmd(ctl, cmd)
        !           592:        char *ctl;
        !           593:        char *cmd;
        !           594: {
        !           595:        static string *args;
        !           596:        FILE *fp;
        !           597:        static char *av[1024];
        !           598:        int ac=0;
        !           599:        char *cp;
        !           600: 
        !           601:        fp = parseline1(ctl);
        !           602:        if (fp==NULL)
        !           603:                return NULL;
        !           604: 
        !           605:        /*
        !           606:         *  make command line
        !           607:         */
        !           608:        av[ac++] = cmd;
        !           609:        args = s_reset(args);
        !           610:        if(s_read_line(fp, args)==NULL){
        !           611:                fprintf(stderr, "smtpsched: error reading ctl file %s\n", ctl);
        !           612:                fclose(fp);
        !           613:                return NULL;
        !           614:        }
        !           615:        fclose(fp);
        !           616:        cp = s_to_c(args);
        !           617:        cp[strlen(cp) - 1] = '\0';      /*zap the newline*/
        !           618:        Syslog(LOG_INFO, "%s <%s", cmd, ctl);
        !           619:        for(cp = s_to_c(args); *cp && ac<1023;){
        !           620:                av[ac++] = cp++;
        !           621:                while(*cp && !isspace(*cp))
        !           622:                        cp++;
        !           623:                while(isspace(*cp))
        !           624:                        *cp++ = 0;
        !           625:        }
        !           626:        av[ac] = 0;
        !           627:        return av;
        !           628: }
        !           629: 
        !           630: /*
        !           631:  *  execute a command, put standard error in the error file.
        !           632:  */
        !           633: docmd(ctl, av)
        !           634:        char *ctl;
        !           635:        char **av;
        !           636: {
        !           637:        int fd;
        !           638:        int pid, status;
        !           639:        int n;
        !           640: 
        !           641:        /*
        !           642:         *  fork off the command
        !           643:         */
        !           644:        switch(pid = fork()){
        !           645:        case -1:
        !           646:                return -1;
        !           647:        case 0:
        !           648:                /*
        !           649:                 *  make data file standard input
        !           650:                 */
        !           651:                close(0);
        !           652:                fd = open(fileoftype('D', ctl), 0);
        !           653:                if(fd<0){
        !           654:                        perror("smtpsched: error reading data file:\n");
        !           655:                        exit(1);
        !           656:                }
        !           657:        
        !           658:                /*
        !           659:                 *  make error file standard output
        !           660:                 */
        !           661:                close(1);
        !           662:                fd = dup(2);
        !           663:        
        !           664:                /*
        !           665:                 *  start the command
        !           666:                 */
        !           667:                execvp(av[0], av);
        !           668:                exit(-2);
        !           669:        default:
        !           670:                /*
        !           671:                 *  wait for the command to terminate
        !           672:                 */
        !           673:                while((n = wait(&status))>=0)
        !           674:                        if(n == pid)
        !           675:                                break;
        !           676:                if(status&0xff)
        !           677:                        return -2;
        !           678:                else
        !           679:                        return (status>>8)&0xff;
        !           680:        }
        !           681: 
        !           682: }
        !           683: 
        !           684: /*
        !           685:  *  see if the number of consumers has been exceeded.  if not, add this process
        !           686:  *  to the list.
        !           687:  *
        !           688:  *  returns 0 if there were the number was not exceeded, -1 otherwise
        !           689:  */
        !           690: toomany(max)
        !           691:        int max;
        !           692: {
        !           693:        FILE *ifp=NULL;
        !           694:        FILE *ofp=NULL;
        !           695:        int cur=0;
        !           696:        int pid;
        !           697: 
        !           698:        /*
        !           699:         *  lock consumers file
        !           700:         */
        !           701:        if(lock(CON)<0)
        !           702:                return -1;
        !           703: 
        !           704:        /*
        !           705:         *  open old and new consumer files
        !           706:         */
        !           707:        ofp = fopen(NCON, "w");
        !           708:        if(ofp==NULL){
        !           709:                fprintf(stderr, "can't open %s\n", NCON);
        !           710:                goto error;
        !           711:        }
        !           712:        ifp = fopen(CON, "r");
        !           713:        if(ifp!=NULL){
        !           714:                /*
        !           715:                 *  see how many consumers are still around
        !           716:                 */
        !           717:                while(fscanf(ifp, "%d", &pid)==1){
        !           718:                        if(kill(pid, 0) == 0){
        !           719:                                cur++;
        !           720:                                if(fprintf(ofp, "%d\n", pid)<0){
        !           721:                                        fprintf(stderr, "error writing %s\n", NCON);
        !           722:                                        goto error;
        !           723:                                }
        !           724:                        }
        !           725:                }
        !           726:                if(cur >= max)
        !           727:                        goto error;
        !           728:        }
        !           729: 
        !           730:        /*
        !           731:         *  add us to the group of consumers
        !           732:         */
        !           733:        if(fprintf(ofp, "%d\n", getpid())<0){
        !           734:                fprintf(stderr, "error writing %s\n", NCON);
        !           735:                goto error;
        !           736:        }
        !           737:        if(ifp!=NULL)
        !           738:                fclose(ifp);
        !           739:        if(fclose(ofp)==EOF)
        !           740:                goto error;
        !           741:        unlink(CON);
        !           742:        if(link(NCON, CON)<0)
        !           743:                fprintf(stderr, "can't link %s to %s file\n", CON, NCON);
        !           744:        unlink(NCON);
        !           745:        unlock(CON);
        !           746:        return 0;
        !           747: error:
        !           748:        /*
        !           749:         *  too many consumers or we can't make a new consumer file
        !           750:         */
        !           751:        if(ifp!=NULL)
        !           752:                fclose(ifp);
        !           753:        if(ofp!=NULL)
        !           754:                fclose(ofp);
        !           755:        unlink(NCON);
        !           756:        unlock(CON);
        !           757:        return -1;
        !           758: }
        !           759: 
        !           760: /*
        !           761:  *  return true if the file is inconsistent.  The following are inconsistent:
        !           762:  *     - a control file without a datafile
        !           763:  *     - an error file without a datafile
        !           764:  *     - a day old data file without a control file
        !           765:  *     - a limit file of any kind
        !           766:  */
        !           767: inconsistent(file)
        !           768:        char *file;
        !           769: {
        !           770:        struct stat s;
        !           771:        int days;
        !           772: 
        !           773:        /*
        !           774:         *  switch on file type
        !           775:         */
        !           776:        switch(file[0]){
        !           777:        case 'C':
        !           778:        case 'X':
        !           779:                /*
        !           780:                 *  if no data file, control file is inconsistent
        !           781:                 */
        !           782:                if(stat(fileoftype('D', file), &s)<0)
        !           783:                        return 1;
        !           784:                break;
        !           785:        case 'E':
        !           786:                /*
        !           787:                 *  if no control file, error file is inconsistent
        !           788:                 */
        !           789:                if(stat(fileoftype('X', file), &s)<0
        !           790:                && stat(fileoftype('C', file), &s)<0)
        !           791:                        return 1;
        !           792: 
        !           793:                /*
        !           794:                 *  if no data file, error file is inconsistent
        !           795:                 */
        !           796:                if(stat(fileoftype('D', file), &s)<0)
        !           797:                        return 1;
        !           798:                break;
        !           799:        case 'D':
        !           800:                /*
        !           801:                 *  look for a control file
        !           802:                 */
        !           803:                if(stat(fileoftype('X', file), &s)==0
        !           804:                || stat(fileoftype('C', file), &s)==0)
        !           805:                        break;
        !           806: 
        !           807:                /*
        !           808:                 *  no control file, data file inconsistent if >=1 day old
        !           809:                 */
        !           810:                if(stat(file, &s)<0)
        !           811:                        return 0;
        !           812:                days = (time((long *)0) - s.st_ctime)/(24*60*60);
        !           813:                if(days>0)
        !           814:                        return 1;
        !           815:                break;
        !           816:        default:
        !           817:                break;
        !           818:        }
        !           819:        return 0;
        !           820: }
        !           821: 
        !           822: /*
        !           823:  *  check the age of a file.  if it is greater than warn or remove, tell the
        !           824:  *  sender.  return 0 if the file is to be removed, -1 otherwise.
        !           825:  */
        !           826: checkage(ctl)
        !           827:        char *ctl;
        !           828: {
        !           829:        struct stat s;
        !           830:        int days;
        !           831:        char buf[256];
        !           832:        FILE *fp;
        !           833: 
        !           834:        /*
        !           835:         *  get the file's age
        !           836:         */
        !           837:        if(stat(ctl, &s)<0)
        !           838:                return -1;
        !           839:        days = (time((long *)0) - s.st_ctime)/(24*60*60);
        !           840: 
        !           841:        /*
        !           842:         *  check for removal
        !           843:         */
        !           844:        if(removedays>=0 && days>=removedays){
        !           845:                fp = parseline1(ctl);
        !           846:                if(fp==NULL)
        !           847:                        return -1;
        !           848:                fclose(fp);
        !           849: 
        !           850:                Syslog(LOG_INFO,"returning mail to %s orig to %s after %d days",
        !           851:                        s_to_c(replyaddr), s_to_c(dest), days);
        !           852:                return returnmail(ctl, 1);
        !           853:        }
        !           854: 
        !           855:        /*
        !           856:         *  check for warning
        !           857:         */
        !           858:        if(warn>=0 && days>=warn){
        !           859:                fp = parseline1(ctl);
        !           860:                if(fp==NULL)
        !           861:                        return -1;
        !           862:                fclose(fp);
        !           863: 
        !           864:                Syslog(LOG_INFO, "warning %s about %s after %d days",
        !           865:                        s_to_c(replyaddr), s_to_c(dest), days);
        !           866:                returnmail(ctl, 0);
        !           867:        }
        !           868: 
        !           869:        return -1;
        !           870: }
        !           871: 
        !           872: /*
        !           873:  *  return a piece of mail with a reason for the return
        !           874:  */
        !           875: returnmail(ctl, warn)
        !           876:        char *ctl;
        !           877: {
        !           878:        int pid, status;
        !           879:        string *cmd;
        !           880:        int pfd[2];
        !           881:        char buf[132];
        !           882:        int fd, n;
        !           883:        int reads;
        !           884:        FILE *fp;
        !           885:        FILE *ifp;
        !           886:        long now;
        !           887:        char asct[27];
        !           888: 
        !           889:        if(pipe(pfd)<0)
        !           890:                return -1;
        !           891: 
        !           892:        switch(pid=fork()){
        !           893:        case -1:
        !           894:                close(pfd[0]);
        !           895:                close(pfd[1]);
        !           896:                return -1;
        !           897:        case 0:
        !           898:                /*
        !           899:                 *  start up the mailer to take the refusal message
        !           900:                 */
        !           901:                close(0);
        !           902:                dup(pfd[0]);
        !           903:                close(pfd[1]);
        !           904:                execl("/bin/rmail", "/bin/rmail",  s_to_c(replyaddr), 0);
        !           905:                exit(1);
        !           906:        default:
        !           907:                /*
        !           908:                 *  pipe the refusal message to the mailer
        !           909:                 */
        !           910:                close(pfd[0]);
        !           911:                fp = fdopen(pfd[1], "w");
        !           912:                if(fp==NULL) {
        !           913:                        close(pfd[1]);
        !           914:                        break;
        !           915:                }
        !           916: 
        !           917:                /*
        !           918:                 *  the From line
        !           919:                 */
        !           920:                now = time((long *)0);
        !           921:                strcpy(asct, ctime(&now));
        !           922:                asct[24] = 0;
        !           923:                fprintf(fp, "From postmaster %s remote from \n", asct);
        !           924: 
        !           925:                /*
        !           926:                 *  the refusal message
        !           927:                 */
        !           928:                if(warn) {
        !           929:                        fprintf(fp, "Subject: smtp mail failed\n\n");
        !           930:                        fprintf(fp, "Your mail to %s is undeliverable.\n",
        !           931:                                s_to_c(dest));
        !           932:                } else {
        !           933:                        fprintf(fp, "Subject: smtp mail warning\n\n");
        !           934:                        fprintf(fp, "Your mail to %s is not yet delivered.\n",
        !           935:                                s_to_c(dest));
        !           936:                        fprintf(fp, "Delivery attempts continue.\n");
        !           937:                }
        !           938: 
        !           939:                /*
        !           940:                 *  then diagnosis of error
        !           941:                 */
        !           942:                fprintf(fp, "---------- diagnosis ----------\n");
        !           943:                ifp = fopen(fileoftype('E', ctl), "r");
        !           944:                if(ifp!=NULL){
        !           945:                        for(reads=0; reads<20; reads++) {
        !           946:                                if(fgets(buf, sizeof(buf), ifp)==NULL)
        !           947:                                        break;
        !           948:                                fputs(buf, fp);
        !           949:                        }
        !           950:                        fclose(ifp);
        !           951:                }
        !           952: 
        !           953:                /*
        !           954:                 *  finally the message itself
        !           955:                 */
        !           956:                fprintf(fp, "---------- unsent mail ----------\n");
        !           957:                ifp = fopen(fileoftype('D', ctl), "r");
        !           958:                if(ifp!=NULL){
        !           959:                        for(reads=0; reads<50; reads++) {
        !           960:                                if(fgets(buf, sizeof(buf), ifp)==NULL)
        !           961:                                        break;
        !           962:                                fputs(buf, fp);
        !           963:                        }
        !           964:                        fclose(ifp);
        !           965:                }
        !           966:                fclose(fp);
        !           967: 
        !           968:                /*
        !           969:                 *  wait for the warning to finish
        !           970:                 */
        !           971:                while((n = wait(&status))>=0)
        !           972:                        if(n == pid)
        !           973:                                break;
        !           974:                return status ? -1 : 0;
        !           975:        }
        !           976:        close(pfd[1]);
        !           977:        return -1;
        !           978: }

unix.superglobalmegacorp.com

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