home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / input / newsspool.c < prev    next >
C/C++ Source or Header  |  1995-04-27  |  5KB  |  283 lines

  1. /*
  2.  * newsspool - copy incoming news into incoming directory
  3.  * -Log-
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <string.h>
  10. #include <errno.h>
  11. #include "fixerrno.h"
  12. #include "libc.h"
  13. #include "news.h"
  14. #include "config.h"
  15.  
  16. #ifndef lint
  17. static char RCSid[] = "$Header$";
  18. #endif
  19.  
  20. #ifndef MAXTRIES
  21. #define    MAXTRIES    100    /* limit on attempts to make links */
  22. #endif
  23.  
  24. int debug = 0;
  25. char *progname;
  26.  
  27. extern void error();
  28. #ifdef UTZOOERR
  29. extern char *mkprogname();
  30. #else
  31. #define    mkprogname(a)    (a)
  32. #endif
  33.  
  34. char buf[BUFSIZ*16];    /* try to get a batch in a few gulps */
  35. char *suffix = ".t";    /* suffix for filename, default is plain text */
  36. char grade[3] = "";    /* 3 = digit, period, NUL */
  37.  
  38. void process();
  39. FILE *outopen();
  40. void outclose();
  41. extern time_t time();
  42. char *outname();
  43.  
  44. /*
  45.  - main - parse arguments and handle options
  46.  */
  47. main(argc, argv)
  48. int argc;
  49. char *argv[];
  50. {
  51.     int c;
  52.     int errflg = 0;
  53.     FILE *in;
  54.     struct stat statbuf;
  55.     extern int optind;
  56.     extern char *optarg;
  57.     extern FILE *efopen();
  58.     void process();
  59.  
  60.     progname = mkprogname(argv[0]);
  61.  
  62.     while ((c = getopt(argc, argv, "g:d")) != EOF)
  63.         switch (c) {
  64.         case 'g':    /* grade */
  65.             if (strchr("0123456789", *optarg) == NULL)
  66.                 error("invalid grade `%s'", optarg);
  67.             sprintf(grade, "%c.", *optarg);
  68.             break;
  69.         case 'd':    /* Debugging. */
  70.             debug++;
  71.             setbuf(stderr, (char *)NULL);
  72.             break;
  73.         case '?':
  74.         default:
  75.             errflg++;
  76.             break;
  77.         }
  78.     if (errflg) {
  79.         fprintf(stderr, "usage: %s [file] ...\n", progname);
  80.         exit(2);
  81.     }
  82.  
  83.     /* probe to get unprivileged() called if necessary */
  84.     (void) ctlfile((char *)NULL);
  85.  
  86.     /* mktemp() uses access(2) [ARGH!] so minimize chances of trouble */
  87.     (void) setgid(getegid());
  88.     (void) setuid(geteuid());
  89.  
  90.     (void) umask(newsumask());
  91.  
  92.     if (optind >= argc)
  93.         process(stdin, "stdin");
  94.     else
  95.         for (; optind < argc; optind++)
  96.             if (STREQ(argv[optind], "-"))
  97.                 process(stdin, "-");
  98.             else {
  99.                 in = efopen(argv[optind], "r");
  100.                 if (fstat(fileno(in), &statbuf) < 0)
  101.                     error("can't fstat `%s'", argv[optind]);
  102.                 process(in, argv[optind]);
  103.                 (void) fclose(in);
  104.             }
  105.  
  106.     exit(0);
  107. }
  108.  
  109. /*
  110.  * process - process input file
  111.  */
  112. /* ARGSUSED */
  113. void
  114. process(in, inname)
  115. FILE *in;
  116. char *inname;
  117. {
  118.     register int count;
  119.     register int firstblock;
  120.     FILE *out;
  121.     register char *p;
  122.     register int n;
  123.     char *name;
  124.     register int wrotesome = 0;
  125.  
  126.     name = outname();
  127.     out = outopen(name);
  128.  
  129.     /* do the copying */
  130.     firstblock = 1;
  131.     while ((count = fread(buf, sizeof(char), sizeof(buf), in)) > 0) {
  132.         if (firstblock) {
  133.             n = cunskip(buf, count);
  134.             p = buf + n;
  135.             count -= n;
  136.             firstblock = 0;
  137.         } else
  138.             p = buf;
  139.         if (count > 0) {
  140.             n = fwrite(p, sizeof(char), count, out);
  141.             if (n != count)
  142.                 error("write error in output to `%s'", name);
  143.             wrotesome = 1;
  144.         }
  145.     }
  146.  
  147.     outclose(out, name, wrotesome);
  148. }
  149.  
  150. /*
  151.  - outname - construct name for the temporary output file
  152.  */
  153. char *
  154. outname()
  155. {
  156.     register char *p;
  157.  
  158.     p = strsave(fullartfile("in.coming/nspool.XXXXXX"));
  159.     mktemp(p);
  160.     return(p);
  161. }
  162.  
  163. /*
  164.  - outopen - acquire an output file
  165.  */
  166. FILE *
  167. outopen(name)
  168. char *name;
  169. {
  170.     FILE *f;
  171.  
  172.     f = fopen(name, "w");
  173.     if (f == NULL)
  174.         error("unable to create temporary `%s'", name);
  175.     if (debug)
  176.         fprintf(stderr, "output into %s\n", name);
  177.  
  178.     return(f);
  179. }
  180.  
  181. /*
  182.  - outclose - close output file, moving it to the right place
  183.  *
  184.  * Names are based on the current time in hopes of keeping input in order.
  185.  */
  186. void
  187. outclose(f, tmpname, wrotesome)
  188. FILE *f;
  189. char *tmpname;
  190. int wrotesome;            /* did anything actually get written to it? */
  191. {
  192.     register char *p;
  193.     register char *name;
  194.     register int ntries;
  195.     time_t now;
  196.  
  197.     if (nfclose(f) == EOF)
  198.         error("close error on file `%s'", tmpname);
  199.     if (!wrotesome) {
  200.         (void) unlink(tmpname);
  201.         return;
  202.     }
  203.  
  204.     if (!mkinperm(tmpname, grade, suffix))
  205.         error("couldn't move %s into the in.coming queue", tmpname);
  206.     if (debug)
  207.         fprintf(stderr, "succeeded\n");
  208. }
  209.  
  210. /*
  211.  - cunskip - inspect block for silly #! cunbatch headers, classify input
  212.  */
  213. int                /* number of chars at start to skip */
  214. cunskip(bufp, count)
  215. char *bufp;
  216. int count;
  217. {
  218.     static char goop[] = "cunbatch";
  219. #    define    GOOPLEN    (sizeof(goop)-1)    /* strlen(goop) */
  220.     static char suf[] = ".Z";
  221.     static char comp[] = "\037\235";    /* compress's magic no. */
  222.     register char *p;
  223.     register int nleft;
  224. #    define    MINCBATCH    5        /* one character, compressed */
  225.  
  226.     nleft = count;
  227.     p = bufp;
  228.  
  229.     if (nleft < 2)                /* no room for a header */
  230.         return(0);
  231.  
  232.     if (p[0] == comp[0] && p[1] == comp[1]) {    /* compressed */
  233.         if (nleft < MINCBATCH)
  234.             return(count);
  235.         suffix = suf;
  236.         return(0);
  237.     }
  238.  
  239.     if (*p++ != '#' || *p++ != '!')        /* doesn't start with #! */
  240.         return(0);
  241.     nleft -= 2;
  242.  
  243.     /* skip space */
  244.     while (nleft > 0 && (*p == ' ' || *p == '\t')) {
  245.         p++;
  246.         nleft--;
  247.     }
  248.  
  249.     /* recognize headers (the +1s ensure room for the newline) */
  250.     if (nleft >= GOOPLEN+1 && STREQN(p, goop, GOOPLEN)) {
  251.         p += GOOPLEN;
  252.         nleft -= GOOPLEN;
  253.         suffix = suf;
  254.     } else                    /* no header */
  255.         return(0);
  256.  
  257.     /* skip more space */
  258.     while (nleft > 0 && (*p == ' ' || *p == '\t')) {
  259.         p++;
  260.         nleft--;
  261.     }
  262.  
  263.     if (nleft == 0 || *p++ != '\n')        /* didn't end properly */
  264.         return(0);
  265.  
  266.     if (nleft < MINCBATCH)            /* null batch */
  267.         return(count);
  268.     return(p - bufp);
  269. }
  270.  
  271. /*
  272.  - unprivileged - drop setuidness if configuration is overridden
  273.  */
  274. /* ARGSUSED */
  275. void
  276. unprivileged(reason)
  277. char *reason;
  278. {
  279.     setgid(getgid());
  280.     setuid(getuid());
  281.     /* tempting to complain, but it fouls up the regression test */
  282. }
  283.