/* * Host Resources MIB - printer device group implementation - hr_print.c * */ #include #if HAVE_STRING_H #include #else #include #endif #if HAVE_UNISTD_H #include #endif #include "host_res.h" #include "hr_print.h" #include "struct.h" #include "util_funcs.h" #define HRPRINT_MONOTONICALLY_INCREASING /********************* * * Kernel & interface information, * and internal forward declarations * *********************/ void Init_HR_Print(void); int Get_Next_HR_Print(void); const char *describe_printer(int); int printer_status(int); int printer_detail_status(int); int printer_errors(int); int header_hrprint(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); FILE *run_lpstat(int *); /********************* * * Initialisation & common implementation functions * *********************/ #define HRPRINT_STATUS 1 #define HRPRINT_ERROR 2 struct variable4 hrprint_variables[] = { {HRPRINT_STATUS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrprint, 2, {1, 1}}, {HRPRINT_ERROR, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrprint, 2, {1, 2}} }; oid hrprint_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 3, 5 }; void init_hr_print(void) { init_device[HRDEV_PRINTER] = Init_HR_Print; next_device[HRDEV_PRINTER] = Get_Next_HR_Print; /* * save_device[ HRDEV_PRINTER ] = Save_HR_Print; */ #ifdef HRPRINT_MONOTONICALLY_INCREASING dev_idx_inc[HRDEV_PRINTER] = 1; #endif device_descr[HRDEV_PRINTER] = describe_printer; device_status[HRDEV_PRINTER] = printer_status; device_errors[HRDEV_PRINTER] = printer_errors; REGISTER_MIB("host/hr_print", hrprint_variables, variable4, hrprint_variables_oid); } /* * header_hrprint(... * Arguments: * vp IN - pointer to variable entry that points here * name IN/OUT - IN/name requested, OUT/name found * length IN/OUT - length of IN/OUT oid's * exact IN - TRUE if an exact match was requested * var_len OUT - length of variable or 0 if function returned * write_method * */ int header_hrprint(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { #define HRPRINT_ENTRY_NAME_LENGTH 11 oid newname[MAX_OID_LEN]; int print_idx, LowIndex = -1; int result; DEBUGMSGTL(("host/hr_print", "var_hrprint: ")); DEBUGMSGOID(("host/hr_print", name, *length)); DEBUGMSG(("host/hr_print", " %d\n", exact)); memcpy((char *) newname, (char *) vp->name, vp->namelen * sizeof(oid)); /* * Find "next" print entry */ Init_HR_Print(); for (;;) { print_idx = Get_Next_HR_Print(); if (print_idx == -1) break; newname[HRPRINT_ENTRY_NAME_LENGTH] = print_idx; result = snmp_oid_compare(name, *length, newname, vp->namelen + 1); if (exact && (result == 0)) { LowIndex = print_idx; /* * Save printer status information */ break; } if ((!exact && (result < 0)) && (LowIndex == -1 || print_idx < LowIndex)) { LowIndex = print_idx; /* * Save printer status information */ #ifdef HRPRINT_MONOTONICALLY_INCREASING break; #endif } } if (LowIndex == -1) { DEBUGMSGTL(("host/hr_print", "... index out of range\n")); return (MATCH_FAILED); } memcpy((char *) name, (char *) newname, (vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; *write_method = (WriteMethod*)0; *var_len = sizeof(long); /* default to 'long' results */ DEBUGMSGTL(("host/hr_print", "... get print stats ")); DEBUGMSGOID(("host/hr_print", name, *length)); DEBUGMSG(("host/hr_print", "\n")); return LowIndex; } /********************* * * System specific implementation functions * *********************/ u_char * var_hrprint(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int print_idx; print_idx = header_hrprint(vp, name, length, exact, var_len, write_method); if (print_idx == MATCH_FAILED) return NULL; switch (vp->magic) { case HRPRINT_STATUS: long_return = printer_detail_status(print_idx); return (u_char *) & long_return; case HRPRINT_ERROR: #if NETSNMP_NO_DUMMY_VALUES return NULL; #else long_return = 0; /* Null string */ return (u_char *) & long_return; #endif default: DEBUGMSGTL(("host/hr_print", "unknown sub-id %d in var_hrprint\n", vp->magic)); } return NULL; } /********************* * * Internal implementation functions * *********************/ static int HRP_index; static char **HRP_name; static int HRP_nbrnames; #if HAVE_LPSTAT || HAVE_CGETNEXT || HAVE_PRINTCAP static int HRP_maxnames; #endif #define HRP_MAX_INCR 10 void Init_HR_Print(void) { #if HAVE_LPSTAT || HAVE_CGETNEXT || HAVE_PRINTCAP int i; #if HAVE_PRINTCAP FILE *p; #elif HAVE_CGETNEXT const char *caps[] = { "/etc/printcap", NULL }; #elif HAVE_LPSTAT int fd; FILE *p; #endif HRP_index = 0; /* fail safe at Get_Next_HR_Print */ if (HRP_name) { for (i = 0; i < HRP_nbrnames; i++) free(HRP_name[i]); HRP_nbrnames = 0; HRP_maxnames = 0; SNMP_FREE(HRP_name); } #if HAVE_PRINTCAP if ((p = fopen("/etc/printcap", "r")) != NULL) { char buf[BUFSIZ], *ptr; while (fgets(buf, sizeof buf, p)) { buf[strlen(buf) - 1] = 0; if (buf[0] == '#' || buf[0] == 0 || buf[0] == ' ' || buf[0] == '\t') continue; if ((ptr = strchr(buf, '\\'))) *ptr = 0; if ((ptr = strchr(buf, ':'))) *ptr = 0; if ((ptr = strchr(buf, '|'))) *ptr = 0; ptr = buf; #elif HAVE_CGETNEXT { char *buf = NULL, *ptr; while (cgetnext(&buf, caps) > 0) { if ((ptr = strchr(buf, ':'))) *ptr = 0; if ((ptr = strchr(buf, '|'))) *ptr = 0; ptr = buf; #elif HAVE_LPSTAT if ((p = run_lpstat(&fd)) != NULL) { char buf[BUFSIZ], ptr[BUFSIZ]; while (fgets(buf, sizeof buf, p)) { sscanf(buf, "%*s %*s %[^:]", ptr); #endif if (HRP_nbrnames == HRP_maxnames) { char **tmp; tmp = (char **) calloc(HRP_maxnames + HRP_MAX_INCR, sizeof(char *)); if (!tmp) goto finish; if (HRP_name) { memcpy(tmp, HRP_name, HRP_nbrnames * sizeof(char *)); free(HRP_name); } HRP_maxnames += HRP_MAX_INCR; HRP_name = tmp; } HRP_name[HRP_nbrnames++] = strdup(ptr); #if !defined(HAVE_PRINTCAP) && defined(HAVE_CGETNEXT) if (buf) free(buf); #endif } finish: #if HAVE_PRINTCAP fclose(p); #elif HAVE_CGETNEXT cgetclose(); #elif HAVE_LPSTAT fclose(p); close(fd); #endif } #endif /* HAVE_anything */ } int Get_Next_HR_Print(void) { /* * The initial implementation system * has no printers attached, and I've * no real idea how to detect them, * so don't bother. */ if (HRP_index < HRP_nbrnames) /* No printer */ return (HRDEV_PRINTER << HRDEV_TYPE_SHIFT) + HRP_index++; else return -1; } const char * describe_printer(int idx) { if (HRP_index == 0) /* return empty string if not initialized */ return ""; DEBUGMSGTL(("host/hr_print", "describe p: %d/%d %s\n", HRP_index, idx, HRP_name[HRP_index - 1])); return HRP_name[HRP_index - 1]; } int printer_status(int idx) { /* * hrDeviceStatus OBJECT-TYPE * SYNTAX INTEGER { * unknown(1), running(2), warning(3), testing(4), down(5) * } */ return 1; /* unknown */ } int printer_detail_status(int idx) { /* * hrPrinterStatus OBJECT-TYPE * SYNTAX INTEGER { * other(1), unknown(2), idle(3), printing(4), warmup(5) * } */ return 2; /* unknown */ } int printer_errors(int idx) { return 0; } #ifdef HAVE_LPSTAT /* * Run the lpstat command. If compiled with EXCACHE support, this * will actually cache the output for a while which helps a lot * with snmpbulkwalk (in fact, it keeps the client from exiting * due to timeouts). */ FILE * run_lpstat(int *fd) { struct extensible ex; memset(&ex, 0, sizeof(ex)); ex.command = strdup(LPSTAT_PATH " -v"); *fd = get_exec_output(&ex); free(ex.command); return *fd >= 0 ? fdopen(*fd, "r") : NULL; } #endif