root/usr/src/cmd/bnu/anlwrk.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */


/*
        This module contains routines that find C. files
        in a system spool directory, return the next C. file
        to process, and break up the C. line into arguments
        for processing.
*/

#include "uucp.h"

#define BOOKMARK_PRE    'A'
#define CLEAN_RETURN(fp) {\
        if (fp != NULL) \
                (void) fclose(fp); \
        fp = NULL; \
        return(0); \
        /* NOTREACHED */ \
}

/* C.princetN0026 - ('C' + '.') - "princet" */
#define SUFSIZE (MAXBASENAME - 2 - SYSNSIZE)
#define LLEN 50
#define MAXRQST 250

static void insert();
static int  anlwrk(), bldflst();
extern int  iswrk(), gtwvec(), gnamef();

static char  Filent[LLEN][NAMESIZE]; /* array of C. file names (text)        */
static char *Fptr[LLEN];             /* pointers to names in Filent          */
static short Nnext;                  /* index of next C. file in Fptr list   */
static short Nfiles = 0;             /* Number of files in Filent            */

/*
 * read a line from the workfile (C.file)
 *      file    -> work file  (Input/Output)  made '\0' after work completion
 *      wvec    -> address of array to return arguments (Output)
 *      wcount  -> maximum # of arguments to return in wvec
 *              NOTE: wvec should be large enough to accept wcount + 1 pointers
 *              since NULL is inserted after last item.
 * returns:
 *      0          ->  no more work in this file
 *      positive # -> number of arguments
 */
static int
anlwrk(char *file, char **wvec, int wcount)
{
        int i;
        FILE *p_bookmark;    /* pointer to afile */
        static   FILE *fp = NULL;    /* currently opened C. file pointer    */
        static char afile[NAMESIZE]; /* file with line count for book marks */
        static char str[MAXRQST];    /* the string which  wvec points to    */
        static short acount;
        struct stat stbuf;
        int     nargs;          /* return value == # args in the line */

        if (file[0] == '\0') {
                if (fp != NULL)
                        errent("anlwrk",
                           "attempt made to use old workfile was thwarted", 0,
                           __FILE__, __LINE__);
                CLEAN_RETURN(fp);
                /* NOTREACHED */
        }
        if (fp == NULL) {
                fp = fopen(file, "r");

                if (fp == NULL){ /* can't open C. file! */
                        errent(Ct_OPEN,file,errno, __FILE__, __LINE__);
                        /* this may not work, but we'll try it */
                        /* It will fail if the C. name is more than */
                        /* the standard 14 characters - if this is the */
                        /* tocorrupt will exit with ASSERT */
                        toCorrupt(file);
                        return(0);
                }
                (void) fstat(fileno(fp), &stbuf);
                Nstat.t_qtime = stbuf.st_mtime;

                (void) strncpy(afile, BASENAME(file, '/'), NAMESIZE);
                afile[NAMESIZE-1] = NULLCHAR;
                *afile = BOOKMARK_PRE; /* make up name by replacing C with A */
                acount = 0;
                p_bookmark = fopen(afile, "r");
                if (p_bookmark != NULL) {
                        /* get count of already completed work */
                        i = fscanf(p_bookmark, "%hd", &acount);
                        (void) fclose(p_bookmark);
                        if (i <= 0)
                                acount = 0;

                        /* skip lines which have already been processed */
                        for (i = 0; i < acount; i++) {
                                if (fgets(str, MAXRQST, fp) == NULL)
                                        break;
                        }
                }

        }

        if (fgets(str, MAXRQST, fp) == NULL) {
                ASSERT(unlink(file) == 0, Ct_UNLINK, file, errno);
                (void) unlink(afile);
                DEBUG(4,"Finished Processing file: %s\n",file);
                *file = '\0';
                CLEAN_RETURN(fp);
                /*NOTREACHED*/
        }

        nargs = getargs(str, wvec, wcount);

        /* sanity checks for C. file */
        if ((str[0] != 'R' && str[0] != 'S')    /* legal wrktypes are R and S */
         || (str[0] == 'R' && nargs < 6)        /* R lines need >= 6 entries */
         || (str[0] == 'S' && nargs < 7)) {     /* S lines need >= 7 entries */
                /* bad C. file - stash it */
                toCorrupt(file);
                (void) unlink(afile);
                *file = '\0';
                CLEAN_RETURN(fp);
                /*NOTREACHED*/
        }

        p_bookmark = fopen(afile, "w"); /* update bookmark file */
        if (p_bookmark == NULL)
            errent(Ct_OPEN, afile, errno, __FILE__, __LINE__);
        else {
            chmod(afile, CFILEMODE);
            (void) fprintf(p_bookmark, "%d", acount);
            (void) fclose(p_bookmark);
        }
        acount++;
        return(nargs);
}

