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

unix.superglobalmegacorp.com

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