Path: blob/main/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c
107468 views
/*-1* Copyright (c) 2005-2006 The FreeBSD Project2* All rights reserved.3*4* Author: Victor Cruceru <[email protected]>5*6* Redistribution of this software and documentation and use in source and7* binary forms, with or without modification, are permitted provided that8* the following conditions are met:9*10* 1. Redistributions of source code or documentation must retain the above11* copyright notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/*30* Host Resources MIB implementation for SNMPd: instrumentation for31* hrPrinterTable32*/3334#include <sys/param.h>35#include <sys/stat.h>3637#include <assert.h>38#include <err.h>39#include <errno.h>40#include <paths.h>41#include <stdlib.h>42#include <string.h>43#include <syslog.h>44#include <unistd.h>4546#include "hostres_snmp.h"47#include "hostres_oid.h"48#include "hostres_tree.h"4950#include <sys/dirent.h>51#include "lp.h"5253/* Constants */54static const struct asn_oid OIDX_hrDevicePrinter_c = OIDX_hrDevicePrinter;5556enum PrinterStatus {57PS_OTHER = 1,58PS_UNKNOWN = 2,59PS_IDLE = 3,60PS_PRINTING = 4,61PS_WARMUP = 562};6364/*65* This structure is used to hold a SNMP table entry66* for HOST-RESOURCES-MIB's hrPrinterTable.67*/68struct printer_entry {69int32_t index;70int32_t status; /* values from PrinterStatus enum above */71u_char detectedErrorState[2];72TAILQ_ENTRY(printer_entry) link;73#define HR_PRINTER_FOUND 0x00174uint32_t flags;7576};77TAILQ_HEAD(printer_tbl, printer_entry);7879/* the hrPrinterTable */80static struct printer_tbl printer_tbl = TAILQ_HEAD_INITIALIZER(printer_tbl);8182/* last (agent) tick when hrPrinterTable was updated */83static uint64_t printer_tick;8485/**86* Create entry into the printer table.87*/88static struct printer_entry *89printer_entry_create(const struct device_entry *devEntry)90{91struct printer_entry *entry = NULL;9293assert(devEntry != NULL);94if (devEntry == NULL)95return (NULL);9697if ((entry = malloc(sizeof(*entry))) == NULL) {98syslog(LOG_WARNING, "hrPrinterTable: %s: %m", __func__);99return (NULL);100}101memset(entry, 0, sizeof(*entry));102entry->index = devEntry->index;103INSERT_OBJECT_INT(entry, &printer_tbl);104return (entry);105}106107/**108* Delete entry from the printer table.109*/110static void111printer_entry_delete(struct printer_entry *entry)112{113114assert(entry != NULL);115if (entry == NULL)116return;117118TAILQ_REMOVE(&printer_tbl, entry, link);119free(entry);120}121122/**123* Find a printer by its index124*/125static struct printer_entry *126printer_find_by_index(int32_t idx)127{128struct printer_entry *entry;129130TAILQ_FOREACH(entry, &printer_tbl, link)131if (entry->index == idx)132return (entry);133134return (NULL);135}136137/**138* Get the status of a printer139*/140static enum PrinterStatus141get_printer_status(const struct printer *pp)142{143char statfile[MAXPATHLEN];144char lockfile[MAXPATHLEN];145char fline[128];146int fd;147FILE *f = NULL;148enum PrinterStatus ps = PS_UNKNOWN;149150if (pp->lock_file[0] == '/')151strlcpy(lockfile, pp->lock_file, sizeof(lockfile));152else153snprintf(lockfile, sizeof(lockfile), "%s/%s",154pp->spool_dir, pp->lock_file);155156fd = open(lockfile, O_RDONLY);157if (fd < 0 || flock(fd, LOCK_SH | LOCK_NB) == 0) {158ps = PS_IDLE;159goto LABEL_DONE;160}161162if (pp->status_file[0] == '/')163strlcpy(statfile, pp->status_file, sizeof(statfile));164else165snprintf(statfile, sizeof(statfile), "%s/%s",166pp->spool_dir, pp->status_file);167168f = fopen(statfile, "r");169if (f == NULL) {170syslog(LOG_ERR, "cannot open status file: %s", strerror(errno));171ps = PS_UNKNOWN;172goto LABEL_DONE;173}174175memset(&fline[0], '\0', sizeof(fline));176if (fgets(fline, sizeof(fline) -1, f) == NULL) {177ps = PS_UNKNOWN;178goto LABEL_DONE;179}180181if (strstr(fline, "is ready and printing") != NULL) {182ps = PS_PRINTING;183goto LABEL_DONE;184}185186if (strstr(fline, "to become ready (offline?)") != NULL) {187ps = PS_OTHER;188goto LABEL_DONE;189}190191LABEL_DONE:192if (fd >= 0)193(void)close(fd); /* unlocks as well */194195if (f != NULL)196(void)fclose(f);197198return (ps);199}200201/**202* Called for each printer found in /etc/printcap.203*/204static void205handle_printer(struct printer *pp)206{207struct device_entry *dev_entry;208struct printer_entry *printer_entry;209char dev_only[128];210struct stat sb;211212if (pp->remote_host != NULL) {213HRDBG("skipped %s -- remote", pp->printer);214return;215}216217if (strncmp(pp->lp, _PATH_DEV, strlen(_PATH_DEV)) != 0) {218HRDBG("skipped %s [device %s] -- remote", pp->printer, pp->lp);219return;220}221222memset(dev_only, '\0', sizeof(dev_only));223snprintf(dev_only, sizeof(dev_only), "%s", pp->lp + strlen(_PATH_DEV));224225HRDBG("printer %s has device %s", pp->printer, dev_only);226227if (stat(pp->lp, &sb) < 0) {228if (errno == ENOENT) {229HRDBG("skipped %s -- device %s missing",230pp->printer, pp->lp);231return;232}233}234235if ((dev_entry = device_find_by_name(dev_only)) == NULL) {236HRDBG("%s not in hrDeviceTable", pp->lp);237return;238}239HRDBG("%s found in hrDeviceTable", pp->lp);240dev_entry->type = &OIDX_hrDevicePrinter_c;241242dev_entry->flags |= HR_DEVICE_IMMUTABLE;243244/* Then check hrPrinterTable for this device */245if ((printer_entry = printer_find_by_index(dev_entry->index)) == NULL &&246(printer_entry = printer_entry_create(dev_entry)) == NULL)247return;248249printer_entry->flags |= HR_PRINTER_FOUND;250printer_entry->status = get_printer_status(pp);251memset(printer_entry->detectedErrorState, 0,252sizeof(printer_entry->detectedErrorState));253}254255static void256hrPrinter_get_OS_entries(void)257{258int status, more;259struct printer myprinter, *pp = &myprinter;260261init_printer(pp);262HRDBG("---->Getting printers .....");263more = firstprinter(pp, &status);264if (status)265goto errloop;266267while (more) {268do {269HRDBG("---->Got printer %s", pp->printer);270271handle_printer(pp);272more = nextprinter(pp, &status);273errloop:274if (status)275syslog(LOG_WARNING,276"hrPrinterTable: printcap entry for %s "277"has errors, skipping",278pp->printer ? pp->printer : "<noname?>");279} while (more && status);280}281282lastprinter();283printer_tick = this_tick;284}285286/**287* Init the things for hrPrinterTable288*/289void290init_printer_tbl(void)291{292293hrPrinter_get_OS_entries();294}295296/**297* Finalization routine for hrPrinterTable298* It destroys the lists and frees any allocated heap memory299*/300void301fini_printer_tbl(void)302{303struct printer_entry *n1;304305while ((n1 = TAILQ_FIRST(&printer_tbl)) != NULL) {306TAILQ_REMOVE(&printer_tbl, n1, link);307free(n1);308}309}310311/**312* Refresh the printer table if needed.313*/314void315refresh_printer_tbl(void)316{317struct printer_entry *entry;318struct printer_entry *entry_tmp;319320if (this_tick <= printer_tick) {321HRDBG("no refresh needed");322return;323}324325/* mark each entry as missing */326TAILQ_FOREACH(entry, &printer_tbl, link)327entry->flags &= ~HR_PRINTER_FOUND;328329hrPrinter_get_OS_entries();330331/*332* Purge items that disappeared333*/334entry = TAILQ_FIRST(&printer_tbl);335while (entry != NULL) {336entry_tmp = TAILQ_NEXT(entry, link);337if (!(entry->flags & HR_PRINTER_FOUND))338printer_entry_delete(entry);339entry = entry_tmp;340}341342printer_tick = this_tick;343344HRDBG("refresh DONE ");345}346347int348op_hrPrinterTable(struct snmp_context *ctx __unused, struct snmp_value *value,349u_int sub, u_int iidx __unused, enum snmp_op curr_op)350{351struct printer_entry *entry;352353refresh_printer_tbl();354355switch (curr_op) {356357case SNMP_OP_GETNEXT:358if ((entry = NEXT_OBJECT_INT(&printer_tbl, &value->var,359sub)) == NULL)360return (SNMP_ERR_NOSUCHNAME);361value->var.len = sub + 1;362value->var.subs[sub] = entry->index;363goto get;364365case SNMP_OP_GET:366if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var,367sub)) == NULL)368return (SNMP_ERR_NOSUCHNAME);369goto get;370371case SNMP_OP_SET:372if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var,373sub)) == NULL)374return (SNMP_ERR_NO_CREATION);375return (SNMP_ERR_NOT_WRITEABLE);376377case SNMP_OP_ROLLBACK:378case SNMP_OP_COMMIT:379abort();380}381abort();382383get:384switch (value->var.subs[sub - 1]) {385386case LEAF_hrPrinterStatus:387value->v.integer = entry->status;388return (SNMP_ERR_NOERROR);389390case LEAF_hrPrinterDetectedErrorState:391return (string_get(value, entry->detectedErrorState,392sizeof(entry->detectedErrorState)));393}394abort();395}396397398