[BACK]Return to lp_displayq.c CVS log [TXT][DIR] Up to [local] / src / usr.sbin / lpd

File: [local] / src / usr.sbin / lpd / lp_displayq.c (download)

Revision 1.1, Fri Apr 27 16:14:36 2018 UTC (6 years, 1 month ago) by eric
Branch point for: MAIN

Initial revision

/*	$OpenBSD: lp_displayq.c,v 1.1 2018/04/27 16:14:36 eric Exp $	*/

/*
 * Copyright (c) 2017 Eric Faurot <eric@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "lp.h"

#include "log.h"

static void dolong(int, struct lp_printer *, struct lp_jobfilter *, int,
    const char *, int);
static void doshort(int, struct lp_printer *, struct lp_jobfilter *, int,
    const char *, int);

void
lp_displayq(int ofd, struct lp_printer *lp, int lng, struct lp_jobfilter *jf)
{
	struct lp_queue q;
	pid_t currpid;
	char status[256], currjob[PATH_MAX];
	int i, active, qstate;

	/* Warn about the queue state if needed. */
	if (lp_getqueuestate(lp, 0, &qstate) == -1)
		log_warnx("cannot get queue state");
	else {
		if (qstate & LPQ_PRINTER_DOWN) {
			if (lp->lp_type == PRN_LPR)
				dprintf(ofd, "%s: ", lpd_hostname);
			dprintf(ofd, "Warning: %s is down\n", lp->lp_name);
		}
		if (qstate & LPQ_QUEUE_OFF) {
			if (lp->lp_type == PRN_LPR)
				dprintf(ofd, "%s: ", lpd_hostname);
			dprintf(ofd, "Warning: %s queue is turned off\n",
			    lp->lp_name);
		}
	}

	/* Read queue content. */
	if ((lp_readqueue(lp, &q)) == -1) {
		log_warnx("cannot read queue");
		if (lp->lp_type == PRN_LPR)
			dprintf(ofd, "%s: ", lpd_hostname);
		dprintf(ofd, "Warning: cannot read queue\n");
	}

	/* Display current printer status. */
	if (lp_getcurrtask(lp, &currpid, currjob, sizeof(currjob)) == -1)
		log_warnx("cannot get current task");

	if (currpid) {
		if (lp->lp_type == PRN_LPR)
			dprintf(ofd, "%s: ", lpd_hostname);
		if (lp_getstatus(lp, status, sizeof(status)) == -1) {
			log_warnx("cannot read printer status");
			dprintf(ofd, "Warning: cannot read status file\n");
		}
		else
			dprintf(ofd, "%s\n", status);
	}

	/* Display queue content. */
	if (q.count == 0) {
		if (lp->lp_type != PRN_LPR)
			dprintf(ofd, "no entries\n");
	}
	else {
		if (currpid == 0) {
			if (lp->lp_type == PRN_LPR)
				dprintf(ofd, "%s: ", lpd_hostname);
			dprintf(ofd, "Warning: no daemon present\n");
		}
		if (!lng) {
			dprintf(ofd, "Rank   Owner      Job  Files");
			dprintf(ofd, "%43s\n", "Total Size");
		}
		for (i = 0; i < q.count; i++) {
			active = !strcmp(q.cfname[i], currjob);
			if (lng)
				dolong(ofd, lp, jf, i+1, q.cfname[i], active);
			else
				doshort(ofd, lp, jf, i+1, q.cfname[i], active);
		}
	}

	lp_clearqueue(&q);
}

static int
checklists(const char *cfname, struct lp_jobfilter *jf, const char *person)
{
	int i;

	if (jf->nuser == 0 && jf->njob == 0)
		return 1;

	/* Check if user is in user list. */
	for (i = 0; i < jf->nuser; i++)
		if (!strcmp(jf->users[i], person))
			return 1;

	/* Skip if hostnames don't match. */
	if (strcmp(LP_JOBHOST(cfname), jf->hostfrom))
		return 0;

	/* Check for matching jobnum. */
	for (i = 0; i < jf->njob; i++)
		if (jf->jobs[i] == LP_JOBNUM(cfname))
			return 1;

	return 0;
}

