1d76947f3SHartmut Brandt /*-
2d76947f3SHartmut Brandt  * Copyright (c) 2005-2006 The FreeBSD Project
3d76947f3SHartmut Brandt  * All rights reserved.
4d76947f3SHartmut Brandt  *
5d76947f3SHartmut Brandt  * Author: Victor Cruceru <soc-victor@freebsd.org>
6d76947f3SHartmut Brandt  *
7d76947f3SHartmut Brandt  * Redistribution of this software and documentation and use in source and
8d76947f3SHartmut Brandt  * binary forms, with or without modification, are permitted provided that
9d76947f3SHartmut Brandt  * the following conditions are met:
10d76947f3SHartmut Brandt  *
11d76947f3SHartmut Brandt  * 1. Redistributions of source code or documentation must retain the above
12d76947f3SHartmut Brandt  *    copyright notice, this list of conditions and the following disclaimer.
13d76947f3SHartmut Brandt  * 2. Redistributions in binary form must reproduce the above copyright
14d76947f3SHartmut Brandt  *    notice, this list of conditions and the following disclaimer in the
15d76947f3SHartmut Brandt  *    documentation and/or other materials provided with the distribution.
16d76947f3SHartmut Brandt  *
17d76947f3SHartmut Brandt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18d76947f3SHartmut Brandt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d76947f3SHartmut Brandt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d76947f3SHartmut Brandt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21d76947f3SHartmut Brandt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d76947f3SHartmut Brandt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d76947f3SHartmut Brandt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d76947f3SHartmut Brandt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d76947f3SHartmut Brandt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d76947f3SHartmut Brandt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d76947f3SHartmut Brandt  * SUCH DAMAGE.
28d76947f3SHartmut Brandt  */
29d76947f3SHartmut Brandt 
30d76947f3SHartmut Brandt /*
31d76947f3SHartmut Brandt  * Host Resources MIB implementation for SNMPd: instrumentation for
32d76947f3SHartmut Brandt  * hrPrinterTable
33d76947f3SHartmut Brandt  */
34d76947f3SHartmut Brandt 
35d76947f3SHartmut Brandt #include <sys/param.h>
36d76947f3SHartmut Brandt #include <sys/stat.h>
37d76947f3SHartmut Brandt 
38d76947f3SHartmut Brandt #include <assert.h>
39d76947f3SHartmut Brandt #include <err.h>
40d76947f3SHartmut Brandt #include <errno.h>
41d76947f3SHartmut Brandt #include <paths.h>
42d76947f3SHartmut Brandt #include <stdlib.h>
43d76947f3SHartmut Brandt #include <string.h>
44d76947f3SHartmut Brandt #include <syslog.h>
45d76947f3SHartmut Brandt #include <unistd.h>
46d76947f3SHartmut Brandt 
47d76947f3SHartmut Brandt #include "hostres_snmp.h"
48d76947f3SHartmut Brandt #include "hostres_oid.h"
49d76947f3SHartmut Brandt #include "hostres_tree.h"
50d76947f3SHartmut Brandt 
51d76947f3SHartmut Brandt #include <sys/dirent.h>
52d76947f3SHartmut Brandt #include "lp.h"
53d76947f3SHartmut Brandt 
54d76947f3SHartmut Brandt /* Constants */
55d76947f3SHartmut Brandt static const struct asn_oid OIDX_hrDevicePrinter_c = OIDX_hrDevicePrinter;
56d76947f3SHartmut Brandt 
57d76947f3SHartmut Brandt enum PrinterStatus {
58d76947f3SHartmut Brandt 	PS_OTHER	= 1,
59d76947f3SHartmut Brandt 	PS_UNKNOWN	= 2,
60d76947f3SHartmut Brandt 	PS_IDLE		= 3,
61d76947f3SHartmut Brandt 	PS_PRINTING	= 4,
62d76947f3SHartmut Brandt 	PS_WARMUP	= 5
63d76947f3SHartmut Brandt };
64d76947f3SHartmut Brandt 
65d76947f3SHartmut Brandt /*
66d76947f3SHartmut Brandt  * This structure is used to hold a SNMP table entry
67d76947f3SHartmut Brandt  * for HOST-RESOURCES-MIB's hrPrinterTable.
68d76947f3SHartmut Brandt  */
69d76947f3SHartmut Brandt struct printer_entry {
70d76947f3SHartmut Brandt 	int32_t		index;
71d76947f3SHartmut Brandt 	int32_t		status;  /* values from PrinterStatus enum above */
72d76947f3SHartmut Brandt 	u_char		detectedErrorState[2];
73d76947f3SHartmut Brandt 	TAILQ_ENTRY(printer_entry) link;
74d76947f3SHartmut Brandt #define	HR_PRINTER_FOUND		0x001
75d76947f3SHartmut Brandt 	uint32_t	flags;
76d76947f3SHartmut Brandt 
77d76947f3SHartmut Brandt };
78d76947f3SHartmut Brandt TAILQ_HEAD(printer_tbl, printer_entry);
79d76947f3SHartmut Brandt 
80d76947f3SHartmut Brandt /* the hrPrinterTable */
81d76947f3SHartmut Brandt static struct printer_tbl printer_tbl = TAILQ_HEAD_INITIALIZER(printer_tbl);
82d76947f3SHartmut Brandt 
83d76947f3SHartmut Brandt /* last (agent) tick when hrPrinterTable was updated */
84d76947f3SHartmut Brandt static uint64_t printer_tick;
85d76947f3SHartmut Brandt 
86d76947f3SHartmut Brandt /**
87d76947f3SHartmut Brandt  * Create entry into the printer table.
88d76947f3SHartmut Brandt  */
89d76947f3SHartmut Brandt static struct printer_entry *
printer_entry_create(const struct device_entry * devEntry)90d76947f3SHartmut Brandt printer_entry_create(const struct device_entry *devEntry)
91d76947f3SHartmut Brandt {
92d76947f3SHartmut Brandt 	struct printer_entry *entry = NULL;
93d76947f3SHartmut Brandt 
94d76947f3SHartmut Brandt 	assert(devEntry != NULL);
95d76947f3SHartmut Brandt 	if (devEntry == NULL)
96d76947f3SHartmut Brandt 		return (NULL);
97d76947f3SHartmut Brandt 
98d76947f3SHartmut Brandt 	if ((entry = malloc(sizeof(*entry))) == NULL) {
99d76947f3SHartmut Brandt 		syslog(LOG_WARNING, "hrPrinterTable: %s: %m", __func__);
100d76947f3SHartmut Brandt 		return (NULL);
101d76947f3SHartmut Brandt 	}
102d76947f3SHartmut Brandt 	memset(entry, 0, sizeof(*entry));
103d76947f3SHartmut Brandt 	entry->index = devEntry->index;
104d76947f3SHartmut Brandt 	INSERT_OBJECT_INT(entry, &printer_tbl);
105d76947f3SHartmut Brandt 	return (entry);
106d76947f3SHartmut Brandt }
107d76947f3SHartmut Brandt 
108d76947f3SHartmut Brandt /**
109d76947f3SHartmut Brandt  * Delete entry from the printer table.
110d76947f3SHartmut Brandt  */
111d76947f3SHartmut Brandt static void
printer_entry_delete(struct printer_entry * entry)112d76947f3SHartmut Brandt printer_entry_delete(struct printer_entry *entry)
113d76947f3SHartmut Brandt {
114d76947f3SHartmut Brandt 
115d76947f3SHartmut Brandt 	assert(entry != NULL);
116d76947f3SHartmut Brandt 	if (entry == NULL)
117d76947f3SHartmut Brandt 		return;
118d76947f3SHartmut Brandt 
119d76947f3SHartmut Brandt 	TAILQ_REMOVE(&printer_tbl, entry, link);
120d76947f3SHartmut Brandt 	free(entry);
121d76947f3SHartmut Brandt }
122d76947f3SHartmut Brandt 
123d76947f3SHartmut Brandt /**
124d76947f3SHartmut Brandt  * Find a printer by its index
125d76947f3SHartmut Brandt  */
126d76947f3SHartmut Brandt static struct printer_entry *
printer_find_by_index(int32_t idx)127d76947f3SHartmut Brandt printer_find_by_index(int32_t idx)
128d76947f3SHartmut Brandt {
129d76947f3SHartmut Brandt 	struct printer_entry *entry;
130d76947f3SHartmut Brandt 
131d76947f3SHartmut Brandt 	TAILQ_FOREACH(entry, &printer_tbl, link)
132d76947f3SHartmut Brandt 		if (entry->index == idx)
133d76947f3SHartmut Brandt 			return (entry);
134d76947f3SHartmut Brandt 
135d76947f3SHartmut Brandt 	return (NULL);
136d76947f3SHartmut Brandt }
137d76947f3SHartmut Brandt 
138d76947f3SHartmut Brandt /**
139d76947f3SHartmut Brandt  * Get the status of a printer
140d76947f3SHartmut Brandt  */
141d76947f3SHartmut Brandt static enum PrinterStatus
get_printer_status(const struct printer * pp)142d76947f3SHartmut Brandt get_printer_status(const struct printer *pp)
143d76947f3SHartmut Brandt {
144d76947f3SHartmut Brandt 	char statfile[MAXPATHLEN];
145d76947f3SHartmut Brandt 	char lockfile[MAXPATHLEN];
146d76947f3SHartmut Brandt 	char fline[128];
147d76947f3SHartmut Brandt 	int fd;
148d76947f3SHartmut Brandt 	FILE *f = NULL;
149d76947f3SHartmut Brandt 	enum PrinterStatus ps = PS_UNKNOWN;
150d76947f3SHartmut Brandt 
151d76947f3SHartmut Brandt 	if (pp->lock_file[0] == '/')
152d76947f3SHartmut Brandt 		strlcpy(lockfile, pp->lock_file, sizeof(lockfile));
153d76947f3SHartmut Brandt 	else
154d76947f3SHartmut Brandt 		snprintf(lockfile, sizeof(lockfile), "%s/%s",
155d76947f3SHartmut Brandt 		    pp->spool_dir, pp->lock_file);
156d76947f3SHartmut Brandt 
157d76947f3SHartmut Brandt 	fd = open(lockfile, O_RDONLY);
158d76947f3SHartmut Brandt 	if (fd < 0 || flock(fd, LOCK_SH | LOCK_NB) == 0) {
159d76947f3SHartmut Brandt 		ps = PS_IDLE;
160d76947f3SHartmut Brandt 		goto LABEL_DONE;
161d76947f3SHartmut Brandt 	}
162d76947f3SHartmut Brandt 
163d76947f3SHartmut Brandt 	if (pp->status_file[0] == '/')
164d76947f3SHartmut Brandt 		strlcpy(statfile, pp->status_file, sizeof(statfile));
165d76947f3SHartmut Brandt 	else
166d76947f3SHartmut Brandt 		snprintf(statfile, sizeof(statfile), "%s/%s",
167d76947f3SHartmut Brandt 		    pp->spool_dir, pp->status_file);
168d76947f3SHartmut Brandt 
169d76947f3SHartmut Brandt 	f = fopen(statfile, "r");
170d76947f3SHartmut Brandt 	if (f == NULL) {
171d76947f3SHartmut Brandt 		syslog(LOG_ERR, "cannot open status file: %s", strerror(errno));
172d76947f3SHartmut Brandt 		ps = PS_UNKNOWN;
173d76947f3SHartmut Brandt 		goto LABEL_DONE;
174d76947f3SHartmut Brandt 	}
175d76947f3SHartmut Brandt 
176d37cb73cSPedro F. Giffuni 	memset(&fline[0], '\0', sizeof(fline));
177d76947f3SHartmut Brandt 	if (fgets(fline, sizeof(fline) -1, f) == NULL) {
178d76947f3SHartmut Brandt 		ps = PS_UNKNOWN;
179d76947f3SHartmut Brandt 		goto LABEL_DONE;
180d76947f3SHartmut Brandt 	}
181d76947f3SHartmut Brandt 
182d76947f3SHartmut Brandt 	if (strstr(fline, "is ready and printing") != NULL) {
183d76947f3SHartmut Brandt 		ps = PS_PRINTING;
184d76947f3SHartmut Brandt 		goto LABEL_DONE;
185d76947f3SHartmut Brandt 	}
186d76947f3SHartmut Brandt 
187d76947f3SHartmut Brandt 	if (strstr(fline, "to become ready (offline?)") != NULL) {
188d76947f3SHartmut Brandt 		ps = PS_OTHER;
189d76947f3SHartmut Brandt 		goto LABEL_DONE;
190d76947f3SHartmut Brandt 	}
191d76947f3SHartmut Brandt 
192d76947f3SHartmut Brandt LABEL_DONE:
193d76947f3SHartmut Brandt 	if (fd >= 0)
194d76947f3SHartmut Brandt 		(void)close(fd);	/* unlocks as well */
195d76947f3SHartmut Brandt 
196d76947f3SHartmut Brandt 	if (f != NULL)
197d76947f3SHartmut Brandt 		(void)fclose(f);
198d76947f3SHartmut Brandt 
199d76947f3SHartmut Brandt 	return (ps);
200d76947f3SHartmut Brandt }
201d76947f3SHartmut Brandt 
202d76947f3SHartmut Brandt /**
203d76947f3SHartmut Brandt  * Called for each printer found in /etc/printcap.
204d76947f3SHartmut Brandt  */
205d76947f3SHartmut Brandt static void
handle_printer(struct printer * pp)206d76947f3SHartmut Brandt handle_printer(struct printer *pp)
207d76947f3SHartmut Brandt {
208d76947f3SHartmut Brandt 	struct device_entry *dev_entry;
209d76947f3SHartmut Brandt 	struct printer_entry *printer_entry;
210d76947f3SHartmut Brandt 	char dev_only[128];
211d76947f3SHartmut Brandt 	struct stat sb;
212d76947f3SHartmut Brandt 
213d76947f3SHartmut Brandt 	if (pp->remote_host != NULL) {
214d76947f3SHartmut Brandt 		HRDBG("skipped %s -- remote", pp->printer);
215d76947f3SHartmut Brandt 		return;
216d76947f3SHartmut Brandt 	}
217d76947f3SHartmut Brandt 
218d76947f3SHartmut Brandt 	if (strncmp(pp->lp, _PATH_DEV, strlen(_PATH_DEV)) != 0) {
219d76947f3SHartmut Brandt 		HRDBG("skipped %s [device %s] -- remote", pp->printer, pp->lp);
220d76947f3SHartmut Brandt 		return;
221d76947f3SHartmut Brandt 	}
222d76947f3SHartmut Brandt 
223d76947f3SHartmut Brandt 	memset(dev_only, '\0', sizeof(dev_only));
224d76947f3SHartmut Brandt 	snprintf(dev_only, sizeof(dev_only), "%s", pp->lp + strlen(_PATH_DEV));
225d76947f3SHartmut Brandt 
226d76947f3SHartmut Brandt 	HRDBG("printer %s has device %s", pp->printer, dev_only);
227d76947f3SHartmut Brandt 
228d76947f3SHartmut Brandt 	if (stat(pp->lp, &sb) < 0) {
229d76947f3SHartmut Brandt 		if (errno == ENOENT) {
230d76947f3SHartmut Brandt 			HRDBG("skipped %s -- device %s missing",
231d76947f3SHartmut Brandt 			    pp->printer, pp->lp);
232d76947f3SHartmut Brandt 			return;
233d76947f3SHartmut Brandt 		}
234d76947f3SHartmut Brandt 	}
235d76947f3SHartmut Brandt 
236d76947f3SHartmut Brandt 	if ((dev_entry = device_find_by_name(dev_only)) == NULL) {
237d76947f3SHartmut Brandt 		HRDBG("%s not in hrDeviceTable", pp->lp);
238d76947f3SHartmut Brandt 		return;
239d76947f3SHartmut Brandt 	}
240d76947f3SHartmut Brandt 	HRDBG("%s found in hrDeviceTable", pp->lp);
241e55adffcSHartmut Brandt 	dev_entry->type = &OIDX_hrDevicePrinter_c;
242d76947f3SHartmut Brandt 
243d76947f3SHartmut Brandt 	dev_entry->flags |= HR_DEVICE_IMMUTABLE;
244d76947f3SHartmut Brandt 
245d76947f3SHartmut Brandt 	/* Then check hrPrinterTable for this device */
246d76947f3SHartmut Brandt 	if ((printer_entry = printer_find_by_index(dev_entry->index)) == NULL &&
247d76947f3SHartmut Brandt 	    (printer_entry = printer_entry_create(dev_entry)) == NULL)
248d76947f3SHartmut Brandt 		return;
249d76947f3SHartmut Brandt 
250d76947f3SHartmut Brandt 	printer_entry->flags |= HR_PRINTER_FOUND;
251d76947f3SHartmut Brandt 	printer_entry->status = get_printer_status(pp);
252d76947f3SHartmut Brandt 	memset(printer_entry->detectedErrorState, 0,
253d76947f3SHartmut Brandt 	    sizeof(printer_entry->detectedErrorState));
254d76947f3SHartmut Brandt }
255d76947f3SHartmut Brandt 
256d76947f3SHartmut Brandt static void
hrPrinter_get_OS_entries(void)257d76947f3SHartmut Brandt hrPrinter_get_OS_entries(void)
258d76947f3SHartmut Brandt {
259d76947f3SHartmut Brandt 	int  status, more;
260d76947f3SHartmut Brandt 	struct printer myprinter, *pp = &myprinter;
261d76947f3SHartmut Brandt 
262d76947f3SHartmut Brandt 	init_printer(pp);
263d76947f3SHartmut Brandt 	HRDBG("---->Getting printers .....");
264d76947f3SHartmut Brandt 	more = firstprinter(pp, &status);
265d76947f3SHartmut Brandt 	if (status)
266d76947f3SHartmut Brandt 		goto errloop;
267d76947f3SHartmut Brandt 
268d76947f3SHartmut Brandt 	while (more) {
269d76947f3SHartmut Brandt 		do {
270d76947f3SHartmut Brandt 			HRDBG("---->Got printer %s", pp->printer);
271d76947f3SHartmut Brandt 
272d76947f3SHartmut Brandt 			handle_printer(pp);
273d76947f3SHartmut Brandt 			more = nextprinter(pp, &status);
274d76947f3SHartmut Brandt errloop:
275d76947f3SHartmut Brandt 			if (status)
276d76947f3SHartmut Brandt 				syslog(LOG_WARNING,
277d76947f3SHartmut Brandt 				    "hrPrinterTable: printcap entry for %s "
278d76947f3SHartmut Brandt 				    "has errors, skipping",
279d76947f3SHartmut Brandt 				    pp->printer ? pp->printer : "<noname?>");
280d76947f3SHartmut Brandt 		} while (more && status);
281d76947f3SHartmut Brandt 	}
282d76947f3SHartmut Brandt 
283d76947f3SHartmut Brandt 	lastprinter();
284d76947f3SHartmut Brandt 	printer_tick = this_tick;
285d76947f3SHartmut Brandt }
286d76947f3SHartmut Brandt 
287d76947f3SHartmut Brandt /**
288d76947f3SHartmut Brandt  * Init the things for hrPrinterTable
289d76947f3SHartmut Brandt  */
290d76947f3SHartmut Brandt void
init_printer_tbl(void)291d76947f3SHartmut Brandt init_printer_tbl(void)
292d76947f3SHartmut Brandt {
293d76947f3SHartmut Brandt 
294d76947f3SHartmut Brandt 	hrPrinter_get_OS_entries();
295d76947f3SHartmut Brandt }
296d76947f3SHartmut Brandt 
297d76947f3SHartmut Brandt /**
298d76947f3SHartmut Brandt  * Finalization routine for hrPrinterTable
299d76947f3SHartmut Brandt  * It destroys the lists and frees any allocated heap memory
300d76947f3SHartmut Brandt  */
301d76947f3SHartmut Brandt void
fini_printer_tbl(void)302d76947f3SHartmut Brandt fini_printer_tbl(void)
303d76947f3SHartmut Brandt {
304d76947f3SHartmut Brandt 	struct printer_entry *n1;
305d76947f3SHartmut Brandt 
306d76947f3SHartmut Brandt 	while ((n1 = TAILQ_FIRST(&printer_tbl)) != NULL) {
307d76947f3SHartmut Brandt 		TAILQ_REMOVE(&printer_tbl, n1, link);
308d76947f3SHartmut Brandt 		free(n1);
309d76947f3SHartmut Brandt 	}
310d76947f3SHartmut Brandt }
311d76947f3SHartmut Brandt 
312d76947f3SHartmut Brandt /**
313d76947f3SHartmut Brandt  * Refresh the printer table if needed.
314d76947f3SHartmut Brandt  */
315d76947f3SHartmut Brandt void
refresh_printer_tbl(void)316d76947f3SHartmut Brandt refresh_printer_tbl(void)
317d76947f3SHartmut Brandt {
318d76947f3SHartmut Brandt 	struct printer_entry *entry;
319d76947f3SHartmut Brandt 	struct printer_entry *entry_tmp;
320d76947f3SHartmut Brandt 
321d76947f3SHartmut Brandt 	if (this_tick <= printer_tick) {
322d76947f3SHartmut Brandt 		HRDBG("no refresh needed");
323d76947f3SHartmut Brandt 		return;
324d76947f3SHartmut Brandt 	}
325d76947f3SHartmut Brandt 
326d76947f3SHartmut Brandt 	/* mark each entry as missing */
327d76947f3SHartmut Brandt 	TAILQ_FOREACH(entry, &printer_tbl, link)
328d76947f3SHartmut Brandt 		entry->flags &= ~HR_PRINTER_FOUND;
329d76947f3SHartmut Brandt 
330d76947f3SHartmut Brandt 	hrPrinter_get_OS_entries();
331d76947f3SHartmut Brandt 
332d76947f3SHartmut Brandt 	/*
333d76947f3SHartmut Brandt 	 * Purge items that disappeared
334d76947f3SHartmut Brandt 	 */
335d76947f3SHartmut Brandt 	entry = TAILQ_FIRST(&printer_tbl);
336d76947f3SHartmut Brandt 	while (entry != NULL) {
337d76947f3SHartmut Brandt 		entry_tmp = TAILQ_NEXT(entry, link);
338d76947f3SHartmut Brandt 		if (!(entry->flags & HR_PRINTER_FOUND))
339d76947f3SHartmut Brandt 			printer_entry_delete(entry);
340d76947f3SHartmut Brandt 		entry = entry_tmp;
341d76947f3SHartmut Brandt 	}
342d76947f3SHartmut Brandt 
343d76947f3SHartmut Brandt 	printer_tick = this_tick;
344d76947f3SHartmut Brandt 
345d76947f3SHartmut Brandt 	HRDBG("refresh DONE ");
346d76947f3SHartmut Brandt }
347d76947f3SHartmut Brandt 
348d76947f3SHartmut Brandt int
op_hrPrinterTable(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op curr_op)349d76947f3SHartmut Brandt op_hrPrinterTable(struct snmp_context *ctx __unused, struct snmp_value *value,
350d76947f3SHartmut Brandt     u_int sub, u_int iidx __unused, enum snmp_op curr_op)
351d76947f3SHartmut Brandt {
352d76947f3SHartmut Brandt 	struct printer_entry *entry;
353d76947f3SHartmut Brandt 
354d76947f3SHartmut Brandt 	refresh_printer_tbl();
355d76947f3SHartmut Brandt 
356d76947f3SHartmut Brandt 	switch (curr_op) {
357d76947f3SHartmut Brandt 
358d76947f3SHartmut Brandt 	case SNMP_OP_GETNEXT:
359d76947f3SHartmut Brandt 		if ((entry = NEXT_OBJECT_INT(&printer_tbl, &value->var,
360d76947f3SHartmut Brandt 		    sub)) == NULL)
361d76947f3SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
362d76947f3SHartmut Brandt 		value->var.len = sub + 1;
363d76947f3SHartmut Brandt 		value->var.subs[sub] = entry->index;
364d76947f3SHartmut Brandt 		goto get;
365d76947f3SHartmut Brandt 
366d76947f3SHartmut Brandt 	case SNMP_OP_GET:
367d76947f3SHartmut Brandt 		if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var,
368d76947f3SHartmut Brandt 		    sub)) == NULL)
369d76947f3SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
370d76947f3SHartmut Brandt 		goto get;
371d76947f3SHartmut Brandt 
372d76947f3SHartmut Brandt 	case SNMP_OP_SET:
373d76947f3SHartmut Brandt 		if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var,
374d76947f3SHartmut Brandt 		    sub)) == NULL)
375d76947f3SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
376d76947f3SHartmut Brandt 		return (SNMP_ERR_NOT_WRITEABLE);
377d76947f3SHartmut Brandt 
378d76947f3SHartmut Brandt 	case SNMP_OP_ROLLBACK:
379d76947f3SHartmut Brandt 	case SNMP_OP_COMMIT:
380d76947f3SHartmut Brandt 		abort();
381d76947f3SHartmut Brandt 	}
382d76947f3SHartmut Brandt 	abort();
383d76947f3SHartmut Brandt 
384d76947f3SHartmut Brandt   get:
385d76947f3SHartmut Brandt 	switch (value->var.subs[sub - 1]) {
386d76947f3SHartmut Brandt 
387d76947f3SHartmut Brandt 	case LEAF_hrPrinterStatus:
388d76947f3SHartmut Brandt 		value->v.integer = entry->status;
389d76947f3SHartmut Brandt 		return (SNMP_ERR_NOERROR);
390d76947f3SHartmut Brandt 
391d76947f3SHartmut Brandt 	case LEAF_hrPrinterDetectedErrorState:
392d76947f3SHartmut Brandt 		return (string_get(value, entry->detectedErrorState,
393d76947f3SHartmut Brandt 		    sizeof(entry->detectedErrorState)));
394d76947f3SHartmut Brandt 	}
395d76947f3SHartmut Brandt 	abort();
396d76947f3SHartmut Brandt }
397