| /* |
| * Host Resources MIB - printer device group implementation - hr_print.c |
| * |
| */ |
| |
| #include <net-snmp/net-snmp-config.h> |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| #if HAVE_UNISTD_H |
| #include <unistd.h> |
| #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); |
| void Save_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)); |
| strcpy(ex.command, LPSTAT_PATH " -v"); |
| if ((*fd = get_exec_output(&ex)) < 0) |
| return NULL; |
| |
| return fdopen(*fd, "r"); |
| } |
| #endif |