root/usr/src/cmd/lp/cmd/lpsched/files.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

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

#include "lpsched.h"
#include <syslog.h>
#include <strings.h>

static char time_buf[50];
#ifdef LP_USE_PAPI_ATTR
static char *extractReqno(char *req_file);
#endif

/**
 ** chfiles() - CHANGE OWNERSHIP OF FILES, RETURN TOTAL SIZE
 **/

off_t chfiles ( char * * list, uid_t uid, gid_t gid )   /* funcdef */
{
    size_t      total;
    struct stat stbuf;
    char        *file;

    total = 0;

    while(file = *list++)
    {
        if (STRNEQU(Lp_Temp, file, strlen(Lp_Temp)) ||
            STRNEQU(Lp_Tmp, file, strlen(Lp_Tmp)))
        {
            /*
             * Once this routine (chfiles) is called for a request,
             * any temporary files are ``ours'', i.e. they are on our
             * machine. A user running on an RFS-connected remote machine
             * can't necessarily know our machine name, so can't put
             * the files where they belong (Lp_Tmp/machine). But now we
             * can. Of course, this is all done with mirrors, as Lp_Temp
             * and Lp_Tmp/local-machine are symbolicly linked. So we just
             * change the name. This saves on wear and tear later.
             */
            if (STRNEQU(Lp_Temp, file, strlen(Lp_Temp)))
            {
                char *newfile = makepath(Lp_Tmp, Local_System,
                                file + strlen(Lp_Temp) + 1, NULL);

                Free(file);
                list[-1] = file = newfile;
            }

            (void) chownmod(file, uid, gid, 0600);
        }

        if (Stat(file, &stbuf) == -1)
            return(-1);

        switch (stbuf.st_mode & S_IFMT) {
        case 0:
        case S_IFREG:
            break;

        case S_IFIFO:
            if (!isadmin(uid))
                return(-1);
            /*
             * If any of the files is a FIFO, the size indicator
             * becomes meaningless. On the other hand, returning
             * a total of zero causes the request to be rejected,
             * so we return something > 0.
             */
            stbuf.st_size = 1;
            break;

        case S_IFDIR:
        case S_IFCHR:
        case S_IFBLK:
        default:
            return(-1);
        }

        total += stbuf.st_size;
    }
    return(total);
}

/**
 ** rmfiles() - DELETE/LOG FILES FOR DEFUNCT REQUEST
 **/

