Annotation of coherent/d/etc/SYSVcron/src/cron.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  *     The information contained herein is a trade secret of Mark Williams
                      3:  *     Company, and  is confidential information.  It is provided  under a
                      4:  *     license agreement,  and may be  copied or disclosed  only under the
                      5:  *     terms of  that agreement.  Any  reproduction or disclosure  of this
                      6:  *     material without the express written authorization of Mark Williams
                      7:  *     Company or persuant to the license agreement is unlawful.
                      8:  *
                      9:  *     An unpublished work by Mark Williams Company, Chicago.
                     10:  *     All rights reserved.
                     11:  */
                     12: 
                     13: /* cron.c
                     14:  *
                     15:  * Execute commands stored in /usr/lib/crontab if it exist (3.2.0 compatibility)
                     16:  * as daemon.
                     17:  * Otherwise execute crontabs from /usr/spool/cron/crontabs.
                     18:  * It sets uid and gid to user which crontab is going to be executed.
                     19:  *
                     20:  * $ 12-10-1991 vlad (Vladimir Smelyansky)
                     21:  *
                     22:  */
                     23: #include <stdio.h>
                     24: #include <time.h>
                     25: #include <signal.h>
                     26: #include <errno.h>
                     27: #include <ctype.h>
                     28: #include <pwd.h>
                     29: #include <sys/types.h>
                     30: #include <dirent.h>
                     31: #include "cron.h"
                     32: 
                     33: /*
                     34:  * Time field types.
                     35:  */
                     36: #define        MIN     0
                     37: #define HOUR   1
                     38: #define        MDAY    2
                     39: #define        MON     3
                     40: #define WDAY   4
                     41: 
                     42: /*
                     43:  * (Finite) States in valid().
                     44:  */
                     45: #define START  0
                     46: #define INT    1
                     47: #define INTDASH        2
                     48: #define RANGE  3
                     49: #define STR    4
                     50: #define STRPLUS        5
                     51: #define ERR    6
                     52: #define END    7
                     53: #define GLOB   ('*')
                     54: 
                     55: /*
                     56:  * Tokens returned by gettoken(). Tokens are integers. EOF is also a token.
                     57:  * INT, STR and GLOB above are also tokens.
                     58:  */
                     59: #define DASH   ('-')
                     60: #define COMMA  (',')
                     61: #define WS     (' ')
                     62: #define PERCENT        (-2)
                     63: #define NEWLINE (-3)
                     64: 
                     65: extern DIR             *opendir();
                     66: extern struct dirent   *readdir();
                     67: extern char            *realloc();
                     68: 
                     69: extern int     set_uid();      /* Set UID */
                     70: extern FILE    *fpOpenTable(); /* Open crintable */
                     71: extern int     lock();         /* Write a lock file */
                     72: extern FILE    *cronpipe();    /* Popen for cron */
                     73: 
                     74: extern void    mail_entry();   /* Send mail to user if command failed */
                     75: extern child_id        *add_entry(),   /* Add an new entry to a link list */
                     76:                *find_entry(),  /* Find an entry in the link list */
                     77:                *del_entry();   /* Remove an entry from the link list */
                     78: 
                     79: int ifmail();
                     80: 
                     81: child_id       *current;       /* Pointer to the current structure */
                     82: char   acRealUser[MAX_UNAME];  /* Real user name */
                     83: 
                     84: int    mailFlag = TRUE;
                     85: int    flag320 = FALSE;
                     86: int    logflag;
                     87: 
                     88: struct tm *tm;
                     89: time_t clock;
                     90: int    tmfield[5];
                     91: FILE   *f;
                     92: extern int     errno;
                     93: 
                     94: int    ugtokflag = FALSE;
                     95: int    ugtoken;
                     96: int    ufetflag = FALSE;
                     97: int    ufetval;
                     98: int    set_uid_flag = FALSE;
                     99: 
                    100: char   *tokbuf;
                    101: int    buflen = MAX_STR_LEN;
                    102: char   crontab[] = "/usr/lib/crontab";
                    103: DIR    *dirp = NULL;
                    104: struct dirent  *dp;
                    105: 
                    106: main()
                    107: {
                    108:        int     n;
                    109:        int     child_pid;
                    110: 
                    111:        sigsetup();
                    112: 
                    113:        tokbuf = malloc(buflen);
                    114:        /* Check if cron should be in COHERENT 3.2.0 mode */
                    115:        if ((f = fopen(crontab, "r")) != NULL) {
                    116:                fclose(f);
                    117:                chdir("/bin");  /* Under 3.2.0 cron started from /bin. */
                    118:                flag320 = TRUE;
                    119:        } else  /* Check if cron was fired. Do it only for SV cron. */
                    120:                if (lock(F_LOCK) == FALSE) {
                    121:                        fprintf(stderr, "cron: locked.\n");
                    122:                        exit(1);
                    123:                }
                    124: 
                    125: #if !DEBUG
                    126:        /* Disassociate from controling terminal and process
                    127:         * group. Close all open files.
                    128:         */
                    129:        bedaemon();
                    130: #endif                 
                    131:        /* Open spool directory. SV mode  */
                    132:        if (flag320 == FALSE) {
                    133:                sleep(10);      /* Allows to mount all */
                    134:                if ((dirp = opendir(D_SPOOL)) == NULL) {
                    135:                        system("echo cron: cannot open spool directory"
                    136:                           " > /dev/console");
                    137:                        exit(1);
                    138:                }
                    139:                if (logflag = if_log()) 
                    140:                        if (freopen(F_LOG, "a", stderr) == NULL) {
                    141:                                fprintf(stderr, 
                    142:                                   "cron: cannot open log file %s\n", F_LOG);
                    143:                                exit(1);
                    144:                        }
                    145:        }
                    146:                        
                    147:        time(&clock);
                    148:        tm = localtime(&clock);
                    149:        alarm(61 - tm->tm_sec);
                    150: 
                    151:        Dprint("Time is %s\n", ctime(&clock));
                    152:        for (;;) {
                    153:                /* Put the time values into tmfield[] for easy reference.
                    154:                 * localtime() gives tm_mon in the range 0-11, tm_wday, 0-6
                    155:                 * (0=sunday). These are adjusted for cron's syntax.
                    156:                 */
                    157:                tmfield[MIN]    = tm->tm_min;
                    158:                tmfield[HOUR]   = tm->tm_hour;
                    159:                tmfield[MDAY]   = tm->tm_mday;
                    160:                tmfield[MON]    = tm->tm_mon + 1;
                    161:                tmfield[WDAY]   = tm->tm_wday;
                    162: 
                    163:                if (flag320 == TRUE) {          /* Run 320 mode */
                    164:                        if ((f = fopen(crontab, "r")) != NULL) {
                    165:                                Dprint("File pointer is 0x%x\n", f);
                    166:                                strcpy(acRealUser, DAEMON);
                    167:                                while (tex() != EOF)
                    168:                                        ;
                    169:                                fclose(f);
                    170:                                while (wait(&n) != -1) 
                    171:                                        ;
                    172:                                if (errno == ECHILD)
                    173:                                        pause();
                    174:                        } else
                    175:                                fprintf(stderr, "cron: cannot open %s\n", 
                    176:                                                crontab);
                    177:                } else {                        /* Run SV mode */
                    178:                        while ((dp = readdir(dirp)) != NULL) {
                    179:                                char    Dbuf[80];
                    180: 
                    181:                                /* Skip '.' and '..' */
                    182:                                if (!strcmp(dp->d_name, ".") ||
                    183:                                                !strcmp(dp->d_name, ".."))
                    184:                                        continue;
                    185:                
                    186:                                strcpy(acRealUser, dp->d_name);
                    187: 
                    188:                                Dprint("User name is %s\n", acRealUser);
                    189:                                set_uid_flag = FALSE; 
                    190: 
                    191:                                if ((f = fpOpenTable("r")) == NULL) {
                    192:                                        sprintf(Dbuf,"cron: cannot open table"
                    193:                                           " '%s' > /dev/console", acRealUser);
                    194:                                        system(Dbuf);
                    195:                                }
                    196:                                while (tex() != EOF)
                    197:                                        ;
                    198:                                fclose(f);
                    199:                        } /* while readdir */
                    200:                        rewinddir(dirp);
                    201:                        /* Wait for the children */
                    202:                        while ((child_pid = wait(&n)) != -1) {
                    203:                                static child_id *pstDone;
                    204: 
                    205:                                Dprint("\nmain: child id %d",child_pid);
                    206:                                Dprint("\treturn is %d\n", n);
                    207:                                pstDone = find_entry(child_pid);
                    208:                                if (n) {
                    209:                                        if (ifmail(pstDone))
                    210:                                                mail_entry(pstDone);
                    211:                                        if (logflag == TRUE)
                    212:                                                fprintf(stderr, "User %s."
                    213:                                                 "Time %sCommand \"%s\".\n\n", 
                    214:                                                      pstDone->name, 
                    215:                                                      ctime(&(pstDone->time)), 
                    216:                                                      pstDone->command);
                    217:                                }
                    218:                                current = del_entry(pstDone);
                    219:                                Dprint("main: current is %d\n", current->pid);
                    220:                        } /* while wait */
                    221:                        if (errno == ECHILD)
                    222:                                pause();
                    223:                        
                    224:                } /* if 320 */
                    225:        } /* for */
                    226: } /* main */
                    227: 
                    228: /*
                    229:  * Check do user want to have a mail messages. 
                    230:  */
                    231: int ifmail(entry)
                    232: child_id       *entry;
                    233: {
                    234:        char    *cBuf;
                    235:        int     fd;     /* Descriptor of lock file */
                    236: 
                    237:        if ((cBuf = malloc(sizeof(D_MAIN) + strlen(entry->name) + 1)) == NULL) {
                    238:                fprintf(stderr, "cron: out of memory\n");
                    239:                return(0);      
                    240:        }
                    241:        sprintf(cBuf, "%s/%s", D_MAIN, entry->name);
                    242:        fd = open(cBuf, 0);
                    243:        free(cBuf);
                    244:        if (fd == -1)
                    245:                return(1);
                    246:        close(fd);
                    247:        return(0);
                    248: }
                    249: 
                    250: /*
                    251:  * Test and Execute: tests a crontab entry against the time fields in `tm' to
                    252:  * see if it should be executed, if so it executes. f is left pointing to the
                    253:  * next entry (line). Returns EOF when encountered, something else otherwise.
                    254:  */
                    255: tex()
                    256: {
                    257:        register int fieldnum;
                    258: 
                    259:        for (fieldnum = MIN; fieldnum <= WDAY; ++fieldnum)
                    260:                if (!valid(fieldnum))
                    261:                        return (skip_it());
                    262:        return (do_it());
                    263: }
                    264: 
                    265: /*
                    266:  * Valid(fieldnum) parses the next time field from the current line in crontab
                    267:  * and checks whether tmfield[fieldnum] satisfies the constraints of that time
                    268:  * field. Returns TRUE if so, FALSE if not. Leaves f at the next field.
                    269:  * Detects syntax errors in the time fields.
                    270:  */
                    271: valid(fieldnum)
                    272: int fieldnum;
                    273: {
                    274:        register int t;
                    275:        register int ival;
                    276:        register int state = START;
                    277:        int ival2;
                    278:        int tm_val = tmfield[fieldnum];
                    279: 
                    280:        if (fieldnum == MIN) {
                    281:                while ((t = gettoken()) == WS  ||  t == NEWLINE)
                    282:                        ;
                    283:                ungettoken(t);
                    284:        }
                    285: 
                    286:        for (;;) {
                    287:                t = gettoken();
                    288:                switch (state) {
                    289:                case START:
                    290:                        switch (t) {
                    291:                        case INT:
                    292:                                if (strlen(tokbuf) <= 2) {
                    293:                                        ival = atoi(tokbuf);
                    294:                                        state = INT;
                    295:                                }
                    296:                                else
                    297:                                        state = ERR;
                    298:                                break;
                    299:                        case GLOB:
                    300:                                state = GLOB;
                    301:                                break;
                    302:                        case WS:
                    303:                                state = END;
                    304:                                break;
                    305:                        default:
                    306:                                state = ERR;
                    307:                                break;
                    308:                        }
                    309:                        break;
                    310:                case INT:
                    311:                        if (t == COMMA  ||  t == WS) {
                    312:                                if (ival == tm_val) {
                    313:                                        while (t != WS)
                    314:                                                t = gettoken();
                    315:                                        return (TRUE);
                    316:                                }
                    317:                                state = (t == WS) ? END : START;
                    318:                        }
                    319:                        else if (t == DASH)
                    320:                                state = INTDASH;
                    321:                        else
                    322:                                state = ERR;
                    323:                        break;
                    324:                case INTDASH:
                    325:                        if (t == INT  &&  strlen(tokbuf) <= 2) {
                    326:                                ival2 = atoi(tokbuf);
                    327:                                state = RANGE;
                    328:                        }
                    329:                        else
                    330:                                state = ERR;
                    331:                        break;
                    332:                case RANGE:
                    333:                        if (t == COMMA  ||  t == WS) {
                    334:                                if (ival <= tm_val  &&  tm_val <= ival2) {
                    335:                                        while (t != WS)
                    336:                                                t = gettoken();
                    337:                                        return (TRUE);
                    338:                                }
                    339:                                state = (t == WS) ? END : START;
                    340:                        }
                    341:                        else
                    342:                                state = ERR;
                    343:                        break;
                    344:                case GLOB:
                    345:                        if (t == COMMA  ||  t == WS) {
                    346:                                while (t != WS)
                    347:                                        t = gettoken();
                    348:                                return (TRUE);
                    349:                        }
                    350:                        else
                    351:                                state = ERR;
                    352:                        break;
                    353:                }               /* End switch on state */
                    354: 
                    355:                if (state == END)
                    356:                        return (FALSE);
                    357:                if (state == ERR) {
                    358:                        ungettoken(t);
                    359:                        ungettoken(skip_it());
                    360:                        return (FALSE);
                    361:                }
                    362:        }
                    363: }
                    364: 
                    365: 
                    366: ungettoken(t)
                    367: int t;
                    368: {
                    369:        ugtokflag = TRUE;
                    370:        ugtoken = t;
                    371: }
                    372: 
                    373: gettoken()
                    374: {
                    375:        register int c;
                    376:        register char *sp = tokbuf;
                    377:        register char *mark;
                    378:        int posn;
                    379: 
                    380:        if (ugtokflag) {
                    381:                ugtokflag = FALSE;
                    382:                return (ugtoken);
                    383:        }
                    384: 
                    385:        switch (c = fetch()) {
                    386:        case NEWLINE:
                    387:        case EOF:
                    388:        case PERCENT:
                    389:                return (c);
                    390:        case ' ':
                    391:        case '\t':
                    392:                while ((c = fetch()) == ' '  ||  c == '\t')
                    393:                        ;
                    394:                unfetch(c);
                    395:                return (WS);
                    396:        case '-':
                    397:                return (DASH);
                    398:        case ',':
                    399:                return (COMMA);
                    400:        case '*':
                    401:                return (GLOB);
                    402:        }
                    403: 
                    404: 
                    405:        /*
                    406:         * Case of INT. Place ascii digit string into tokbuf.
                    407:         */
                    408:        if (isdigit(c)) {
                    409:                *sp++ = c;
                    410:                while (isdigit(c = fetch()))
                    411:                        *sp++ = c;
                    412:                unfetch(c);
                    413:                *sp = '\0';
                    414:                return (INT);
                    415:        }
                    416: 
                    417:        /*
                    418:         * The only remaining possibility is the token STR or STRPLUS.
                    419:         */
                    420:        *sp++ = c;
                    421:        mark = tokbuf + buflen - 2;
                    422:        while ((c = fetch()) != EOF  &&  c != NEWLINE  &&  c != PERCENT) {
                    423:                if (sp == mark) {
                    424:                        posn = sp - tokbuf;
                    425:                        Dprint("cron: realloc on %d bytes\n", 128);
                    426:                        tokbuf = realloc(tokbuf, (buflen += 128));
                    427:                        sp = tokbuf + posn;
                    428:                        mark = sp + buflen;
                    429:                }
                    430:                *sp++ = c;
                    431:        }
                    432:        *sp = '\0';
                    433:        if (c == PERCENT)
                    434:                return (STRPLUS);
                    435:        unfetch(c);
                    436:        return (STR);
                    437: }
                    438: 
                    439: 
                    440: unfetch(c)
                    441: int c;
                    442: {
                    443:        ufetval = c;
                    444:        ufetflag = TRUE;
                    445: }
                    446: 
                    447: fetch()
                    448: {
                    449:        register int c;
                    450:        register int c2;
                    451: 
                    452:        if (ufetflag) {
                    453:                ufetflag = FALSE;
                    454:                return (ufetval);
                    455:        }
                    456: 
                    457:        for (;;)
                    458:                switch (c = getc(f)) {
                    459:                case '%':
                    460:                        return (PERCENT);
                    461:                case '\n':
                    462:                        return (NEWLINE);
                    463:                case '\\':
                    464:                        if ((c2 = getc(f)) == '%')
                    465:                                return ('%');
                    466:                        else if (c2 == '\n')
                    467:                                continue;
                    468:                        else {
                    469:                                ungetc(c2, f);
                    470:                                return ('\\');
                    471:                        }
                    472:                default:
                    473:                        return (c);
                    474:                }
                    475: }
                    476: 
                    477: 
                    478: skip_it()
                    479: {
                    480:        register int t;
                    481: 
                    482:        while ((t = gettoken()) != EOF  &&  t != NEWLINE)
                    483:                ;
                    484:        return (t);
                    485: }
                    486: 
                    487: do_it()
                    488: {
                    489:        register int c;
                    490:        register FILE *fp;
                    491: 
                    492:        if ((c = gettoken()) != STR  &&  c != STRPLUS) {
                    493:                ungettoken(c);
                    494:                return (skip_it());
                    495:        }
                    496:        
                    497:        Dprint("Tokken is %s\n", tokbuf);
                    498: 
                    499:        if ((fp = cronpipe(tokbuf, "w")) == NULL) {
                    500:                fprintf(stderr, "cron:\tCould not popen: %s\n\t\
                    501:                                errno = %d\n", tokbuf, errno);
                    502:                return (skip_it());
                    503:        }
                    504: 
                    505:        if (c == STR) {
                    506:                fclose(fp);
                    507:                return (gettoken());
                    508:        }
                    509:        while ((c = fetch()) != NEWLINE  &&  c != EOF)
                    510:                if (c == PERCENT)
                    511:                        putc('\n', fp);
                    512:                else
                    513:                        putc(c, fp);
                    514:        putc('\n', fp);
                    515:        fclose(fp);
                    516:        return(c);
                    517: }
                    518: 
                    519: /*
                    520:  * We have to catch all signals.
                    521:  * Ignore signals INT, HUP, & PIPE.
                    522:  * Reset time on ALRM.
                    523:  * Remove lock file and take default action on the rest of them.
                    524:  */
                    525: sigsetup()
                    526: {
                    527:        register int    i;
                    528:        int             catchalarm();   /* Catch alarm signal */
                    529:        int             catchsignals(); /* Catch all signals */
                    530: 
                    531:        for (i = 1; i < NSIG; i++)
                    532:                signal(i, catchsignals);
                    533: 
                    534:        signal(SIGINT, SIG_IGN);
                    535:        signal(SIGHUP, SIG_IGN);
                    536:        signal(SIGPIPE, SIG_IGN);
                    537:        signal(SIGALRM, catchalarm);
                    538:        signal(SIGCLD, SIG_DFL);
                    539: }
                    540: 
                    541: /*
                    542:  * Remove lock file. Restore default action. Send the catched signal to itself.
                    543:  */
                    544: int catchsignals(sig)
                    545: int    sig;
                    546: {
                    547:        unlink(F_LOCK);         /* Remove lock FIFO. Do not care if unlink */
                    548:                                /* failed (case cron 3.2.0) */
                    549:        Dprint("Remove lock file %s\n", F_LOCK);
                    550:        signal(sig, SIG_DFL);   /* Reset to default */
                    551:        kill(getpid(), sig);    /* Send catched signal */
                    552:        wait(); 
                    553: }
                    554: 
                    555: /* 
                    556:  * Catch alarm.
                    557:  */
                    558: int catchalarm()
                    559: {
                    560:        signal(SIGALRM, catchalarm);
                    561:        time(&clock);
                    562:        tm = localtime(&clock);
                    563:        alarm(61 - tm->tm_sec);
                    564: }
                    565: 

unix.superglobalmegacorp.com

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