static const char *
rankstr(int rank, int active)
{
	static char buf[16];
	const char *sfx;

	if (active)
		return "active";

	sfx = "th";
	switch (rank % 10) {
	case 1:
		if ((rank / 10) % 10 != 1)
			sfx = "st";
		break;
	case 2:
		sfx = "nd";
		break;
	case 3:
		sfx = "rd";

	}

	snprintf(buf, sizeof(buf), "%d%s", rank, sfx);
	return buf;
}

static void
doshort(int ofd, struct lp_printer *lp,  struct lp_jobfilter *jf, int rank,
    const char *cfname, int active)
{
	struct stat st;
	FILE *fp;
	const char *fname;
	char dfname[PATH_MAX], names[80], *line = NULL;
	ssize_t len;
	size_t linesz = 0, totalsz = 0;
	int copies = 0;

	fp = lp_fopen(lp, cfname);
	if (fp == NULL) {
		log_warn("cannot open %s", cfname);
		return;
	}

	names[0] = '\0';

	while ((len = getline(&line, &linesz, fp)) != -1) {
		if (line[len-1] == '\n')
			line[len - 1] = '\0';
		switch (line[0]) {
		case 'P':
			if (!checklists(cfname, jf, line + 1))
				goto end;

			dprintf(ofd, "%-7s%-11s%-4i ", rankstr(rank, active),
			    line + 1, LP_JOBNUM(cfname));
			break;

		case 'N':
			fname = line + 1;
			if (!strcmp(fname, " "))
				fname = "(standard input)";

			if (names[0])
				(void)strlcat(names, ", ", sizeof(names));
			(void)strlcat(names, fname, sizeof(names));
			if (lp_stat(lp, dfname, &st) == -1)
				log_warn("cannot stat %s", dfname);
			else
				totalsz += copies * st.st_size;
			copies = 0;
			break;

		default:
			if (line[0] < 'a' || line[0] > 'z')
				continue;
			if (copies++ == 0)
				(void)strlcpy(dfname, line+1, sizeof(dfname));
			break;
		}
	}

	dprintf(ofd, "%-37s %lld bytes\n", names, (long long)totalsz);

    end:
	free(line);
}

static void
dolong(int ofd, struct lp_printer *lp,  struct lp_jobfilter *jf, int rank,
    const char *cfname, int active)
{
	struct stat st;
	FILE *fp;
	const char *fname;
	char dfname[PATH_MAX], names[80], buf[64], *line = NULL;
	ssize_t len;
	size_t linesz = 0;
	int copies = 0;

	fp = lp_fopen(lp, cfname);
	if (fp == NULL) {
		log_warn("cannot open %s", cfname);
		return;
	}

	names[0] = '\0';

	while ((len = getline(&line, &linesz, fp)) != -1) {
		if (line[len-1] == '\n')
			line[len - 1] = '\0';
		switch (line[0]) {
		case 'P':
			if (!checklists(cfname, jf, line + 1))
				goto end;

			snprintf(buf, sizeof(buf), "%s: %s", line+1,
			    rankstr(rank, active));
			dprintf(ofd, "\n%-41s[job %s]\n", buf, cfname + 3);
			break;

		case 'N':
			fname = line + 1;
			if (!strcmp(fname, " "))
				fname = "(standard input)";

			if (copies > 1)
				dprintf(ofd, "\t%-2d copies of %-19s", copies,
				    fname);
			else
				dprintf(ofd, "\t%-32s", fname);

			if (lp_stat(lp, dfname, &st) == -1) {
				log_warn("cannot stat %s", dfname);
				dprintf(ofd, " ??? bytes\n");
			}
			else
				dprintf(ofd, " %lld bytes\n",
				    (long long)st.st_size);
			copies = 0;
			break;

		default:
			if (line[0] < 'a' || line[0] > 'z')
				continue;
			if (copies++ == 0)
				(void)strlcpy(dfname, line+1, sizeof(dfname));
			break;
		}
	}

    end:
	free(line);
}