home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / newbatchb / batcher.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  9.3 KB  |  442 lines

  1. /*    Chris Lewis, June 1986    */
  2. #include <stdio.h>
  3. #if    defined(BSD4_2) || defined(BSD4_1C)
  4. #include <strings.h>
  5. #else
  6. #include <string.h>
  7. #endif
  8. extern char *malloc();
  9. extern void free();
  10.  
  11. #define    NUMFLDS    7
  12. #define    NAME    0
  13. #define    CLASS    1
  14. #define    COMPRESS 2
  15. #define    UUXFLAGS 3
  16. #define    SIZE    4
  17. #define    QSIZE    5
  18. #define    UUX    6
  19.  
  20. #define    UUQ    /* define this if you have BSD 4.3 uuq utility */
  21. #define    DFABLE    /* define this if "df /usr/spool/uucp" works on your system */
  22.  
  23. /* Take a look at these, too. */
  24. #ifdef    DEBUG
  25. #define    BATCHCTRL    "batcher.ctrl"
  26. #else
  27. #define    BATCHCTRL    "/usr/lib/news/batcher.ctrl"
  28. #endif
  29.  
  30. #define    BATCH    "/usr/spool/batch"
  31. #define    SBATCH    "/usr/lib/news/batch"
  32.  
  33.  
  34. int    fldlen[NUMFLDS] = {10, 2, 20, 10, 7, 10, 30};
  35.  
  36. struct desc {
  37.     char         *flds[NUMFLDS];
  38.     struct desc    *next;
  39. } *head = (struct desc *) NULL, 
  40.   *dptr = (struct desc *) NULL;
  41.  
  42. #if    defined(BSD4_2) || defined(BSD4_1C)
  43. #define    strchr    index
  44. #endif
  45.  
  46. struct desc *getflds();
  47.  
  48. int    verbose = 0;
  49. int    class;
  50. int    spoolok = 1;
  51.  
  52. long    spoollim = 5000000;
  53.  
  54. /*
  55.  *    main:
  56.  *        - process arguments
  57.  *        - read control file
  58.  *        - for each system selected, see if there is any work,
  59.  *            if so, go try to do it.
  60.  */
  61.  
  62. main(argc, argv)
  63. int    argc;
  64. char    **argv; {
  65.     register char *p;
  66.     register struct desc *curptr;
  67.     argc--; argv++;
  68.     for (;argc > 0 && **argv == '-'; argv++) {
  69.         for (p = (*argv)+1; *p; p++)
  70.             switch(*p) {
  71.                 case 'v':
  72.                     verbose = 1;
  73.                     break;
  74.                 case 'c':
  75.                     class = *(p+1);
  76.                     if (class == 0)
  77.                         class = 'z';
  78.                     else
  79.                         p++;
  80.                     break;
  81.                 default:
  82.                     fprintf(stderr, "batcher: Bad arg %s\n", *argv);
  83.                     exit(1);
  84.             }
  85.     }
  86.     readctrl();
  87.     if (!checkspool()) {
  88.         exit(0);
  89.     }
  90.     if (verbose)
  91.         dumpctrl();
  92.     if (class) {
  93.         for (curptr = head; curptr && spoolok; curptr = curptr->next) {
  94.             if (*(curptr->flds[CLASS]) == class &&
  95.                 (chkbatch(curptr->flds[NAME], "") || 
  96.                 chkbatch(curptr->flds[NAME], ".work")) &&
  97.                 (spoolok = checkspool()))
  98.                 doit(curptr->flds[NAME]);
  99.         }
  100.     }
  101.     while(*argv && spoolok) {
  102.         if (chkbatch(*argv, "") || chkbatch(*argv, ".work")) {
  103.             doit(*argv);
  104.         }
  105.         argv++;
  106.     }
  107.     exit(0);
  108.  
  109. }
  110.  
  111. /*
  112.  *    readctrl:
  113.  *
  114.  *    Each line in the batch.ctrl file contains NUMFLDS colon-separated
  115.  *    parameters.  This function reads each line, and calls getflds
  116.  *    to separate out the parameters.  If getflds returns a system descriptor
  117.  *    it is linked into the list of system descriptors.
  118.  */
  119.  
  120. readctrl() {
  121.     char    buf[BUFSIZ];
  122.     register char    *p;
  123.     register struct desc *ptr;
  124.     struct desc *getflds();
  125.     register FILE    *ctrl = fopen(BATCHCTRL, "r");
  126.     if (!ctrl) {
  127.         fprintf(stderr, "batcher: could not open %s file\n",
  128.             BATCHCTRL);
  129.         exit(1);
  130.     }
  131.     while (fgets(buf, sizeof(buf), ctrl)) {
  132.         if (buf[0] == '#')
  133.             continue;
  134.         p = buf + strlen(buf) - 1;
  135.         if (*p == '\n')
  136.             *p = '\0';
  137.         if ((ptr = getflds(buf)) && processctrl(ptr)) {
  138.             if (!head)
  139.                 head = dptr = ptr;
  140.             else {
  141.                 dptr->next = ptr;
  142.                 dptr = ptr;
  143.             }
  144.             ptr->next = (struct desc *) NULL;
  145.         }
  146.     }
  147.     fclose(ctrl);
  148. }
  149.  
  150. /*
  151.  *    dumpctrl:
  152.  *
  153.  *    If verbose is on, dump the tables
  154.  */
  155.  
  156. dumpctrl() {
  157.     register struct desc *p;
  158.     register int i;
  159.     for (p = head; p; p = p->next) {
  160.         for (i = 0; i < NUMFLDS; i++)
  161.             printf("%-*s", fldlen[i], p->flds[i]);
  162.         printf("\n");
  163.     }
  164. }
  165.  
  166. char *strsave();
  167.  
  168. /*
  169.  *    getflds:
  170.  *
  171.  *    This routine parses a single line from the batch.ctrl file,
  172.  *    and if successfully parsed and checked out, returns a system
  173.  *    descriptor pointer
  174.  */
  175.  
  176. struct desc *
  177. getflds(buf)
  178. char    *buf; {
  179.     register int cnt;
  180.     char b2[100];
  181.     char *curp, *p;
  182.     int    len;
  183.     struct desc *dptr;
  184.     dptr = (struct desc *) malloc(sizeof (struct desc));
  185.     if (!dptr) {
  186.         fprintf(stderr, "batcher: Cannot malloc\n");
  187.         exit(1);
  188.     }
  189.     curp = buf;
  190.     for (cnt = 0; cnt < NUMFLDS; cnt++) {
  191.         if (cnt == (NUMFLDS - 1)) {
  192.             if (strchr(curp, ':')) {
  193.                 fprintf(stderr, "batcher: too many colons: %s\n",
  194.                     buf);
  195.                 free(dptr);
  196.                 return(NULL);
  197.             }
  198.             p = curp + strlen(curp);
  199.         } else
  200.             p = strchr(curp, ':');
  201.         if (p == NULL) {
  202.             fprintf(stderr, "batcher: invalid format (%d): %s\n", 
  203.                 cnt, buf);
  204.             free(dptr);
  205.             return(NULL);
  206.         }
  207.         len = p - curp;
  208.         if (len >= fldlen[cnt]) {
  209.             fprintf(stderr, "batcher: field %d too long: %s\n",
  210.                 cnt+1, buf);
  211.             free(dptr);
  212.             return(NULL);
  213.         }
  214.         if (!(dptr->flds[cnt] = malloc(len + 1))) {
  215.             fprintf(stderr, "batcher: cannot malloc\n");
  216.             exit(1);
  217.         }
  218.         strncpy(dptr->flds[cnt], curp, len);
  219.         dptr->flds[cnt][len] = '\0';
  220.         curp = p + 1;
  221.     }
  222.     return(dptr);
  223. }
  224.  
  225. /*
  226.  *    strsave:
  227.  *    returns pointer to malloc'd copy of argument
  228.  */
  229. char *
  230. strsave(s)
  231. char    *s; {
  232.     register char *p = malloc(strlen(s) + 1);
  233.     if (!p) {
  234.         fprintf(stderr, "batcher: cannot malloc\n");
  235.         exit(1);
  236.     }
  237.     strcpy(p, s);
  238.     return(p);
  239. }
  240.  
  241. /*
  242.  *    chkbatch:
  243.  *
  244.  *    return 1 if a batcher work file <batchdir>/<name><type> exists.
  245.  */
  246.  
  247. chkbatch(name, type)
  248. char    *name;
  249. char    *type; {
  250.     char batch[BUFSIZ];
  251.     sprintf(batch, "%s/%s%s", BATCH, name, type);
  252.     if (access(batch, 04) == 0)
  253.         return(1);
  254.     else
  255.         return(0);
  256. }
  257.  
  258. /*
  259.  *    doit:
  260.  *
  261.  *    This routine is called with the name of the system that has
  262.  *    been determined to have work for it.  The system is searched
  263.  *    for in the system descriptors.  If found, a "system" line
  264.  *    is contructed from the tables, and executed if system has not
  265.  *    exceeded it's UUCP queue limit.
  266.  */
  267.  
  268. doit(name)
  269. char    *name; {
  270.     char    cmdbuf[BUFSIZ];
  271.     int    rc;
  272.     long    queuesize;
  273.     long    checkqueue(), checkspool();
  274.     long    queuemax;
  275.     register struct desc *ptr;
  276.     if (verbose)
  277.         printf("batcher: doing %s\n", name);
  278.     for (ptr = head; ptr; ptr = ptr->next)
  279.         if (!strcmp(ptr->flds[NAME], name)) {
  280.             /*    form the command line for batching    */
  281.             sprintf(cmdbuf, "%s %s/%s %s",
  282.                 SBATCH, BATCH, name, ptr->flds[SIZE]);
  283.             if (*(ptr->flds[COMPRESS]))
  284.                 sprintf(cmdbuf + strlen(cmdbuf), "|%s",
  285.                     ptr->flds[COMPRESS]);
  286.             /*    Find the queue limit    */
  287.             sprintf(cmdbuf + strlen(cmdbuf), "|%s", ptr->flds[UUX]);
  288.             if (1 != sscanf(ptr->flds[QSIZE], "%ld", &queuemax)) {
  289.                 fprintf(stderr, "batcher: bad qmax field: %s\n",
  290.                     ptr->flds[QSIZE]);
  291.                 return;
  292.             }
  293.             queuesize = checkqueue(ptr->flds[NAME]);
  294.             rc = 0;
  295.             /*    While we haven't exceeded the queue limit &
  296.                 there's work to do, issue the command */
  297.             while (queuesize < queuemax && !rc && 
  298.                 (chkbatch(ptr->flds[NAME], "") || 
  299.                    chkbatch(ptr->flds[NAME], ".work")) &&
  300.                    (spoolok = checkspool())) {
  301. #ifdef    DEBUG
  302.                 printf("batcher: cmd: %s\n", cmdbuf);
  303.                 rc = 1;
  304. #else
  305.                 rc = system(cmdbuf);
  306.                 queuesize = checkqueue(ptr->flds[NAME]);
  307. #endif
  308.             }
  309.             return;
  310.         }
  311.     fprintf(stderr, "batcher: no control line for %s\n", name);
  312. }
  313.  
  314. /*
  315.  *    processctrl:
  316.  *
  317.  *    Check validity of batch.ctrl entries and supply defaults.
  318.  */
  319. processctrl(ptr)
  320. struct    desc *ptr; {
  321.     char    buf[100];
  322.     register char    *p, *uuxflags;
  323.     if (!ptr) return;
  324.     if (strlen(ptr->flds[NAME]) == 0) {
  325.         fprintf(stderr, "batcher: null system name\n");
  326.         free(ptr);
  327.         return(0);
  328.     }
  329.  
  330.     if (strlen(ptr->flds[QSIZE]) == 0) {
  331.         free(ptr->flds[QSIZE]);
  332.         ptr->flds[QSIZE] = strsave("500000");
  333.     }
  334.  
  335.     if (strlen(ptr->flds[CLASS]) == 0) {
  336.         free(ptr->flds[CLASS]);
  337.         ptr->flds[CLASS] = strsave("z");
  338.     }
  339.  
  340.     if (strlen(ptr->flds[SIZE]) == 0) {
  341.         free(ptr->flds[SIZE]);
  342.         ptr->flds[SIZE] = strsave("100000");
  343.     }
  344.  
  345.     if (strlen(ptr->flds[UUXFLAGS]) == 0) {
  346.         free(ptr->flds[UUXFLAGS]);
  347.         ptr->flds[UUXFLAGS] = strsave("-r -z -gd");
  348.     }
  349.  
  350.     if (strlen(ptr->flds[UUX]) == 0) {
  351.         sprintf(buf, "uux - %s %s!%s", ptr->flds[UUXFLAGS],
  352.             ptr->flds[NAME], 
  353.             *ptr->flds[COMPRESS] ? "cunbatch" : "rnews");
  354.         ptr->flds[UUX] = strsave(buf);
  355.     }
  356.     return(1);
  357. }
  358.  
  359. /*
  360.  *    checkqueue:
  361.  *
  362.  *    Logically, all this code does is return the size of the UUCP queue
  363.  *    for system "name".
  364.  *    I've taken the easy way out and popen'd "uuq" (4.3 BSD UUCP utility)
  365.  *    to parse the first line, which looks something like this:
  366.  *
  367.  *    <systemname>: <n> jobs, <nnnn> bytes, ....
  368.  *
  369.  *    I merely look for the first comma, and sscanf the number following.
  370.  *    A proper solution would be to dive in and parse the UUCP queues
  371.  *    themselves, but: it's moderately difficult, and it changes from 
  372.  *    system to system.
  373.  */
  374.  
  375. long
  376. checkqueue(name)
  377. char    *name; {
  378. #ifdef    UUQ
  379.     char buf[BUFSIZ];
  380.     long retval;
  381.     register char *p2;
  382.     FILE *p, *popen();
  383.     /* Gross, but the easiest way */
  384.     sprintf(buf, "uuq -l -s%s", name);
  385.     p = popen(buf, "r");
  386.     if (!fgets(buf, sizeof(buf), p)) {
  387.         return(0);
  388.     }
  389.     pclose(p);
  390.     p2 = strchr(buf, ',');
  391.     if (p2 && 1 == sscanf(p2+1, "%ld", &retval)) {
  392.         return(retval);
  393.     }
  394.     fprintf(stderr, "batcher: could not interpret %s\n", buf);
  395.     return(10000000);
  396. #else
  397.     return(10000000);
  398. #endif
  399. }
  400.  
  401. /*    This function returns the amount of free space on the spool
  402.     device, this may not work on your system - it reads the
  403.     second line from a "df /usr/spool/uucp" */
  404. #define    SPOOL "/usr/spool/uucp"
  405.  
  406. checkspool() {
  407. #ifdef    DFABLE
  408.     char buf[100];
  409.     FILE *p, *popen();
  410.     long val;
  411.     sprintf(buf, "df %s", SPOOL);
  412.     if (!(p = popen(buf, "r"))) {
  413.         fprintf(stderr, "batcher: couldn't popen %s\n", buf);
  414.         return(0);
  415.     }
  416.     if (!fgets(buf, sizeof(buf), p)) {
  417.         fprintf(stderr, "batcher: no first line in df\n");
  418.         return(0);
  419.     }
  420.     if (!fgets(buf, sizeof(buf), p)) {
  421.         fprintf(stderr, "batcher: no second line in df\n");
  422.         return(0);
  423.     }
  424.     if (1 != sscanf(buf, "%*s %*ld %*ld %ld", &val)) {
  425.         fprintf(stderr, "batcher: couldn't get size from %s\n", buf);
  426.         return(0);
  427.     }
  428.     if (pclose(p)) {
  429.         fprintf(stderr, "batcher: DF failed\n");
  430.         return(0);
  431.     }
  432.     val *= 1024;
  433.     if (val < spoollim) {
  434.         printf("batcher: spool limit exceeded, %ld bytes left\n", val);
  435.         return(0);
  436.     } else
  437.         return(1);
  438. #else
  439.     return(1);
  440. #endif
  441. }
  442.