net-snmp
5.4.1
|
00001 #include <net-snmp/net-snmp-config.h> 00002 #include <net-snmp/net-snmp-includes.h> 00003 00004 #include <stdio.h> 00005 #include <ctype.h> 00006 #if HAVE_STDLIB_H 00007 # include <stdlib.h> 00008 #endif 00009 #if HAVE_UNISTD_H 00010 # include <unistd.h> 00011 #endif 00012 #if HAVE_STRING_H 00013 # include <string.h> 00014 #else 00015 # include <strings.h> 00016 #endif 00017 00018 #include <sys/types.h> 00019 00020 #if HAVE_LIMITS_H 00021 # include <limits.h> 00022 #endif 00023 #if HAVE_SYS_PARAM_H 00024 # include <sys/param.h> 00025 #endif 00026 #ifdef HAVE_SYS_STAT_H 00027 # include <sys/stat.h> 00028 #endif 00029 #ifdef HAVE_FCNTL_H 00030 # include <fcntl.h> 00031 #endif 00032 00033 #include <errno.h> 00034 00035 #if HAVE_DMALLOC_H 00036 # include <dmalloc.h> 00037 #endif 00038 00039 #include <net-snmp/types.h> 00040 #include <net-snmp/library/snmp_debug.h> 00041 #include <net-snmp/library/container.h> 00042 #include <net-snmp/library/file_utils.h> 00043 #include <net-snmp/library/text_utils.h> 00044 00045 00046 /*------------------------------------------------------------------ 00047 * 00048 * Prototypes 00049 * 00050 */ 00051 /* 00052 * parse methods 00053 */ 00054 void 00055 _pm_save_index_string_string(FILE *f, netsnmp_container *cin, 00056 int flags); 00057 void 00058 _pm_save_everything(FILE *f, netsnmp_container *cin, int flags); 00059 void 00060 _pm_user_function(FILE *f, netsnmp_container *cin, 00061 netsnmp_line_process_info *lpi, int flags); 00062 00063 00064 /* 00065 * line processors 00066 */ 00067 int _process_line_tvi(netsnmp_line_info *line_info, void *mem, 00068 struct netsnmp_line_process_info_s* lpi); 00069 00070 00071 00072 /*------------------------------------------------------------------ 00073 * 00074 * Text file processing functions 00075 * 00076 */ 00077 00081 netsnmp_container * 00082 netsnmp_file_text_parse(netsnmp_file *f, netsnmp_container *cin, 00083 int parse_mode, u_int flags, void *context) 00084 { 00085 netsnmp_container *c = cin; 00086 FILE *fin; 00087 int rc; 00088 00089 if (NULL == f) 00090 return NULL; 00091 00092 if ((NULL == c) && (!(flags & PM_FLAG_NO_CONTAINER))) { 00093 c = netsnmp_container_find("text_parse:binary_array"); 00094 if (NULL == c) 00095 return NULL; 00096 } 00097 00098 rc = netsnmp_file_open(f); 00099 if (rc < 0) { 00100 if ((NULL !=c) && (c != cin)) 00101 CONTAINER_FREE(c); 00102 return NULL; 00103 } 00104 00105 /* 00106 * get a stream from the file descriptor. This DOES NOT rewind the 00107 * file (if fd was previously opened). 00108 */ 00109 fin = fdopen(f->fd, "r"); 00110 if (NULL == fin) { 00111 if (NS_FI_AUTOCLOSE(f->ns_flags)) 00112 close(f->fd); 00113 if ((NULL !=c) && (c != cin)) 00114 CONTAINER_FREE(c); 00115 return NULL; 00116 } 00117 00118 switch (parse_mode) { 00119 00120 case PM_SAVE_EVERYTHING: 00121 _pm_save_everything(fin, c, flags); 00122 break; 00123 00124 case PM_INDEX_STRING_STRING: 00125 _pm_save_index_string_string(fin, c, flags); 00126 break; 00127 00128 case PM_USER_FUNCTION: 00129 if (NULL != context) 00130 _pm_user_function(fin, c, (netsnmp_line_process_info*)context, 00131 flags); 00132 break; 00133 00134 default: 00135 snmp_log(LOG_ERR, "unknown parse mode %d\n", parse_mode); 00136 break; 00137 } 00138 00139 00140 /* 00141 * close the stream, which will have the side effect of also closing 00142 * the file descriptor, so we need to reset it. 00143 */ 00144 fclose(fin); 00145 f->fd = -1; 00146 00147 return c; 00148 } 00149 00150 netsnmp_container * 00151 netsnmp_text_token_container_from_file(const char *file, u_int flags, 00152 netsnmp_container *cin, void *context) 00153 { 00154 netsnmp_line_process_info lpi; 00155 netsnmp_container *c = cin, *c_rc; 00156 netsnmp_file *fp; 00157 00158 if (NULL == file) 00159 return NULL; 00160 00161 /* 00162 * allocate file resources 00163 */ 00164 fp = netsnmp_file_fill(NULL, file, O_RDONLY, 0, 0); 00165 if (NULL == fp) 00166 return NULL; 00167 00168 memset(&lpi, 0x0, sizeof(lpi)); 00169 lpi.mem_size = sizeof(netsnmp_token_value_index); 00170 lpi.process = _process_line_tvi; 00171 lpi.user_context = context; 00172 00173 if (NULL == c) { 00174 c = netsnmp_container_find("string:binary_array"); 00175 if (NULL == c) { 00176 snmp_log(LOG_ERR,"malloc failed\n"); 00177 netsnmp_file_release(fp); 00178 return NULL; 00179 } 00180 } 00181 00182 c_rc = netsnmp_file_text_parse(fp, c, PM_USER_FUNCTION, 0, &lpi); 00183 00184 /* 00185 * if we got a bad return and the user didn't pass us a container, 00186 * we need to release the container we allocated. 00187 */ 00188 if ((NULL == c_rc) && (NULL == cin)) { 00189 CONTAINER_FREE(c); 00190 c = NULL; 00191 } 00192 else 00193 c = c_rc; 00194 00195 /* 00196 * release file resources 00197 */ 00198 netsnmp_file_release(fp); 00199 00200 return c; 00201 } 00202 00203 00204 /*------------------------------------------------------------------ 00205 * 00206 * Text file process modes helper functions 00207 * 00208 */ 00209 00214 void 00215 _pm_save_everything(FILE *f, netsnmp_container *cin, int flags) 00216 { 00217 char line[STRINGMAX], *ptr; 00218 size_t len; 00219 00220 netsnmp_assert(NULL != f); 00221 netsnmp_assert(NULL != cin); 00222 00223 while (fgets(line, sizeof(line), f) != NULL) { 00224 00225 ptr = line; 00226 len = strlen(line) - 1; 00227 if (line[len] == '\n') 00228 line[len] = 0; 00229 00230 /* 00231 * save blank line or comment? 00232 */ 00233 if (flags & PM_FLAG_SKIP_WHITESPACE) { 00234 if (NULL == (ptr = skip_white(ptr))) 00235 continue; 00236 } 00237 00238 ptr = strdup(line); 00239 if (NULL == ptr) { 00240 snmp_log(LOG_ERR,"malloc failed\n"); 00241 break; 00242 } 00243 00244 CONTAINER_INSERT(cin,ptr); 00245 } 00246 } 00247 00252 void 00253 _pm_save_index_string_string(FILE *f, netsnmp_container *cin, 00254 int flags) 00255 { 00256 char line[STRINGMAX], *ptr; 00257 netsnmp_token_value_index *tvi; 00258 size_t count = 0, len; 00259 00260 netsnmp_assert(NULL != f); 00261 netsnmp_assert(NULL != cin); 00262 00263 while (fgets(line, sizeof(line), f) != NULL) { 00264 00265 ++count; 00266 ptr = line; 00267 len = strlen(line) - 1; 00268 if (line[len] == '\n') 00269 line[len] = 0; 00270 00271 /* 00272 * save blank line or comment? 00273 */ 00274 if (flags & PM_FLAG_SKIP_WHITESPACE) { 00275 if (NULL == (ptr = skip_white(ptr))) 00276 continue; 00277 } 00278 00279 tvi = SNMP_MALLOC_TYPEDEF(netsnmp_token_value_index); 00280 if (NULL == tvi) { 00281 snmp_log(LOG_ERR,"malloc failed\n"); 00282 break; 00283 } 00284 00285 /* 00286 * copy whole line, then set second pointer to 00287 * after token. One malloc, 2 strings! 00288 */ 00289 tvi->index = count; 00290 tvi->token = strdup(line); 00291 if (NULL == tvi->token) { 00292 snmp_log(LOG_ERR,"malloc failed\n"); 00293 free(tvi); 00294 break; 00295 } 00296 tvi->value.cp = skip_not_white(tvi->token); 00297 if (NULL != tvi->value.cp) { 00298 *(tvi->value.cp) = 0; 00299 ++(tvi->value.cp); 00300 } 00301 CONTAINER_INSERT(cin, tvi); 00302 } 00303 } 00304 00309 void 00310 _pm_user_function(FILE *f, netsnmp_container *cin, 00311 netsnmp_line_process_info *lpi, int flags) 00312 { 00313 char buf[STRINGMAX]; 00314 netsnmp_line_info li; 00315 void *mem = NULL; 00316 int rc; 00317 00318 netsnmp_assert(NULL != f); 00319 netsnmp_assert(NULL != cin); 00320 00321 /* 00322 * static buf, or does the user want the memory? 00323 */ 00324 if (flags & PMLP_FLAG_ALLOC_LINE) { 00325 if (0 != lpi->line_max) 00326 li.line_max = lpi->line_max; 00327 else 00328 li.line_max = STRINGMAX; 00329 li.line = (char *)calloc(li.line_max, 1); 00330 if (NULL == li.line) { 00331 snmp_log(LOG_ERR,"malloc failed\n"); 00332 return; 00333 } 00334 } 00335 else { 00336 li.line = buf; 00337 li.line_max = sizeof(buf); 00338 } 00339 00340 li.index = 0; 00341 while (fgets(li.line, li.line_max, f) != NULL) { 00342 00343 ++li.index; 00344 li.start = li.line; 00345 li.line_len = strlen(li.line) - 1; 00346 if ((!(lpi->flags & PMLP_FLAG_LEAVE_NEWLINE)) && 00347 (li.line[li.line_len] == '\n')) 00348 li.line[li.line_len] = 0; 00349 00350 /* 00351 * save blank line or comment? 00352 */ 00353 if (!(lpi->flags & PMLP_FLAG_PROCESS_WHITESPACE)) { 00354 if (NULL == (li.start = skip_white(li.start))) 00355 continue; 00356 } 00357 00358 /* 00359 * do we need to allocate memory for the use? 00360 * if the last call didn't use the memory we allocated, 00361 * re-use it. Otherwise, allocate new chunk. 00362 */ 00363 if ((0 != lpi->mem_size) && (NULL == mem)) { 00364 mem = calloc(lpi->mem_size, 1); 00365 if (NULL == mem) { 00366 snmp_log(LOG_ERR,"malloc failed\n"); 00367 break; 00368 } 00369 } 00370 00371 /* 00372 * do they want a copy ot the line? 00373 */ 00374 if (lpi->flags & PMLP_FLAG_STRDUP_LINE) { 00375 li.start = strdup(li.start); 00376 if (NULL == li.start) { 00377 snmp_log(LOG_ERR,"malloc failed\n"); 00378 break; 00379 } 00380 } 00381 else if (lpi->flags & PMLP_FLAG_ALLOC_LINE) { 00382 li.start = li.line; 00383 } 00384 00385 /* 00386 * call the user function. If the function wants to save 00387 * the memory chunk, insert it in the container, the clear 00388 * pointer so we reallocate next time. 00389 */ 00390 li.start_len = strlen(li.start); 00391 rc = (*lpi->process)(&li, mem, lpi); 00392 if (PMLP_RC_MEMORY_USED == rc) { 00393 00394 if (!(lpi->flags & PMLP_FLAG_NO_CONTAINER)) 00395 CONTAINER_INSERT(cin, mem); 00396 00397 mem = NULL; 00398 00399 if (lpi->flags & PMLP_FLAG_ALLOC_LINE) { 00400 li.line = (char *)calloc(li.line_max, 1); 00401 if (NULL == li.line) { 00402 snmp_log(LOG_ERR,"malloc failed\n"); 00403 break; 00404 } 00405 } 00406 } 00407 else if (PMLP_RC_MEMORY_UNUSED == rc ) { 00408 /* 00409 * they didn't use the memory. if li.start was a strdup, we have 00410 * to release it. leave mem, we can re-use it (its a fixed size). 00411 */ 00412 if (lpi->flags & PMLP_FLAG_STRDUP_LINE) 00413 free(li.start); /* no point in SNMP_FREE */ 00414 } 00415 else { 00416 if (PMLP_RC_STOP_PROCESSING != rc ) 00417 snmp_log(LOG_ERR, "unknown rc %d from text processor\n", rc); 00418 break; 00419 } 00420 } 00421 SNMP_FREE(mem); 00422 } 00423 00424 /*------------------------------------------------------------------ 00425 * 00426 * Test line process helper functions 00427 * 00428 */ 00433 int 00434 _process_line_tvi(netsnmp_line_info *line_info, void *mem, 00435 struct netsnmp_line_process_info_s* lpi) 00436 { 00437 netsnmp_token_value_index *tvi = (netsnmp_token_value_index *)mem; 00438 char *ptr; 00439 00440 /* 00441 * get token 00442 */ 00443 ptr = skip_not_white(line_info->start); 00444 if (NULL == ptr) { 00445 DEBUGMSGTL(("text:util:tvi", "no value after token '%s'\n", 00446 line_info->start)); 00447 return PMLP_RC_MEMORY_UNUSED; 00448 } 00449 00450 /* 00451 * null terminate, search for value; 00452 */ 00453 *(ptr++) = 0; 00454 ptr = skip_white(ptr); 00455 if (NULL == ptr) { 00456 DEBUGMSGTL(("text:util:tvi", "no value after token '%s'\n", 00457 line_info->start)); 00458 return PMLP_RC_MEMORY_UNUSED; 00459 } 00460 00461 /* 00462 * get value 00463 */ 00464 switch((int)(intptr_t)lpi->user_context) { 00465 00466 case PMLP_TYPE_UNSIGNED: 00467 tvi->value.ul = strtoul(ptr, NULL, 0); 00468 if ((errno == ERANGE) &&(ULONG_MAX == tvi->value.sl)) 00469 snmp_log(LOG_WARNING,"value overflow\n"); 00470 break; 00471 00472 00473 case PMLP_TYPE_INTEGER: 00474 tvi->value.ul = strtol(ptr, NULL, 0); 00475 if ((errno == ERANGE) && 00476 ((LONG_MAX == tvi->value.sl) || 00477 (LONG_MIN == tvi->value.sl))) 00478 snmp_log(LOG_WARNING,"value over/under-flow\n"); 00479 break; 00480 00481 case PMLP_TYPE_STRING: 00482 tvi->value.cp = strdup(ptr); 00483 break; 00484 00485 case PMLP_TYPE_BOOLEAN: 00486 if (isdigit(*ptr)) 00487 tvi->value.ul = strtoul(ptr, NULL, 0); 00488 else if (strcasecmp(ptr,"true") == 0) 00489 tvi->value.ul = 1; 00490 else if (strcasecmp(ptr,"false") == 0) 00491 tvi->value.ul = 0; 00492 else { 00493 snmp_log(LOG_WARNING,"bad value for boolean\n"); 00494 return PMLP_RC_MEMORY_UNUSED; 00495 } 00496 break; 00497 00498 default: 00499 snmp_log(LOG_ERR,"unsupported value type %d\n", 00500 (int)(intptr_t)lpi->user_context); 00501 break; 00502 } 00503 00504 /* 00505 * save token and value 00506 */ 00507 tvi->token = strdup(line_info->start); 00508 tvi->index = line_info->index; 00509 00510 return PMLP_RC_MEMORY_USED; 00511 } 00512