1154133Sharti/*- 2154133Sharti * Copyright (c) 2005-2006 The FreeBSD Project 3154133Sharti * All rights reserved. 4154133Sharti * 5154133Sharti * Author: Victor Cruceru <soc-victor@freebsd.org> 6154133Sharti * 7154133Sharti * Redistribution of this software and documentation and use in source and 8154133Sharti * binary forms, with or without modification, are permitted provided that 9154133Sharti * the following conditions are met: 10154133Sharti * 11154133Sharti * 1. Redistributions of source code or documentation must retain the above 12154133Sharti * copyright notice, this list of conditions and the following disclaimer. 13154133Sharti * 2. Redistributions in binary form must reproduce the above copyright 14154133Sharti * notice, this list of conditions and the following disclaimer in the 15154133Sharti * documentation and/or other materials provided with the distribution. 16154133Sharti * 17154133Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18154133Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19154133Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20154133Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21154133Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22154133Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23154133Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24154133Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25154133Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26154133Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27154133Sharti * SUCH DAMAGE. 28154133Sharti * 29154133Sharti * $FreeBSD: releng/11.0/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c 285719 2015-07-20 16:08:01Z pfg $ 30154133Sharti */ 31154133Sharti 32154133Sharti/* 33154133Sharti * Host Resources MIB implementation for SNMPd: instrumentation for 34154133Sharti * hrPrinterTable 35154133Sharti */ 36154133Sharti 37154133Sharti#include <sys/param.h> 38154133Sharti#include <sys/stat.h> 39154133Sharti 40154133Sharti#include <assert.h> 41154133Sharti#include <err.h> 42154133Sharti#include <errno.h> 43154133Sharti#include <paths.h> 44154133Sharti#include <stdlib.h> 45154133Sharti#include <string.h> 46154133Sharti#include <syslog.h> 47154133Sharti#include <unistd.h> 48154133Sharti 49154133Sharti#include "hostres_snmp.h" 50154133Sharti#include "hostres_oid.h" 51154133Sharti#include "hostres_tree.h" 52154133Sharti 53154133Sharti#include <sys/dirent.h> 54154133Sharti#include "lp.h" 55154133Sharti 56154133Sharti/* Constants */ 57154133Shartistatic const struct asn_oid OIDX_hrDevicePrinter_c = OIDX_hrDevicePrinter; 58154133Sharti 59154133Shartienum PrinterStatus { 60154133Sharti PS_OTHER = 1, 61154133Sharti PS_UNKNOWN = 2, 62154133Sharti PS_IDLE = 3, 63154133Sharti PS_PRINTING = 4, 64154133Sharti PS_WARMUP = 5 65154133Sharti}; 66154133Sharti 67154133Sharti/* 68154133Sharti * This structure is used to hold a SNMP table entry 69154133Sharti * for HOST-RESOURCES-MIB's hrPrinterTable. 70154133Sharti */ 71154133Shartistruct printer_entry { 72154133Sharti int32_t index; 73154133Sharti int32_t status; /* values from PrinterStatus enum above */ 74154133Sharti u_char detectedErrorState[2]; 75154133Sharti TAILQ_ENTRY(printer_entry) link; 76160341Sharti#define HR_PRINTER_FOUND 0x001 77154133Sharti uint32_t flags; 78154133Sharti 79154133Sharti}; 80154133ShartiTAILQ_HEAD(printer_tbl, printer_entry); 81154133Sharti 82154133Sharti/* the hrPrinterTable */ 83154133Shartistatic struct printer_tbl printer_tbl = TAILQ_HEAD_INITIALIZER(printer_tbl); 84154133Sharti 85154133Sharti/* last (agent) tick when hrPrinterTable was updated */ 86154133Shartistatic uint64_t printer_tick; 87154133Sharti 88154133Sharti/** 89154133Sharti * Create entry into the printer table. 90154133Sharti */ 91154133Shartistatic struct printer_entry * 92154133Shartiprinter_entry_create(const struct device_entry *devEntry) 93154133Sharti{ 94154133Sharti struct printer_entry *entry = NULL; 95154133Sharti 96154133Sharti assert(devEntry != NULL); 97154133Sharti if (devEntry == NULL) 98154133Sharti return (NULL); 99154133Sharti 100154133Sharti if ((entry = malloc(sizeof(*entry))) == NULL) { 101154133Sharti syslog(LOG_WARNING, "hrPrinterTable: %s: %m", __func__); 102154133Sharti return (NULL); 103154133Sharti } 104154133Sharti memset(entry, 0, sizeof(*entry)); 105154133Sharti entry->index = devEntry->index; 106154133Sharti INSERT_OBJECT_INT(entry, &printer_tbl); 107154133Sharti return (entry); 108154133Sharti} 109154133Sharti 110154133Sharti/** 111154133Sharti * Delete entry from the printer table. 112154133Sharti */ 113154133Shartistatic void 114154133Shartiprinter_entry_delete(struct printer_entry *entry) 115154133Sharti{ 116154133Sharti 117154133Sharti assert(entry != NULL); 118154133Sharti if (entry == NULL) 119154133Sharti return; 120154133Sharti 121154133Sharti TAILQ_REMOVE(&printer_tbl, entry, link); 122154133Sharti free(entry); 123154133Sharti} 124154133Sharti 125154133Sharti/** 126154133Sharti * Find a printer by its index 127154133Sharti */ 128154133Shartistatic struct printer_entry * 129154133Shartiprinter_find_by_index(int32_t idx) 130154133Sharti{ 131154133Sharti struct printer_entry *entry; 132154133Sharti 133154133Sharti TAILQ_FOREACH(entry, &printer_tbl, link) 134154133Sharti if (entry->index == idx) 135154133Sharti return (entry); 136154133Sharti 137154133Sharti return (NULL); 138154133Sharti} 139154133Sharti 140154133Sharti/** 141154133Sharti * Get the status of a printer 142154133Sharti */ 143154133Shartistatic enum PrinterStatus 144154133Shartiget_printer_status(const struct printer *pp) 145154133Sharti{ 146154133Sharti char statfile[MAXPATHLEN]; 147154133Sharti char lockfile[MAXPATHLEN]; 148154133Sharti char fline[128]; 149154133Sharti int fd; 150154133Sharti FILE *f = NULL; 151154133Sharti enum PrinterStatus ps = PS_UNKNOWN; 152154133Sharti 153154133Sharti if (pp->lock_file[0] == '/') 154154133Sharti strlcpy(lockfile, pp->lock_file, sizeof(lockfile)); 155154133Sharti else 156154133Sharti snprintf(lockfile, sizeof(lockfile), "%s/%s", 157154133Sharti pp->spool_dir, pp->lock_file); 158154133Sharti 159154133Sharti fd = open(lockfile, O_RDONLY); 160154133Sharti if (fd < 0 || flock(fd, LOCK_SH | LOCK_NB) == 0) { 161154133Sharti ps = PS_IDLE; 162154133Sharti goto LABEL_DONE; 163154133Sharti } 164154133Sharti 165154133Sharti if (pp->status_file[0] == '/') 166154133Sharti strlcpy(statfile, pp->status_file, sizeof(statfile)); 167154133Sharti else 168154133Sharti snprintf(statfile, sizeof(statfile), "%s/%s", 169154133Sharti pp->spool_dir, pp->status_file); 170154133Sharti 171154133Sharti f = fopen(statfile, "r"); 172154133Sharti if (f == NULL) { 173154133Sharti syslog(LOG_ERR, "cannot open status file: %s", strerror(errno)); 174154133Sharti ps = PS_UNKNOWN; 175154133Sharti goto LABEL_DONE; 176154133Sharti } 177154133Sharti 178285719Spfg memset(&fline[0], '\0', sizeof(fline)); 179154133Sharti if (fgets(fline, sizeof(fline) -1, f) == NULL) { 180154133Sharti ps = PS_UNKNOWN; 181154133Sharti goto LABEL_DONE; 182154133Sharti } 183154133Sharti 184154133Sharti if (strstr(fline, "is ready and printing") != NULL) { 185154133Sharti ps = PS_PRINTING; 186154133Sharti goto LABEL_DONE; 187154133Sharti } 188154133Sharti 189154133Sharti if (strstr(fline, "to become ready (offline?)") != NULL) { 190154133Sharti ps = PS_OTHER; 191154133Sharti goto LABEL_DONE; 192154133Sharti } 193154133Sharti 194154133ShartiLABEL_DONE: 195154133Sharti if (fd >= 0) 196154133Sharti (void)close(fd); /* unlocks as well */ 197154133Sharti 198154133Sharti if (f != NULL) 199154133Sharti (void)fclose(f); 200154133Sharti 201154133Sharti return (ps); 202154133Sharti} 203154133Sharti 204154133Sharti/** 205154133Sharti * Called for each printer found in /etc/printcap. 206154133Sharti */ 207154133Shartistatic void 208154133Shartihandle_printer(struct printer *pp) 209154133Sharti{ 210154133Sharti struct device_entry *dev_entry; 211154133Sharti struct printer_entry *printer_entry; 212154133Sharti char dev_only[128]; 213154133Sharti struct stat sb; 214154133Sharti 215154133Sharti if (pp->remote_host != NULL) { 216154133Sharti HRDBG("skipped %s -- remote", pp->printer); 217154133Sharti return; 218154133Sharti } 219154133Sharti 220154133Sharti if (strncmp(pp->lp, _PATH_DEV, strlen(_PATH_DEV)) != 0) { 221154133Sharti HRDBG("skipped %s [device %s] -- remote", pp->printer, pp->lp); 222154133Sharti return; 223154133Sharti } 224154133Sharti 225154133Sharti memset(dev_only, '\0', sizeof(dev_only)); 226154133Sharti snprintf(dev_only, sizeof(dev_only), "%s", pp->lp + strlen(_PATH_DEV)); 227154133Sharti 228154133Sharti HRDBG("printer %s has device %s", pp->printer, dev_only); 229154133Sharti 230154133Sharti if (stat(pp->lp, &sb) < 0) { 231154133Sharti if (errno == ENOENT) { 232154133Sharti HRDBG("skipped %s -- device %s missing", 233154133Sharti pp->printer, pp->lp); 234154133Sharti return; 235154133Sharti } 236154133Sharti } 237154133Sharti 238154133Sharti if ((dev_entry = device_find_by_name(dev_only)) == NULL) { 239154133Sharti HRDBG("%s not in hrDeviceTable", pp->lp); 240154133Sharti return; 241154133Sharti } 242154133Sharti HRDBG("%s found in hrDeviceTable", pp->lp); 243160341Sharti dev_entry->type = &OIDX_hrDevicePrinter_c; 244154133Sharti 245154133Sharti dev_entry->flags |= HR_DEVICE_IMMUTABLE; 246154133Sharti 247154133Sharti /* Then check hrPrinterTable for this device */ 248154133Sharti if ((printer_entry = printer_find_by_index(dev_entry->index)) == NULL && 249154133Sharti (printer_entry = printer_entry_create(dev_entry)) == NULL) 250154133Sharti return; 251154133Sharti 252154133Sharti printer_entry->flags |= HR_PRINTER_FOUND; 253154133Sharti printer_entry->status = get_printer_status(pp); 254154133Sharti memset(printer_entry->detectedErrorState, 0, 255154133Sharti sizeof(printer_entry->detectedErrorState)); 256154133Sharti} 257154133Sharti 258154133Shartistatic void 259154133ShartihrPrinter_get_OS_entries(void) 260154133Sharti{ 261154133Sharti int status, more; 262154133Sharti struct printer myprinter, *pp = &myprinter; 263154133Sharti 264154133Sharti init_printer(pp); 265154133Sharti HRDBG("---->Getting printers ....."); 266154133Sharti more = firstprinter(pp, &status); 267154133Sharti if (status) 268154133Sharti goto errloop; 269154133Sharti 270154133Sharti while (more) { 271154133Sharti do { 272154133Sharti HRDBG("---->Got printer %s", pp->printer); 273154133Sharti 274154133Sharti handle_printer(pp); 275154133Sharti more = nextprinter(pp, &status); 276154133Shartierrloop: 277154133Sharti if (status) 278154133Sharti syslog(LOG_WARNING, 279154133Sharti "hrPrinterTable: printcap entry for %s " 280154133Sharti "has errors, skipping", 281154133Sharti pp->printer ? pp->printer : "<noname?>"); 282154133Sharti } while (more && status); 283154133Sharti } 284154133Sharti 285154133Sharti lastprinter(); 286154133Sharti printer_tick = this_tick; 287154133Sharti} 288154133Sharti 289154133Sharti/** 290154133Sharti * Init the things for hrPrinterTable 291154133Sharti */ 292154133Shartivoid 293154133Shartiinit_printer_tbl(void) 294154133Sharti{ 295154133Sharti 296154133Sharti hrPrinter_get_OS_entries(); 297154133Sharti} 298154133Sharti 299154133Sharti/** 300154133Sharti * Finalization routine for hrPrinterTable 301154133Sharti * It destroys the lists and frees any allocated heap memory 302154133Sharti */ 303154133Shartivoid 304154133Shartifini_printer_tbl(void) 305154133Sharti{ 306154133Sharti struct printer_entry *n1; 307154133Sharti 308154133Sharti while ((n1 = TAILQ_FIRST(&printer_tbl)) != NULL) { 309154133Sharti TAILQ_REMOVE(&printer_tbl, n1, link); 310154133Sharti free(n1); 311154133Sharti } 312154133Sharti} 313154133Sharti 314154133Sharti/** 315154133Sharti * Refresh the printer table if needed. 316154133Sharti */ 317154133Shartivoid 318154133Shartirefresh_printer_tbl(void) 319154133Sharti{ 320154133Sharti struct printer_entry *entry; 321154133Sharti struct printer_entry *entry_tmp; 322154133Sharti 323154133Sharti if (this_tick <= printer_tick) { 324154133Sharti HRDBG("no refresh needed"); 325154133Sharti return; 326154133Sharti } 327154133Sharti 328154133Sharti /* mark each entry as missing */ 329154133Sharti TAILQ_FOREACH(entry, &printer_tbl, link) 330154133Sharti entry->flags &= ~HR_PRINTER_FOUND; 331154133Sharti 332154133Sharti hrPrinter_get_OS_entries(); 333154133Sharti 334154133Sharti /* 335154133Sharti * Purge items that disappeared 336154133Sharti */ 337154133Sharti entry = TAILQ_FIRST(&printer_tbl); 338154133Sharti while (entry != NULL) { 339154133Sharti entry_tmp = TAILQ_NEXT(entry, link); 340154133Sharti if (!(entry->flags & HR_PRINTER_FOUND)) 341154133Sharti printer_entry_delete(entry); 342154133Sharti entry = entry_tmp; 343154133Sharti } 344154133Sharti 345154133Sharti printer_tick = this_tick; 346154133Sharti 347154133Sharti HRDBG("refresh DONE "); 348154133Sharti} 349154133Sharti 350154133Shartiint 351154133Shartiop_hrPrinterTable(struct snmp_context *ctx __unused, struct snmp_value *value, 352154133Sharti u_int sub, u_int iidx __unused, enum snmp_op curr_op) 353154133Sharti{ 354154133Sharti struct printer_entry *entry; 355154133Sharti 356154133Sharti refresh_printer_tbl(); 357154133Sharti 358154133Sharti switch (curr_op) { 359154133Sharti 360154133Sharti case SNMP_OP_GETNEXT: 361154133Sharti if ((entry = NEXT_OBJECT_INT(&printer_tbl, &value->var, 362154133Sharti sub)) == NULL) 363154133Sharti return (SNMP_ERR_NOSUCHNAME); 364154133Sharti value->var.len = sub + 1; 365154133Sharti value->var.subs[sub] = entry->index; 366154133Sharti goto get; 367154133Sharti 368154133Sharti case SNMP_OP_GET: 369154133Sharti if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var, 370154133Sharti sub)) == NULL) 371154133Sharti return (SNMP_ERR_NOSUCHNAME); 372154133Sharti goto get; 373154133Sharti 374154133Sharti case SNMP_OP_SET: 375154133Sharti if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var, 376154133Sharti sub)) == NULL) 377154133Sharti return (SNMP_ERR_NO_CREATION); 378154133Sharti return (SNMP_ERR_NOT_WRITEABLE); 379154133Sharti 380154133Sharti case SNMP_OP_ROLLBACK: 381154133Sharti case SNMP_OP_COMMIT: 382154133Sharti abort(); 383154133Sharti } 384154133Sharti abort(); 385154133Sharti 386154133Sharti get: 387154133Sharti switch (value->var.subs[sub - 1]) { 388154133Sharti 389154133Sharti case LEAF_hrPrinterStatus: 390154133Sharti value->v.integer = entry->status; 391154133Sharti return (SNMP_ERR_NOERROR); 392154133Sharti 393154133Sharti case LEAF_hrPrinterDetectedErrorState: 394154133Sharti return (string_get(value, entry->detectedErrorState, 395154133Sharti sizeof(entry->detectedErrorState))); 396154133Sharti } 397154133Sharti abort(); 398154133Sharti} 399