/*
 * Check the list of work files (C.sys).
 * If it is empty or the present work is exhausted, it
 * will call bldflst to generate a new list.
 *
 * If there are no more jobs in the current job grade,
 * it will call findgrade to get the new job grade to process.
 *
 *      file    -> address of array to return full pathname in
 * returns:
 *      0       -> no more work (or some error)
 *      1       -> there is work
 */
extern int
iswrk(file)
char *file;
{
        char newspool[MAXFULLNAME];
        char lockname[MAXFULLNAME];
        char gradedir[2*MAXBASENAME];

        if (Nfiles == 0) {
                /* If Role is MASTER and JobGrade is null, then
                 * there is no work for the remote.
                 *
                 * In the case of uucico slave, the job grade
                 * to process should be determined before building
                 * the work list.
                 */
                if (Role == MASTER) {
                    if (*JobGrade == NULLCHAR)
                        return(0);

                    if (bldflst() != 0) {
                        (void) sprintf(file, "%s/%s", RemSpool, Fptr[Nnext]);
                        Nfiles--;
                        Nnext++;
                        return(1);
                    }
                    (void) sprintf(lockname, "%.*s.%s", SYSNSIZE, Rmtname, JobGrade);
                    delock(LOCKPRE, lockname);
                } else {
                    (void) sprintf(lockname, "%ld", (long) getpid());
                    delock(LOCKPRE, lockname);
                }

                (void) sprintf(newspool, "%s/%s", SPOOL, Rmtname);
                ASSERT(chdir(newspool) == 0, Ct_CHDIR, newspool, errno);

                findgrade(newspool, JobGrade);
                DEBUG(4, "Job grade to process - %s\n", JobGrade);
                if (*JobGrade == NULLCHAR)
                    return(0);

                (void) sprintf(lockname, "%.*s.%s", SYSNSIZE, Rmtname, JobGrade);
                (void) umlock(LOCKPRE, lockname);

                /* Make the new job grade directory the working directory
                 * and set RemSpool.
                 */
                (void) sprintf(gradedir, "%s/%s", Rmtname, JobGrade);
                chremdir(gradedir);
                bldflst();
        }

        (void) sprintf(file, "%s/%s", RemSpool, Fptr[Nnext]);
        Nfiles--;
        Nnext++;
        return(1);
}


/*
 * build list of work files for given system using an insertion sort
 * Nfiles, Nnext, RemSpool and Rmtname are global
 *
 * return:
 *      number of C. files in list - (Nfiles)
 */
static int
bldflst()
{
        DIR *pdir;
        char filename[NAMESIZE];
        char prefix[SYSNSIZE+3];

        Nnext = Nfiles = 0;
        if ((pdir = opendir(RemSpool)) == NULL)
                return(0);

        (void) sprintf(prefix, "C.%.*s", SYSNSIZE, Rmtname);
        while (gnamef(pdir, filename) ) {
                if (!PREFIX(prefix, filename))
                        continue;
                if ((strlen(filename)-strlen(prefix)) != SUFSIZE) {
                        errent("bldflst: Funny filename", filename, 0,
                           __FILE__, __LINE__);
                        continue;
                }
                insert(filename);
        }
        closedir(pdir);
        return(Nfiles);
}

/*
 * get work return
 *      file    -> place to deposit file name
 *      wrkvec  -> array to return arguments
 *      wcount  -> max number of args for wrkvec
 * returns:
 *      nargs   ->  number of arguments
 *      0       ->  no arguments - fail
 */
extern int
gtwvec(char *file, char **wrkvec, int wcount)
{
        int nargs;

        DEBUG(7, "gtwvec: dir %s\n", RemSpool);
        while ((nargs = anlwrk(file, wrkvec, wcount)) == 0) {
                if (!iswrk(file))
                        return(0);
        }
        DEBUG(7, "        return - %d\n", nargs);
        return(nargs);
}


/*
 * insert - insert file name in sorted list
 * return - none
 */
static void
insert(file)
char *file;
{
        int i, j;
        char *p;

        DEBUG(7, "insert(%s)  ", file);
        for (i = Nfiles; i>0; i--) {
            if (strcmp(file, Fptr[i-1]) > 0)
                break;
        }
        if (i == LLEN) /* if this is off the end get out */
            return;

        /* get p (pointer) to where the text of name will go */
        if (Nfiles == LLEN)     /* last possible entry */
            /* put in text of last and decrement Nfiles for make hole */
            p = strcpy(Fptr[--Nfiles], file);
        else
            p = strcpy(Filent[Nfiles], file);   /* copy to next free  */

        /* make a hole for new entry */
        for (j = Nfiles; j >i; j--)
            Fptr[j] = Fptr[j-1];

        DEBUG(7, "insert %s ", p);
        DEBUG(7, "at %d\n", i);
        Fptr[i] = p;
        Nfiles++;
        return;
}