util_funcs.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:26k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * util_funcs.c
  3.  */
  4. /*
  5.  * Portions of this file are copyrighted by:
  6.  * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  7.  * Use is subject to license terms specified in the COPYING file
  8.  * distributed with the Net-SNMP package.
  9.  */
  10. #include <net-snmp/net-snmp-config.h>
  11. #if HAVE_IO_H
  12. #include <io.h>
  13. #endif
  14. #include <stdio.h>
  15. #if HAVE_STDLIB_H
  16. #include <stdlib.h>
  17. #endif
  18. #if HAVE_MALLOC_H
  19. #include <malloc.h>
  20. #endif
  21. #include <sys/types.h>
  22. #ifdef __alpha
  23. #ifndef _BSD
  24. #define _BSD
  25. #define _myBSD
  26. #endif
  27. #endif
  28. #if HAVE_SYS_WAIT_H
  29. # include <sys/wait.h>
  30. #endif
  31. #ifdef __alpha
  32. #ifdef _myBSD
  33. #undef _BSD
  34. #undef _myBSD
  35. #endif
  36. #endif
  37. #ifndef WEXITSTATUS
  38. # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
  39. #endif
  40. #ifndef WIFEXITED
  41. # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
  42. #endif
  43. #if TIME_WITH_SYS_TIME
  44. # ifdef WIN32
  45. #  include <sys/timeb.h>
  46. # else
  47. #  include <sys/time.h>
  48. # endif
  49. # include <time.h>
  50. #else
  51. # if HAVE_SYS_TIME_H
  52. #  include <sys/time.h>
  53. # else
  54. #  include <time.h>
  55. # endif
  56. #endif
  57. #if HAVE_UNISTD_H
  58. #include <unistd.h>
  59. #endif
  60. #if HAVE_FCNTL_H
  61. #include <fcntl.h>
  62. #endif
  63. #include <errno.h>
  64. #include <signal.h>
  65. #if HAVE_STRING_H
  66. #include <string.h>
  67. #else
  68. #include <strings.h>
  69. #endif
  70. #include <ctype.h>
  71. #if HAVE_WINSOCK_H
  72. #include <winsock.h>
  73. #endif
  74. #if HAVE_NETINET_IN_H
  75. #include <netinet/in.h>
  76. #endif
  77. #if HAVE_BASETSD_H
  78. #include <basetsd.h>
  79. #define ssize_t SSIZE_T
  80. #endif
  81. #if HAVE_RAISE
  82. #define alarm raise
  83. #endif
  84. #ifdef HAVE_SYS_STAT_H
  85. #include <sys/stat.h>
  86. #endif
  87. #include <net-snmp/net-snmp-includes.h>
  88. #include <net-snmp/agent/net-snmp-agent-includes.h>
  89. #include "struct.h"
  90. #include "util_funcs.h"
  91. #if HAVE_LIMITS_H
  92. #include "limits.h"
  93. #endif
  94. #ifdef USING_UCD_SNMP_ERRORMIB_MODULE
  95. #include "ucd-snmp/errormib.h"
  96. #else
  97. #define setPerrorstatus(x) snmp_log_perror(x)
  98. #endif
  99. #ifdef EXCACHETIME
  100. static long     cachetime;
  101. #endif
  102. extern int      numprocs, numextens;
  103. void
  104. Exit(int var)
  105. {
  106.     snmp_log(LOG_ERR, "Server Exiting with code %dn", var);
  107.     exit(var);
  108. }
  109. const char *
  110. make_tempfile(void)
  111. {
  112.     static char     name[32];
  113.     int             fd = -1;
  114.     strcpy(name, get_temp_file_pattern());
  115. #ifdef HAVE_MKSTEMP
  116.     fd = mkstemp(name);
  117. #else
  118.     if (mktemp(name)) {
  119. # ifndef WIN32        
  120.         fd = open(name, O_CREAT | O_EXCL | O_WRONLY);
  121. # else
  122.         /*
  123.           Win32 needs _S_IREAD | _S_IWRITE to set permissions on file after closing
  124.          */
  125.         fd = _open(name, _O_CREAT, _S_IREAD | _S_IWRITE | _O_EXCL | _O_WRONLY);
  126. # endif
  127.     }
  128. #endif
  129.     if (fd >= 0) {
  130.         close(fd);
  131.         DEBUGMSGTL(("make_tempfile", "temp file created: %sn", name));
  132.         return name;
  133.     }
  134.     snmp_log(LOG_ERR,"make_tempfile: error creating file %sn", name);
  135.     return NULL;
  136. }
  137. int
  138. shell_command(struct extensible *ex)
  139. {
  140. #if HAVE_SYSTEM
  141.     const char     *ofname;
  142.     char            shellline[STRMAX];
  143.     FILE           *shellout;
  144.     ofname = make_tempfile();
  145.     if (ofname == NULL) {
  146.         ex->output[0] = 0;
  147.         ex->result = 127;
  148.         return ex->result;
  149.     }
  150.     snprintf(shellline, sizeof(shellline), "%s > %s", ex->command, ofname);
  151.     shellline[ sizeof(shellline)-1 ] = 0;
  152.     ex->result = system(shellline);
  153.     ex->result = WEXITSTATUS(ex->result);
  154.     shellout = fopen(ofname, "r");
  155.     if (shellout != NULL) {
  156.         if (fgets(ex->output, sizeof(ex->output), shellout) == NULL) {
  157.             ex->output[0] = 0;
  158.         }
  159.         fclose(shellout);
  160.     }
  161.     unlink(ofname);
  162. #else
  163.     ex->output[0] = 0;
  164.     ex->result = 0;
  165. #endif
  166.     return (ex->result);
  167. }
  168. #define MAXOUTPUT 300
  169. int
  170. exec_command(struct extensible *ex)
  171. {
  172. #if HAVE_EXECV
  173.     int             fd;
  174.     FILE           *file;
  175.     if ((fd = get_exec_output(ex)) != -1) {
  176.         file = fdopen(fd, "r");
  177.         if (fgets(ex->output, sizeof(ex->output), file) == NULL) {
  178.             ex->output[0] = 0;
  179.         }
  180.         fclose(file);
  181.         wait_on_exec(ex);
  182.     } else
  183. #endif
  184.     {
  185.         ex->output[0] = 0;
  186.         ex->result = 0;
  187.     }
  188.     return (ex->result);
  189. }
  190. struct extensible *
  191. get_exten_instance(struct extensible *exten, size_t inst)
  192. {
  193.     int             i;
  194.     if (exten == NULL)
  195.         return (NULL);
  196.     for (i = 1; i != (int) inst && exten != NULL; i++)
  197.         exten = exten->next;
  198.     return (exten);
  199. }
  200. void
  201. wait_on_exec(struct extensible *ex)
  202. {
  203. #ifndef EXCACHETIME
  204.     if (ex->pid && waitpid(ex->pid, &ex->result, 0) < 0) {
  205.         setPerrorstatus("waitpid");
  206.     }
  207.     ex->pid = 0;
  208. #endif
  209. }
  210. #define MAXARGS 30
  211. int
  212. get_exec_output(struct extensible *ex)
  213. {
  214. #if HAVE_EXECV
  215.     int             fd[2], i, cnt;
  216.     char            ctmp[STRMAX], *cptr1, *cptr2, argvs[STRMAX], **argv,
  217.         **aptr;
  218. #ifdef EXCACHETIME
  219.     char            cachefile[STRMAX];
  220.     char            cache[MAXCACHESIZE];
  221.     ssize_t         cachebytes;
  222.     long            curtime;
  223.     static char     lastcmd[STRMAX];
  224.     int             cfd;
  225.     static int      lastresult;
  226.     int             readcount;
  227. #endif
  228.     DEBUGMSGTL(("exec:get_exec_output","calling %sn", ex->command));
  229. #ifdef EXCACHETIME
  230.     sprintf(cachefile, "%s/%s", get_persistent_directory(), CACHEFILE);
  231.     curtime = time(NULL);
  232.     if (curtime > (cachetime + EXCACHETIME) ||
  233.         strcmp(ex->command, lastcmd) != 0) {
  234.         strcpy(lastcmd, ex->command);
  235.         cachetime = curtime;
  236. #endif
  237.         if (pipe(fd)) {
  238.             setPerrorstatus("pipe");
  239. #ifdef EXCACHETIME
  240.             cachetime = 0;
  241. #endif
  242.             return -1;
  243.         }
  244.         if ((ex->pid = fork()) == 0) {
  245.             close(1);
  246.             if (dup(fd[1]) != 1) {
  247.                 setPerrorstatus("dup");
  248.                 return -1;
  249.             }
  250.             /*
  251.              * write standard output and standard error to pipe. 
  252.              */
  253.             /*
  254.              * close all other file descriptors. 
  255.              */
  256.             for (cnt = getdtablesize() - 1; cnt >= 2; --cnt)
  257.                 (void) close(cnt);
  258.             (void) dup(1);      /* stderr */
  259.             /*
  260.              * set standard input to /dev/null 
  261.              */
  262.             close(0);
  263.             (void) open("/dev/null", O_RDWR);
  264.             for (cnt = 1, cptr1 = ex->command, cptr2 = argvs;
  265.                  cptr1 && *cptr1 != 0; cptr2++, cptr1++) {
  266.                 *cptr2 = *cptr1;
  267.                 if (*cptr1 == ' ') {
  268.                     *(cptr2++) = 0;
  269.                     if ((cptr1 = skip_white(cptr1)) == NULL)
  270.                         break;
  271.                     if (cptr1) {
  272.                         *cptr2 = *cptr1;
  273.                         if (*cptr1 != 0)
  274.                             cnt++;
  275.                     }
  276.                 }
  277.             }
  278.             *cptr2 = 0;
  279.             *(cptr2 + 1) = 0;
  280.             argv = (char **) malloc((cnt + 2) * sizeof(char *));
  281.             if (argv == NULL)
  282.                 return 0;       /* memory alloc error */
  283.             aptr = argv;
  284.             *(aptr++) = argvs;
  285.             for (cptr2 = argvs, i = 1; i != cnt; cptr2++)
  286.                 if (*cptr2 == 0) {
  287.                     *(aptr++) = cptr2 + 1;
  288.                     i++;
  289.                 }
  290.             while (*cptr2 != 0)
  291.                 cptr2++;
  292.             *(aptr++) = NULL;
  293.             copy_nword(ex->command, ctmp, sizeof(ctmp));
  294.             execv(ctmp, argv);
  295.             perror(ctmp);
  296.             exit(1);
  297.         } else {
  298.             close(fd[1]);
  299.             if (ex->pid < 0) {
  300.                 close(fd[0]);
  301.                 setPerrorstatus("fork");
  302. #ifdef EXCACHETIME
  303.                 cachetime = 0;
  304. #endif
  305.                 return -1;
  306.             }
  307. #ifdef EXCACHETIME
  308.             unlink(cachefile);
  309.             /*
  310.              * XXX  Use SNMP_FILEMODE_CLOSED instead of 644? 
  311.              */
  312.             if ((cfd =
  313.                  open(cachefile, O_WRONLY | O_TRUNC | O_CREAT,
  314.                       0644)) < 0) {
  315.                 snmp_log(LOG_ERR,"can not create cache filen");
  316.                 setPerrorstatus(cachefile);
  317.                 cachetime = 0;
  318.                 return -1;
  319.             }
  320.             fcntl(fd[0], F_SETFL, O_NONBLOCK);  /* don't block on reads */
  321. #ifdef HAVE_USLEEP
  322.             for (readcount = 0; readcount <= MAXREADCOUNT * 100 &&
  323.                  (cachebytes = read(fd[0], (void *) cache, MAXCACHESIZE));
  324.                  readcount++) {
  325. #else
  326.             for (readcount = 0; readcount <= MAXREADCOUNT &&
  327.                  (cachebytes = read(fd[0], (void *) cache, MAXCACHESIZE));
  328.                  readcount++) {
  329. #endif
  330.                 if (cachebytes > 0)
  331.                     write(cfd, (void *) cache, cachebytes);
  332.                 else if (cachebytes == -1 && errno != EAGAIN) {
  333.                     setPerrorstatus("read");
  334.                     break;
  335.                 } else
  336. #ifdef HAVE_USLEEP
  337.                     usleep(10000);      /* sleeps for 0.01 sec */
  338. #else
  339.                     sleep(1);
  340. #endif
  341.             }
  342.             close(cfd);
  343.             close(fd[0]);
  344.             /*
  345.              * wait for the child to finish 
  346.              */
  347.             if (ex->pid > 0 && waitpid(ex->pid, &ex->result, 0) < 0) {
  348.                 setPerrorstatus("waitpid()");
  349.                 cachetime = 0;
  350.                 return -1;
  351.             }
  352.             ex->pid = 0;
  353.             ex->result = WEXITSTATUS(ex->result);
  354.             lastresult = ex->result;
  355. #else                           /* !EXCACHETIME */
  356.             return (fd[0]);
  357. #endif
  358.         }
  359. #ifdef EXCACHETIME
  360.     } else {
  361.         ex->result = lastresult;
  362.     }
  363.     DEBUGMSGTL(("exec:get_exec_output","using cached valuen"));
  364.     if ((cfd = open(cachefile, O_RDONLY)) < 0) {
  365.         snmp_log(LOG_ERR,"can not open cache filen");
  366.         setPerrorstatus(cachefile);
  367.         return -1;
  368.     }
  369.     return (cfd);
  370. #endif
  371. #else                           /* !HAVE_EXECV */
  372.     return -1;
  373. #endif
  374. }
  375. int
  376. get_exec_pipes(char *cmd, int *fdIn, int *fdOut, int *pid)
  377. {
  378. #if HAVE_EXECV
  379.     int             fd[2][2], i, cnt;
  380.     char            ctmp[STRMAX], *cptr1, *cptr2, argvs[STRMAX], **argv,
  381.         **aptr;
  382.     /*
  383.      * Setup our pipes 
  384.      */
  385.     if (pipe(fd[0]) || pipe(fd[1])) {
  386.         setPerrorstatus("pipe");
  387.         return 0;
  388.     }
  389.     if ((*pid = fork()) == 0) { /* First handle for the child */
  390.         close(0);
  391.         if (dup(fd[0][0]) != 0) {
  392.             setPerrorstatus("dup 0");
  393.             return 0;
  394.         }
  395.         close(1);
  396.         if (dup(fd[1][1]) != 1) {
  397.             setPerrorstatus("dup 1");
  398.             return 0;
  399.         }
  400.         /*
  401.          * write standard output and standard error to pipe. 
  402.          */
  403.         /*
  404.          * close all non-standard open file descriptors 
  405.          */
  406.         for (cnt = getdtablesize() - 1; cnt >= 2; --cnt)
  407.             (void) close(cnt);
  408.         (void) dup(1);          /* stderr */
  409.         for (cnt = 1, cptr1 = cmd, cptr2 = argvs; *cptr1 != 0;
  410.              cptr2++, cptr1++) {
  411.             *cptr2 = *cptr1;
  412.             if (*cptr1 == ' ') {
  413.                 *(cptr2++) = 0;
  414.                 if ((cptr1 = skip_white(cptr1)) == NULL)
  415.                     break;
  416.                 *cptr2 = *cptr1;
  417.                 if (*cptr1 != 0)
  418.                     cnt++;
  419.             }
  420.         }
  421.         *cptr2 = 0;
  422.         *(cptr2 + 1) = 0;
  423.         argv = (char **) malloc((cnt + 2) * sizeof(char *));
  424.         if (argv == NULL)
  425.             return 0;           /* memory alloc error */
  426.         aptr = argv;
  427.         *(aptr++) = argvs;
  428.         for (cptr2 = argvs, i = 1; i != cnt; cptr2++)
  429.             if (*cptr2 == 0) {
  430.                 *(aptr++) = cptr2 + 1;
  431.                 i++;
  432.             }
  433.         while (*cptr2 != 0)
  434.             cptr2++;
  435.         *(aptr++) = NULL;
  436.         copy_nword(cmd, ctmp, sizeof(ctmp));
  437.         execv(ctmp, argv);
  438.         perror(ctmp);
  439.         exit(1);
  440.     } else {
  441.         close(fd[0][0]);
  442.         close(fd[1][1]);
  443.         if (*pid < 0) {
  444.             close(fd[0][1]);
  445.             close(fd[1][0]);
  446.             setPerrorstatus("fork");
  447.             return 0;
  448.         }
  449.         *fdIn = fd[1][0];
  450.         *fdOut = fd[0][1];
  451.         return (1);             /* We are returning 0 for error... */
  452.     }
  453. #endif                          /* !HAVE_EXECV */
  454.     return 0;
  455. }
  456. int
  457. clear_cache(int action,
  458.             u_char * var_val,
  459.             u_char var_val_type,
  460.             size_t var_val_len,
  461.             u_char * statP, oid * name, size_t name_len)
  462. {
  463.     long            tmp = 0;
  464.     if (var_val_type != ASN_INTEGER) {
  465.         snmp_log(LOG_NOTICE, "Wrong type != intn");
  466.         return SNMP_ERR_WRONGTYPE;
  467.     }
  468.     tmp = *((long *) var_val);
  469.     if (tmp == 1 && action == COMMIT) {
  470. #ifdef EXCACHETIME
  471.         cachetime = 0;          /* reset the cache next read */
  472. #endif
  473.     }
  474.     return SNMP_ERR_NOERROR;
  475. }
  476. char          **argvrestartp, *argvrestartname, *argvrestart;
  477. RETSIGTYPE
  478. restart_doit(int a)
  479. {
  480.     snmp_shutdown("snmpd");
  481.     /*
  482.      * do the exec 
  483.      */
  484. #if HAVE_EXECV
  485.     execv(argvrestartname, argvrestartp);
  486.     setPerrorstatus(argvrestartname);
  487. #endif
  488. }
  489. int
  490. restart_hook(int action,
  491.              u_char * var_val,
  492.              u_char var_val_type,
  493.              size_t var_val_len,
  494.              u_char * statP, oid * name, size_t name_len)
  495. {
  496.     long            tmp = 0;
  497.     if (var_val_type != ASN_INTEGER) {
  498.         snmp_log(LOG_NOTICE, "Wrong type != intn");
  499.         return SNMP_ERR_WRONGTYPE;
  500.     }
  501.     tmp = *((long *) var_val);
  502.     if (tmp == 1 && action == COMMIT) {
  503. #ifdef SIGALRM
  504.         signal(SIGALRM, restart_doit);
  505. #endif
  506.         alarm(RESTARTSLEEP);
  507.     }
  508.     return SNMP_ERR_NOERROR;
  509. }
  510. void
  511. print_mib_oid(oid name[], size_t len)
  512. {
  513.     char           *buffer;
  514.     buffer = (char *) malloc(11 * len); /* maximum digit lengths for int32 + a '.' */
  515.     if (!buffer) {
  516.         snmp_log(LOG_ERR, "Malloc failed - out of memory?");
  517.         return;
  518.     }
  519.     sprint_mib_oid(buffer, name, len);
  520.     snmp_log(LOG_NOTICE, "Mib: %sn", buffer);
  521.     free(buffer);
  522. }
  523. void
  524. sprint_mib_oid(char *buf, oid name[], size_t len)
  525. {
  526.     int             i;
  527.     for (i = 0; i < (int) len; i++) {
  528.         sprintf(buf, ".%d", (int) name[i]);
  529.         while (*buf != 0)
  530.             buf++;
  531.     }
  532. }
  533. /*******************************************************************-o-******
  534.  * header_simple_table
  535.  *
  536.  * Parameters:
  537.  *   *vp  Variable data.
  538.  *   *name  Fully instantiated OID name.
  539.  *   *length  Length of name.
  540.  *    exact  TRUE if an exact match is desired.
  541.  *   *var_len  Hook for size of returned data type.
  542.  * (**write_method) Hook for write method (UNUSED).
  543.  *    max
  544.  *      
  545.  * Returns:
  546.  * 0 If name matches vp->name (accounting for 'exact') and is
  547.  * not greater in length than 'max'.
  548.  * 1 Otherwise.
  549.  *
  550.  *
  551.  * Compare 'name' to vp->name for the best match or an exact match (if
  552.  * requested).  Also check that 'name' is not longer than 'max' if
  553.  * max is greater-than/equal 0.
  554.  * Store a successful match in 'name', and increment the OID instance if
  555.  * the match was not exact.  
  556.  *
  557.  * 'name' and 'length' are undefined upon failure.
  558.  *
  559.  */
  560. int
  561. header_simple_table(struct variable *vp, oid * name, size_t * length,
  562.                     int exact, size_t * var_len,
  563.                     WriteMethod ** write_method, int max)
  564. {
  565.     int             i, rtest;   /* Set to:      -1      If name < vp->name,
  566.                                  *              1       If name > vp->name,
  567.                                  *              0       Otherwise.
  568.                                  */
  569.     oid             newname[MAX_OID_LEN];
  570.     for (i = 0, rtest = 0;
  571.          i < (int) vp->namelen && i < (int) (*length) && !rtest; i++) {
  572.         if (name[i] != vp->name[i]) {
  573.             if (name[i] < vp->name[i])
  574.                 rtest = -1;
  575.             else
  576.                 rtest = 1;
  577.         }
  578.     }
  579.     if (rtest > 0 ||
  580.         (exact == 1
  581.          && (rtest || (int) *length != (int) (vp->namelen + 1)))) {
  582.         if (var_len)
  583.             *var_len = 0;
  584.         return MATCH_FAILED;
  585.     }
  586.     memset(newname, 0, sizeof(newname));
  587.     if (((int) *length) <= (int) vp->namelen || rtest == -1) {
  588.         memmove(newname, vp->name, (int) vp->namelen * sizeof(oid));
  589.         newname[vp->namelen] = 1;
  590.         *length = vp->namelen + 1;
  591.     } else if (((int) *length) > (int) vp->namelen + 1) {       /* exact case checked earlier */
  592.         *length = vp->namelen + 1;
  593.         memmove(newname, name, (*length) * sizeof(oid));
  594.         if (name[*length - 1] < ULONG_MAX) {
  595.             newname[*length - 1] = name[*length - 1] + 1;
  596.         } else {
  597.             /*
  598.              * Careful not to overflow...  
  599.              */
  600.             newname[*length - 1] = name[*length - 1];
  601.         }
  602.     } else {
  603.         *length = vp->namelen + 1;
  604.         memmove(newname, name, (*length) * sizeof(oid));
  605.         if (!exact) {
  606.             if (name[*length - 1] < ULONG_MAX) {
  607.                 newname[*length - 1] = name[*length - 1] + 1;
  608.             } else {
  609.                 /*
  610.                  * Careful not to overflow...  
  611.                  */
  612.                 newname[*length - 1] = name[*length - 1];
  613.             }
  614.         } else {
  615.             newname[*length - 1] = name[*length - 1];
  616.         }
  617.     }
  618.     if ((max >= 0 && ((int)newname[*length - 1] > max)) ||
  619.                ( 0 == newname[*length - 1] )) {
  620.         if (var_len)
  621.             *var_len = 0;
  622.         return MATCH_FAILED;
  623.     }
  624.     memmove(name, newname, (*length) * sizeof(oid));
  625.     if (write_method)
  626.         *write_method = 0;
  627.     if (var_len)
  628.         *var_len = sizeof(long);        /* default */
  629.     return (MATCH_SUCCEEDED);
  630. }
  631. /*
  632.  * header_generic(...
  633.  * Arguments:
  634.  * vp     IN      - pointer to variable entry that points here
  635.  * name    IN/OUT  - IN/name requested, OUT/name found
  636.  * length  IN/OUT  - length of IN/OUT oid's 
  637.  * exact   IN      - TRUE if an exact match was requested
  638.  * var_len OUT     - length of variable or 0 if function returned
  639.  * write_method
  640.  * 
  641.  */
  642. /*******************************************************************-o-******
  643.  * generic_header
  644.  *
  645.  * Parameters:
  646.  *   *vp    (I)     Pointer to variable entry that points here.
  647.  *   *name    (I/O)   Input name requested, output name found.
  648.  *   *length  (I/O)   Length of input and output oid's.
  649.  *    exact   (I)     TRUE if an exact match was requested.
  650.  *   *var_len (O)     Length of variable or 0 if function returned.
  651.  * (**write_method)   Hook to name a write method (UNUSED).
  652.  *      
  653.  * Returns:
  654.  * MATCH_SUCCEEDED If vp->name matches name (accounting for exact bit).
  655.  * MATCH_FAILED Otherwise,
  656.  *
  657.  *
  658.  * Check whether variable (vp) matches name.
  659.  */
  660. int
  661. header_generic(struct variable *vp,
  662.                oid * name,
  663.                size_t * length,
  664.                int exact, size_t * var_len, WriteMethod ** write_method)
  665. {
  666.     oid             newname[MAX_OID_LEN];
  667.     int             result;
  668.     DEBUGMSGTL(("util_funcs", "header_generic: "));
  669.     DEBUGMSGOID(("util_funcs", name, *length));
  670.     DEBUGMSG(("util_funcs", " exact=%dn", exact));
  671.     memcpy((char *) newname, (char *) vp->name,
  672.            (int) vp->namelen * sizeof(oid));
  673.     newname[vp->namelen] = 0;
  674.     result = snmp_oid_compare(name, *length, newname, vp->namelen + 1);
  675.     DEBUGMSGTL(("util_funcs", "  result: %dn", result));
  676.     if ((exact && (result != 0)) || (!exact && (result >= 0)))
  677.         return (MATCH_FAILED);
  678.     memcpy((char *) name, (char *) newname,
  679.            ((int) vp->namelen + 1) * sizeof(oid));
  680.     *length = vp->namelen + 1;
  681.     *write_method = 0;
  682.     *var_len = sizeof(long);    /* default to 'long' results */
  683.     return (MATCH_SUCCEEDED);
  684. }
  685. /*
  686.  * checkmib(): provided for backwards compatibility, do not use: 
  687.  */
  688. int
  689. checkmib(struct variable *vp, oid * name, size_t * length,
  690.          int exact, size_t * var_len, WriteMethod ** write_method, int max)
  691. {
  692.     /*
  693.      * checkmib used to be header_simple_table, with reveresed boolean
  694.      * return output.  header_simple_table() was created to match
  695.      * header_generic(). 
  696.      */
  697.     return (!header_simple_table(vp, name, length, exact, var_len,
  698.                                  write_method, max));
  699. }
  700. char           *
  701. find_field(char *ptr, int field)
  702. {
  703.     int             i;
  704.     char           *init = ptr;
  705.     if (field == LASTFIELD) {
  706.         /*
  707.          * skip to end 
  708.          */
  709.         while (*ptr++);
  710.         ptr = ptr - 2;
  711.         /*
  712.          * rewind a field length 
  713.          */
  714.         while (*ptr != 0 && isspace(*ptr) && init <= ptr)
  715.             ptr--;
  716.         while (*ptr != 0 && !isspace(*ptr) && init <= ptr)
  717.             ptr--;
  718.         if (isspace(*ptr))
  719.             ptr++;              /* past space */
  720.         if (ptr < init)
  721.             ptr = init;
  722.         if (!isspace(*ptr) && *ptr != 0)
  723.             return (ptr);
  724.     } else {
  725.         if ((ptr = skip_white(ptr)) == NULL)
  726.             return (NULL);
  727.         for (i = 1; *ptr != 0 && i != field; i++) {
  728.             if ((ptr = skip_not_white(ptr)) == NULL)
  729.                 return (NULL);
  730.             if ((ptr = skip_white(ptr)) == NULL)
  731.                 return (NULL);
  732.         }
  733.         if (*ptr != 0 && i == field)
  734.             return (ptr);
  735.         return (NULL);
  736.     }
  737.     return (NULL);
  738. }
  739. int
  740. parse_miboid(const char *buf, oid * oidout)
  741. {
  742.     int             i;
  743.     if (!buf)
  744.         return 0;
  745.     if (*buf == '.')
  746.         buf++;
  747.     for (i = 0; isdigit(*buf); i++) {
  748.         oidout[i] = atoi(buf);
  749.         while (isdigit(*buf++));
  750.         if (*buf == '.')
  751.             buf++;
  752.     }
  753.     /*
  754.      * oidout[i] = -1; hmmm 
  755.      */
  756.     return i;
  757. }
  758. void
  759. string_append_int(char *s, int val)
  760. {
  761.     char            textVal[16];
  762.     if (val < 10) {
  763.         *s++ = '0' + val;
  764.         *s = '';
  765.         return;
  766.     }
  767.     sprintf(textVal, "%d", val);
  768.     strcpy(s, textVal);
  769.     return;
  770. }
  771. struct internal_mib_table {
  772.     int             max_size;   /* Size of the current data table */
  773.     int             next_index; /* Index of the next free entry */
  774.     int             current_index;      /* Index of the 'current' entry */
  775.     int             cache_timeout;
  776.     marker_t        cache_marker;
  777.     RELOAD         *reload;     /* Routine to read in the data */
  778.     COMPARE        *compare;    /* Routine to compare two entries */
  779.     int             data_size;  /* Size of an individual entry */
  780.     void           *data;       /* The table itself */
  781. };
  782. mib_table_t
  783. Initialise_Table(int size, int timeout, RELOAD *reload, COMPARE *compare)
  784. {
  785.     struct internal_mib_table *t;
  786.     t = (struct internal_mib_table *)
  787.         malloc(sizeof(struct internal_mib_table));
  788.     if (t == NULL)
  789.         return NULL;
  790.     t->max_size = 0;
  791.     t->next_index = 1;          /* Don't use index 0 */
  792.     t->current_index = 1;
  793.     t->cache_timeout = timeout;
  794.     t->cache_marker = NULL;
  795.     t->reload = reload;
  796.     t->compare = compare;
  797.     t->data_size = size;
  798.     t->data = NULL;
  799.     return (mib_table_t) t;
  800. }
  801. #define TABLE_ADD( x, y ) ((void*)((char*)(x) + y))
  802. #define TABLE_INDEX(t, i) (TABLE_ADD(t->data, i * t->data_size))
  803. #define TABLE_START(t) (TABLE_INDEX(t, 1))
  804. #define TABLE_NEXT(t) (TABLE_INDEX(t, t->next_index))
  805. #define TABLE_CURRENT(t) (TABLE_INDEX(t, t->current_index))
  806. int
  807. check_and_reload_table(struct internal_mib_table *table)
  808. {
  809.     /*
  810.      * If the saved data is fairly recent,
  811.      *    we don't need to reload it
  812.      */
  813.     if (table->cache_marker &&
  814.         !(atime_ready(table->cache_marker, table->cache_timeout * 1000)))
  815.         return 1;
  816.     /*
  817.      * Call the routine provided to read in the data
  818.      *
  819.      * N.B:  Update the cache marker *before* calling
  820.      *   this routine, to avoid problems with recursion
  821.      */
  822.     if (!table->cache_marker)
  823.         table->cache_marker = atime_newMarker();
  824.     else
  825.         atime_setMarker(table->cache_marker);
  826.     table->next_index = 1;
  827.     if (table->reload((mib_table_t) table) < 0) {
  828.         free(table->cache_marker);
  829.         table->cache_marker = NULL;
  830.         return 0;
  831.     }
  832.     table->current_index = 1;
  833.     if (table->compare != NULL) /* Sort the table */
  834.         qsort(TABLE_START(table), table->next_index,
  835.               table->data_size, table->compare);
  836.     return 1;
  837. }
  838. int
  839. Search_Table(mib_table_t t, void *entry, int exact)
  840. {
  841.     struct internal_mib_table *table = (struct internal_mib_table *) t;
  842.     void           *entry2;
  843.     int             res;
  844.     if (!check_and_reload_table(table))
  845.         return -1;
  846.     if (table->compare == NULL) {
  847.         /*
  848.          * XXX - not sure this is right ? 
  849.          */
  850.         memcpy(entry, table->data, table->data_size);
  851.         return 0;
  852.     }
  853.     if (table->next_index == table->current_index)
  854.         table->current_index = 1;
  855.     entry2 = TABLE_CURRENT(table);
  856.     res = table->compare(entry, entry2);
  857.     if ((res < 0) && (table->current_index != 1)) {
  858.         table->current_index = 1;
  859.         entry2 = TABLE_CURRENT(table);
  860.         res = table->compare(entry, entry2);
  861.     }
  862.     while (res > 0) {
  863.         table->current_index++;
  864.         if (table->next_index == table->current_index)
  865.             return -1;
  866.         entry2 = TABLE_CURRENT(table);
  867.         res = table->compare(entry, entry2);
  868.     }
  869.     if (exact && res != 0)
  870.         return -1;
  871.     if (!exact && res == 0) {
  872.         table->current_index++;
  873.         if (table->next_index == table->current_index)
  874.             return -1;
  875.         entry2 = TABLE_CURRENT(table);
  876.     }
  877.     memcpy(entry, entry2, table->data_size);
  878.     return 0;
  879. }
  880. int
  881. Add_Entry(mib_table_t t, void *entry)
  882. {
  883.     struct internal_mib_table *table = (struct internal_mib_table *) t;
  884.     int             new_max;
  885.     void           *new_data;   /* Used for
  886.                                  *      a) extending the data table
  887.                                  *      b) the next entry to use
  888.                                  */
  889.     if (table->max_size <= table->next_index) {
  890.         /*
  891.          * Table is full, so extend it to double the size
  892.          */
  893.         new_max = 2 * table->max_size;
  894.         if (new_max == 0)
  895.             new_max = 10;       /* Start with 10 entries */
  896.         new_data = (void *) malloc(new_max * table->data_size);
  897.         if (new_data == NULL)
  898.             return -1;
  899.         if (table->data) {
  900.             memcpy(new_data, table->data,
  901.                    table->max_size * table->data_size);
  902.             free(table->data);
  903.         }
  904.         table->data = new_data;
  905.         table->max_size = new_max;
  906.     }
  907.     /*
  908.      * Insert the new entry into the data array
  909.      */
  910.     new_data = TABLE_NEXT(table);
  911.     memcpy(new_data, entry, table->data_size);
  912.     table->next_index++;
  913.     return 0;
  914. }
  915. void           *
  916. Retrieve_Table_Data(mib_table_t t, int *max_idx)
  917. {
  918.     struct internal_mib_table *table = (struct internal_mib_table *) t;
  919.     if (!check_and_reload_table(table))
  920.         return NULL;
  921.     *max_idx = table->next_index - 1;
  922.     return table->data;
  923. }