Mercurial > flash_v2
comparison packages/net/snmp/lib/current/src/read_config.c @ 103:95f3e12a6327 ecos-sw-2000-06-23
Merge from eCos master repository on 2000-06-23-16:41:10-BST
| author | jlarmour |
|---|---|
| date | Fri, 23 Jun 2000 17:06:31 +0000 |
| parents | |
| children | e0c0827131d1 |
comparison
equal
deleted
inserted
replaced
| 102:6409b6d94dd7 | 103:95f3e12a6327 |
|---|---|
| 1 //========================================================================== | |
| 2 // | |
| 3 // ./lib/current/src/read_config.c | |
| 4 // | |
| 5 // | |
| 6 //========================================================================== | |
| 7 //####COPYRIGHTBEGIN#### | |
| 8 // | |
| 9 // ------------------------------------------- | |
| 10 // The contents of this file are subject to the Red Hat eCos Public License | |
| 11 // Version 1.1 (the "License"); you may not use this file except in | |
| 12 // compliance with the License. You may obtain a copy of the License at | |
| 13 // http://www.redhat.com/ | |
| 14 // | |
| 15 // Software distributed under the License is distributed on an "AS IS" | |
| 16 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | |
| 17 // License for the specific language governing rights and limitations under | |
| 18 // the License. | |
| 19 // | |
| 20 // The Original Code is eCos - Embedded Configurable Operating System, | |
| 21 // released September 30, 1998. | |
| 22 // | |
| 23 // The Initial Developer of the Original Code is Red Hat. | |
| 24 // Portions created by Red Hat are | |
| 25 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. | |
| 26 // All Rights Reserved. | |
| 27 // ------------------------------------------- | |
| 28 // | |
| 29 //####COPYRIGHTEND#### | |
| 30 //####UCDSNMPCOPYRIGHTBEGIN#### | |
| 31 // | |
| 32 // ------------------------------------------- | |
| 33 // | |
| 34 // Portions of this software may have been derived from the UCD-SNMP | |
| 35 // project, <http://ucd-snmp.ucdavis.edu/> from the University of | |
| 36 // California at Davis, which was originally based on the Carnegie Mellon | |
| 37 // University SNMP implementation. Portions of this software are therefore | |
| 38 // covered by the appropriate copyright disclaimers included herein. | |
| 39 // | |
| 40 // The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2" | |
| 41 // ------------------------------------------- | |
| 42 // | |
| 43 //####UCDSNMPCOPYRIGHTEND#### | |
| 44 //========================================================================== | |
| 45 //#####DESCRIPTIONBEGIN#### | |
| 46 // | |
| 47 // Author(s): hmt | |
| 48 // Contributors: hmt | |
| 49 // Date: 2000-05-30 | |
| 50 // Purpose: Port of UCD-SNMP distribution to eCos. | |
| 51 // Description: | |
| 52 // | |
| 53 // | |
| 54 //####DESCRIPTIONEND#### | |
| 55 // | |
| 56 //========================================================================== | |
| 57 /******************************************************************** | |
| 58 Copyright 1989, 1991, 1992 by Carnegie Mellon University | |
| 59 | |
| 60 Derivative Work - | |
| 61 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California | |
| 62 | |
| 63 All Rights Reserved | |
| 64 | |
| 65 Permission to use, copy, modify and distribute this software and its | |
| 66 documentation for any purpose and without fee is hereby granted, | |
| 67 provided that the above copyright notice appears in all copies and | |
| 68 that both that copyright notice and this permission notice appear in | |
| 69 supporting documentation, and that the name of CMU and The Regents of | |
| 70 the University of California not be used in advertising or publicity | |
| 71 pertaining to distribution of the software without specific written | |
| 72 permission. | |
| 73 | |
| 74 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL | |
| 75 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED | |
| 76 WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU OR | |
| 77 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL, | |
| 78 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING | |
| 79 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF | |
| 80 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
| 81 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 82 *********************************************************************/ | |
| 83 /* | |
| 84 * read_config.c | |
| 85 */ | |
| 86 | |
| 87 #include <config.h> | |
| 88 | |
| 89 #include <stdio.h> | |
| 90 #include <ctype.h> | |
| 91 #if HAVE_STDLIB_H | |
| 92 #include <stdlib.h> | |
| 93 #endif | |
| 94 #if HAVE_STRING_H | |
| 95 #include <string.h> | |
| 96 #else | |
| 97 #include <strings.h> | |
| 98 #endif | |
| 99 #if HAVE_UNISTD_H | |
| 100 #include <unistd.h> | |
| 101 #endif | |
| 102 #include <sys/types.h> | |
| 103 #if HAVE_SYS_PARAM_H | |
| 104 #include <sys/param.h> | |
| 105 #endif | |
| 106 #if TIME_WITH_SYS_TIME | |
| 107 # ifdef WIN32 | |
| 108 # include <sys/timeb.h> | |
| 109 # else | |
| 110 # include <sys/time.h> | |
| 111 # endif | |
| 112 # include <time.h> | |
| 113 #else | |
| 114 # if HAVE_SYS_TIME_H | |
| 115 # include <sys/time.h> | |
| 116 # else | |
| 117 # include <time.h> | |
| 118 # endif | |
| 119 #endif | |
| 120 #ifdef HAVE_SYS_STAT_H | |
| 121 #include <sys/stat.h> | |
| 122 #endif | |
| 123 #if HAVE_NETINET_IN_H | |
| 124 #include <netinet/in.h> | |
| 125 #endif | |
| 126 #if HAVE_ARPA_INET_H | |
| 127 #include <arpa/inet.h> | |
| 128 #endif | |
| 129 #if HAVE_SYS_SELECT_H | |
| 130 #include <sys/select.h> | |
| 131 #endif | |
| 132 #if HAVE_WINSOCK_H | |
| 133 #include <winsock.h> | |
| 134 #endif | |
| 135 #if HAVE_SYS_SOCKET_H | |
| 136 #include <sys/socket.h> | |
| 137 #endif | |
| 138 #if HAVE_NETDB_H | |
| 139 #include <netdb.h> | |
| 140 #endif | |
| 141 #include <errno.h> | |
| 142 | |
| 143 #if HAVE_DMALLOC_H | |
| 144 #include <dmalloc.h> | |
| 145 #endif | |
| 146 | |
| 147 #include "asn1.h" | |
| 148 #include "mib.h" | |
| 149 #include "parse.h" | |
| 150 #include "system.h" | |
| 151 #include "snmp_api.h" | |
| 152 #include "snmp_debug.h" | |
| 153 #include "snmp_logging.h" | |
| 154 #include "snmp_impl.h" | |
| 155 #include "default_store.h" | |
| 156 #include "callback.h" | |
| 157 | |
| 158 #include "read_config.h" | |
| 159 #include "tools.h" | |
| 160 | |
| 161 int config_errors; | |
| 162 | |
| 163 struct config_files *config_files = NULL; | |
| 164 | |
| 165 struct config_line * | |
| 166 register_premib_handler(const char *type, | |
| 167 const char *token, | |
| 168 void (*parser) (const char *, char *), | |
| 169 void (*releaser) (void), | |
| 170 const char *help) | |
| 171 { | |
| 172 struct config_line *ltmp; | |
| 173 ltmp = register_config_handler(type, token, parser, releaser, help); | |
| 174 if (ltmp != NULL) | |
| 175 ltmp->config_time = PREMIB_CONFIG; | |
| 176 return (ltmp); | |
| 177 } | |
| 178 | |
| 179 struct config_line * | |
| 180 register_app_premib_handler(const char *token, | |
| 181 void (*parser) (const char *, char *), | |
| 182 void (*releaser) (void), | |
| 183 const char *help) | |
| 184 { | |
| 185 return(register_premib_handler( NULL, token, parser, releaser, help )); | |
| 186 } | |
| 187 | |
| 188 /*******************************************************************-o-****** | |
| 189 * register_config_handler | |
| 190 * | |
| 191 * Parameters: | |
| 192 * *type | |
| 193 * *token | |
| 194 * *parser | |
| 195 * *releaser | |
| 196 * | |
| 197 * Returns: | |
| 198 * Pointer to a new config line entry -OR- NULL on error. | |
| 199 */ | |
| 200 struct config_line * | |
| 201 register_config_handler(const char *type_param, | |
| 202 const char *token, | |
| 203 void (*parser) (const char *, char *), | |
| 204 void (*releaser) (void), | |
| 205 const char *help) | |
| 206 { | |
| 207 struct config_files **ctmp = &config_files; | |
| 208 struct config_line **ltmp; | |
| 209 const char *type = type_param; | |
| 210 | |
| 211 if ( type == NULL ) | |
| 212 type = ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE); | |
| 213 | |
| 214 /* | |
| 215 * Find type in current list -OR- create a new file type. | |
| 216 */ | |
| 217 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) { | |
| 218 ctmp = &((*ctmp)->next); | |
| 219 } | |
| 220 | |
| 221 if (*ctmp == NULL) { | |
| 222 *ctmp = (struct config_files *) | |
| 223 malloc(sizeof(struct config_files)); | |
| 224 if ( !*ctmp ) { | |
| 225 return NULL; | |
| 226 } | |
| 227 | |
| 228 (*ctmp)->next = NULL; | |
| 229 (*ctmp)->start = NULL; | |
| 230 (*ctmp)->fileHeader = strdup(type); | |
| 231 } | |
| 232 | |
| 233 /* | |
| 234 * Find parser type in current list -OR- create a new | |
| 235 * line parser entry. | |
| 236 */ | |
| 237 ltmp = &((*ctmp)->start); | |
| 238 | |
| 239 while (*ltmp != NULL && strcmp((*ltmp)->config_token, token)) { | |
| 240 ltmp = &((*ltmp)->next); | |
| 241 } | |
| 242 | |
| 243 if (*ltmp == NULL) { | |
| 244 *ltmp = (struct config_line *) | |
| 245 malloc(sizeof(struct config_line)); | |
| 246 if ( !*ltmp ) { | |
| 247 return NULL; | |
| 248 } | |
| 249 | |
| 250 (*ltmp)->next = NULL; | |
| 251 (*ltmp)->config_time = NORMAL_CONFIG; | |
| 252 (*ltmp)->parse_line = 0; | |
| 253 (*ltmp)->free_func = 0; | |
| 254 (*ltmp)->config_token = strdup(token); | |
| 255 if (help != NULL) | |
| 256 (*ltmp)->help = strdup(help); | |
| 257 | |
| 258 } | |
| 259 | |
| 260 /* | |
| 261 * Add/Replace the parse/free functions for the given line type | |
| 262 * in the given file type. | |
| 263 */ | |
| 264 (*ltmp)->parse_line = parser; | |
| 265 (*ltmp)->free_func = releaser; | |
| 266 | |
| 267 return (*ltmp); | |
| 268 | |
| 269 } /* end register_config_handler() */ | |
| 270 | |
| 271 struct config_line * | |
| 272 register_app_config_handler(const char *token, | |
| 273 void (*parser) (const char *, char *), | |
| 274 void (*releaser) (void), | |
| 275 const char *help) | |
| 276 { | |
| 277 return(register_config_handler( NULL, token, parser, releaser, help )); | |
| 278 } | |
| 279 | |
| 280 void | |
| 281 unregister_config_handler(const char *type_param, | |
| 282 const char *token) | |
| 283 { | |
| 284 struct config_files **ctmp = &config_files; | |
| 285 struct config_line **ltmp, *ltmp2; | |
| 286 const char *type = type_param; | |
| 287 | |
| 288 if ( type == NULL ) | |
| 289 type = ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE); | |
| 290 | |
| 291 /* find type in current list */ | |
| 292 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader,type)) { | |
| 293 ctmp = &((*ctmp)->next); | |
| 294 } | |
| 295 | |
| 296 if (*ctmp == NULL) { | |
| 297 /* Not found, return. */ | |
| 298 return; | |
| 299 } | |
| 300 | |
| 301 ltmp = &((*ctmp)->start); | |
| 302 if (*ltmp == NULL) { | |
| 303 /* Not found, return. */ | |
| 304 return; | |
| 305 } | |
| 306 if (strcmp((*ltmp)->config_token,token) == 0) { | |
| 307 /* found it at the top of the list */ | |
| 308 (*ctmp)->start = (*ltmp)->next; | |
| 309 free((*ltmp)->config_token); | |
| 310 SNMP_FREE((*ltmp)->help); | |
| 311 free(*ltmp); | |
| 312 return; | |
| 313 } | |
| 314 while ((*ltmp)->next != NULL && strcmp((*ltmp)->next->config_token,token)) { | |
| 315 ltmp = &((*ltmp)->next); | |
| 316 } | |
| 317 if (*ltmp == NULL) { | |
| 318 free((*ltmp)->config_token); | |
| 319 SNMP_FREE((*ltmp)->help); | |
| 320 ltmp2 = (*ltmp)->next->next; | |
| 321 free((*ltmp)->next); | |
| 322 (*ltmp)->next = ltmp2; | |
| 323 } | |
| 324 } | |
| 325 | |
| 326 void | |
| 327 unregister_app_config_handler(const char *token) | |
| 328 { | |
| 329 unregister_config_handler( NULL, token ); | |
| 330 } | |
| 331 | |
| 332 #ifdef TESTING | |
| 333 void print_config_handlers (void) | |
| 334 { | |
| 335 struct config_files *ctmp = config_files; | |
| 336 struct config_line *ltmp; | |
| 337 | |
| 338 for(;ctmp != NULL; ctmp = ctmp->next) { | |
| 339 DEBUGMSGTL(("read_config", "read_conf: %s\n", ctmp->fileHeader)); | |
| 340 for(ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) | |
| 341 DEBUGMSGTL(("read_config", " %s\n", ltmp->config_token)); | |
| 342 } | |
| 343 } | |
| 344 #endif | |
| 345 | |
| 346 int linecount; | |
| 347 const char *curfilename; | |
| 348 | |
| 349 void read_config_with_type(const char *filename, | |
| 350 const char *type) | |
| 351 { | |
| 352 struct config_files *ctmp = config_files; | |
| 353 for(;ctmp != NULL && strcmp(ctmp->fileHeader,type); ctmp = ctmp->next); | |
| 354 if (ctmp) | |
| 355 read_config(filename, ctmp->start, EITHER_CONFIG); | |
| 356 else | |
| 357 DEBUGMSGTL(("read_config", "read_config: I have no registrations for type:%s,file:%s\n", | |
| 358 type, filename)); | |
| 359 } | |
| 360 | |
| 361 /*******************************************************************-o-****** | |
| 362 * read_config | |
| 363 * | |
| 364 * Parameters: | |
| 365 * *filename | |
| 366 * *line_handler | |
| 367 * when | |
| 368 * | |
| 369 * Read <filename> and process each line in accordance with the list of | |
| 370 * <line_handler> functions. | |
| 371 * | |
| 372 * | |
| 373 * For each line in <filename>, search the list of <line_handler>'s | |
| 374 * for an entry that matches the first token on the line. This comparison is | |
| 375 * case insensitive. | |
| 376 * | |
| 377 * For each match, check that <when> is the designated time for the | |
| 378 * <line_handler> function to be executed before processing the line. | |
| 379 */ | |
| 380 void read_config(const char *filename, | |
| 381 struct config_line *line_handler, | |
| 382 int when) | |
| 383 { | |
| 384 | |
| 385 FILE *ifile; | |
| 386 char line[STRINGMAX], token[STRINGMAX], tmpbuf[STRINGMAX]; | |
| 387 char *cptr; | |
| 388 int i, done; | |
| 389 struct config_line *lptr; | |
| 390 | |
| 391 linecount = 0; | |
| 392 curfilename = filename; | |
| 393 | |
| 394 if ((ifile = fopen(filename, "r")) == NULL) { | |
| 395 #ifdef ENOENT | |
| 396 if (errno == ENOENT) { | |
| 397 DEBUGMSGTL(("read_config", "%s: %s\n", filename, strerror(errno))); | |
| 398 } else | |
| 399 #endif /* ENOENT */ | |
| 400 #ifdef EACCES | |
| 401 if (errno == EACCES) { | |
| 402 DEBUGMSGTL(("read_config", "%s: %s\n", filename, strerror(errno))); | |
| 403 } else | |
| 404 #endif /* EACCES */ | |
| 405 #if defined(ENOENT) || defined(EACCES) | |
| 406 { | |
| 407 snmp_log_perror(filename); | |
| 408 } | |
| 409 #else /* defined(ENOENT) || defined(EACCES) */ | |
| 410 snmp_log_perror(filename); | |
| 411 #endif /* ENOENT */ | |
| 412 return; | |
| 413 } else { | |
| 414 DEBUGMSGTL(("read_config", "Reading configuration %s\n", filename)); | |
| 415 } | |
| 416 | |
| 417 while (fgets(line, sizeof(line), ifile) != NULL) | |
| 418 { | |
| 419 lptr = line_handler; | |
| 420 linecount++; | |
| 421 cptr = line; | |
| 422 i = strlen(line)-1; | |
| 423 if (line[i] == '\n') | |
| 424 line[i] = 0; | |
| 425 /* check blank line or # comment */ | |
| 426 if ((cptr = skip_white(cptr))) | |
| 427 { | |
| 428 cptr = copy_word(cptr,token); | |
| 429 if (cptr == NULL) { | |
| 430 sprintf(tmpbuf,"Blank line following %s token.", token); | |
| 431 config_perror(tmpbuf); | |
| 432 } else { | |
| 433 for(lptr = line_handler, done=0; | |
| 434 lptr != NULL && !done; | |
| 435 lptr = lptr->next) { | |
| 436 if (!strcasecmp(token,lptr->config_token)) { | |
| 437 if (when == EITHER_CONFIG || lptr->config_time == when) { | |
| 438 DEBUGMSGTL(("read_config", "%s:%d Parsing: %s\n", | |
| 439 filename, linecount, line)); | |
| 440 (*(lptr->parse_line))(token,cptr); | |
| 441 } | |
| 442 done = 1; | |
| 443 } | |
| 444 } | |
| 445 if (!done && when != PREMIB_CONFIG && | |
| 446 !ds_get_boolean(DS_LIBRARY_ID, DS_LIB_NO_TOKEN_WARNINGS)) { | |
| 447 sprintf(tmpbuf,"Unknown token: %s.", token); | |
| 448 config_pwarn(tmpbuf); | |
| 449 } | |
| 450 } | |
| 451 } | |
| 452 } | |
| 453 fclose(ifile); | |
| 454 return; | |
| 455 | |
| 456 } /* end read_config() */ | |
| 457 | |
| 458 | |
| 459 | |
| 460 void | |
| 461 free_config (void) | |
| 462 { | |
| 463 struct config_files *ctmp = config_files; | |
| 464 struct config_line *ltmp; | |
| 465 | |
| 466 for(;ctmp != NULL; ctmp = ctmp->next) | |
| 467 for(ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) | |
| 468 if (ltmp->free_func) | |
| 469 (*(ltmp->free_func))(); | |
| 470 } | |
| 471 | |
| 472 void | |
| 473 read_configs (void) | |
| 474 { | |
| 475 | |
| 476 char *optional_config = ds_get_string(DS_LIBRARY_ID, DS_LIB_OPTIONALCONFIG); | |
| 477 char *type = ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE); | |
| 478 | |
| 479 DEBUGMSGTL(("read_config","reading normal configuration tokens\n")); | |
| 480 | |
| 481 if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DONT_READ_CONFIGS)) | |
| 482 read_config_files(NORMAL_CONFIG); | |
| 483 | |
| 484 /* do this even when the normal above wasn't done */ | |
| 485 if (optional_config && type) | |
| 486 read_config_with_type(optional_config, type); | |
| 487 | |
| 488 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG, | |
| 489 NULL); | |
| 490 } | |
| 491 | |
| 492 void | |
| 493 read_premib_configs (void) | |
| 494 { | |
| 495 DEBUGMSGTL(("read_config","reading premib configuration tokens\n")); | |
| 496 | |
| 497 if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DONT_READ_CONFIGS)) | |
| 498 read_config_files(PREMIB_CONFIG); | |
| 499 | |
| 500 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, | |
| 501 SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, | |
| 502 NULL); | |
| 503 } | |
| 504 | |
| 505 | |
| 506 | |
| 507 | |
| 508 /*******************************************************************-o-****** | |
| 509 * read_config_files | |
| 510 * | |
| 511 * Parameters: | |
| 512 * when == PREMIB_CONFIG, NORMAL_CONFIG -or- EITHER_CONFIG | |
| 513 * | |
| 514 * | |
| 515 * Traverse the list of config file types, performing the following actions | |
| 516 * for each -- | |
| 517 * | |
| 518 * First, build a search path for config files. If the contents of | |
| 519 * environment variable SNMPCONFPATH are NULL, then use the following | |
| 520 * path list (where the last entry exists only if HOME is non-null): | |
| 521 * | |
| 522 * SNMPSHAREPATH:SNMPLIBPATH:${HOME}/.snmp | |
| 523 * | |
| 524 * Then, In each of these directories, read config files by the name of: | |
| 525 * | |
| 526 * <dir>/<fileHeader>.conf -AND- | |
| 527 * <dir>/<fileHeader>.local.conf | |
| 528 * | |
| 529 * where <fileHeader> is taken from the config file type structure. | |
| 530 * | |
| 531 * | |
| 532 * PREMIB_CONFIG causes free_config() to be invoked prior to any other action. | |
| 533 * | |
| 534 * | |
| 535 * EXITs if any 'config_errors' are logged while parsing config file lines. | |
| 536 */ | |
| 537 void | |
| 538 read_config_files (int when) | |
| 539 { | |
| 540 #ifndef ECOSFIXME_NEEDFILESYSTEM | |
| 541 | |
| 542 int i, j; | |
| 543 char configfile[300]; | |
| 544 char *envconfpath, *homepath; | |
| 545 char *cptr1, *cptr2; | |
| 546 char defaultPath[SPRINT_MAX_LEN]; | |
| 547 | |
| 548 struct config_files *ctmp = config_files; | |
| 549 struct config_line *ltmp; | |
| 550 struct stat statbuf; | |
| 551 | |
| 552 if (when == PREMIB_CONFIG) | |
| 553 free_config(); | |
| 554 | |
| 555 /* read all config file types */ | |
| 556 for(;ctmp != NULL; ctmp = ctmp->next) { | |
| 557 | |
| 558 ltmp = ctmp->start; | |
| 559 | |
| 560 /* read the config files */ | |
| 561 if ((envconfpath = getenv("SNMPCONFPATH")) == NULL) { | |
| 562 homepath=getenv("HOME"); | |
| 563 sprintf(defaultPath,"%s%c%s%c%s%s%s%s%c%s", | |
| 564 SNMPCONFPATH, ENV_SEPARATOR_CHAR, | |
| 565 SNMPSHAREPATH, ENV_SEPARATOR_CHAR, SNMPLIBPATH, | |
| 566 ((homepath == NULL) ? "" : ENV_SEPARATOR), | |
| 567 ((homepath == NULL) ? "" : homepath), | |
| 568 ((homepath == NULL) ? "" : "/.snmp"), | |
| 569 ENV_SEPARATOR_CHAR, PERSISTENT_DIRECTORY); | |
| 570 envconfpath = defaultPath; | |
| 571 } | |
| 572 envconfpath = strdup(envconfpath); /* prevent actually writing in env */ | |
| 573 DEBUGMSGTL(("read_config","config path used:%s\n", envconfpath)); | |
| 574 cptr1 = cptr2 = envconfpath; | |
| 575 i = 1; | |
| 576 while (i && *cptr2 != 0) { | |
| 577 while(*cptr1 != 0 && *cptr1 != ENV_SEPARATOR_CHAR) | |
| 578 cptr1++; | |
| 579 if (*cptr1 == 0) | |
| 580 i = 0; | |
| 581 else | |
| 582 *cptr1 = 0; | |
| 583 /* | |
| 584 * for proper persistent storage retrival, we need to read old backup | |
| 585 * copies of the previous storage files. If the application in | |
| 586 * question has died without the proper call to snmp_clean_persistent, | |
| 587 * then we read all the configuration files we can, starting with | |
| 588 * the oldest first. | |
| 589 */ | |
| 590 if (strncmp(cptr2, PERSISTENT_DIRECTORY, | |
| 591 strlen(PERSISTENT_DIRECTORY)) == 0 || | |
| 592 (getenv("SNMP_PERSISTENT_FILE") != NULL && | |
| 593 strncmp(cptr2, getenv("SNMP_PERSISTENT_FILE"), | |
| 594 strlen(getenv("SNMP_PERSISTENT_FILE"))) == 0)) { | |
| 595 /* limit this to the known storage directory only */ | |
| 596 for(j=0; j <= MAX_PERSISTENT_BACKUPS; j++) { | |
| 597 sprintf(configfile,"%s/%s.%d.conf",cptr2, ctmp->fileHeader, j); | |
| 598 if (stat(configfile, &statbuf) != 0) { | |
| 599 /* file not there, continue */ | |
| 600 break; | |
| 601 } else { | |
| 602 /* backup exists, read it */ | |
| 603 DEBUGMSGTL(("read_config_files","old config file found: %s, parsing\n", configfile)); | |
| 604 read_config (configfile, ltmp, when); | |
| 605 } | |
| 606 } | |
| 607 } | |
| 608 sprintf(configfile,"%s/%s.conf",cptr2, ctmp->fileHeader); | |
| 609 read_config (configfile, ltmp, when); | |
| 610 sprintf(configfile,"%s/%s.local.conf",cptr2, ctmp->fileHeader); | |
| 611 read_config (configfile, ltmp, when); | |
| 612 cptr2 = ++cptr1; | |
| 613 } | |
| 614 free(envconfpath); | |
| 615 } | |
| 616 | |
| 617 if (config_errors) { | |
| 618 snmp_log(LOG_ERR, "ucd-snmp: %d errors in config file\n", config_errors); | |
| 619 /* exit(1); */ | |
| 620 } | |
| 621 #endif | |
| 622 } | |
| 623 | |
| 624 void read_config_print_usage(const char *lead) | |
| 625 { | |
| 626 struct config_files *ctmp = config_files; | |
| 627 struct config_line *ltmp; | |
| 628 | |
| 629 if (lead == NULL) | |
| 630 lead = ""; | |
| 631 | |
| 632 for(ctmp = config_files; ctmp != NULL; ctmp = ctmp->next) { | |
| 633 snmp_log(LOG_INFO, "%sIn %s.conf and %s.local.conf:\n", lead, ctmp->fileHeader, | |
| 634 ctmp->fileHeader); | |
| 635 for(ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) { | |
| 636 if (ltmp->help != NULL) | |
| 637 snmp_log(LOG_INFO, "%s%s%-15s %s\n", lead, lead, ltmp->config_token, | |
| 638 ltmp->help); | |
| 639 } | |
| 640 } | |
| 641 } | |
| 642 | |
| 643 /*******************************************************************-o-****** | |
| 644 * read_config_store | |
| 645 * | |
| 646 * Parameters: | |
| 647 * *type | |
| 648 * *line | |
| 649 * | |
| 650 * | |
| 651 * Append line to a file named either ENV(SNMP_PERSISTENT_FILE) or | |
| 652 * "<PERSISTENT_DIRECTORY>/<type>.conf". | |
| 653 * Add a trailing newline to the stored file if necessary. | |
| 654 * | |
| 655 * Intended for use by applications to store permenant configuration | |
| 656 * information generated by sets or persistent counters. | |
| 657 * | |
| 658 */ | |
| 659 void | |
| 660 read_config_store(const char *type, const char *line) | |
| 661 { | |
| 662 #ifdef PERSISTENT_DIRECTORY | |
| 663 char file[512], *filep; | |
| 664 FILE *fout; | |
| 665 #ifdef PERSISTENT_MASK | |
| 666 mode_t oldmask; | |
| 667 #endif | |
| 668 | |
| 669 /* store configuration directives in the following order of preference: | |
| 670 1. ENV variable SNMP_PERSISTENT_FILE | |
| 671 2. configured <PERSISTENT_DIRECTORY>/<type>.conf | |
| 672 */ | |
| 673 if ((filep = getenv("SNMP_PERSISTENT_FILE")) == NULL) { | |
| 674 sprintf(file,"%s/%s.conf",PERSISTENT_DIRECTORY,type); | |
| 675 filep = file; | |
| 676 } | |
| 677 | |
| 678 #ifdef PERSISTENT_MASK | |
| 679 oldmask = umask(PERSISTENT_MASK); | |
| 680 #endif | |
| 681 if (mkdirhier(filep, AGENT_DIRECTORY_MODE, 1)) { | |
| 682 snmp_log(LOG_ERR, "Failed to create the persistent directory for %s\n", | |
| 683 file); | |
| 684 } | |
| 685 if ((fout = fopen(filep, "a")) != NULL) { | |
| 686 fprintf(fout,line); | |
| 687 if (line[strlen(line)] != '\n') | |
| 688 fprintf(fout,"\n"); | |
| 689 DEBUGMSGTL(("read_config","storing: %s\n",line)); | |
| 690 fclose(fout); | |
| 691 } else { | |
| 692 DEBUGMSGTL(("read_config","open failure")); | |
| 693 } | |
| 694 #ifdef PERSISTENT_MASK | |
| 695 umask(oldmask); | |
| 696 #endif | |
| 697 | |
| 698 #endif | |
| 699 } /* end read_config_store() */ | |
| 700 | |
| 701 void | |
| 702 read_app_config_store(const char *line) | |
| 703 { | |
| 704 read_config_store(ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE), line); | |
| 705 } | |
| 706 | |
| 707 | |
| 708 | |
| 709 | |
| 710 /*******************************************************************-o-****** | |
| 711 * snmp_save_persistent | |
| 712 * | |
| 713 * Parameters: | |
| 714 * *type | |
| 715 * | |
| 716 * | |
| 717 * Save the file "<PERSISTENT_DIRECTORY>/<type>.conf" into a backup copy | |
| 718 * called "<PERSISTENT_DIRECTORY>/<type>.%d.conf", which %d is an | |
| 719 * incrementing number on each call, but less than MAX_PERSISTENT_BACKUPS. | |
| 720 * | |
| 721 * Should be called just before all persistent information is supposed to be | |
| 722 * written to move aside the existing persistent cache. | |
| 723 * snmp_clean_persistent should then be called afterward all data has been | |
| 724 * saved to remove these backup files. | |
| 725 * | |
| 726 * Note: on an rename error, the files are removed rather than saved. | |
| 727 * | |
| 728 */ | |
| 729 void | |
| 730 snmp_save_persistent(const char *type) | |
| 731 { | |
| 732 #ifndef ECOSFIXME_NEEDFILESYSTEM | |
| 733 | |
| 734 char file[512], fileold[512]; | |
| 735 struct stat statbuf; | |
| 736 int j; | |
| 737 | |
| 738 DEBUGMSGTL(("snmp_save_persistent","saving %s files...\n", type)); | |
| 739 sprintf(file,"%s/%s.conf", PERSISTENT_DIRECTORY, type); | |
| 740 if (stat(file, &statbuf) == 0) { | |
| 741 for(j=0; j <= MAX_PERSISTENT_BACKUPS; j++) { | |
| 742 sprintf(fileold,"%s/%s.%d.conf", PERSISTENT_DIRECTORY, type, j); | |
| 743 if (stat(fileold, &statbuf) != 0) { | |
| 744 DEBUGMSGTL(("snmp_save_persistent"," saving old config file: %s -> %s.\n", file, fileold)); | |
| 745 if (rename(file, fileold)) { | |
| 746 unlink(file);/* moving it failed, try nuking it, as leaving | |
| 747 it around is very bad. */ | |
| 748 } | |
| 749 break; | |
| 750 } | |
| 751 } | |
| 752 } | |
| 753 #endif | |
| 754 } | |
| 755 | |
| 756 | |
| 757 /*******************************************************************-o-****** | |
| 758 * snmp_clean_persistent | |
| 759 * | |
| 760 * Parameters: | |
| 761 * *type | |
| 762 * | |
| 763 * | |
| 764 * Unlink all backup files called "<PERSISTENT_DIRECTORY>/<type>.%d.conf". | |
| 765 * | |
| 766 * Should be called just after we successfull dumped the last of the | |
| 767 * persistent data, to remove the backup copies of previous storage dumps. | |
| 768 * | |
| 769 * XXX Worth overwriting with random bytes first? This would | |
| 770 * ensure that the data is destroyed, even a buffer containing the | |
| 771 * data persists in memory or swap. Only important if secrets | |
| 772 * will be stored here. | |
| 773 */ | |
| 774 void | |
| 775 snmp_clean_persistent(const char *type) | |
| 776 { | |
| 777 #ifndef ECOSFIXME_NEEDFILESYSTEM | |
| 778 | |
| 779 char file[512]; | |
| 780 struct stat statbuf; | |
| 781 int j; | |
| 782 | |
| 783 DEBUGMSGTL(("snmp_clean_persistent","cleaning %s files...\n", type)); | |
| 784 sprintf(file,"%s/%s.conf",PERSISTENT_DIRECTORY,type); | |
| 785 if (stat(file, &statbuf) == 0) { | |
| 786 for(j=0; j <= MAX_PERSISTENT_BACKUPS; j++) { | |
| 787 sprintf(file,"%s/%s.%d.conf", PERSISTENT_DIRECTORY, type, j); | |
| 788 if (stat(file, &statbuf) == 0) { | |
| 789 DEBUGMSGTL(("snmp_clean_persistent"," removing old config file: %s\n", file)); | |
| 790 unlink(file); | |
| 791 } | |
| 792 } | |
| 793 } | |
| 794 #endif | |
| 795 } | |
| 796 | |
| 797 | |
| 798 | |
| 799 | |
| 800 /* config_perror: prints a warning string associated with a file and | |
| 801 line number of a .conf file and increments the error count. */ | |
| 802 void config_perror(const char *string) | |
| 803 { | |
| 804 config_pwarn(string); | |
| 805 config_errors++; | |
| 806 } | |
| 807 | |
| 808 void config_pwarn(const char *string) | |
| 809 { | |
| 810 snmp_log(LOG_WARNING, "%s: line %d: %s\n", curfilename, linecount, string); | |
| 811 } | |
| 812 | |
| 813 /* skip all white spaces and return 1 if found something either end of | |
| 814 line or a comment character */ | |
| 815 char *skip_white(char *ptr) | |
| 816 { | |
| 817 | |
| 818 if (ptr == NULL) return (NULL); | |
| 819 while (*ptr != 0 && isspace(*ptr)) ptr++; | |
| 820 if (*ptr == 0 || *ptr == '#') return (NULL); | |
| 821 return (ptr); | |
| 822 } | |
| 823 | |
| 824 char *skip_not_white(char *ptr) | |
| 825 { | |
| 826 | |
| 827 if (ptr == NULL) return (NULL); | |
| 828 while (*ptr != 0 && !isspace(*ptr)) ptr++; | |
| 829 if (*ptr == 0 || *ptr == '#') return (NULL); | |
| 830 return (ptr); | |
| 831 } | |
| 832 | |
| 833 char *skip_token(char *ptr) | |
| 834 { | |
| 835 ptr = skip_white(ptr); | |
| 836 ptr = skip_not_white(ptr); | |
| 837 ptr = skip_white(ptr); | |
| 838 return (ptr); | |
| 839 } | |
| 840 | |
| 841 /* copy_word | |
| 842 copies the next 'token' from 'from' into 'to'. | |
| 843 currently a token is anything seperate by white space | |
| 844 or within quotes (double or single) (i.e. "the red rose" | |
| 845 is one token, \"the red rose\" is three tokens) | |
| 846 a '\' character will allow a quote character to be treated | |
| 847 as a regular character | |
| 848 It returns a pointer to first non-white space after the end of the token | |
| 849 being copied or to 0 if we reach the end.*/ | |
| 850 | |
| 851 char *copy_word(char *from, char *to) | |
| 852 { | |
| 853 char quote; | |
| 854 if ( (*from == '\"') || (*from =='\'') ){ | |
| 855 quote = *(from++); | |
| 856 while ( (*from != quote) && (*from != 0) ) { | |
| 857 if ((*from == '\\') && (*(from+1) != 0)) { | |
| 858 *to++ = *(from+1); | |
| 859 from = from +2; | |
| 860 } | |
| 861 else *to++ = *from++; | |
| 862 } | |
| 863 if (*from == 0) { | |
| 864 DEBUGMSGTL(("read_config_copy_word", | |
| 865 "no end quote found in config string\n")); | |
| 866 } else from++; | |
| 867 } | |
| 868 else { | |
| 869 while (*from != 0 && !isspace(*from)) { | |
| 870 if ((*from == '\\') && (*(from+1) != 0)) { | |
| 871 *to++ = *(from+1); | |
| 872 from = from +2; | |
| 873 } | |
| 874 else *to++ = *from++; | |
| 875 } | |
| 876 } | |
| 877 *to = 0; | |
| 878 from = skip_white(from); | |
| 879 return(from); | |
| 880 } /* copy_word */ | |
| 881 | |
| 882 /* read_config_save_octet_string(): saves an octet string as a length | |
| 883 followed by a string of hex */ | |
| 884 char *read_config_save_octet_string(char *saveto, u_char *str, size_t len) { | |
| 885 int i; | |
| 886 if (str != NULL) { | |
| 887 sprintf(saveto, "0x"); | |
| 888 saveto += 2; | |
| 889 for(i = 0; i < (int)len; i++) { | |
| 890 sprintf(saveto,"%02x", str[i]); | |
| 891 saveto = saveto + 2; | |
| 892 } | |
| 893 return saveto; | |
| 894 } else { | |
| 895 sprintf(saveto,"\"\""); | |
| 896 saveto += 2; | |
| 897 } | |
| 898 return saveto; | |
| 899 } | |
| 900 | |
| 901 /* read_config_read_octet_string(): reads an octet string that was | |
| 902 saved by the read_config_save_octet_string() function */ | |
| 903 char *read_config_read_octet_string(char *readfrom, u_char **str, size_t *len) { | |
| 904 u_char *cptr=NULL; | |
| 905 char *cptr1; | |
| 906 u_int tmp; | |
| 907 int i; | |
| 908 | |
| 909 if (readfrom == NULL || str == NULL) | |
| 910 return NULL; | |
| 911 | |
| 912 if (strncasecmp(readfrom,"0x",2) == 0) { | |
| 913 /* A hex string submitted. How long? */ | |
| 914 readfrom += 2; | |
| 915 cptr1 = skip_not_white(readfrom); | |
| 916 if (cptr1) | |
| 917 *len = (cptr1 - readfrom); | |
| 918 else | |
| 919 *len = strlen(readfrom); | |
| 920 | |
| 921 if (*len % 2) { | |
| 922 DEBUGMSGTL(("read_config_read_octet_string","invalid hex string: wrong length")); | |
| 923 return NULL; | |
| 924 } | |
| 925 *len = *len / 2; | |
| 926 | |
| 927 /* malloc data space if needed */ | |
| 928 if (*str == NULL) { | |
| 929 if (*len == 0) { | |
| 930 /* null length string found */ | |
| 931 cptr = NULL; | |
| 932 | |
| 933 } else if (*len > 0 && (str == NULL || (cptr = (u_char *)malloc(*len)) == NULL)) { | |
| 934 return NULL; | |
| 935 } | |
| 936 *str = cptr; | |
| 937 } else { | |
| 938 cptr = *str; | |
| 939 } | |
| 940 | |
| 941 /* copy data */ | |
| 942 for(i = 0; i < (int)*len; i++) { | |
| 943 sscanf(readfrom,"%2x",&tmp); | |
| 944 *cptr++ = (u_char) tmp; | |
| 945 readfrom += 2; | |
| 946 } | |
| 947 readfrom = skip_white(readfrom); | |
| 948 } else { | |
| 949 /* Normal string */ | |
| 950 | |
| 951 /* malloc data space if needed */ | |
| 952 if (*str == NULL) { | |
| 953 char buf[SNMP_MAXBUF]; | |
| 954 readfrom = copy_word(readfrom, buf); | |
| 955 | |
| 956 *len = strlen(buf); | |
| 957 /* malloc an extra space to add a null */ | |
| 958 if (*len > 0 && (str == NULL || | |
| 959 (cptr = (u_char *) malloc(*len + 1)) | |
| 960 == NULL)) | |
| 961 return NULL; | |
| 962 *str = cptr; | |
| 963 if (cptr) | |
| 964 memcpy(cptr, buf, (*len+1)); | |
| 965 } else { | |
| 966 readfrom = copy_word(readfrom, (char *)*str); | |
| 967 } | |
| 968 } | |
| 969 | |
| 970 return readfrom; | |
| 971 } | |
| 972 | |
| 973 | |
| 974 /* read_config_save_objid(): saves an objid as a numerical string */ | |
| 975 char *read_config_save_objid(char *saveto, oid *objid, size_t len) { | |
| 976 int i; | |
| 977 | |
| 978 if (len == 0) { | |
| 979 strcat(saveto, "NULL"); | |
| 980 saveto += strlen(saveto); | |
| 981 return saveto; | |
| 982 } | |
| 983 | |
| 984 /* in case len=0, this makes it easier to read it back in */ | |
| 985 for(i=0; i < (int)len; i++) { | |
| 986 sprintf(saveto,".%ld", objid[i]); | |
| 987 saveto += strlen(saveto); | |
| 988 } | |
| 989 return saveto; | |
| 990 } | |
| 991 | |
| 992 /* read_config_read_objid(): reads an objid from a format saved by the above */ | |
| 993 char *read_config_read_objid(char *readfrom, oid **objid, size_t *len) { | |
| 994 | |
| 995 if (objid == NULL || readfrom == NULL) | |
| 996 return NULL; | |
| 997 | |
| 998 if (*objid != NULL) { | |
| 999 char buf[SPRINT_MAX_LEN]; | |
| 1000 | |
| 1001 if (strncmp(readfrom,"NULL",4) == 0) { | |
| 1002 /* null length oid */ | |
| 1003 *len = 0; | |
| 1004 } else { | |
| 1005 /* read_objid is touchy with trailing stuff */ | |
| 1006 copy_word(readfrom, buf); | |
| 1007 | |
| 1008 /* read the oid into the buffer passed to us */ | |
| 1009 if (!read_objid(buf, *objid, len)) { | |
| 1010 DEBUGMSGTL(("read_config_read_objid","Invalid OID")); | |
| 1011 return NULL; | |
| 1012 } | |
| 1013 } | |
| 1014 | |
| 1015 readfrom = skip_token(readfrom); | |
| 1016 } else { | |
| 1017 if (strncmp(readfrom,"NULL",4) == 0) { | |
| 1018 /* null length oid */ | |
| 1019 *len = 0; | |
| 1020 readfrom = skip_token(readfrom); | |
| 1021 } else { | |
| 1022 /* space needs to be malloced. Call ourself recursively to figure | |
| 1023 out how long the oid actually is */ | |
| 1024 oid obuf[MAX_OID_LEN]; | |
| 1025 size_t obuflen = MAX_OID_LEN; | |
| 1026 oid *oidp = obuf; | |
| 1027 oid **oidpp = &oidp; /* done this way for odd, untrue, gcc warnings */ | |
| 1028 | |
| 1029 readfrom = read_config_read_objid(readfrom, oidpp, &obuflen); | |
| 1030 | |
| 1031 /* Then malloc and copy the results */ | |
| 1032 *len = obuflen; | |
| 1033 if (*len > 0 && (*objid = (oid*)malloc(*len * sizeof(oid))) == NULL) | |
| 1034 return NULL; | |
| 1035 | |
| 1036 if (obuflen > 0) | |
| 1037 memcpy(*objid, obuf, obuflen*sizeof(oid)); | |
| 1038 } | |
| 1039 } | |
| 1040 return readfrom; | |
| 1041 } | |
| 1042 | |
| 1043 /* read_config_read_data(): | |
| 1044 reads data of a given type from a token(s) on a configuration line. | |
| 1045 | |
| 1046 Returns: character pointer to the next token in the configuration line. | |
| 1047 NULL if none left. | |
| 1048 NULL if an unknown type. | |
| 1049 */ | |
| 1050 char *read_config_read_data(int type, char *readfrom, void *dataptr, size_t *len) { | |
| 1051 | |
| 1052 int *intp; | |
| 1053 char **charpp; | |
| 1054 oid **oidpp; | |
| 1055 | |
| 1056 if (dataptr == NULL || readfrom == NULL) | |
| 1057 return NULL; | |
| 1058 | |
| 1059 switch(type) { | |
| 1060 case ASN_INTEGER: | |
| 1061 intp = (int *) dataptr; | |
| 1062 *intp = atoi(readfrom); | |
| 1063 readfrom = skip_token(readfrom); | |
| 1064 return readfrom; | |
| 1065 | |
| 1066 case ASN_OCTET_STR: | |
| 1067 charpp = (char **) dataptr; | |
| 1068 return read_config_read_octet_string(readfrom, (u_char **) charpp, len); | |
| 1069 | |
| 1070 case ASN_OBJECT_ID: | |
| 1071 oidpp = (oid **) dataptr; | |
| 1072 return read_config_read_objid(readfrom, oidpp, len); | |
| 1073 | |
| 1074 default: | |
| 1075 DEBUGMSGTL(("read_config_read_data","Fail: Unknown type: %d", type)); | |
| 1076 return NULL; | |
| 1077 } | |
| 1078 return NULL; | |
| 1079 } | |
| 1080 | |
| 1081 /* read_config_read_data(): | |
| 1082 reads data of a given type from a token(s) on a configuration line. | |
| 1083 | |
| 1084 Returns: character pointer to the next token in the configuration line. | |
| 1085 NULL if none left. | |
| 1086 NULL if an unknown type. | |
| 1087 */ | |
| 1088 char *read_config_store_data(int type, char *storeto, void *dataptr, size_t *len) { | |
| 1089 | |
| 1090 int *intp; | |
| 1091 u_char **charpp; | |
| 1092 oid **oidpp; | |
| 1093 | |
| 1094 if (dataptr == NULL || storeto == NULL) | |
| 1095 return NULL; | |
| 1096 | |
| 1097 switch(type) { | |
| 1098 case ASN_INTEGER: | |
| 1099 intp = (int *) dataptr; | |
| 1100 sprintf(storeto," %d", *intp); | |
| 1101 return (storeto + strlen(storeto)); | |
| 1102 | |
| 1103 case ASN_OCTET_STR: | |
| 1104 charpp = (u_char **) dataptr; | |
| 1105 return read_config_save_octet_string(storeto, *charpp, *len); | |
| 1106 | |
| 1107 case ASN_OBJECT_ID: | |
| 1108 oidpp = (oid **) dataptr; | |
| 1109 return read_config_save_objid(storeto, *oidpp, *len); | |
| 1110 | |
| 1111 default: | |
| 1112 DEBUGMSGTL(("read_config_store_data","Fail: Unknown type: %d", type)); | |
| 1113 return NULL; | |
| 1114 } | |
| 1115 return NULL; | |
| 1116 } |
