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