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