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 }