void rmfiles ( RSTATUS * rp, int log_it )       /* funcdef */
{
    char        **file  = rp->request->file_list;
    char        *path;
    char        num[STRSIZE(MOST_FILES) + 1];
    static int  fd      = -1;
    int         reqfd;
    int         count   = 0;
#ifdef LP_USE_PAPI_ATTR
    struct stat tmpBuf;
    char        *idno = NULL;
    char        tmpName[BUFSIZ];
#endif


    if (rp->req_file) {
            char *p, *q;

           /*
            * The secure request file is removed first to prevent
            * reloading should the system crash while in rmfiles().
            */
            path = makepath(Lp_Requests, rp->req_file, (char *)0);
            (void) Unlink(path);
            Free(path);

            /*
             * Copy the request file to the log file, if asked,
             * or simply remove it.
             */
            path = makepath(Lp_Tmp, rp->req_file, (char *)0);
            if (log_it && rp->secure && rp->secure->req_id) {
                if (fd == -1)
                    fd = open_locked(Lp_ReqLog, "a", MODE_NOREAD);
                if ((fd  >= 0) && (reqfd = Open(path, O_RDONLY, 0)) != -1) {
                    register int        n;
                    char                buf[BUFSIZ];

                    (void) strftime(time_buf, sizeof (time_buf),
                        NULL, localtime(&(rp->secure->date)));
                    fdprintf(fd, "= %s, uid %u, gid %u, size %ld, %s\n",
                        rp->secure->req_id, rp->secure->uid, rp->secure->gid,
                        rp->secure->size, time_buf);
                    if (rp->slow)
                        fdprintf(fd, "x %s\n", rp->slow);
                    if (rp->fast)
                        fdprintf(fd, "y %s\n", rp->fast);
                    if (rp->printer && rp->printer->printer)
                        fdprintf(fd, "z %s\n", rp->printer->printer->name);
                    while ((n = Read(reqfd, buf, BUFSIZ)) > 0)
                        write (fd, buf, n);
                    Close (reqfd);
                }
            }
            (void)Unlink (path);                /* remove request file */
            Free (path);

            p = strdup(rp->req_file);           /* remove host/id file */
            if (q = strrchr(p, '-')) {
                    *q = '\0';
                    path = makepath(Lp_Tmp, p, NULL);
                    (void) Unlink(path);
                    Free(path);
            }
            Free(p);

#ifdef LP_USE_PAPI_ATTR
        /* Look for a PAPI job attribute file, if it exists remove it */
        idno = extractReqno(rp->req_file);
        snprintf(tmpName, sizeof (tmpName), "%s-%s", idno, LP_PAPIATTRNAME);
        path = makepath(Lp_Temp, tmpName, (char *)0);

        if (((path != NULL) && (idno != NULL)) && (stat(path, &tmpBuf) == 0))
        {
            /* PAPI job attribute file exists for this job so remove it */
            (void) Unlink(path);
        }

        Free(idno);
        Free(path);
#endif
    }

    if (file)                                   /* remove file in filelist */
        while(*file)
        {
                /*
                 * The copies of user files.
                 */
                if ((STRNEQU(Lp_Temp, *file, strlen(Lp_Temp)) ||
                    STRNEQU(Lp_Tmp, *file, strlen(Lp_Tmp))) &&
                    (! strstr(*file, "../")))

                    (void) Unlink(*file);

                count++;
                file++;
        }

    if (rp->secure && rp->secure->req_id) {
        char *p;
        p = getreqno(rp->secure->req_id);

        /*
         * The filtered files. We can't rely on just the RS_FILTERED
         * flag, since the request may have been cancelled while
         * filtering. On the other hand, just checking "rp->slow"
         * doesn't mean that the files exist, because the request
         * may have been canceled BEFORE filtering started. Oh well.
         */
        if (rp->slow)
            while(count > 0)
            {
                sprintf(num, "%d", count--);
                path = makestr(Lp_Temp, "/F", p, "-", num, (char *)0);
                Unlink(path);
                Free(path);
            }

        /*
         * The notify/error file.
         */
        path = makepath(Lp_Temp, p, (char *)0);
        (void) Unlink(path);
        Free(path);
    }
}

/**
 ** _alloc_req_id(void) - ALLOCATE NEXT REQUEST ID
 **/

#define SEQF_DEF_START  1
#define SEQF_DEF_END    59999
#define SEQF_DEF_INCR   1
#define SEQF            ".SEQF"


long
_alloc_req_id ( void )
{
        static short            started = 0;

        static int              fd;

        static long             start;
        static long             end;
        static long             incr;
        static long             curr;
        static long             wrap;

        static char             fmt[
                                STRSIZE(BIGGEST_REQID_S)/* start   */
                              + 1                       /* :       */
                              + STRSIZE(BIGGEST_REQID_S)/* end     */
                              + 1                       /* :       */
                              + STRSIZE(BIGGEST_REQID_S)/* incr    */
                              + 1                       /* :       */
                              + 4                       /* %ld\n   */
                              + 1                       /* (nul)   */
                                ];

        char                    buf[256];
        int len;

        long                    ret;


        if (!started) {
                snprintf(buf, sizeof (buf), "%s/%s", Lp_Temp, SEQF);
                if (((fd = open_locked(buf, "r+", 0644)) < 0) &&
                    ((fd = open_locked(buf, "w", 0644)) < 0))
                        fail ("Can't open file %s (%s).\n", buf, PERROR);

                lseek(fd, 0, SEEK_SET);

                read(fd, buf, sizeof (buf));
                if (sscanf(buf, "%ld:%ld:%ld:%ld\n", &start, &end, &incr, &curr) != 4) {
                        start = SEQF_DEF_START;
                        end = SEQF_DEF_END;
                        curr = start;
                        incr = SEQF_DEF_INCR;
                }

                if (start < 0)
                        start = SEQF_DEF_START;
                if (end > SEQF_DEF_END)
                        end = SEQF_DEF_END;
                if (curr < start || curr > end)
                        curr = start;

                sprintf (fmt, "%ld:%ld:%ld:%%ld\n", start, end, incr);
                started = 1;
        }

        wrap = curr;
        do {
                ret = curr;
                if ((curr += incr) > end)
                curr = start;

        } while ( wrap != curr && ((RSTATUS *)request_by_id_num(ret)) ) ;

        /* write the new id file */
        lseek(fd, 0, SEEK_SET);
        len = sprintf(buf, fmt, curr);
        write(fd, buf, len);
        ftruncate(fd, len);

        if (curr == wrap) {
                note("alloc_req_id(): out of ids\n");
                errno = EEXIST;
                return(SEQF_DEF_START-1);
        } else
                return (ret);
}

