home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff319.lzh / CNewsSrc / uupc.lzh / uupc / rnews.c < prev    next >
C/C++ Source or Header  |  1990-01-16  |  8KB  |  351 lines

  1. /*
  2.  *    newsspool - copy incoming news into incoming directory
  3.  *
  4.  *    The -i option relies on the parent setting (and exporting) $PATH.
  5.  *
  6.  *    $Id: rnews.c,v 1.2 90/01/16 10:27:09 crash Exp Locker: crash $
  7.  */
  8.  
  9. #ifndef lint
  10. static char RCSid[] = "$Id: rnews.c,v 1.2 90/01/16 10:27:09 crash Exp Locker: crash $";
  11. #endif /* lint */
  12.  
  13. #ifdef AMIGA
  14.     /*
  15.      *    If being compiled for an Amiga, then this code should be linked into
  16.      *    the executable for UUPC to replace the built-in "rnews" command.
  17.      *    Note that this bypasses the "rnews.{batch,immed}" script.
  18.      */
  19. #  define MAIN        rnews
  20. #  define LOCAL        static
  21. #else
  22. #  define MAIN        main
  23. #  define LOCAL
  24. #endif
  25.  
  26. #include <stdio.h>
  27.  
  28. #ifndef AMIGA
  29. #  include <sys/types.h>
  30. #  include <sys/stat.h>
  31. #else
  32. #  include <time.h>
  33. #  include <libraries/dos.h>
  34. #  define stat        FileInfoBlock
  35. #  define st_mode    fib_DirEntryType
  36. extern struct FileLock *Lock();
  37. #endif /* AMIGA */
  38.  
  39. #include <string.h>
  40. #include <errno.h>
  41. #include "libc.h"
  42. #include "news.h"
  43. #include "config.h"
  44.  
  45. #ifndef lint
  46. static char RCSid[] = "$Id: rnews.c,v 1.2 90/01/16 10:27:09 crash Exp Locker: crash $";
  47. #endif
  48.  
  49. #ifndef MAXTRIES
  50. #  define    MAXTRIES    100    /* limit on attempts to make links */
  51. #endif
  52.  
  53. extern int debuglevel;
  54. int debug = 0;
  55. char *progname;
  56.  
  57. extern void error(), exit();
  58. #ifdef UTZOOERR
  59. extern char *mkprogname();
  60. #else
  61. #define    mkprogname(a)    (a)
  62. #endif
  63.  
  64. char buf[BUFSIZ*16];    /* try to get a batch in a few gulps */
  65. int immed = 0;            /* try an immediate newsrun? */
  66.  
  67. void process();
  68. FILE *outopen();
  69. void outclose();
  70. extern time_t time();
  71. char *outname();
  72.  
  73. /*
  74.  * main - parse arguments and handle options
  75.  *        when used with UUPC, this becomes "rnews( argc, argv )"
  76.  *        which is called by RNews() in the ulib.c module
  77.  */
  78. MAIN (argc, argv)
  79. int argc;
  80. char *argv[];
  81. {
  82.     int c;
  83.     int errflg = 0;
  84.     FILE *in;
  85.     struct stat statbuf;
  86.     extern int optind;
  87.     extern char *optarg;
  88.     extern FILE *efopen();
  89.     void process();
  90.  
  91.     printmsg(3, "calling mkprogname(\"%s\")", *argv);
  92.     progname = mkprogname(argv[0]);
  93.  
  94.     printmsg(3, "parsing command line");
  95.     while ((c = getopt(argc, argv, "id")) != EOF)
  96.         switch (c) {
  97.         case 'i':    /* try immediate newsrun */
  98.             immed++;
  99.             break;
  100.         case 'd':    /* Debugging. */
  101.             debug++;
  102.             setbuf(stderr, (char *)NULL);
  103.             break;
  104.         case '?':
  105.         default:
  106.             errflg++;
  107.             break;
  108.         }
  109.     if (errflg) {
  110.         fprintf(stderr, "Usage:  %s [file] ...\n", progname);
  111.         exit(2);
  112.     }
  113.     /* probe to get unprivileged() called if necessary */
  114.     (void) ctlfile((char *)NULL);
  115.  
  116.     /* mktemp() uses access(2) [ARGH!] so minimize chances of trouble */
  117.     printmsg(3, "doing setuid()/getuid() funniness...");
  118.     (void) setgid(getegid());
  119.     (void) setuid(geteuid());
  120.     (void) umask(newsumask());
  121.  
  122.     if (optind >= argc)
  123.         process(stdin, "stdin");
  124.     else
  125.         for (; optind < argc; optind++)
  126.             if (STREQ(argv[optind], "-"))
  127.                 process(stdin, "-");
  128.             else {
  129. #ifdef AMIGA
  130.                 struct FileLock *lock;
  131.  
  132.                 printmsg(2, "checking input file's mode");
  133.                 if (lock = Lock(argv[optind], ACCESS_READ)) {
  134.                     Examine(lock, &statbuf);
  135.                     UnLock(lock);
  136.                 } else
  137.                     statbuf.st_mode = -1;
  138.                 in = efopen(argv[optind], "r");
  139.                 if (statbuf.st_mode > 0)            /* AmigaDOS directory */
  140.                     error("`%s' is directory!", argv[optind]);
  141. #else
  142.                 in = efopen(argv[optind], "r");
  143.                 if (fstat(fileno(in), &statbuf) < 0)
  144.                     error("can't fstat `%s'", argv[optind]);
  145.                 if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  146.                     error("`%s' is directory!", argv[optind]);
  147. #endif /* AMIGA */
  148.                 process(in, argv[optind]);
  149.                 (void) fclose(in);
  150.             }
  151. #ifndef AMIGA
  152.     if (immed) {
  153.         execlp("newsrun", "newsrun", (char *)NULL);
  154.         error("attempt to run newsrun failed!", "");
  155.     }
  156.     exit(0);
  157. #else /* AMIGA */
  158.     return( 0 );            /* exit() isn't called from anywhere else... */
  159. #endif /* AMIGA */
  160. }
  161.  
  162. /*
  163.  * process - process input file
  164.  */
  165.  
  166. /* ARGSUSED */
  167. LOCAL void process(in, inname)
  168. FILE *in;
  169. char *inname;
  170. {
  171.     register int count;
  172.     register int firstblock;
  173.     FILE *out;
  174.     register char *p;
  175.     register int n;
  176.     char *name;
  177.  
  178.     name = outname();
  179.     out = outopen(name);
  180.  
  181.     /* do the copying */
  182.     printmsg(4, "performing file copy...");
  183.     firstblock = 1;
  184.     while ((count = fread(buf, sizeof(char), sizeof(buf), in)) > 0) {
  185.         if (firstblock) {
  186.             n = cunskip(buf, count);
  187.             p = buf + n;
  188.             count -= n;
  189.             firstblock = 0;
  190.         } else
  191.             p = buf;
  192.         n = fwrite(p, sizeof(char), count, out);
  193.         if (n != count)
  194.             error("write error in output to `%s'", name);
  195.     }
  196.     outclose(out, name);
  197. }
  198.  
  199. /*
  200.  * outname - construct name for the temporary output file
  201.  */
  202. LOCAL char *outname()
  203. {
  204.     register char *p;
  205.  
  206.     p = strsave(fullartfile("in.coming/nspool.XXXXXX"));
  207.     mktemp(p);
  208.     printmsg(5, "temporary output file is '%s'", p);
  209.     return(p);
  210. }
  211.  
  212. /*
  213.  * outopen - acquire an output file
  214.  */
  215. LOCAL FILE *outopen(name)
  216. char *name;
  217. {
  218.     FILE *f;
  219.  
  220.     f = fopen(name, "w");
  221.     if (f == NULL)
  222.         error("unable to create temporary `%s'", name);
  223.     printmsg(4, "output into '%s'", name);
  224.  
  225.     return(f);
  226. }
  227.  
  228. /*
  229.  * outclose - close output file, moving it to the right place
  230.  *
  231.  * Names are based on the current time in hopes of keeping input in order.
  232.  */
  233. LOCAL void outclose(f, tmpname)
  234. FILE *f;
  235. char *tmpname;
  236. {
  237.     register char *p;
  238.     register char *name;
  239.     register int ntries;
  240.     time_t now;
  241.     extern int errno;
  242.  
  243.     if (fclose(f) == EOF)
  244.         error("fclose error on file `%s'", tmpname);
  245.  
  246.     p = fullartfile("in.coming/");
  247.     name = emalloc(strlen(p) + 20);            /* plenty for a number */
  248.     (void) strcpy(name, p);
  249.     p = name + strlen(name);
  250.  
  251.     ntries = 0;
  252.     for (;;) {
  253.         now = time((time_t *)NULL);
  254. #ifdef AMIGA
  255.         sprintf(p, "%ld.z", now);
  256.         printmsg(7, "\ttrying '%s'", name);
  257.         /*
  258.          *    Try the normal "rename(from, to)" function...
  259.          *    This *should* be okay since the directory is
  260.          *    the same (because "fullartfile()" was used) so that
  261.          *    only possible error is EEXIST (?).
  262.          */
  263.         if (rename(tmpname, name) == 0)
  264.             break;
  265. #else
  266.         sprintf(p, "%ld", now);
  267.         if (debug)
  268.             fprintf(stderr, "trying to rename to %s\n", name);
  269.         if (link(tmpname, name) >= 0)
  270.             break;                /* NOTE BREAK OUT */
  271. #endif /* AMIGA */
  272.         if (errno != EEXIST)    /* something strange is wrong */
  273.             error("unable to link `%s'", tmpname);
  274.         errno = 0;
  275.         if (ntries > MAXTRIES)    /* sanity check */
  276.             error("too many attempts to link `%s'", tmpname);
  277.         if (debug)
  278.             fprintf(stderr, "failed\n");
  279.         sleep(2);    /* avoid rumored race in 1-sec sleep */
  280.         ntries++;
  281.     }
  282.     printmsg(6, "destination file is '%s'", name);
  283.     if (debug)
  284.         fprintf(stderr, "succeeded\n");
  285.     /*
  286.      *    If running on an Amiga, we wouldn't be here unless the
  287.      *    rename() function, above, worked and so we *know* that
  288.      *    this unlink() is going to fail.  ...who cares?
  289.      */
  290.     (void) unlink(tmpname);
  291. }
  292.  
  293. /*
  294.  * cunskip - inspect block for silly #! cunbatch headers
  295.  *
  296.  * number of chars at start to skip
  297.  */
  298. LOCAL int cunskip(bufp, count)
  299. char *bufp;
  300. int count;
  301. {
  302.     static char goop[] = "cunbatch";
  303. #    define    GOOPLEN    (sizeof(goop)-1)    /* strlen(goop) */
  304.     static char goop2[] = "c7unbatch";
  305. #    define    GOOP2LEN    (sizeof(goop2)-1)    /* strlen(goop2) */
  306.     register char *p;
  307.     register int nleft;
  308.  
  309.     nleft = count;
  310.     p = bufp;
  311.  
  312.     if (nleft < 2)                /* no room for a header */
  313.         return(0);
  314.     if (*p++ != '#' || *p++ != '!')        /* doesn't start with #! */
  315.         return(0);
  316.     nleft -= 2;
  317.  
  318.     /* skip space */
  319.     while (nleft > 0 && (*p == ' ' || *p == '\t')) {
  320.         p++;
  321.         nleft--;
  322.     }
  323.     /* recognize headers (the +1s ensure room for the newline) */
  324.     if (nleft >= GOOPLEN+1 && STREQN(p, goop, GOOPLEN)) {
  325.         p += GOOPLEN;
  326.         nleft -= GOOPLEN;
  327.     } else if (nleft >= GOOP2LEN+1 && STREQN(p, goop2, GOOP2LEN)) {
  328.         p += GOOP2LEN;
  329.         nleft -= GOOP2LEN;
  330.     } else                                /* no header */
  331.         return(0);
  332.  
  333.     /* skip more space */
  334.     while (nleft > 0 && (*p == ' ' || *p == '\t')) {
  335.         p++;
  336.         nleft--;
  337.     }
  338.     if (nleft == 0 || *p++ != '\n')        /* didn't end properly */
  339.         return(0);
  340.     return(p - bufp);
  341. }
  342.  
  343. /*
  344.  * unprivileged - drop setuid-ness if configuration is overridden
  345.  */
  346. void unprivileged()
  347. {
  348.     setgid(getgid());
  349.     setuid(getuid());
  350. }
  351.