home *** CD-ROM | disk | FTP | other *** search
/ Nebula / nebula.bin / SourceCode / CronVixie2.1 / misc.c < prev    next >
C/C++ Source or Header  |  1992-01-14  |  14KB  |  700 lines

  1. #if !defined(lint) && !defined(LINT)
  2. static char rcsid[] = "$Header: misc.c,v 2.1 90/07/18 00:24:33 vixie Exp $";
  3. #endif
  4.  
  5. /* vix 26jan87 [RCS has the rest of the log]
  6.  * vix 15jan87 [added TIOCNOTTY, thanks csg@pyramid]
  7.  * vix 30dec86 [written]
  8.  */
  9.  
  10. /* Copyright 1988,1990 by Paul Vixie
  11.  * All rights reserved
  12.  *
  13.  * Distribute freely, except: don't remove my name from the source or
  14.  * documentation (don't take credit for my work), mark your changes (don't
  15.  * get me blamed for your possible bugs), don't alter or remove this
  16.  * notice.  May be sold if buildable source is provided to buyer.  No
  17.  * warrantee of any kind, express or implied, is included with this
  18.  * software; use at your own risk, responsibility for damages (if any) to
  19.  * anyone resulting from the use of this software rests entirely with the
  20.  * user.
  21.  *
  22.  * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  23.  * I'll try to keep a version up to date.  I can be reached as follows:
  24.  * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
  25.  * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
  26.  */
  27.  
  28.  
  29. #include "cron.h"
  30. #include <sys/time.h>
  31. #include <sys/resource.h>
  32. #include <sys/ioctl.h>
  33. #include <sys/file.h>
  34. #include <errno.h>
  35. #if defined(ATT)
  36. # include <fcntl.h>
  37. #endif
  38.  
  39.  
  40. void log_it(), be_different(), acquire_daemonlock();
  41.  
  42.  
  43. char *
  44. savestr(str)
  45.     char    *str;
  46. {
  47.     extern    int    strlen();
  48.     extern    char    *malloc(), *strcpy();
  49.     /**/    char    *temp;
  50.  
  51.     temp = malloc((unsigned) (strlen(str) + 1));
  52.     (void) strcpy(temp, str);
  53.     return temp;
  54. }
  55.  
  56.  
  57. int
  58. nocase_strcmp(left, right)
  59.     char    *left;
  60.     char    *right;
  61. {
  62.     while (*left && (MkLower(*left) == MkLower(*right)))
  63.     {
  64.         left++;
  65.         right++;
  66.     }
  67.     return MkLower(*left) - MkLower(*right);
  68. }
  69.  
  70.  
  71. int
  72. strcmp_until(left, right, until)
  73.     char    *left;
  74.     char    *right;
  75.     char    until;
  76. {
  77.     register int    diff;
  78.  
  79.     Debug(DPARS|DEXT, ("strcmp_until(%s,%s,%c) ... ", left, right, until))
  80.  
  81.     while (*left && *left != until && *left == *right)
  82.     {
  83.         left++;
  84.         right++;
  85.     }
  86.  
  87.     if (    (*left=='\0' || *left == until) 
  88.         &&    (*right=='\0' || *right == until)
  89.        )
  90.         diff = 0;
  91.     else
  92.         diff = *left - *right;
  93.  
  94.     Debug(DPARS|DEXT, ("%d\n", diff))
  95.  
  96.     return diff;
  97. }
  98.  
  99.  
  100. /* strdtb(s) - delete trailing blanks in string 's' and return new length
  101.  */
  102. int
  103. strdtb(s)
  104.     register char    *s;
  105. {
  106.     register char    *x = s;
  107.  
  108.     /* scan forward to the null
  109.      */
  110.     while (*x)
  111.         x++;
  112.  
  113.     /* scan backward to either the first character before the string,
  114.      * or the last non-blank in the string, whichever comes first.
  115.      */
  116.     do    {x--;}
  117.     while (x >= s && isspace(*x));
  118.  
  119.     /* one character beyond where we stopped above is where the null
  120.      * goes.
  121.      */
  122.     *++x = '\0';
  123.  
  124.     /* the difference between the position of the null character and
  125.      * the position of the first character of the string is the length.
  126.      */
  127.     return x - s;
  128. }
  129.  
  130.  
  131. int
  132. set_debug_flags(flags)
  133.     char    *flags;
  134. {
  135.     /* debug flags are of the form    flag[,flag ...]
  136.      *
  137.      * if an error occurs, print a message to stdout and return FALSE.
  138.      * otherwise return TRUE after setting ERROR_FLAGS.
  139.      */
  140.  
  141. #if !DEBUGGING
  142.  
  143.     printf("this program was compiled without debugging enabled\n");
  144.     return FALSE;
  145.  
  146. #else /* DEBUGGING */
  147.  
  148.     char    *pc = flags;
  149.  
  150.     DebugFlags = 0;
  151.  
  152.     while (*pc)
  153.     {
  154.         char    **test;
  155.         int    mask;
  156.  
  157.         /* try to find debug flag name in our list.
  158.          */
  159.         for (    test = DebugFlagNames, mask = 1;
  160.             *test && strcmp_until(*test, pc, ',');
  161.             test++, mask <<= 1
  162.             )
  163.             ;
  164.  
  165.         if (!*test)
  166.         {
  167.             fprintf(stderr,
  168.                 "unrecognized debug flag <%s> <%s>\n",
  169.                 flags, pc);
  170.             return FALSE;
  171.         }
  172.  
  173.         DebugFlags |= mask;
  174.  
  175.         /* skip to the next flag
  176.          */
  177.         while (*pc && *pc != ',')
  178.             pc++;
  179.         if (*pc == ',')
  180.             pc++;
  181.     }
  182.  
  183.     if (DebugFlags)
  184.     {
  185.         int    flag;
  186.  
  187.         fprintf(stderr, "debug flags enabled:");
  188.  
  189.         for (flag = 0;  DebugFlagNames[flag];  flag++)
  190.             if (DebugFlags & (1 << flag))
  191.                 fprintf(stderr, " %s", DebugFlagNames[flag]);
  192.         fprintf(stderr, "\n");
  193.     }
  194.  
  195.     return TRUE;
  196.  
  197. #endif /* DEBUGGING */
  198. }
  199.  
  200.  
  201. #if defined(BSD)
  202. void
  203. set_cron_uid()
  204. {
  205.     int    seteuid();
  206.  
  207.     if (seteuid(ROOT_UID) < OK)
  208.     {
  209.         perror("seteuid");
  210.         exit(ERROR_EXIT);
  211.     }
  212. }
  213. #endif
  214.  
  215. #if defined(ATT)
  216. void
  217. set_cron_uid()
  218. {
  219.     int    setuid();
  220.  
  221.     if (setuid(ROOT_UID) < OK)
  222.     {
  223.         perror("setuid");
  224.         exit(ERROR_EXIT);
  225.     }
  226. }
  227. #endif
  228.  
  229. void
  230. set_cron_cwd()
  231. {
  232.     extern int    errno;
  233.     struct stat    sb;
  234.  
  235.     /* first check for CRONDIR ("/var/cron" or some such)
  236.      */
  237.     if (stat(CRONDIR, &sb) < OK && errno == ENOENT) {
  238.         perror(CRONDIR);
  239.         if (OK == mkdir(CRONDIR, 0700)) {
  240.             fprintf(stderr, "%s: created\n", CRONDIR);
  241.             stat(CRONDIR, &sb);
  242.         } else {
  243.             fprintf(stderr, "%s: ", CRONDIR);
  244.             perror("mkdir");
  245.             exit(ERROR_EXIT);
  246.         }
  247.     }
  248.     if (!(sb.st_mode & S_IFDIR)) {
  249.         fprintf(stderr, "'%s' is not a directory, bailing out.\n",
  250.             CRONDIR);
  251.         exit(ERROR_EXIT);
  252.     }
  253.     if (chdir(CRONDIR) < OK) {
  254.         fprintf(stderr, "cannot chdir(%s), bailing out.\n", CRONDIR);
  255.         perror(CRONDIR);
  256.         exit(ERROR_EXIT);
  257.     }
  258.  
  259.     /* CRONDIR okay (now==CWD), now look at SPOOL_DIR ("tabs" or some such)
  260.      */
  261.     if (stat(SPOOL_DIR, &sb) < OK && errno == ENOENT) {
  262.         perror(SPOOL_DIR);
  263.         if (OK == mkdir(SPOOL_DIR, 0700)) {
  264.             fprintf(stderr, "%s: created\n", SPOOL_DIR);
  265.             stat(SPOOL_DIR, &sb);
  266.         } else {
  267.             fprintf(stderr, "%s: ", SPOOL_DIR);
  268.             perror("mkdir");
  269.             exit(ERROR_EXIT);
  270.         }
  271.     }
  272.     if (!(sb.st_mode & S_IFDIR)) {
  273.         fprintf(stderr, "'%s' is not a directory, bailing out.\n",
  274.             SPOOL_DIR);
  275.         exit(ERROR_EXIT);
  276.     }
  277. }
  278.  
  279.  
  280. #if defined(BSD)
  281. void
  282. be_different()
  283. {
  284.     /* release the control terminal:
  285.      *  get new pgrp (name after our PID)
  286.      *  do an IOCTL to void tty association
  287.      */
  288.  
  289.     extern int    getpid(), setpgrp(), open(), ioctl(), close();
  290.     auto int    fd;
  291.  
  292.     (void) setpgrp(0, getpid());
  293.  
  294.     if ((fd = open("/dev/tty", 2)) >= 0)
  295.     {
  296.         (void) ioctl(fd, TIOCNOTTY, (char*)0);
  297.         (void) close(fd);
  298.     }
  299. }
  300. #endif /*BSD*/
  301.  
  302. #if defined(ATT)
  303. void
  304. be_different()
  305. {
  306.     /* not being a system V wiz, I don't know if this is what you have
  307.      * to do to release your control terminal.  what I want to accomplish
  308.      * is to keep this process from getting any signals from the tty.
  309.      *
  310.      * some system V person should let me know if this works... (vixie)
  311.      */
  312.     int    setpgrp(), close(), open();
  313.  
  314.     (void) setpgrp();
  315.  
  316.     (void) close(STDIN);    (void) open("/dev/null", 0);
  317.     (void) close(STDOUT);    (void) open("/dev/null", 1);
  318.     (void) close(STDERR);    (void) open("/dev/null", 2);
  319. }
  320. #endif /*ATT*/
  321.  
  322.  
  323. /* acquire_daemonlock() - write our PID into /etc/crond.pid, unless
  324.  *    another daemon is already running, which we detect here.
  325.  */
  326. void
  327. acquire_daemonlock()
  328. {
  329.     int    fd = open(PIDFILE, O_RDWR|O_CREAT, 0644);
  330.     FILE    *fp = fdopen(fd, "r+");
  331.     int    pid = getpid(), otherpid;
  332.     char    buf[MAX_TEMPSTR];
  333.  
  334.     if (fd < 0 || fp == NULL) {
  335.         sprintf(buf, "can't open or create %s, errno %d", PIDFILE, errno);
  336.         log_it("CROND", pid, "DEATH", buf);
  337.         exit(ERROR_EXIT);
  338.     }
  339.  
  340.     if (flock(fd, LOCK_EX|LOCK_NB) < OK) {
  341.         int save_errno = errno;
  342.  
  343.         fscanf(fp, "%d", &otherpid);
  344.         sprintf(buf, "can't lock %s, otherpid may be %d, errno %d",
  345.             PIDFILE, otherpid, save_errno);
  346.         log_it("CROND", pid, "DEATH", buf);
  347.         exit(ERROR_EXIT);
  348.     }
  349.  
  350.     rewind(fp);
  351.     fprintf(fp, "%d\n", pid);
  352.     fflush(fp);
  353.     ftruncate(fd, ftell(fp));
  354.  
  355.     /* abandon fd and fp even though the file is open. we need to
  356.      * keep it open and locked, but we don't need the handles elsewhere.
  357.      */
  358. }
  359.  
  360. /* get_char(file) : like getc() but increment LineNumber on newlines
  361.  */
  362. int
  363. get_char(file)
  364.     FILE    *file;
  365. {
  366.     int    ch;
  367.  
  368.     ch = getc(file);
  369.     if (ch == '\n')
  370.         Set_LineNum(LineNumber + 1)
  371.     return ch;
  372. }
  373.  
  374.  
  375. /* unget_char(ch, file) : like ungetc but do LineNumber processing
  376.  */
  377. void
  378. unget_char(ch, file)
  379.     int    ch;
  380.     FILE    *file;
  381. {
  382.     ungetc(ch, file);
  383.     if (ch == '\n')
  384.         Set_LineNum(LineNumber - 1)
  385. }
  386.  
  387.  
  388. /* get_string(str, max, file, termstr) : like fgets() but
  389.  *        (1) has terminator string which should include \n
  390.  *        (2) will always leave room for the null
  391.  *        (3) uses get_char() so LineNumber will be accurate
  392.  *        (4) returns EOF or terminating character, whichever
  393.  */
  394. int
  395. get_string(string, size, file, terms)
  396.     char    *string;
  397.     int    size;
  398.     FILE    *file;
  399.     char    *terms;
  400. {
  401.     int    ch;
  402.     char    *index();
  403.  
  404.     while (EOF != (ch = get_char(file)) && !index(terms, ch))
  405.         if (size > 1)
  406.         {
  407.             *string++ = (char) ch;
  408.             size--;
  409.         }
  410.  
  411.     if (size > 0)
  412.         *string = '\0';
  413.  
  414.     return ch;
  415. }
  416.  
  417.  
  418. /* skip_comments(file) : read past comment (if any)
  419.  */
  420. void
  421. skip_comments(file)
  422.     FILE    *file;
  423. {
  424.     int    ch;
  425.  
  426.     while (EOF != (ch = get_char(file)))
  427.     {
  428.         /* ch is now the first character of a line.
  429.          */
  430.  
  431.         while (ch == ' ' || ch == '\t')
  432.             ch = get_char(file);
  433.  
  434.         if (ch == EOF)
  435.             break;
  436.  
  437.         /* ch is now the first non-blank character of a line.
  438.          */
  439.  
  440.         if (ch != '\n' && ch != '#')
  441.             break;
  442.  
  443.         /* ch must be a newline or comment as first non-blank
  444.          * character on a line.
  445.          */
  446.  
  447.         while (ch != '\n' && ch != EOF)
  448.             ch = get_char(file);
  449.  
  450.         /* ch is now the newline of a line which we're going to
  451.          * ignore.
  452.          */
  453.     }
  454.     unget_char(ch, file);
  455. }
  456.  
  457. /* int in_file(char *string, FILE *file)
  458.  *    return TRUE if one of the lines in file matches string exactly,
  459.  *    FALSE otherwise.
  460.  */
  461. int
  462. in_file(string, file)
  463.     char *string;
  464.     FILE *file;
  465. {
  466.     char line[MAX_TEMPSTR];
  467.  
  468.     /* let's be persnickety today.
  469.      */
  470.     if (!file) {
  471.         if (!string)
  472.             string = "0x0";
  473.         fprintf(stderr,
  474.             "in_file(\"%s\", 0x%x): called with NULL file--botch",
  475.             string, file);
  476.         exit(ERROR_EXIT);
  477.     }
  478.  
  479.     rewind(file);
  480.     while (fgets(line, MAX_TEMPSTR, file)) {
  481.         if (line[0] != '\0')
  482.             line[strlen(line)-1] = '\0';
  483.         if (0 == strcmp(line, string))
  484.             return TRUE;
  485.     }
  486.     return FALSE;
  487. }
  488.  
  489.  
  490. /* int allowed(char *username)
  491.  *    returns TRUE if (ALLOW_FILE exists and user is listed)
  492.  *    or (DENY_FILE exists and user is NOT listed)
  493.  *    or (neither file exists but user=="root" so it's okay)
  494.  */
  495. int
  496. allowed(username)
  497.     char *username;
  498. {
  499.     static int    init = FALSE;
  500.     static FILE    *allow, *deny;
  501.  
  502.     if (!init) {
  503.         init = TRUE;
  504. #if defined(ALLOW_FILE) && defined(DENY_FILE)
  505.         allow = fopen(ALLOW_FILE, "r");
  506.         deny = fopen(DENY_FILE, "r");
  507.         Debug(DMISC, ("allow/deny enabled, %d/%d\n", !!allow, !!deny))
  508. #else
  509.         allow = NULL;
  510.         deny = NULL;
  511. #endif
  512.     }
  513.  
  514.     if (allow)
  515.         return (in_file(username, allow));
  516.     if (deny)
  517.         return (!in_file(username, deny));
  518.  
  519. #if defined(ALLOW_ONLY_ROOT)
  520.     return (strcmp(username, ROOT_USER) == 0);
  521. #else
  522.     return TRUE;
  523. #endif
  524. }
  525.  
  526.  
  527. #if defined(LOG_FILE) || defined(SYSLOG)
  528. void
  529. log_it(username, pid, event, detail)
  530.     char    *username;
  531.     int    pid;
  532.     char    *event;
  533.     char    *detail;
  534. {
  535. #if defined(LOG_FILE)
  536.     extern struct tm    *localtime();
  537.     extern long        time();
  538.     extern char        *malloc();
  539.     auto char        *msg;
  540.     auto long        now = time((long *) 0);
  541.     register struct tm    *t = localtime(&now);
  542.     static int        log_fd = -1;
  543. #endif /*LOG_FILE*/
  544.  
  545. #if defined(SYSLOG)
  546.     static int        syslog_open = 0;
  547. #endif
  548.  
  549.  
  550. #if defined(LOG_FILE)
  551.     /* we assume that MAX_TEMPSTR will hold the date, time, &punctuation.
  552.      */
  553.     msg = malloc(strlen(username)
  554.           + strlen(event)
  555.           + strlen(detail)
  556.           + MAX_TEMPSTR);
  557.  
  558.     if (log_fd < OK) {
  559.         log_fd = open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0600);
  560.         if (log_fd < OK) {
  561.             fprintf(stderr, "%s: can't open log file\n", ProgramName);
  562.             perror(LOG_FILE);
  563.         }
  564.     }
  565.  
  566.     /* we have to sprintf() it because fprintf() doesn't always write
  567.      * everything out in one chunk and this has to be atomically appended
  568.      * to the log file.
  569.      */
  570.     sprintf(msg, "%s (%02d/%02d-%02d:%02d:%02d-%d) %s (%s)\n",
  571.         username,
  572.         t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, pid,
  573.         event, detail);
  574.  
  575.     /* we have to run strlen() because sprintf() returns (char*) on BSD
  576.      */
  577.     if (log_fd < OK || write(log_fd, msg, strlen(msg)) < OK) {
  578.         fprintf(stderr, "%s: can't write to log file\n", ProgramName);
  579.         if (log_fd >= OK)
  580.             perror(LOG_FILE);
  581.         write(STDERR, msg, strlen(msg));
  582.     }
  583.  
  584.     /* I suppose we could use alloca()...
  585.      */
  586.     free(msg);
  587. #endif /*LOG_FILE*/
  588.  
  589. #if defined(SYSLOG)
  590.     if (!syslog_open) {
  591.         /* we don't use LOG_PID since the pid passed to us by
  592.          * our client may not be our own.  therefore we want to
  593.          * print the pid ourselves.
  594.          */
  595. # ifdef LOG_CRON
  596.         openlog(ProgramName, 0, LOG_CRON);
  597. # else
  598. # ifdef LOG_DAEMON
  599.         openlog(ProgramName, 0, LOG_DAEMON);
  600. # else
  601.         openlog(ProgramName, 0);
  602. # endif /*LOG_DAEMON*/
  603. # endif /*LOG_CRON*/
  604.         syslog_open = TRUE;        /* assume openlog success */
  605.     }
  606.  
  607.     syslog(LOG_INFO, "(%s %d) %s (%s)\n",
  608.         username, pid, event, detail);
  609.  
  610. #endif /*SYSLOG*/
  611.  
  612.     if (DebugFlags) {
  613.         fprintf(stderr, "log_it: (%s %d) %s (%s)",
  614.             username, pid, event, detail);
  615.     }
  616. }
  617. #endif /*LOG_FILE || SYSLOG */
  618.  
  619.  
  620. /* two warnings:
  621.  *    (1) this routine is fairly slow
  622.  *    (2) it returns a pointer to static storage
  623.  */
  624. char *
  625. first_word(s, t)
  626.     local char *s;    /* string we want the first word of */
  627.     local char *t;    /* terminators, implicitly including \0 */
  628. {
  629.     static char retbuf[2][MAX_TEMPSTR + 1];    /* sure wish I had GC */
  630.     static int retsel = 0;
  631.     local char *rb, *rp;
  632.     extern char *index();
  633.  
  634.     /* select a return buffer */
  635.     retsel = 1-retsel;
  636.     rb = &retbuf[retsel][0];
  637.     rp = rb;
  638.  
  639.     /* skip any leading terminators */
  640.     while (*s && (NULL != index(t, *s))) {s++;}
  641.  
  642.     /* copy until next terminator or full buffer */
  643.     while (*s && (NULL == index(t, *s)) && (rp < &rb[MAX_TEMPSTR])) {
  644.         *rp++ = *s++;
  645.     }
  646.  
  647.     /* finish the return-string and return it */
  648.     *rp = '\0';
  649.     return rb;
  650. }
  651.  
  652.  
  653. /* warning:
  654.  *    heavily ascii-dependent.
  655.  */
  656.  
  657. void
  658. mkprint(dst, src, len)
  659.     register char *dst;
  660.     register unsigned char *src;
  661.     register int len;
  662. {
  663.     while (len-- > 0)
  664.     {
  665.         register unsigned char ch = *src++;
  666.  
  667.         if (ch < ' ') {            /* control character */
  668.             *dst++ = '^';
  669.             *dst++ = ch + '@';
  670.         } else if (ch < 0177) {        /* printable */
  671.             *dst++ = ch;
  672.         } else if (ch == 0177) {    /* delete/rubout */
  673.             *dst++ = '^';
  674.             *dst++ = '?';
  675.         } else {            /* parity character */
  676.             sprintf(dst, "\\%03o", ch);
  677.             dst += 4;
  678.         }
  679.     }
  680.     *dst = NULL;
  681. }
  682.  
  683.  
  684. /* warning:
  685.  *    returns a pointer to malloc'd storage, you must call free yourself.
  686.  */
  687.  
  688. char *
  689. mkprints(src, len)
  690.     register unsigned char *src;
  691.     register unsigned int len;
  692. {
  693.     extern char *malloc();
  694.     register char *dst = malloc(len*4 + 1);
  695.  
  696.     mkprint(dst, src, len);
  697.  
  698.     return dst;
  699. }
  700.