/**
 ** _alloc_file() - ALLOCATE FILES FOR A REQUEST
 **/

char *
_alloc_files (
        int                     num,
        char *                  prefix,
        uid_t                   uid,
        gid_t                   gid
)
{
        static char             base[
                                1                       /* F       */
                              + STRSIZE(BIGGEST_REQID_S)/* req-id  */
                              + 1                       /* -       */
                              + STRSIZE(MOST_FILES_S)   /* file-no */
                              + 1                       /* (nul)   */
                                ];

        char *                  file;
        char *                  cp;

        int                     fd;
        int                     plus;


        if (num > BIGGEST_REQID)
                return (0);

        if (!prefix) {
                int id;

                if ((id = _alloc_req_id()) < SEQF_DEF_START )
                        return(NULL); /* Out of request IDs (errno = EEXIST) */
                snprintf (base, sizeof (base), "%d-%d", id, MOST_FILES);
                plus = 0;
        } else {
                if (strlen(prefix) > (size_t) 6)
                        return (0);
                snprintf (base, sizeof (base), "F%s-%d", prefix, MOST_FILES);
                plus = 1;
        }

        file = makepath(Lp_Temp, base, (char *)0);

        cp = strrchr(file, '-') + 1;
        while (num--) {
                sprintf (cp, "%d", num + plus);
                if ((fd = Open(file, O_CREAT|O_TRUNC, 0600)) == -1) {
                        Free (file);
                        return (0);
                } else {
                        Close (fd);
                        (void) chownmod(file, uid, gid, 0600);
                }
        }

#ifdef LP_USE_PAPI_ATTR
        if (prefix == NULL)
        {
                /*
                 * Initial job request (s_alloc_files) so create an empty PAPI
                 * Attribute file; note, this file will only be used if the
                 * print job has been submitted via the PAPI interface.
                 */

                file = (char *)Realloc(file, strlen(file) +
                                        strlen(LP_PAPIATTRNAME) + 1);
                if (file != NULL)
                {
                        cp = strrchr(file, '-') + 1;
                        sprintf(cp, "%s", LP_PAPIATTRNAME);

                        if ((fd = Open(file, O_CREAT|O_TRUNC, 0600)) == -1)
                        {
                                Free(file);
                                return (0);
                        }
                        else
                        {
                                Close(fd);
                                (void) chownmod(file, uid, gid, 0600);
                        }

                        Free(file);
                }
        }
#endif


        if ((cp = strrchr(base, '-')))
                *cp = 0;

        return (base);
}


#ifdef LP_USE_PAPI_ATTR
static char *extractReqno(char *req_file)

{
        char *start = NULL;
        char *end = NULL;
        char *result = NULL;

        start = strrchr(req_file, '/');
        end = strrchr(req_file, '-');

        if ((start != NULL) && (end != NULL))
        {
                start++;
                if (end > start)
                {
                        int n = end - start;
                        result = (char *)Malloc(n+1);
                        strncpy(result, start, n);
                        result[n] = '\0';
                }
        }

        return (result);
} /* extractReqno() */
#endif