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