1 /*===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================
24  *
25  */
26 
27 #include <kfg/kfg-priv.h>
28 #include "kfg-priv.h"
29 
30 struct KfgConfigNamelist;
31 #define KNAMELIST_IMPL struct KfgConfigNamelist
32 #include <klib/namelist.h>
33 #include <klib/impl.h>
34 
35 #include <klib/container.h>
36 #include <klib/data-buffer.h> /* KDataBuffer */
37 #include <klib/debug.h>
38 #include <klib/log.h>
39 #include <klib/out.h> /* OUTMSG */
40 #include <klib/printf.h>
41 #include <klib/rc.h>
42 #include <klib/refcount.h>
43 #include <klib/text.h>
44 #include <klib/token.h>
45 #include <klib/klib-priv.h>
46 
47 #include <kfs/directory.h>
48 #include <kfs/gzip.h> /* KFileMakeGzipForRead */
49 #include <kfs/subfile.h> /* KFileMakeSubRead */
50 #include <kfs/file.h>
51 #include <kfs/dyload.h>
52 #include <kfs/mmap.h>
53 #include <vfs/path.h>
54 #include <strtol.h>
55 #include <sysalloc.h>
56 
57 #include <string.h>
58 #include <ctype.h>
59 #include <os-native.h>
60 #include <stdlib.h>
61 #include <assert.h>
62 #include <va_copy.h>
63 
64 #if !WINDOWS
65     #include <sys/utsname.h>
66 #endif
67 
68 #include "default_kfg.h" /* DEFAUTL_KFG */
69 
70 #include "kfg-parse.h"
71 #include "config-tokens.h"
72 
73 #include "../vfs/resolver-cgi.h" /* RESOLVER_CGI */
74 #include "docker.h"
75 
76 #ifndef PATH_MAX
77 #define PATH_MAX 4096
78 #endif
79 
80 /* the leaf name of the user's modifiable settings,
81    must reside in the user's $HOME/.ncbi directory */
82 #define MAGIC_LEAF_NAME "user-settings.mkfg"
83 
84 static bool s_disable_user_settings = false;
85 
86 static const char * s_ngc_file = NULL;
87 
88 static const char default_kfg[] = { DEFAUTL_KFG };
89 
90 /*--------------------------------------------------------------------------
91  * KConfig
92  */
93 static
94 rc_t KConfigSever ( const KConfig *self );
95 
96 
97 /*--------------------------------------------------------------------------
98  * KConfigIncluded
99  *  node within configuration tree
100  */
101 
102 typedef struct KConfigIncluded KConfigIncluded;
103 struct KConfigIncluded
104 {
105     BSTNode n;
106     bool is_magic_file;
107     char path [ 1 ];
108 };
109 
110 
111 static
KConfigIncludedWhack(BSTNode * n,void * ignore)112 void CC KConfigIncludedWhack ( BSTNode *n, void *ignore )
113 {
114     free ( n );
115 }
116 
117 static
KConfigIncludedSort(const BSTNode * item,const BSTNode * n)118 int64_t CC KConfigIncludedSort ( const BSTNode *item, const BSTNode *n )
119 {
120     const KConfigIncluded *a = ( const KConfigIncluded* ) item;
121     const KConfigIncluded *b = ( const KConfigIncluded* ) n;
122     return strcmp ( a -> path, b -> path );
123 }
124 
125 enum {
126     eInternalFalse = false, /* internal = false: non internal nodes */
127     eInternalTrue  = true,  /* internal = true ; internal nodes: read-only */
128     eInternalTrueUpdatable
129                        /* internal = true ; internal nodes, but can be updated :
130                                             "kfg/dir", "kfg/name" */
131 } EInternal;
132 typedef uint32_t TInternal;
133 
134 /*--------------------------------------------------------------------------
135  * KConfigNode
136  *  node within configuration tree
137  */
138 struct KConfigNode
139 {
140     BSTNode n;
141 
142     /* needs to hold a dependency reference to mgr */
143     KConfig *mgr;
144 
145     /* uncounted reference to parent node */
146     KConfigNode *dad;
147 
148     /* File node came from; null if created during runtime*/
149     KConfigIncluded *came_from;
150 
151     /* named children - always unique */
152     BSTree children;
153 
154     /* named attributes */
155     BSTree attr;
156 
157     /* node value */
158     char * val_buffer;
159     String value;
160 
161     /* node name */
162     String name;
163 
164     KRefcount refcount;
165 
166     TInternal internal; /* EInternal */
167     bool read_only;
168     bool dirty;
169 };
170 
171 /* replace this once we introduce attributes */
172 #define KConfigAttrWhack NULL
173 
174 
175 /* Whack
176  */
177 static
KConfigNodeWhack(BSTNode * n,void * data)178 void CC KConfigNodeWhack ( BSTNode *n, void * data )
179 {
180     KConfigNode *self = ( KConfigNode* ) n;
181     KConfig *mgr = data;
182 
183     if ( mgr == NULL )
184     {
185         /* just releasing reference */
186         KConfigSever ( self -> mgr );
187         self -> mgr = NULL;
188         self -> read_only = false;
189     }
190     else
191     {
192         /* tearing down structure */
193         BSTreeWhack ( & self -> children, KConfigNodeWhack, mgr );
194         BSTreeWhack ( & self -> attr, KConfigAttrWhack, mgr );
195         free ( self -> val_buffer );
196         free ( self );
197     }
198 }
199 
200 /* Init
201  */
202 static
KConfigNodeInit(KConfigNode * self,const String * name)203 void KConfigNodeInit ( KConfigNode *self, const String *name )
204 {
205     /* clear out here, ignoring the string space */
206     memset ( self, 0, sizeof * self );
207 
208     /* initialize name early for the sake of KRefcountInit */
209     string_copy ( ( char* ) ( self + 1 ), name -> size + 1, name -> addr, name -> size );
210     StringInit ( & self -> name, ( char* ) ( self + 1 ), name -> size, name -> len );
211     StringInit ( & self -> value, "", 0, 0 );
212     KRefcountInit ( & self -> refcount, 0, "KConfigNode", "init", self -> name . addr );
213 }
214 
215 /* Make
216  */
217 static
KConfigNodeMake(KConfigNode ** n,const String * name)218 rc_t KConfigNodeMake ( KConfigNode **n, const String *name )
219 {
220     /* don't use calloc, because of string space */
221     KConfigNode *cn = malloc ( sizeof * cn + name -> size + 1 );
222     if ( cn == NULL )
223     {
224         rc_t rc = RC ( rcKFG, rcNode, rcCreating, rcMemory, rcExhausted );
225         PLOGERR (klogErr, (klogErr, rc, "Unable to create a config item for $(i)", "i=%S", name));
226         return rc;
227     }
228     KConfigNodeInit ( cn, name );
229     * n = cn;
230 
231     return 0;
232 }
233 
234 
235 /* Cmp
236  * Sort
237  */
238 static
KConfigNodeCmp(const void * item,const BSTNode * n)239 int64_t CC KConfigNodeCmp ( const void *item, const BSTNode *n )
240 {
241     const String *a = ( const String* ) item;
242     const KConfigNode *b = ( const KConfigNode* ) n;
243     return StringCompare ( a, & b -> name );
244 }
245 
246 static
KConfigNodeSort(const BSTNode * item,const BSTNode * n)247 int64_t CC KConfigNodeSort ( const BSTNode *item, const BSTNode *n )
248 {
249     const KConfigNode *a = ( const KConfigNode* ) item;
250     const KConfigNode *b = ( const KConfigNode* ) n;
251     return StringCompare ( & a -> name, & b -> name );
252 }
253 
254 
255 /* AddRef
256  * Release
257  *  all objects are reference counted
258  *  NULL references are ignored
259  */
KConfigNodeAddRef(const KConfigNode * self)260 LIB_EXPORT rc_t CC KConfigNodeAddRef ( const KConfigNode *self )
261 {
262     if ( self != NULL )
263     {
264         switch ( KRefcountAdd ( & self -> refcount, "KConfigNode" ) )
265         {
266         case krefLimit:
267             return RC ( rcKFG, rcNode, rcAttaching, rcRange, rcExcessive );
268         }
269     }
270     return 0;
271 }
272 
KConfigNodeRelease(const KConfigNode * self)273 LIB_EXPORT rc_t CC KConfigNodeRelease ( const KConfigNode *self )
274 {
275     if ( self != NULL )
276     {
277         switch ( KRefcountDrop ( & self -> refcount, "KConfigNode" ) )
278         {
279         case krefWhack:
280             KConfigNodeWhack ( & ( ( KConfigNode* ) self ) -> n, NULL );
281         break;
282         case krefNegative:
283             return RC ( rcKFG, rcNode, rcReleasing, rcRange, rcExcessive );
284         }
285     }
286     return 0;
287 }
288 
289 
290 /*--------------------------------------------------------------------------
291  * KConfig
292  *  configuration parameter manager
293  */
294 struct KConfig
295 {
296     BSTree tree;
297     BSTree included;
298     KDualRef refcount;
299     KConfigIncluded *current_file;
300 
301     char * load_path;
302     size_t load_path_sz_tmp;
303 
304     const char *magic_file_path;
305     size_t magic_file_path_size;
306 
307     bool disableFileLoadOnKfgCreating;
308 
309     bool dirty;
310     bool initialized;
311 };
312 
313 static atomic_ptr_t G_kfg;
314 
KConfigAppendToLoadPath(KConfig * self,const char * chunk)315 rc_t KConfigAppendToLoadPath(KConfig *self, const char* chunk)
316 {
317     rc_t rc = 0;
318     size_t new_sz = 0;
319 
320     assert(self);
321 
322     if (chunk == NULL || chunk[0] == '\0') {
323         return rc;
324     }
325 
326     if (self->load_path == NULL) {
327         self->load_path_sz_tmp = PATH_MAX;
328         self->load_path = malloc(self->load_path_sz_tmp);
329         if (self->load_path == NULL) {
330             return RC ( rcKFG, rcMgr, rcCreating, rcMemory, rcExhausted );
331         }
332         self->load_path[0] = '\0';
333     }
334 
335     new_sz = string_size(self->load_path) + 1 + string_size(chunk) + 1;
336     if (self->load_path_sz_tmp < new_sz) {
337         self->load_path_sz_tmp = 2 * new_sz;
338         self->load_path = realloc(self->load_path, self->load_path_sz_tmp);
339         if (self->load_path == NULL) {
340             return RC ( rcKFG, rcMgr, rcCreating, rcMemory, rcExhausted );
341         }
342     }
343 
344     if (self->load_path[0] != '\0') {
345         strcat(self->load_path, ":");
346     }
347     strcat(self->load_path, chunk);
348 
349     return rc;
350 }
351 
352 
353 /* Whack
354  */
355 static
KConfigEmpty(KConfig * self)356 rc_t KConfigEmpty ( KConfig * self)
357 {
358     if (self)
359     {
360         BSTreeWhack ( & self -> tree, KConfigNodeWhack, self );
361         BSTreeWhack ( & self -> included, KConfigIncludedWhack, NULL );
362 
363         self -> magic_file_path_size = 0;
364         free ( ( void* ) self -> magic_file_path );
365         self -> magic_file_path = NULL;
366 
367         self->load_path_sz_tmp = 0;
368         free ( self->load_path );
369         self->load_path = NULL;
370     }
371     return 0;
372 }
373 
374 static
find_home_directory(KDyld * dyld,const KDirectory ** dir,bool release_cached_dir)375 rc_t find_home_directory ( KDyld *dyld,
376     const KDirectory **dir, bool release_cached_dir )
377 {
378     static const KDirectory * cached_dir = NULL;
379     static rc_t cached_rc = 0;
380     rc_t rc;
381 
382     if (release_cached_dir) {
383         rc = KDirectoryRelease(cached_dir);
384         cached_dir = NULL;
385         cached_rc = 0;
386         return rc;
387     }
388     else if ( cached_dir != NULL )
389     {
390         rc = KDirectoryAddRef ( cached_dir );
391         if ( rc == 0 ) {
392             * dir = cached_dir;
393         }
394         return rc;
395     }
396     else if ( cached_rc != 0 )
397     {
398         return cached_rc;
399     }
400 
401     rc = KDyldHomeDirectory ( dyld, dir, ( fptr_t ) KConfigMake );
402     if ( rc == 0  &&  KDirectoryAddRef ( * dir ) == 0 )
403     {
404         cached_dir = * dir;
405     }
406     else
407     {
408         cached_rc = rc;
409     }
410 
411     return rc;
412 }
413 
414 static
KConfigWhack(KConfig * self)415 rc_t KConfigWhack ( KConfig *self )
416 {
417     bool release_cached_dir = true;
418     find_home_directory(NULL, NULL, release_cached_dir);
419 
420     if ( self == G_kfg.ptr )
421         atomic_test_and_set_ptr ( & G_kfg, NULL, self );
422 
423     KConfigEmpty (self);
424 
425     free ( self );
426 
427     return 0;
428 }
429 
430 /* Init
431  */
432 static
KConfigInit(KConfig * self,KConfigNode * root)433 void KConfigInit ( KConfig *self, KConfigNode * root )
434 {
435     KDualRefInit ( & self -> refcount, 1, 0, "KConfig", "init", "kfg" );
436     BSTreeInit ( & self -> tree );
437     self -> dirty = false;
438     self -> initialized = false;
439     BSTreeInit ( & self -> included );
440     BSTreeInsert ( & self -> tree, & root -> n, KConfigNodeSort );
441     self -> magic_file_path = NULL;
442 }
443 
444 
445 /* AddRef
446  * Release
447  */
KConfigAddRef(const KConfig * self)448 LIB_EXPORT rc_t CC KConfigAddRef ( const KConfig *self )
449 {
450     if ( self != NULL )
451     {
452         switch ( KDualRefAdd ( & self -> refcount, "KConfig" ) )
453         {
454         case krefLimit:
455             return RC ( rcKFG, rcMgr, rcAttaching, rcRange, rcExcessive );
456         }
457     }
458     return 0;
459 }
460 
KConfigRelease(const KConfig * self)461 LIB_EXPORT rc_t CC KConfigRelease ( const KConfig *self )
462 {
463     if ( self != NULL )
464     {
465         switch ( KDualRefDrop ( & self -> refcount, "KConfig" ) )
466         {
467         case krefWhack:
468             return KConfigWhack ( ( KConfig* ) self );
469         case krefLimit:
470             return RC ( rcKFG, rcMgr, rcReleasing, rcRange, rcExcessive );
471         }
472     }
473     return 0;
474 }
475 
476 static
KConfigAttach(const KConfig * self)477 KConfig *KConfigAttach ( const KConfig *self )
478 {
479     if ( self != NULL )
480     {
481         switch ( KDualRefAddDep ( & self -> refcount, "KConfig" ) )
482         {
483         case krefLimit:
484             return NULL;
485         }
486     }
487     return ( KConfig* ) self;
488 }
489 
490 static
KConfigSever(const KConfig * self)491 rc_t KConfigSever ( const KConfig *self )
492 {
493     if ( self != NULL )
494     {
495         switch ( KDualRefDropDep ( & self -> refcount, "KConfig" ) )
496         {
497         case krefWhack:
498             return KConfigWhack ( ( KConfig* ) self );
499         case krefLimit:
500             return RC ( rcKFG, rcMgr, rcReleasing, rcRange, rcExcessive );
501         }
502     }
503     return 0;
504 }
505 
506 
507 /* init_token_source
508  */
509 static
init_token_source(KTokenText * tt,KTokenSource * src,char * full,size_t fsize,const char * srcpath,const char * path,va_list args)510 rc_t init_token_source ( KTokenText *tt, KTokenSource *src,
511                          char *full, size_t fsize, const char *srcpath, const char *path, va_list args )
512 {
513     size_t num_writ;
514     rc_t rc = 0;
515 
516     /* VDB-4386: cannot treat va_list as a pointer! */
517 /*-    if (args == NULL)
518         num_writ = string_copy ( full, fsize, path, string_size ( path ));
519     else*/
520     if ( path != NULL )
521         rc = string_vprintf ( full, fsize, & num_writ, path, args );
522     if ( rc == 0 )
523     {
524         String text, fpath;
525         StringInit ( & text, full, num_writ, string_len ( full, num_writ ) );
526         StringInitCString ( & fpath, srcpath );
527         KTokenTextInit ( tt, & text, & fpath );
528         KTokenSourceInit ( src, tt );
529     }
530     return rc;
531 }
532 
533 /* Find
534  */
535 static
KConfigNodeFind(const KConfigNode * self,const KConfigNode ** n,KTokenSource * src,KToken * t)536 KToken *KConfigNodeFind ( const KConfigNode *self, const KConfigNode **n, KTokenSource *src, KToken *t )
537 {
538     * n = NULL;
539 
540     while ( t -> id != eEndOfInput )
541     {
542         switch ( t -> id )
543         {
544         case ePeriod:
545             break;
546         case eDblPeriod:
547             if ( self -> dad == NULL )
548                 return NULL;
549             self = self -> dad;
550             break;
551         case eDecimal:
552         case eHex:
553         case eOctal:
554         case eIdent:
555         case eName:
556             self = ( const KConfigNode* ) BSTreeFind
557                 ( & self -> children, &t -> str, KConfigNodeCmp );
558             if ( self == NULL )
559                 return t;
560             break;
561         default:
562             * n = self;
563             return t;
564         }
565 
566         if ( KTokenizerNext ( kPOSIXPathTokenizer, src, t ) -> id != eFwdSlash )
567             break;
568 
569         KTokenizerNext ( kPOSIXPathTokenizer, src, t );
570     }
571 
572     * n = self;
573     return t;
574 }
575 
576 /* Create
577  */
578 static
KConfigNodeCreate(KConfigNode * self,KConfigNode ** n,KTokenSource * src,KToken * t,KConfigIncluded * current_file)579 KToken *KConfigNodeCreate ( KConfigNode *self, KConfigNode **n, KTokenSource *src, KToken *t,
580                             KConfigIncluded *current_file )
581 {
582     bool created = false;
583     KConfigNode * nself;
584     * n = NULL;
585 
586     while ( t -> id != eEndOfInput )
587     {
588         switch ( t -> id )
589         {
590         case ePeriod:
591             break;
592         case eDblPeriod:
593             if ( self -> dad == NULL )
594                 return NULL;
595             self = self -> dad;
596             break;
597         case eDecimal:
598         case eHex:
599         case eOctal:
600         case eName:
601         case eIdent:
602             nself = ( KConfigNode* ) BSTreeFind
603                 ( & self -> children, & t -> str, KConfigNodeCmp );
604             if ( nself == NULL )
605             {
606                 KConfigNode *child;
607                 rc_t rc = KConfigNodeMake ( & child, & t -> str );
608                 if ( rc != 0 )
609                     return t;
610                 BSTreeInsert ( & self -> children, & child -> n, KConfigNodeSort );
611                 child -> dad = self;
612                 self = child;
613                 created = true;
614             }
615             else
616             {
617                 self = nself;
618             }
619             break;
620         default:
621             * n = self;
622             return t;
623         }
624 
625         if ( KTokenizerNext ( kPOSIXPathTokenizer, src, t ) -> id != eFwdSlash )
626             break;
627 
628         KTokenizerNext ( kPOSIXPathTokenizer, src, t );
629     }
630 
631     if ( created )
632         self -> came_from = current_file;
633 
634     * n = self;
635     return t;
636 }
637 
638 
639 /* OpenNodeRead
640  * VOpenNodeRead
641  *  opens a configuration node
642  *
643  *  "node" [ OUT ] - return parameter for indicated configuration node
644  *
645  *  "path" [ IN, NULL OKAY ] - optional path for specifying named
646  *  node within configuration hierarchy. paths will be interpreted as
647  *  if they were file system paths, using '/' as separator. the
648  *  special values NULL and "" are interpreted as "."
649  */
650 static
KConfigNodeVOpenNodeReadInt(const KConfigNode * self,const KConfig * mgr,const KConfigNode ** node,const char * path,va_list args)651 rc_t KConfigNodeVOpenNodeReadInt ( const KConfigNode *self, const KConfig *mgr,
652                                    const KConfigNode **node, const char *path, va_list args )
653 {
654     rc_t rc;
655 
656     if ( node == NULL )
657     {
658         rc = RC ( rcKFG, rcNode, rcOpening, rcParam, rcNull );
659         PLOGERR (klogErr, (klogErr, rc, "faile to provide node to open $(n)", "n=%s", path));
660     }
661     else
662     {
663         if ( self == NULL )
664         {
665             rc = RC ( rcKFG, rcNode, rcOpening, rcSelf, rcNull );
666             PLOGERR (klogErr, (klogErr, rc, "failed to provide node reference for opening $(n)", "n=%s", path));
667         }
668         else
669         {
670             if ( path == NULL || path [ 0 ] == 0 )
671             {
672                 * node = self;
673                 rc = 0;
674             }
675             else
676             {
677                 KTokenText tt;
678                 KTokenSource src;
679                 char full [ 4096 ];
680 
681                 rc = init_token_source ( & tt, & src, full, sizeof full, "", path, args );
682                 if ( rc == 0 )
683                 {
684                     /* look ahead */
685                     KToken t;
686 
687                     /* skip over fwd slashes */
688                     do
689                         KTokenizerNext ( kPOSIXPathTokenizer, & src, & t );
690                     while ( t.id == eFwdSlash );
691 
692                     /* follow path */
693                     if ( KConfigNodeFind ( self, node, & src, & t ) == NULL )
694                     {
695                         rc = RC ( rcKFG, rcNode, rcOpening, rcPath, rcInvalid );
696                         PLOGERR (klogErr, (klogErr, rc, "bad path $(p)", "p=%s", path));
697                     }
698                     if ( ( self = * node ) == NULL )
699                     {
700                         rc = SILENT_RC ( rcKFG, rcNode, rcOpening, rcPath, rcNotFound );
701                         /* don't complain about this
702                            PLOGERR (klogErr, (klogErr, rc, "can't find symbol $(p)", "p=%s", path));
703                         */
704                     }
705                     else if ( t . id != eEndOfInput )
706                     {
707                         rc = RC ( rcKFG, rcNode, rcOpening, rcPath, rcInvalid );
708                         PLOGERR (klogErr, (klogErr, rc, "bad path $(p)", "p=%s", path));
709                     }
710                 }
711             }
712 
713             if ( rc == 0 )
714             {
715                 /* open node for read */
716                 if ( self -> read_only )
717                 {
718                     assert ( self -> mgr == mgr );
719                     return KConfigNodeAddRef ( self );
720                 }
721 
722                 /* check to see if already open */
723                 if ( atomic32_read ( & self -> refcount ) == 0 )
724                 {
725                     ( ( KConfigNode* ) self ) -> mgr = KConfigAttach ( mgr );
726                     ( ( KConfigNode* ) self ) -> read_only = true;
727                     return KConfigNodeAddRef ( self );
728                 }
729 
730                 rc = RC ( rcKFG, rcNode, rcOpening, rcNode, rcBusy );
731             }
732         }
733 
734         * node = NULL;
735     }
736 
737     return rc;
738 }
739 
740 
KConfigNodeGetMgr(const KConfigNode * self,KConfig ** mgr)741 LIB_EXPORT rc_t CC KConfigNodeGetMgr( const KConfigNode * self, KConfig ** mgr )
742 {
743     if ( self == NULL )
744         return RC ( rcKFG, rcNode, rcOpening, rcSelf, rcNull );
745     if ( mgr == NULL )
746         return RC ( rcKFG, rcNode, rcOpening, rcParam, rcNull );
747     *mgr = self->mgr;
748     return KConfigAddRef ( *mgr );
749 }
750 
751 
KConfigNodeVOpenNodeRead(const KConfigNode * self,const KConfigNode ** node,const char * path,va_list args)752 LIB_EXPORT rc_t CC KConfigNodeVOpenNodeRead ( const KConfigNode *self,
753                                               const KConfigNode **node, const char *path, va_list args )
754 {
755     if ( self != NULL )
756         return KConfigNodeVOpenNodeReadInt ( self, self -> mgr, node, path, args );
757 
758     if ( node == NULL )
759         return RC ( rcKFG, rcNode, rcOpening, rcParam, rcNull );
760 
761     * node = NULL;
762     return RC ( rcKFG, rcNode, rcOpening, rcSelf, rcNull );
763 }
764 
KConfigNodeOpenNodeRead(const KConfigNode * self,const KConfigNode ** node,const char * path,...)765 LIB_EXPORT rc_t CC KConfigNodeOpenNodeRead ( const KConfigNode *self,
766                                              const KConfigNode **node, const char *path, ... )
767 {
768     rc_t rc;
769     va_list args;
770 
771     va_start ( args, path );
772     rc = KConfigNodeVOpenNodeRead ( self, node, path, args );
773     va_end ( args );
774 
775     return rc;
776 }
777 
KConfigVOpenNodeRead(const KConfig * self,const KConfigNode ** node,const char * path,va_list args)778 LIB_EXPORT rc_t CC KConfigVOpenNodeRead ( const KConfig *self,
779                                           const KConfigNode **node, const char *path, va_list args )
780 {
781     rc_t rc;
782 
783     if ( node == NULL )
784         rc = RC ( rcKFG, rcMgr, rcOpening, rcParam, rcNull );
785     else
786     {
787         if ( self == NULL )
788             rc = RC ( rcKFG, rcMgr, rcOpening, rcSelf, rcNull );
789         else if (self->tree.root == NULL)
790             rc = RC ( rcKFG, rcMgr, rcOpening, rcPath, rcNotFound );
791         else
792         {
793             return KConfigNodeVOpenNodeReadInt
794                 ( (const KConfigNode *) self -> tree . root, self, node, path, args );
795         }
796 
797         * node = NULL;
798     }
799 
800     return rc;
801 }
802 
KConfigOpenNodeRead(const KConfig * self,const KConfigNode ** node,const char * path,...)803 LIB_EXPORT rc_t CC KConfigOpenNodeRead ( const KConfig *self,
804                                          const KConfigNode **node, const char *path, ... )
805 {
806     rc_t rc;
807     va_list args;
808 
809     va_start ( args, path );
810     rc = KConfigVOpenNodeRead ( self, node, path, args );
811     va_end ( args );
812 
813     return rc;
814 }
815 
816 
817 /* OpenNodeUpdate
818  * VOpenNodeUpdate
819  *  opens a configuration node
820  *
821  *  "node" [ OUT ] - return parameter for indicated configuration node
822  *
823  *  "path" [ IN, NULL OKAY ] - optional path for specifying named
824  *  node within configuration hierarchy. paths will be interpreted as
825  *  if they were file system paths, using '/' as separator. the
826  *  special values NULL and "" are interpreted as "."
827  */
828 static
KConfigNodeVOpenNodeUpdateInt(KConfigNode * self,KConfig * mgr,KConfigNode ** node,const char * path,va_list args)829 rc_t KConfigNodeVOpenNodeUpdateInt ( KConfigNode *self, KConfig *mgr,
830                                      KConfigNode **node, const char *path, va_list args )
831 {
832     rc_t rc;
833 
834     if ( node == NULL )
835         rc = RC ( rcKFG, rcNode, rcOpening, rcParam, rcNull );
836     else
837     {
838         if ( self == NULL )
839             rc = RC ( rcKFG, rcNode, rcOpening, rcSelf, rcNull );
840         else
841         {
842             if ( path == NULL || path [ 0 ] == 0 )
843             {
844                 * node = self;
845                 rc = 0;
846             }
847             else
848             {
849                 KTokenText tt;
850                 KTokenSource src;
851                 char full [ 4096 ];
852 
853                 rc = init_token_source ( & tt, & src, full, sizeof full, "", path, args );
854                 if ( rc == 0 )
855                 {
856                     /* look ahead */
857                     KToken t;
858 
859                     do
860                         KTokenizerNext ( kPOSIXPathTokenizer, & src, & t );
861                     while ( t.id == eFwdSlash);
862 
863                     /* follow path */
864                     assert ( mgr != NULL );
865                     if ( KConfigNodeCreate ( self, node, & src, & t, mgr -> current_file ) == NULL )
866                         return RC ( rcKFG, rcNode, rcOpening, rcPath, rcInvalid );
867                     if ( ( self = * node ) == NULL )
868                         rc = RC ( rcKFG, rcNode, rcOpening, rcMemory, rcExhausted );
869                     else if ( t . id != eEndOfInput )
870                         rc = RC ( rcKFG, rcNode, rcOpening, rcPath, rcInvalid );
871                 }
872             }
873 
874             if ( rc == 0 )
875             {
876                 /* check to see if internal */
877                 if ( self -> internal == eInternalTrue )
878                     rc = RC ( rcKFG, rcNode, rcOpening, rcNode, rcReadonly );
879                 else
880                 {
881                     /* check to see if open */
882                     if ( atomic32_read ( & self -> refcount ) == 0 )
883                     {
884                         self -> mgr = KConfigAttach ( mgr );
885                         assert ( ! self -> read_only );
886                         return KConfigNodeAddRef ( self );
887                     }
888 
889                     rc = RC ( rcKFG, rcNode, rcOpening, rcNode, rcBusy );
890                 }
891             }
892         }
893 
894         * node = NULL;
895     }
896 
897     return rc;
898 }
899 
KConfigNodeVOpenNodeUpdate(KConfigNode * self,KConfigNode ** node,const char * path,va_list args)900 LIB_EXPORT rc_t CC KConfigNodeVOpenNodeUpdate ( KConfigNode *self,
901                                                 KConfigNode **node, const char *path, va_list args )
902 {
903     if ( self != NULL )
904         return KConfigNodeVOpenNodeUpdateInt ( self, self -> mgr, node, path, args );
905 
906     if ( node == NULL )
907         return RC ( rcKFG, rcNode, rcOpening, rcParam, rcNull );
908 
909     * node = NULL;
910     return RC ( rcKFG, rcNode, rcOpening, rcSelf, rcNull );
911 }
912 
KConfigNodeOpenNodeUpdate(KConfigNode * self,KConfigNode ** node,const char * path,...)913 LIB_EXPORT rc_t CC KConfigNodeOpenNodeUpdate ( KConfigNode *self,
914                                                KConfigNode **node, const char *path, ... )
915 {
916     rc_t rc;
917     va_list args;
918 
919     va_start ( args, path );
920     rc = KConfigNodeVOpenNodeUpdate ( self, node, path, args );
921     va_end ( args );
922 
923     return rc;
924 }
925 
KConfigVOpenNodeUpdate(KConfig * self,KConfigNode ** node,const char * path,va_list args)926 LIB_EXPORT rc_t CC KConfigVOpenNodeUpdate ( KConfig *self,
927                                             KConfigNode **node, const char *path, va_list args )
928 {
929     rc_t rc;
930 
931     if ( node == NULL )
932         rc = RC ( rcKFG, rcMgr, rcOpening, rcParam, rcNull );
933     else
934     {
935         if ( self == NULL )
936             rc = RC ( rcKFG, rcMgr, rcOpening, rcSelf, rcNull );
937         else if (self->tree.root == NULL)
938             rc = RC ( rcKFG, rcMgr, rcOpening, rcSelf, rcCorrupt );
939         else
940         {
941             return KConfigNodeVOpenNodeUpdateInt
942                 ( ( KConfigNode* ) self -> tree . root, self, node, path, args );
943         }
944 
945         * node = NULL;
946     }
947 
948     return rc;
949 }
950 
KConfigOpenNodeUpdate(KConfig * self,KConfigNode ** node,const char * path,...)951 LIB_EXPORT rc_t CC KConfigOpenNodeUpdate ( KConfig *self,
952                                            KConfigNode **node, const char *path, ... )
953 {
954     rc_t rc;
955     va_list args;
956 
957     va_start ( args, path );
958     rc = KConfigVOpenNodeUpdate ( self, node, path, args );
959     va_end ( args );
960 
961     return rc;
962 }
963 
964 
965 /* Read
966  *  read a node value
967  *
968  *  "offset" [ IN ] - initial offset into configuration
969  *
970  *  "buffer" [ OUT ] and "bsize" [ IN ] - return buffer for read
971  *
972  *  "num_read" [ OUT ] - number of bytes actually read
973  *
974  *  "remaining" [ OUT, NULL OKAY ] - optional return parameter for
975  *  the number of bytes remaining to be read.
976  *  specifically, "offset" + "num_read" + "remaining" == sizeof node data
977  */
KConfigNodeRead(const KConfigNode * self,size_t offset,char * buffer,size_t bsize,size_t * num_read,size_t * remaining)978 LIB_EXPORT rc_t CC KConfigNodeRead ( const KConfigNode *self,
979                                      size_t offset, char *buffer, size_t bsize,
980                                      size_t *num_read, size_t *remaining )
981 {
982     rc_t rc;
983     size_t dummy;
984 
985     if ( remaining == NULL )
986         remaining = & dummy;
987 
988     if ( num_read == NULL )
989         rc = RC ( rcKFG, rcNode, rcReading, rcParam, rcNull );
990     else
991     {
992         if ( self == NULL )
993             rc = RC ( rcKFG, rcNode, rcReading, rcSelf, rcNull );
994         else if ( buffer == NULL && bsize != 0 )
995             rc = RC ( rcKFG, rcNode, rcReading, rcBuffer, rcNull );
996         else if ( offset >= self -> value . size )
997             rc = 0;
998         else
999         {
1000             size_t avail = * remaining = self -> value . size - offset;
1001             if ( avail > bsize )
1002                 avail = bsize;
1003             if ( avail > 0 )
1004                 memmove ( buffer, & self -> value . addr [ offset ], avail );
1005             * num_read = avail;
1006             * remaining -= avail;
1007             return 0;
1008         }
1009 
1010         * num_read = 0;
1011     }
1012 
1013     * remaining = 0;
1014 
1015     return rc;
1016 }
1017 
1018 static
KConfigNodeSetDirty(KConfigNode * self)1019 void KConfigNodeSetDirty ( KConfigNode *self )
1020 {
1021     KConfig *mgr = self -> mgr;
1022 
1023     if ( mgr == NULL )
1024         self -> dirty = true;
1025     else if ( mgr -> initialized )
1026         self -> dirty = mgr -> dirty = true;
1027 }
1028 
1029 /* Write
1030  *  write a node value or attribute
1031  *  replaces anything already there
1032  *
1033  *  "buffer" [ IN ] and "size" [ IN ] - new value data
1034  */
KConfigNodeWrite(KConfigNode * self,const char * buffer,size_t size)1035 LIB_EXPORT rc_t CC KConfigNodeWrite ( KConfigNode *self, const char *buffer, size_t size )
1036 {
1037     rc_t rc;
1038 
1039     if ( self == NULL )
1040         rc = RC ( rcKFG, rcNode, rcWriting, rcSelf, rcNull );
1041     else if ( self -> read_only || self -> internal == eInternalTrue )
1042         rc = RC ( rcKFG, rcNode, rcWriting, rcSelf, rcReadonly );
1043     else if ( size == 0 )
1044     {
1045         free ( self -> val_buffer ), self -> val_buffer = NULL;
1046         StringInit ( & self -> value, "", 0, 0 );
1047         KConfigNodeSetDirty ( self );
1048         rc = 0;
1049     }
1050     else if ( buffer == NULL )
1051         rc = RC ( rcKFG, rcNode, rcWriting, rcBuffer, rcNull );
1052     else
1053     {
1054         if ( size != self -> value . size )
1055         {
1056             void *new_buffer = realloc ( self -> val_buffer, size + 1 );
1057             if ( new_buffer == NULL )
1058                 return RC ( rcKFG, rcNode, rcWriting, rcMemory, rcExhausted );
1059             self -> val_buffer = new_buffer;
1060             self -> value . size = size;
1061             self -> value . addr = new_buffer;
1062         }
1063 
1064         assert ( self -> val_buffer != NULL );
1065         string_copy ( self -> val_buffer, self -> value . size + 1, buffer, size );
1066         self -> value . len = string_len ( self -> val_buffer, size );
1067 
1068         KConfigNodeSetDirty ( self );
1069 
1070         rc = 0;
1071     }
1072 
1073     return rc;
1074 }
1075 
1076 
1077 /* Write Boolean
1078  *  write a boolean value ( literally the text "true" or "false:
1079  *  overwrites anything already there
1080  *
1081  *  "state" [ IN ] - new value
1082  */
KConfigNodeWriteBool(KConfigNode * self,bool state)1083 KFG_EXTERN rc_t CC KConfigNodeWriteBool ( KConfigNode *self, bool state )
1084 {
1085     rc_t rc;
1086     size_t written;
1087     char value[ 8 ];
1088 
1089     if ( state )
1090         rc = string_printf( value, sizeof value, &written, "true" );
1091     else
1092         rc = string_printf( value, sizeof value, &written, "false" );
1093 
1094     if ( rc == 0 )
1095         rc = KConfigNodeWrite ( self, value, written );
1096     return rc;
1097 }
1098 
1099 
1100 /* Append
1101  *  append data to value
1102  *
1103  *  "buffer" [ IN ] and "size" [ IN ] - value data to be appended
1104  */
KConfigNodeAppend(KConfigNode * self,const char * buffer,size_t size)1105 LIB_EXPORT rc_t CC KConfigNodeAppend ( KConfigNode *self, const char *buffer, size_t size )
1106 {
1107     rc_t rc;
1108 
1109     if ( self == NULL )
1110         rc = RC ( rcKFG, rcNode, rcWriting, rcSelf, rcNull );
1111     else if ( self -> read_only || self -> internal )
1112         rc = RC ( rcKFG, rcNode, rcWriting, rcSelf, rcReadonly );
1113     else if ( size == 0 )
1114         rc = 0;
1115     else if ( buffer == NULL )
1116         rc = RC ( rcKFG, rcNode, rcWriting, rcBuffer, rcNull );
1117     else
1118     {
1119         void *new_buffer = realloc ( self -> val_buffer, self -> value . size + size + 1 );
1120         if ( new_buffer == NULL )
1121             return RC ( rcKFG, rcNode, rcWriting, rcMemory, rcExhausted );
1122         self -> val_buffer = new_buffer;
1123         string_copy ( & self -> val_buffer [ self -> value . size ], self -> value . size + size + 1, buffer, size );
1124         self -> value . size += size;
1125         self -> value . len = string_len ( self -> val_buffer, self -> value . size );
1126 
1127         KConfigNodeSetDirty ( self );
1128 
1129         rc = 0;
1130     }
1131 
1132     return rc;
1133 }
1134 
1135 
1136 /* ReadAttr
1137  *  reads as NUL-terminated string
1138  *
1139  *  "name" [ IN ] - NUL terminated attribute name
1140  *
1141  *  "buffer" [ OUT ] and "bsize" - return parameter for attribute value
1142  *
1143  *  "size" [ OUT ] - return parameter giving size of string
1144  *  not including NUL byte. the size is set both upon success
1145  *  and insufficient buffer space error.
1146  */
KConfigNodeReadAttr(const KConfigNode * self,const char * name,char * buffer,size_t bsize,size_t * size)1147 LIB_EXPORT rc_t CC KConfigNodeReadAttr ( const KConfigNode *self, const char *name,
1148                                          char *buffer, size_t bsize, size_t *size )
1149 {
1150     PLOGMSG (klogFatal, (klogFatal, "$(F) unimplemented", "F=%s", __func__));
1151     return -1;
1152 }
1153 
1154 
1155 /* WriteAttr
1156  *  writes NUL-terminated string
1157  *
1158  *  "name" [ IN ] - NUL terminated attribute name
1159  *
1160  *  "value" [ IN ] - NUL terminated attribute value
1161  */
KConfigNodeWriteAttr(KConfigNode * self,const char * name,const char * value)1162 LIB_EXPORT rc_t CC KConfigNodeWriteAttr ( KConfigNode *self,
1163                                           const char *name, const char *value )
1164 {
1165     PLOGMSG (klogFatal, (klogFatal, "$(F) unimplemented", "F=%s", __func__));
1166     return -1;
1167 }
1168 
1169 
1170 /* Drop
1171  * VDrop
1172  *  drop some or all node content
1173  */
KConfigNodeDropAll(KConfigNode * self)1174 LIB_EXPORT rc_t CC KConfigNodeDropAll ( KConfigNode *self )
1175 {
1176     if ( self == NULL )
1177         return RC ( rcKFG, rcNode, rcClearing, rcSelf, rcNull );
1178     BSTreeWhack ( & self->children, KConfigNodeWhack, self->mgr);
1179     return 0;
1180 }
1181 
KConfigNodeDropAttr(KConfigNode * self,const char * attr)1182 LIB_EXPORT rc_t CC KConfigNodeDropAttr ( KConfigNode *self, const char *attr )
1183 {
1184     PLOGMSG (klogFatal, (klogFatal, "$(F) unimplemented", "F=%s", __func__));
1185     return -1;
1186 }
1187 
KConfigNodeVDropChild(KConfigNode * self,const char * path,va_list args)1188 LIB_EXPORT rc_t CC KConfigNodeVDropChild ( KConfigNode *self, const char *path, va_list args )
1189 {
1190     PLOGMSG (klogFatal, (klogFatal, "$(F) unimplemented", "F=%s", __func__));
1191     return -1;
1192 }
1193 
KConfigNodeDropChild(KConfigNode * self,const char * path,...)1194 LIB_EXPORT rc_t CC KConfigNodeDropChild ( KConfigNode *self, const char *path, ... )
1195 {
1196     PLOGMSG (klogFatal, (klogFatal, "$(F) unimplemented", "F=%s", __func__));
1197     return -1;
1198 }
1199 
1200 
1201 /* Rename
1202  *  renames a contained object
1203  *
1204  *  "from" [ IN ] - NUL terminated string in UTF-8
1205  *  giving simple name of existing attr
1206  *
1207  *  "to" [ IN ] - NUL terminated string in UTF-8
1208  *  giving new simple attr name
1209  */
KConfigNodeRenameAttr(KConfigNode * self,const char * from,const char * to)1210 LIB_EXPORT rc_t CC KConfigNodeRenameAttr ( KConfigNode *self, const char *from, const char *to )
1211 {
1212     PLOGMSG (klogFatal, (klogFatal, "$(F) unimplemented", "F=%s", __func__));
1213     return -1;
1214 }
1215 
KConfigNodeRenameChild(KConfigNode * self,const char * from,const char * to)1216 LIB_EXPORT rc_t CC KConfigNodeRenameChild ( KConfigNode *self, const char *from, const char *to )
1217 {
1218     PLOGMSG (klogFatal, (klogFatal, "$(F) unimplemented", "F=%s", __func__));
1219     return -1;
1220 }
1221 
1222 
1223 /*--------------------------------------------------------------------------
1224  * KConfig
1225  */
1226 
1227 static
1228 rc_t
update_node(KConfig * self,const char * key,const char * value,TInternal internal)1229 update_node ( KConfig* self, const char* key, const char* value,
1230     TInternal internal )
1231 {
1232     KConfigNode * node;
1233     rc_t rc = KConfigOpenNodeUpdate ( self, &node, "%s", key);
1234     if (rc == 0)
1235     {
1236 /*        pLogMsg(klogInfo, "updating config key $(KEY) with '$(VALUE)'",
1237                           "KEY=%s,VALUE=%s",
1238                           key, value);*/
1239         rc = KConfigNodeWrite (node, value, string_size(value));
1240         node -> internal = internal;
1241         if (self->current_file != NULL && self->current_file->is_magic_file) {
1242             if (node->came_from == NULL || !node->came_from->is_magic_file) {
1243                 node->came_from = self->current_file;
1244             }
1245         }
1246         KConfigNodeRelease ( node );
1247     }
1248     return rc;
1249 }
1250 
1251 static
write_nvp(void * pself,const char * name,size_t nameLen,VNamelist * values)1252 rc_t write_nvp(void* pself, const char* name, size_t nameLen, VNamelist* values)
1253 {   /* concatenate all values from the namelist and put the result into config under the given name */
1254     uint32_t count;
1255     size_t size=0;
1256     size_t concatTo=0;
1257     uint32_t i;
1258 
1259     char* buf;
1260     KConfig *self = (KConfig *)pself;
1261     rc_t rc=VNameListCount(values, &count);
1262     if (rc != 0)
1263     {
1264         return rc;
1265     }
1266     for (i=0; i < count; ++i)
1267     {
1268         const char* val;
1269         rc=VNameListGet(values, i, &val);
1270         if (rc != 0)
1271         {
1272             return rc;
1273         }
1274         size+=string_size(val);
1275     }
1276 
1277     buf=(char*)malloc(size+1);
1278     if (buf == 0)
1279     {
1280         return RC ( rcKFG, rcMgr, rcLoading, rcMemory, rcExhausted );
1281     }
1282 
1283     concatTo=0;
1284     for (i=0; i < count; ++i)
1285     {
1286         const char* val;
1287         rc=VNameListGet(values, i, &val);
1288         if (rc != 0)
1289         {
1290             free(buf);
1291             return rc;
1292         }
1293         string_copy(buf+concatTo, size+1-concatTo, val, string_size(val));
1294         concatTo+=string_size(val);
1295     }
1296     buf[size]=0;
1297 
1298     {   /* create the node */
1299         String* nameStr;
1300 
1301         /* some old config files may have "dbGaP" in their repository keys misspelled as "dbGap" - fix if seen */
1302         const char* oldGaPprefix = "/repository/user/protected/dbGap-";
1303         size_t size = sizeof("/repository/user/protected/dbGap-") - 1;
1304         bool needsFix = string_cmp(name, string_size(name), oldGaPprefix, size, (uint32_t)size) == 0;
1305 
1306         String tmp;
1307         StringInit(&tmp, name, nameLen, (uint32_t)nameLen);
1308         StringCopy((const String**)&nameStr, &tmp);
1309         if (needsFix)
1310             ((char*)(nameStr->addr)) [ size - 2 ] = 'P';
1311 
1312         rc = update_node(self, nameStr->addr, buf, false);
1313         if (needsFix)
1314         {
1315             KConfigNode * node;
1316             rc = KConfigOpenNodeUpdate ( self, &node, "%s", nameStr->addr );
1317             if (rc == 0)
1318             {   /* we are likely to be initializing, so have to set the dirty flags directly, not through KConfigNodeSetDirty() */
1319                 self -> dirty = true;
1320                 node -> dirty = true;
1321                 KConfigNodeRelease ( node );
1322             }
1323         }
1324         StringWhack(nameStr);
1325     }
1326 
1327     free(buf);
1328     return rc;
1329 }
1330 
1331 static
look_up_var(void * self,struct KFGToken * pb)1332 bool look_up_var(void * self, struct KFGToken* pb)
1333 {
1334     const KConfigNode* node;
1335     rc_t rc = KConfigOpenNodeRead((KConfig*)self, &node, "%.*s", pb->tokenLength-3, pb->tokenText+2);
1336     if (rc == 0)
1337     {
1338         pb->tokenText   = node->value.addr;
1339         pb->tokenLength = node->value.len;
1340         pb->tokenId     = kfgVAR_REF;
1341     }
1342     KConfigNodeRelease(node);
1343     return rc == 0;
1344 }
1345 
1346 static
report_error(KFGScanBlock * sb,const char * msg)1347 void CC report_error(KFGScanBlock* sb, const char* msg)
1348 {
1349     pLogMsg(klogErr, "$(file):$(line):$(column): error: token='$(token)', msg='$(msg)'",
1350                      "file=%s,line=%d,column=%d,token=%.*s,msg=%s",
1351                      sb->file,
1352                      sb->lastToken->line_no,
1353                      sb->lastToken->column_no,
1354                      sb->lastToken->tokenLength,
1355                      sb->lastToken->tokenText,
1356                      msg);
1357 }
1358 
1359 #define DISP_RC2(rc, name, msg) (void)((rc == 0) ? 0 : \
1360     PLOGERR(klogInt, (klogInt, rc, \
1361         "$(name): $(msg)", "name=%s,msg=%s", name, msg)))
1362 
1363 typedef struct
1364 {
1365     KFile *f; /* NULL for OUTMSG */
1366 
1367     /* total bytes flushed to the file*/
1368     size_t flushed;
1369 
1370     /* total bytes in buffer */
1371     size_t buffered;
1372 
1373     rc_t rc;
1374 
1375     /* buffer */
1376     char buffer [ 32 * 1024 ];
1377 
1378 } PrintBuff;
1379 
1380 /* Init
1381  *  initialize your structure
1382  */
1383 static
PrintBuffInit(PrintBuff * pb,KFile * f)1384 void PrintBuffInit ( PrintBuff *pb, KFile *f )
1385 {
1386     assert ( pb != NULL );
1387     pb -> f = f; /* NULL for OUTMSG */
1388     pb -> flushed = 0;
1389     pb -> buffered = 0;
1390     pb -> rc = 0;
1391 }
1392 
1393 /* Flush
1394  * Write buffer out to file
1395  */
PrintBuffFlush(PrintBuff * self)1396 static rc_t PrintBuffFlush ( PrintBuff *self )
1397 {
1398     rc_t rc = 0;
1399 
1400     assert ( self != NULL );
1401     if ( self -> buffered != 0 )
1402     {
1403         size_t num_writ = 0;
1404 
1405         if (self -> f == NULL) {
1406             OUTMSG(("%.*s", self -> buffered - self -> flushed,
1407                 self -> buffer + self -> flushed));
1408             num_writ = self -> buffered;
1409         }
1410         else {
1411             rc = KFileWriteAll ( self -> f, self -> flushed,
1412                 self -> buffer, self -> buffered, & num_writ );
1413         }
1414 
1415         if ( rc == 0 )
1416         {
1417             if ( num_writ != self -> buffered )
1418                 rc = RC ( rcKFG, rcBuffer, rcFlushing,
1419                     rcTransfer, rcIncomplete );
1420             else
1421             {
1422                 self -> flushed += num_writ;
1423                 self -> buffered = 0;
1424             }
1425         }
1426     }
1427 
1428     return self -> rc = rc;
1429 }
1430 
1431 /* Print
1432  *  printf style writing to the buffer
1433  */
1434 static
PrintBuffPrint(PrintBuff * self,const char * fmt,...)1435 rc_t PrintBuffPrint ( PrintBuff *self, const char *fmt, ... )
1436 {
1437     rc_t rc;
1438     size_t num_writ;
1439     va_list args1, args2;
1440 
1441     assert ( self != NULL );
1442     assert ( fmt != NULL );
1443     assert ( fmt [ 0 ] != 0 );
1444 
1445     va_start ( args1, fmt );
1446     va_copy ( args2, args1 );
1447 
1448     rc = string_vprintf ( & self -> buffer [ self -> buffered ],
1449             sizeof self -> buffer - self -> buffered, & num_writ, fmt, args1 );
1450     if ( rc == 0 )
1451         self -> buffered += num_writ;
1452     else if ( GetRCObject ( rc ) == (enum RCObject)rcBuffer
1453         && GetRCState ( rc ) == rcInsufficient )
1454     {
1455         rc = PrintBuffFlush ( self );
1456         if ( rc == 0 )
1457         {
1458             rc = string_vprintf ( & self -> buffer [ self -> buffered ],
1459              sizeof self -> buffer - self -> buffered, & num_writ, fmt, args2 );
1460             if ( rc == 0 )
1461                 self -> buffered += num_writ;
1462         }
1463     }
1464 
1465     va_end ( args2 );
1466     va_end ( args1 );
1467 
1468     return self -> rc = rc;
1469 }
1470 
printIndent(int indent,PrintBuff * pb)1471 static rc_t printIndent(int indent, PrintBuff *pb) {
1472     rc_t rc = 0;
1473 
1474     int i = 0;
1475     for (i = 0; i < indent * 2; ++i) {
1476         rc_t rc2 = PrintBuffPrint(pb, " ");
1477         if (rc == 0 && rc2 != 0) {
1478             rc = rc2;
1479         }
1480     }
1481 
1482     return rc;
1483 }
1484 
KConfigNodeReadData(const KConfigNode * self,char * buf,size_t blen,size_t * num_read)1485 static rc_t KConfigNodeReadData(const KConfigNode* self,
1486     char* buf, size_t blen, size_t* num_read)
1487 {
1488     rc_t rc = 0;
1489     size_t remaining = 0;
1490 
1491     assert(buf && blen && num_read);
1492 
1493     rc = KConfigNodeRead(self, 0, buf, blen, num_read, &remaining);
1494 
1495     assert(remaining == 0); /* TODO overflow check */
1496     assert(*num_read <= blen);
1497 
1498     return rc;
1499 }
1500 
ToHex(uint32_t i)1501 char ToHex(uint32_t i)
1502 {
1503     if (i <= 9)
1504         return '0' + i;
1505     return 'A' + (i - 10);
1506 }
1507 
1508 static
PrintBuffPrintQuoted(PrintBuff * self,const String * data)1509 rc_t CC PrintBuffPrintQuoted ( PrintBuff *self, const String* data )
1510 {
1511     rc_t rc = PrintBuffPrint(self, "\"");
1512     const char* str = (const char*)(data->addr);
1513     uint32_t i;
1514     for ( i = 0; i < StringLength(data); ++i )
1515     {
1516         if (rc != 0)
1517             break;
1518         if (str[i] < ' ')
1519         {
1520             rc = PrintBuffPrint(self, "\\x%c%c",
1521                 ToHex(str[i]/16), ToHex(str[i]%16) );
1522         }
1523         else
1524         {
1525             switch (str[i])
1526             {
1527             case '"':
1528                 rc = PrintBuffPrint(self, "\\\"");
1529                 break;
1530             default:
1531                 rc = PrintBuffPrint(self, "%c", str[i]);
1532             }
1533         }
1534     }
1535     if (rc == 0)
1536         rc = PrintBuffPrint(self, "\"");
1537     return rc;
1538 }
1539 
_printNodeData(const char * name,const char * data,uint32_t dlen,bool native,const char * fullpath,bool hide,PrintBuff * pb)1540 static rc_t _printNodeData(const char *name, const char *data, uint32_t dlen,
1541     bool native, const char *fullpath, bool hide, PrintBuff *pb)
1542 {
1543     bool secret = false;
1544     {
1545         const char d1[] = "download-ticket";
1546         size_t l1 = sizeof d1 - 1;
1547 
1548         const char d2[] = "aws_access_key_id";
1549         size_t l2 = sizeof d2 - 1;
1550 
1551         const char d3[] = "aws_secret_access_key";
1552         size_t l3 = sizeof d3 - 1;
1553 
1554         if ((string_cmp(name,
1555                 string_measure(name, NULL), d1, l1, (uint32_t)l1) == 0) ||
1556             (string_cmp(name,
1557                 string_measure(name, NULL), d2, l2, (uint32_t)l2) == 0) ||
1558             (string_cmp(name,
1559                 string_measure(name, NULL), d3, l3, (uint32_t)l3) == 0))
1560         {
1561             secret = true;
1562         }
1563     }
1564     if (hide && !native && secret) {
1565         const char *ellipsis = "";
1566         const char replace[] =
1567 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
1568         if (dlen > 70) {
1569             dlen = 70;
1570             ellipsis = "...";
1571         }
1572         return PrintBuffPrint(pb, "%.*s%s", dlen, replace, ellipsis);
1573     }
1574     else if (!native) {
1575         String s;
1576         StringInit(&s, data, dlen, dlen);
1577         return PrintBuffPrintQuoted(pb, &s);
1578     }
1579     else {
1580         rc_t rc = PrintBuffPrint(pb, "%s = ", fullpath);
1581         if (rc == 0) {
1582             String s;
1583             StringInit(&s, data, dlen, dlen);
1584             rc = PrintBuffPrintQuoted(pb, &s);
1585         }
1586         if (rc == 0) {
1587             rc = PrintBuffPrint(pb, "\n");
1588         }
1589         return rc;
1590     }
1591 }
1592 
1593 
1594 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
1595     if (rc2 && !rc) { rc = rc2; } obj = NULL; } while (false)
1596 
KConfigNodePrintWithIncluded(const KConfigNode * self,int indent,const char * root,bool debug,bool native,const char * aFullpath,PrintBuff * pb,uint32_t skipCount,va_list args,const KConfig * withIncluded)1597 static rc_t KConfigNodePrintWithIncluded (const KConfigNode *self, int indent,
1598     const char* root, bool debug, bool native, const char* aFullpath,
1599     PrintBuff *pb, uint32_t skipCount, va_list args,
1600     const KConfig * withIncluded )
1601 {
1602     rc_t rc = 0;
1603     KNamelist* names = NULL;
1604     uint32_t count = 0;
1605     uint32_t i = 0;
1606     char data[4097] = "";
1607     size_t num_data = 0;
1608 
1609     assert(self);
1610 
1611     if (!native) {
1612         rc = printIndent(indent, pb);
1613         if (rc == 0) {
1614             bool found = false;
1615             uint32_t i = 0;
1616             va_list args_copy;
1617             if (skipCount > 0)
1618                 va_copy(args_copy, args);
1619             for (i = 0; i < skipCount; ++i) {
1620                 const char *skip = va_arg(args_copy, const char*);
1621                 if (string_cmp(skip, string_measure(skip, NULL), root,
1622                         string_measure(root, NULL), string_measure(root, NULL))
1623                     == 0)
1624                 {
1625                     rc = PrintBuffPrint
1626                         (pb, "<%s><!-- skipped --></%s>\n", root, root);
1627                     found = true;
1628                     break;
1629                 }
1630             }
1631             if (skipCount > 0)
1632                 va_end(args_copy);
1633             if (found)
1634                 return rc;
1635             rc = PrintBuffPrint(pb, "<%s>", root);
1636             if ( withIncluded ) {
1637 //              bool hasAny = false;
1638                 uint32_t count = 0;
1639                 KNamelist * names = NULL;
1640                 rc_t rc = KConfigListIncluded ( withIncluded, & names );
1641                 if ( rc == 0 )
1642                     rc = KNamelistCount ( names, & count );
1643                 if ( rc == 0 ) {
1644                     uint32_t i = 0;
1645                     rc = printIndent(indent, pb);
1646                     PrintBuffPrint ( pb, "\n  <ConfigurationFiles>\n" );
1647                     for ( i = 0; i < count && rc == 0; ++i ) {
1648                         const char * name = NULL;
1649                         if ( rc == 0 )
1650                             rc = KNamelistGet(names, i, &name);
1651                         if (rc == 0) {
1652                             PrintBuffPrint ( pb, "%s\n", name );
1653 //                          hasAny = true;
1654                         }
1655                     }
1656                     rc = printIndent(indent, pb);
1657                     PrintBuffPrint ( pb, "  </ConfigurationFiles>" );
1658                 }
1659                 RELEASE ( KNamelist, names );
1660             }
1661         }
1662     }
1663 
1664     if (rc == 0) {
1665         rc_t rc = KConfigNodeReadData(self, data, sizeof data, &num_data);
1666         DISP_RC2(rc, "KConfigNodeReadData()", root);
1667         if (rc == 0 && num_data > 0) {
1668             _printNodeData(root, data, num_data,
1669                 native, aFullpath, !native, pb);
1670         }
1671         if (debug && self->came_from) {
1672             OUTMSG(("<came_from is_magic_file=\"%s\"/>",
1673                 self->came_from->is_magic_file ? "true" : "false"));
1674         }
1675     }
1676 
1677     if (rc == 0) {
1678         rc = KConfigNodeListChild(self, &names);
1679         DISP_RC2(rc, "KConfigNodeListChild()", root);
1680     }
1681     if (rc == 0) {
1682         rc = KNamelistCount(names, &count);
1683         DISP_RC2(rc, "KNamelistCount()", root);
1684     }
1685 
1686     if (rc == 0) {
1687         if (count > 0 && !native)
1688             rc = PrintBuffPrint(pb, "\n");
1689         for (i = 0; i < count; ++i) {
1690             char *fullpath = NULL;
1691             const char* name = NULL;
1692             const KConfigNode* node = NULL;
1693             if (rc == 0) {
1694                 rc = KNamelistGet(names, i, &name);
1695                 DISP_RC2(rc, "KNamelistGet()", root);
1696             }
1697             if (rc == 0) {
1698                 rc = KConfigNodeOpenNodeRead(self, &node, "%s", name);
1699                 DISP_RC2(rc, "KConfigNodeOpenNodeRead()", name);
1700             }
1701             if (rc == 0) {
1702                 size_t bsize = strlen(aFullpath) + 1 + strlen(name) + 1;
1703                 fullpath = malloc(bsize + 1);
1704                 if (fullpath == NULL) {
1705                     rc = RC(rcKFG, rcStorage, rcAllocating,
1706                         rcMemory, rcExhausted);
1707                 }
1708                 else {
1709                     string_printf(fullpath, bsize, NULL,
1710                         "%s/%s", aFullpath, name);
1711                 }
1712             }
1713             if (rc == 0) {
1714                 if (! isdigit(name[0])) {
1715                     KConfigNodePrintWithIncluded(node, indent + 1, name,
1716                         debug, native, fullpath, pb, skipCount, args, NULL );
1717                 }
1718                 else {
1719                     /* XML node names cannot start with a number */
1720                     size_t dsize = strlen(name) + 2;
1721                     char *dname =  malloc(dsize);
1722                     if (dname == NULL) {
1723                         rc = RC(rcKFG, rcStorage, rcAllocating,
1724                             rcMemory, rcExhausted);
1725                     }
1726                     else {
1727                         string_printf(dname, dsize, NULL, "_%s", name);
1728                         KConfigNodePrintWithIncluded ( node, indent + 1, dname,
1729                             debug, native, fullpath, pb, skipCount, args,
1730                             NULL );
1731                         free(dname);
1732                     }
1733                 }
1734             }
1735             KConfigNodeRelease(node);
1736             free(fullpath);
1737         }
1738     }
1739 
1740     if (count > 0 && !native) {
1741         printIndent(indent, pb);
1742     }
1743 
1744     if (rc == 0 && !native) {
1745         rc = PrintBuffPrint(pb, "</%s>\n", root);
1746     }
1747 
1748     KNamelistRelease(names);
1749 
1750     return rc;
1751 }
1752 
KConfigNodePrint(const KConfigNode * self,int indent,const char * root,bool debug,bool native,const char * aFullpath,PrintBuff * pb,uint32_t skipCount,va_list args,const KConfig * cfg)1753 static rc_t KConfigNodePrint(const KConfigNode *self, int indent,
1754     const char* root, bool debug, bool native, const char* aFullpath,
1755     PrintBuff *pb, uint32_t skipCount, va_list args, const KConfig* cfg )
1756 {
1757     return KConfigNodePrintWithIncluded ( self, indent, root, debug, native,
1758             aFullpath, pb, skipCount, args, cfg );
1759 }
1760 
KConfigPrintImpl(const KConfig * self,int indent,const char * root,bool debug,bool native,PrintBuff * pb,uint32_t skipCount,va_list args)1761 static rc_t CC KConfigPrintImpl(const KConfig* self,
1762     int indent, const char *root, bool debug, bool native,
1763     PrintBuff *pb, uint32_t skipCount, va_list args)
1764 {
1765     const KConfig * withIncluded = NULL;
1766     rc_t rc = 0;
1767 
1768     if (root == NULL) {
1769         root = "Config";
1770         withIncluded = self;
1771     }
1772 
1773     if (self == NULL) {
1774         OUTMSG(("<%s>", root));
1775         OUTMSG(("KConfigPrint(const KConfig* self = NULL)\n"));
1776         OUTMSG(("</%s>\n", root));
1777     }
1778     else {
1779         const KConfigNode* node = NULL;
1780         if (rc == 0) {
1781             rc = KConfigOpenNodeRead(self, &node, "/");
1782             DISP_RC2(rc, "KConfigOpenNodeRead()", "/");
1783         }
1784         if (rc == 0)
1785             KConfigNodePrint ( node, indent, root, debug, native, "", pb,
1786                                skipCount, args, withIncluded );
1787         KConfigNodeRelease(node);
1788     }
1789 
1790     return rc;
1791 }
1792 
KConfigPrintImpl_noargs(const KConfig * self,int indent,const char * root,bool debug,bool native,PrintBuff * pb,uint32_t skipCount,...)1793 static rc_t CC KConfigPrintImpl_noargs(const KConfig* self,
1794     int indent, const char *root, bool debug, bool native,
1795     PrintBuff *pb, uint32_t skipCount, ...)
1796 {
1797     va_list vl;
1798     va_start( vl, skipCount );
1799     rc_t ret = KConfigPrintImpl( self, indent, root, debug, native, pb, skipCount, vl );
1800     va_end(vl);
1801     return ret;
1802 }
1803 
KConfigPrintDebug(const KConfig * self,const char * path)1804 LIB_EXPORT rc_t CC KConfigPrintDebug(const KConfig* self, const char *path) {
1805     rc_t rc = 0;
1806 
1807     PrintBuff pb;
1808 
1809     if (rc == 0) {
1810         PrintBuffInit(&pb, NULL);
1811     }
1812 
1813     if (rc == 0) {
1814         rc = KConfigPrintImpl_noargs(self, 0, path, true, false, &pb, 0);
1815     }
1816 
1817     if (rc == 0) {
1818         rc = PrintBuffFlush(&pb);
1819     }
1820 
1821     return rc;
1822 }
1823 
1824 /*
1825  * Set up the parameter block and start parsing lines
1826  */
1827 static
parse_file(KConfig * self,const char * path,const char * src)1828 rc_t parse_file ( KConfig * self, const char* path, const char * src )
1829 {
1830     KFGParseBlock pb;
1831     KFGScanBlock sb;
1832 
1833     pb.write_nvp    = write_nvp;
1834 
1835     sb.self         = self;
1836     sb.file         = path;
1837     sb.look_up_var  = look_up_var;
1838     sb.report_error = report_error;
1839 
1840     if  ( ! KFGScan_yylex_init(&sb, src) )
1841     {   /* out of memory is the only reason we can get false here */
1842         return RC ( rcKFG, rcMgr, rcParsing, rcMemory, rcExhausted );
1843     }
1844 
1845     KFG_parse(&pb, &sb); /* may have reported parse errors into log, but we should have been able to extract enough data to proceed regardless */
1846     KFGScan_yylex_destroy(&sb);
1847 
1848     return 0;
1849 }
1850 
1851 LIB_EXPORT rc_t CC
KConfigParse(KConfig * self,const char * path,const char * src)1852 KConfigParse ( KConfig * self, const char* path, const char * src )
1853 {
1854     if ( self == NULL )
1855         return RC ( rcKFG, rcMgr, rcLoading, rcSelf, rcNull );
1856     else if ( src == NULL )
1857         return RC ( rcKFG, rcMgr, rcLoading, rcParam, rcNull );
1858 
1859     if ( path == NULL )
1860     {
1861         path = "UNSPECIFIED";
1862     }
1863     return parse_file ( self, path, src );
1864 }
1865 
1866 /* LoadFile
1867  * loads a configuration file
1868  */
KConfigLoadFile(KConfig * self,const char * path,const KFile * file)1869 LIB_EXPORT rc_t CC KConfigLoadFile ( KConfig * self, const char * path, const KFile * file )
1870 {
1871     rc_t rc;
1872 
1873     if ( self == NULL )
1874         rc = RC ( rcKFG, rcMgr, rcLoading, rcSelf, rcNull );
1875     else if ( file == NULL )
1876         rc = RC ( rcKFG, rcMgr, rcLoading, rcFile, rcNull );
1877     else
1878     {
1879         const KMMap * mm;
1880         bool entry_initialized = self -> initialized;
1881         self -> initialized = false;
1882 
1883         /* populate file-specific predefined nodes */
1884 #define UPDATE_NODES(dir, file)                             \
1885         rc = update_node(self, "kfg/dir", dir, eInternalTrueUpdatable );     \
1886         if (rc == 0)                                        \
1887             rc = update_node(self, "kfg/name", file, eInternalTrueUpdatable )
1888 
1889         if ( path == NULL || path [ 0 ] == 0)
1890         {
1891             path = "UNSPECIFIED";
1892             UPDATE_NODES ( "", "" );
1893         }
1894         else
1895         {
1896             KDirectory* dir;
1897             rc = KDirectoryNativeDir(&dir);
1898             if (rc == 0 )
1899             {
1900                 char buff [ 4096 ];
1901                 rc = KDirectoryResolvePath ( dir, true, buff, sizeof buff,
1902                     "%.*s", string_size(path), path );
1903                 if ( rc == 0 )
1904                 {
1905                     char* name = strrchr (buff, '/');
1906                     DBGMSG ( DBG_KFG, DBG_FLAG ( DBG_KFG ),
1907                         ( "KFG: loading file '%s'\n", buff ) );
1908                     if (name == NULL)
1909                     {   /* no dir name */
1910                         UPDATE_NODES("", buff);
1911                     }
1912                     else
1913                     {
1914                         *name=0; /* nul-terminate dir name; file name follows the 0 */
1915                         UPDATE_NODES(buff, name+1);
1916                     }
1917                 }
1918                 KDirectoryRelease ( dir );
1919             }
1920             else
1921             {
1922                 update_node(self, "kfg/dir", "", eInternalTrueUpdatable);
1923                 update_node(self, "kfg/name", "", eInternalTrueUpdatable);
1924             }
1925         }
1926 #undef UPDATE_NODES
1927 
1928 
1929         rc = KMMapMakeRead ( & mm, file );
1930         if ( rc == 0 )
1931         {
1932             size_t size;
1933             const void * ptr;
1934             rc = KMMapAddrRead ( mm, & ptr );
1935             if ( rc == 0 )
1936                 rc = KMMapSize ( mm, & size );
1937             if ( rc == 0 )
1938             {
1939                 /* make a 0-terminated copy for parsing */
1940                 char* buf=malloc(size+1);
1941                 if (buf == 0)
1942                 {
1943                     rc = RC ( rcKFG, rcMgr, rcLoading, rcMemory, rcExhausted );
1944                 }
1945                 else
1946                 {
1947                     string_copy(buf, size+1, ptr, size);
1948                     buf[size]=0;
1949 
1950                     /* Parse the path to populate: */
1951                  /* update_node(self, "kfg/dir", dir, eInternalTrueUpdatable);*/
1952                /* update_node(self, "kfg/name", name, eInternalTrueUpdatable);*/
1953 
1954                     /* parse config file */
1955                     rc = parse_file ( self, path, buf );
1956                     free(buf);
1957                 }
1958             }
1959 
1960             KMMapRelease ( mm );
1961         }
1962         self -> initialized = entry_initialized;
1963     }
1964 
1965     return rc;
1966 }
1967 
1968 static
KConfigNodePrintPath(KConfigNode * self,PrintBuff * pb)1969 bool KConfigNodePrintPath ( KConfigNode *self, PrintBuff *pb )
1970 {
1971     if ( self -> dad == NULL )
1972         PrintBuffPrint ( pb, "%S", & self -> name );
1973     else
1974     {
1975         if ( KConfigNodePrintPath ( self -> dad, pb ) )
1976             return true;
1977 
1978         PrintBuffPrint ( pb, "/%S", & self -> name );
1979     }
1980     return pb -> rc != 0;
1981 }
1982 
1983 /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv KfgSettings vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
1984 typedef struct {
1985     const char *envrNcbiHome;
1986     char        envrNcbiSettings[ PATH_MAX ];
1987     char        dfltNcbiHome    [ PATH_MAX ];
1988     char        dfltNcbiSettings[ PATH_MAX ];
1989 } KfgSettings;
1990 static
_KConfigIniKfgSettings(const KConfig * self,KfgSettings * ks)1991 void _KConfigIniKfgSettings ( const KConfig * self, KfgSettings * ks ) {
1992     size_t bytes = 0;
1993 
1994     assert(ks);
1995     memset(ks, 0, sizeof *ks);
1996 
1997     /* load environment */
1998     ks -> envrNcbiHome = getenv ( "NCBI_HOME" );
1999     {
2000         const char *value = getenv ( "NCBI_SETTINGS" );
2001         if ( value != NULL ) {
2002             string_copy_measure (
2003                 ks -> envrNcbiSettings, sizeof ks -> envrNcbiSettings, value );
2004         }
2005         else if ( ks -> envrNcbiHome != NULL ) {
2006             string_printf ( ks->envrNcbiSettings,
2007                 sizeof ks -> envrNcbiSettings,
2008                 & bytes, "%s/%s", ks -> envrNcbiHome, MAGIC_LEAF_NAME);
2009         }
2010     }
2011 
2012     /* default values */
2013     {
2014         char home [ PATH_MAX ] = "";
2015         size_t num_read = 0;
2016         size_t remaining = 0;
2017         rc_t rc = KConfigRead
2018             ( self, "HOME", 0, home, sizeof home, & num_read, & remaining);
2019         if ( rc != 0 || remaining != 0 ) {
2020             return;
2021         }
2022         string_printf ( ks -> dfltNcbiHome  , sizeof ks -> dfltNcbiHome,
2023             & bytes, "%.*s/.ncbi", num_read, home );
2024         string_printf ( ks->dfltNcbiSettings, sizeof ks -> dfltNcbiSettings,
2025             & bytes, "%.*s/.ncbi/%s", num_read, home, MAGIC_LEAF_NAME );
2026     }
2027 }
2028 
2029 static
MayICommitTo(const KConfig * self,const char * path,size_t size)2030 bool MayICommitTo(const KConfig *self, const char *path, size_t size)
2031 {
2032     if ( ! s_disable_user_settings ) {
2033         return true;
2034     }
2035     else {
2036         size_t bytes = 0;
2037         char home             [ PATH_MAX ] = "";
2038         char dfltNcbiSettings [ PATH_MAX ] = "";
2039         size_t num_read = 0;
2040         size_t remaining = 0;
2041         rc_t rc = KConfigRead
2042             ( self, "HOME", 0, home, sizeof home, & num_read, & remaining);
2043         if ( rc != 0 || remaining != 0 ) {
2044             return false;
2045         }
2046         string_printf ( dfltNcbiSettings, sizeof dfltNcbiSettings,
2047             & bytes, "%.*s/.ncbi/%s", num_read, home, MAGIC_LEAF_NAME );
2048         return string_cmp
2049             (dfltNcbiSettings, bytes, path, size, sizeof dfltNcbiSettings) != 0;
2050     }
2051 }
2052 
2053 static
_KConfigGetNcbiHome(const KConfig * self,const KfgSettings * ks,char * buf,size_t size)2054 rc_t _KConfigGetNcbiHome ( const KConfig * self, const KfgSettings * ks,
2055     char * buf, size_t size)
2056 {
2057     size_t num_read = 0;
2058     size_t remaining = 0;
2059 
2060     if (KConfigRead ( self, "NCBI_HOME", 0, buf, size, & num_read, & remaining)
2061         != 0)
2062     {
2063         assert ( ks );
2064         if ( ks -> envrNcbiHome != 0 ) {
2065             string_copy_measure ( buf, size, ks -> envrNcbiHome );
2066         }
2067         else {
2068             string_copy_measure ( buf, size, ks -> dfltNcbiHome );
2069         }
2070     }
2071     else if ( remaining > 0 || num_read >= size ) {
2072         return RC ( rcKFG, rcNode, rcReading, rcBuffer, rcInsufficient );
2073     }
2074     else {
2075         buf [ num_read ] = '\0';
2076     }
2077 
2078     return 0;
2079 }
2080 
2081 static
_KConfigGetNcbiSettings(const KConfig * self,const KfgSettings * ks,char * buf,size_t size,const char * root)2082 rc_t _KConfigGetNcbiSettings ( const KConfig * self, const KfgSettings * ks,
2083     char * buf, size_t size, const char * root)
2084 {
2085     size_t num_read = 0;
2086     size_t remaining = 0;
2087 
2088     rc_t rc = 0;
2089 
2090     assert(ks && buf && size);
2091 
2092     buf[0] = '\0';
2093 
2094     rc = KConfigRead
2095         ( self, "NCBI_SETTINGS", 0, buf, size, & num_read, & remaining );
2096     if ( rc != 0 ) {
2097         if ( ks -> envrNcbiSettings [ 0 ] != '\0' ) {
2098             string_copy_measure ( buf, size, ks -> envrNcbiSettings );
2099             rc = 0;
2100         }
2101         else if ( root != NULL && root[0] != '\0' ) {
2102             rc = string_printf
2103                 ( buf, size, & num_read, "%s/%s", root, MAGIC_LEAF_NAME );
2104         }
2105         if ( rc != 0 ) {
2106             string_copy_measure ( buf, size, ks -> dfltNcbiSettings );
2107             rc = 0;
2108         }
2109     }
2110     else if ( remaining > 0 || num_read >= size ) {
2111         return RC ( rcKFG, rcNode, rcReading, rcBuffer, rcInsufficient );
2112     }
2113     else {
2114         buf [ num_read ] = '\0';
2115     }
2116 
2117     return rc;
2118 }
2119 
2120 static
_KConfigSetNcbiHome(KConfig * self,const KfgSettings * ks,const char * ncbi_home)2121 void _KConfigSetNcbiHome ( KConfig * self, const KfgSettings * ks,
2122     const char * ncbi_home)
2123 {
2124     size_t num_read = 0;
2125     size_t remaining = 0;
2126     char buf [ PATH_MAX ] = "";
2127 
2128     if ( KConfigRead ( self, "NCBI_HOME", 0,
2129             buf, sizeof buf, & num_read, & remaining) == 0 )
2130     {
2131         DBGMSG( DBG_KFG, DBG_FLAG ( DBG_KFG ),
2132             ( "KFG: NCBI_HOME='%.*s'\n", num_read, buf ) );
2133     }
2134     else {
2135         if ( ncbi_home == NULL ) {
2136             if ( ks -> envrNcbiHome != NULL ) {
2137                 ncbi_home = ks -> envrNcbiHome;
2138             }
2139             else {
2140                 ncbi_home = ks -> dfltNcbiHome;
2141             }
2142         }
2143 
2144         update_node ( self, "NCBI_HOME", ncbi_home, false );
2145 
2146         DBGMSG ( DBG_KFG, DBG_FLAG ( DBG_KFG ),
2147             ( "KFG: NCBI_HOME     was set to '%s'\n", ncbi_home ) );
2148     }
2149 }
2150 
2151 static
_KConfigSetNcbiSettings(KConfig * self,const KfgSettings * ks,const char * ncbi_settings)2152 void _KConfigSetNcbiSettings ( KConfig * self, const KfgSettings * ks,
2153     const char * ncbi_settings )
2154 {
2155     size_t num_read = 0;
2156     size_t remaining = 0;
2157     char buf [ PATH_MAX ] = "";
2158 
2159     if ( KConfigRead ( self, "NCBI_SETTINGS", 0,
2160             buf, sizeof buf, & num_read, & remaining) == 0 )
2161     {
2162         DBGMSG( DBG_KFG, DBG_FLAG ( DBG_KFG ),
2163             ( "KFG: NCBI_SETTINGS='%.*s'\n", num_read, buf ) );
2164     }
2165     else {
2166         if ( ncbi_settings == NULL ) {
2167             if ( ks -> envrNcbiSettings [ 0 ] != '\0' ) {
2168                 ncbi_settings = ks -> envrNcbiSettings;
2169             }
2170             else {
2171                 ncbi_settings = ks -> dfltNcbiSettings;
2172             }
2173         }
2174 
2175         update_node ( self, "NCBI_SETTINGS", ncbi_settings, false );
2176         DBGMSG ( DBG_KFG, DBG_FLAG ( DBG_KFG ),
2177             ( "KFG: NCBI_SETTINGS was set to '%s'\n", ncbi_settings ) );
2178     }
2179 }
2180 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ KfgSettings ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
2181 
2182 static
WriteDirtyNode(BSTNode * n,void * data)2183 bool CC WriteDirtyNode ( BSTNode *n, void *data )
2184 {
2185     KConfigNode *self = ( KConfigNode * ) n;
2186     PrintBuff *pb = data;
2187 
2188     if ( self -> dirty
2189         || ( self -> came_from != NULL && self -> came_from -> is_magic_file
2190              && ! self -> internal ) )
2191     {
2192         if ( KConfigNodePrintPath ( self, pb ) )
2193             return true;
2194 
2195         if ( PrintBuffPrint ( pb, " = " ) != 0 )
2196             return true;
2197 
2198         if ( PrintBuffPrintQuoted ( pb, &self->value ) != 0 )
2199             return true;
2200 
2201         if ( PrintBuffPrint ( pb, "\n" ) != 0 )
2202             return true;
2203     }
2204 
2205     return BSTreeDoUntil ( & self -> children, false, WriteDirtyNode, pb );
2206 }
2207 
2208 static
UnsetDirtyNode(BSTNode * n,void * data)2209 void CC UnsetDirtyNode ( BSTNode *n, void *data )
2210 {
2211     KConfigNode *self = ( KConfigNode * ) n;
2212 
2213     if ( self -> dirty )
2214         self -> dirty = false;
2215 
2216     BSTreeForEach ( & self -> children, false, UnsetDirtyNode, data );
2217 }
2218 
2219 static
path_to_magic_file(const KConfig * self,char * path,size_t buffer_size,size_t * path_size)2220 rc_t path_to_magic_file ( const KConfig *self, char *path, size_t buffer_size, size_t *path_size )
2221 {
2222     const KConfigNode *node;
2223     rc_t rc = KConfigOpenNodeRead ( self, & node, "NCBI_SETTINGS" );
2224 
2225     if ( rc == 0 )
2226     {
2227         size_t num_read, remaining;
2228         rc = KConfigNodeRead ( node, 0, path, buffer_size - 1, & num_read, & remaining );
2229 
2230         if ( rc == 0 && remaining != 0 )
2231            rc = RC ( rcKFG, rcNode, rcReading, rcBuffer, rcInsufficient );
2232 
2233         path[num_read] = '\0';
2234 
2235         KConfigNodeRelease ( node );
2236     }
2237     return rc;
2238 }
2239 
2240 /* Commit
2241  *  commits changes to user's private configuration file
2242  */
KConfigCommit(KConfig * self)2243 LIB_EXPORT rc_t CC KConfigCommit ( KConfig *self )
2244 {
2245     rc_t rc;
2246     size_t path_size = 0;
2247     char magic_file_path [ 4096 ];
2248 
2249     if ( self == NULL )
2250         return RC ( rcKFG, rcData, rcCommitting, rcSelf, rcNull );
2251 
2252     /* Must only commit dirty nodes*/
2253     if ( ! self -> dirty )
2254         return 0;
2255 
2256     rc = path_to_magic_file ( self, magic_file_path, sizeof magic_file_path, & path_size );
2257     if ( rc == 0 )
2258     {
2259         char tmp_file_path [ 4096 ];
2260 
2261         if ( ! MayICommitTo ( self, magic_file_path, path_size ) ) {
2262             DBGMSG ( DBG_KFG, DBG_FLAG ( DBG_KFG ), (
2263                 "KFG: User Settings Are Disables: Skipped KConfigCommit\n" ) );
2264             return RC ( rcKFG, rcData, rcCommitting, rcSelf, rcReadonly );
2265         }
2266 
2267         DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG),
2268             ( "KFG: Committing to '%s'\n", magic_file_path ) );
2269         rc = string_printf ( tmp_file_path, sizeof tmp_file_path, NULL, "%s.tmp", magic_file_path );
2270         if ( rc == 0 )
2271         {
2272             KDirectory *dir;
2273 
2274             /* get current directory */
2275             rc = KDirectoryNativeDir ( & dir );
2276             if ( rc == 0 )
2277             {
2278                 KFile *tmp;
2279 
2280                 /* create temp magic file */
2281                 rc = KDirectoryCreateFile ( dir, & tmp, false, 0600, kcmInit | kcmParents, "%s", tmp_file_path );
2282 
2283                 if ( rc == 0 )
2284                 {
2285                     PrintBuff pb;
2286                     PrintBuffInit ( & pb, tmp );
2287 
2288                     /* issue warning */
2289                     rc = PrintBuffPrint ( & pb, "## auto-generated configuration file - DO NOT EDIT ##\n\n" );
2290                     if ( rc == 0 )
2291                     {
2292                         /* flush nodes to file */
2293                         if ( BSTreeDoUntil ( & self -> tree, false, WriteDirtyNode, & pb ) )
2294                             /* failure */
2295                             rc = pb . rc;
2296                         else
2297                             rc = PrintBuffFlush ( & pb );
2298                     }
2299 
2300                     KFileRelease ( tmp );
2301 
2302                     if ( rc == 0 )
2303                     {
2304                         /* Rename file */
2305                         rc = KDirectoryRename ( dir, true, tmp_file_path, magic_file_path  );
2306                         if ( rc == 0 )
2307                         {
2308                             /* clear dirty flags */
2309                             BSTreeForEach (  & self -> tree, false, UnsetDirtyNode, & pb);
2310 
2311                             self -> dirty = false;
2312                         }
2313                     }
2314 
2315                     if ( rc != 0 )
2316                         KDirectoryRemove ( dir, true, "%s", tmp_file_path );
2317                 }
2318 
2319                 /* release dir */
2320                 KDirectoryRelease ( dir );
2321             }
2322         }
2323     }
2324     return rc;
2325 }
2326 
2327 static
record_magic_path(KConfig * self,const KDirectory * dir,const char * path,size_t sz)2328 rc_t record_magic_path ( KConfig *self, const KDirectory *dir, const char *path, size_t sz )
2329 {
2330     char buff [ 4096 ];
2331     rc_t rc = KDirectoryResolvePath ( dir, true, buff, sizeof buff, "%.*s", ( int ) sz, path );
2332     if ( rc == 0 )
2333     {
2334         char *magic_file_path;
2335         sz = string_size ( buff );
2336         magic_file_path = malloc ( sz + 1 );
2337         if ( magic_file_path == NULL )
2338             rc = RC ( rcKFG, rcMgr, rcLoading, rcMemory, rcExhausted );
2339         else
2340         {
2341             free ( (void*) self -> magic_file_path );
2342             self -> magic_file_path = magic_file_path;
2343             self -> magic_file_path_size = sz;
2344             memmove ( magic_file_path, buff, sz + 1 );
2345         }
2346     }
2347 
2348     return rc;
2349 }
2350 
2351 
2352 static
make_include_path(KConfigIncluded ** p,const KDirectory * dir,const char * path,size_t sz,bool is_magic)2353 rc_t make_include_path ( KConfigIncluded **p, const KDirectory *dir, const char *path, size_t sz, bool is_magic )
2354 {
2355     char buff [ 4096 ];
2356     rc_t rc = KDirectoryResolvePath ( dir, true, buff, sizeof buff, "%.*s", ( int ) sz, path );
2357     if ( rc == 0 )
2358     {
2359         KConfigIncluded *include;
2360         sz = string_size ( buff );
2361         include = malloc ( sizeof * include + sz );
2362         if ( include == NULL )
2363             rc = RC ( rcKFG, rcMgr, rcLoading, rcMemory, rcExhausted );
2364         else
2365         {
2366             include -> is_magic_file = is_magic;
2367             string_copy ( include -> path, sz + sizeof include -> path, buff, sz );
2368             * p = include;
2369             return 0;
2370         }
2371     }
2372     * p = NULL;
2373     return rc;
2374 }
2375 
2376 
2377 static
load_from_file_path(KConfig * self,const KDirectory * dir,const char * path,size_t sz,bool is_magic)2378 bool load_from_file_path ( KConfig *self, const KDirectory *dir, const char *path, size_t sz, bool is_magic )
2379 {
2380     rc_t rc;
2381     const KFile *cfg_file;
2382 
2383     /* record magic file path, regardless of whether it exists as a file */
2384     if ( is_magic )
2385         record_magic_path ( self, dir, path, sz );
2386 
2387     DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: try to load from file '%.*s'\n", (int)sz, path ) );
2388     rc = KDirectoryOpenFileRead ( dir, & cfg_file, "%.*s", ( int ) sz, path );
2389     if ( rc == 0 )
2390     {
2391         KConfigIncluded *include;
2392         rc = make_include_path ( & include, dir, path, sz, is_magic );
2393         if ( rc == 0 )
2394         {
2395             BSTNode *existing;
2396             if ( BSTreeInsertUnique ( & self -> included, & include -> n, & existing, KConfigIncludedSort ) != 0 )
2397                 free ( include );
2398             else
2399             {
2400                 self -> current_file = include;
2401                 rc = KConfigLoadFile ( self, include -> path, cfg_file );
2402                 self -> current_file = NULL;
2403                 if ( rc != 0 )
2404                 {
2405                     BSTreeUnlink ( & self -> included, & include -> n );
2406                     free ( include );
2407                 }
2408             }
2409         }
2410 
2411         KFileRelease ( cfg_file );
2412     }
2413     return ( rc == 0 ) ? true : false;
2414 }
2415 
2416 typedef struct scan_config_path_data scan_config_path_data;
2417 struct scan_config_path_data
2418 {
2419     KConfig *self;
2420     bool loaded;
2421 };
2422 
2423 static
scan_config_path(const KDirectory * dir,uint32_t type,const char * name,void * data)2424 rc_t CC scan_config_path ( const KDirectory *dir, uint32_t type, const char *name, void *data )
2425 {
2426     scan_config_path_data * pb = data;
2427     switch ( type )
2428     {
2429     case kptFile:
2430     case kptFile | kptAlias:
2431     {
2432         size_t sz = string_size ( name );
2433         if ( sz >= 5 && strcase_cmp ( & name [ sz - 4 ], 4, ".kfg", 4, 4 ) == 0 )
2434             pb -> loaded |= load_from_file_path ( pb -> self, dir, name, sz, false );
2435 
2436         break;
2437     }}
2438 
2439     return 0;
2440 }
2441 
2442 static
scan_config_dir(KConfig * self,const KDirectory * dir)2443 bool scan_config_dir ( KConfig *self, const KDirectory *dir )
2444 {
2445     scan_config_path_data pb;
2446 
2447     pb . self = self;
2448     pb . loaded = false;
2449 
2450     KDirectoryVisit_v1 ( dir, false, scan_config_path, & pb, "." );
2451 
2452     return pb . loaded;
2453 }
2454 
2455 static
load_from_dir_path(KConfig * self,const KDirectory * dir,const char * path,size_t sz)2456 bool load_from_dir_path ( KConfig *self, const KDirectory *dir, const char *path, size_t sz )
2457 {
2458     bool loaded = false;
2459     const KDirectory *cfg_dir;
2460     rc_t rc = KDirectoryOpenDirRead ( dir, & cfg_dir, false, "%.*s", ( uint32_t ) sz, path );
2461     if ( rc == 0 )
2462     {
2463         DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: try to load from directory '%.*s'\n", (int)sz, path ) );
2464         loaded = scan_config_dir ( self, cfg_dir );
2465         KDirectoryRelease ( cfg_dir );
2466     }
2467     return loaded;
2468 }
2469 
2470 static
load_from_path(KConfig * self,const KDirectory * dir,const char * path,size_t sz)2471 bool load_from_path ( KConfig *self, const KDirectory * dir, const char *path, size_t sz )
2472 {
2473     bool loaded = false;
2474     const char *naughty = string_chr ( path, sz, '%' );
2475     if ( naughty == NULL && sz != 0 )
2476     {
2477         DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: try to load from path '%.*s'\n", (int)sz, path ) );
2478         switch ( KDirectoryPathType ( dir, "%.*s", ( int ) sz, path ) & ~ kptAlias )
2479         {
2480         case kptFile:
2481             loaded = load_from_file_path ( self, dir, path, sz, false );
2482             break;
2483         case kptDir:
2484             loaded = load_from_dir_path ( self, dir, path, sz );
2485             break;
2486         }
2487     }
2488     return loaded;
2489 }
2490 
2491 static
load_from_path_list(KConfig * self,const KDirectory * dir,const char * path)2492 bool load_from_path_list ( KConfig *self, const KDirectory *dir, const char *path )
2493 {
2494     bool loaded = false;
2495     const char *end = path + string_size ( path );
2496     while ( path < end )
2497     {
2498         const char *sep = string_chr ( path, end - path, ':' );
2499         if ( sep == NULL )
2500             sep = end;
2501         if ( load_from_path ( self, dir, path, sep - path ) )
2502             loaded = true;
2503         path = sep + 1;
2504     }
2505     return loaded;
2506 }
2507 
2508 static
load_from_env_variable(KConfig * self,const KDirectory * dir)2509 bool load_from_env_variable ( KConfig *self, const KDirectory *dir )
2510 {
2511     const char * env_list [] =
2512     {
2513         "KLIB_CONFIG",
2514         "VDB_CONFIG",
2515         "VDBCONFIG"
2516     };
2517 
2518     int i;
2519     bool loaded = false;
2520     for ( i = 0; ! loaded && i < sizeof env_list / sizeof env_list [ 0 ]; ++ i )
2521     {
2522         const char *eval = getenv ( env_list [ i ] );
2523         DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: try to load from env. var '%s'\n", env_list[ i ] ) );
2524         if ( eval != NULL && eval [ 0 ] != 0 )
2525         {
2526             /* rc_t rc = 0; */
2527             DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: try to load from env. var '%s'\n", eval ) );
2528             /* rc = */ KConfigAppendToLoadPath(self, eval);
2529             loaded = load_from_path_list ( self, dir, eval );
2530             if ( loaded )
2531                 DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: found from env. var '%s'\n", eval ) );
2532         }
2533     }
2534 
2535     return loaded;
2536 }
2537 
2538 static
load_env_variable_rc(KConfig * self,const KDirectory * dir,bool * loaded)2539 rc_t load_env_variable_rc ( KConfig *self, const KDirectory *dir, bool *loaded )
2540 {
2541     const char * env_list [] =
2542     {
2543         "NCBI_VDB_CONFIG"
2544     };
2545 
2546     int i;
2547     rc_t rc;
2548 
2549     * loaded = false;
2550 
2551     for ( i = 0; ! * loaded && i < sizeof env_list / sizeof env_list [ 0 ]; ++ i )
2552     {
2553         const char *eval = getenv ( env_list [ i ] );
2554         DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: try to load from env. var '%s'\n", env_list[ i ] ) );
2555         if ( eval == NULL || eval [ 0 ] == 0 )
2556             return 0;
2557 
2558         DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: try to load from env. var '%s'\n", eval ) );
2559         rc = KConfigAppendToLoadPath(self, eval);
2560         if ( rc != 0 )
2561             return rc;
2562 
2563         * loaded = load_from_path_list ( self, dir, eval );
2564         if ( * loaded )
2565             DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: found from env. var '%s'\n", eval ) );
2566         else
2567             return RC ( rcKFG, rcFile, rcListing, rcEnvironment, rcEmpty );
2568 
2569     }
2570 
2571     return 0;
2572 }
2573 
2574 static
load_from_std_location(KConfig * self,const KDirectory * dir)2575 bool load_from_std_location ( KConfig *self, const KDirectory *dir )
2576 {
2577     const char * std_locs [] =
2578     {
2579 #if ! WINDOWS
2580         "/usr/local" "/etc/ncbi",
2581 #else
2582         "/c/ncbi",
2583 #endif
2584     };
2585 
2586     int i;
2587     bool loaded = false;
2588 
2589     const char* NCBI_VDB_NO_ETC_NCBI_KFG = getenv("NCBI_VDB_NO_ETC_NCBI_KFG");
2590     if (NCBI_VDB_NO_ETC_NCBI_KFG != NULL &&
2591         NCBI_VDB_NO_ETC_NCBI_KFG[0] != '\0')
2592     {
2593         DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG),
2594             ("KFG: load from std. location /etc/ncbi is disabled. "
2595                 "NCBI_VDB_NO_ETC_NCBI_KFG='%s'\n", NCBI_VDB_NO_ETC_NCBI_KFG));
2596         return loaded;
2597     }
2598 
2599     for ( i = 0; ! loaded && i < sizeof std_locs / sizeof std_locs [ 0 ]; ++ i )
2600     {
2601         DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: try to load from std. location '%s'\n", std_locs[ i ] ) );
2602         /* rc = */ KConfigAppendToLoadPath(self, std_locs [ i ]);
2603         loaded = load_from_path ( self, dir,
2604             std_locs [ i ], string_size ( std_locs [ i ] ));
2605     }
2606     if ( loaded )
2607         DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: found from std. location\n" ) );
2608     return loaded;
2609 }
2610 
2611 static
load_from_fs_location(KConfig * self,const char * confdir)2612 bool load_from_fs_location ( KConfig *self, const char *confdir )
2613 {
2614     bool loaded = false;
2615     KDyld *dyld;
2616     rc_t rc = KDyldMake ( & dyld );
2617     if ( rc == 0 )
2618     {
2619         const KDirectory *dir;
2620         rc = find_home_directory ( dyld, & dir, false );
2621         if ( rc == 0 )
2622         {
2623             char resolved[PATH_MAX + 1];
2624             assert ( confdir );
2625             DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG),
2626                 ( "KFG: try to load from dyn. loader %s\n", confdir ) );
2627 
2628 /* N.B. Duplication of ResolvePath here and in load_from_dir_path ? */
2629             if (KDirectoryResolvePath
2630                     (dir, true, resolved, sizeof resolved, confdir) == 0)
2631             {
2632                 rc = KConfigAppendToLoadPath(self, resolved);
2633             }
2634             if ((loaded = load_from_dir_path(self, dir, confdir,
2635                                        string_measure ( confdir, NULL ))))
2636                 DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG),
2637                     ( "KFG: found from dyn. loader %s\n", confdir ) );
2638             KDirectoryRelease ( dir );
2639         }
2640         KDyldRelease ( dyld );
2641     }
2642     return loaded;
2643 }
2644 
load_from_default_string(KConfig * self)2645 static bool load_from_default_string(KConfig *self) {
2646     DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KFG: loading from default string\n"));
2647     return parse_file(self,
2648         "enbedded default configuration string", default_kfg) == 0;
2649 }
2650 
KConfigGetLoadPath(const KConfig * self,const char ** path)2651 LIB_EXPORT rc_t CC KConfigGetLoadPath ( const KConfig *self,
2652     const char **path )
2653 {
2654     if (self == NULL) {
2655         return RC ( rcKFG, rcPath, rcListing, rcSelf, rcNull );
2656     }
2657 
2658     if (path == NULL) {
2659         return RC ( rcKFG, rcPath, rcListing, rcParam, rcNull );
2660     }
2661 
2662     *path = self->load_path;
2663     return 0;
2664 }
2665 
2666 static
load_user_settings(KConfig * self,const KDirectory * dir,const char * path)2667 bool load_user_settings
2668     ( KConfig * self, const KDirectory * dir, const char * path )
2669 {
2670     return load_from_file_path
2671         (self, dir, path, string_measure ( path, NULL ), true );
2672 }
2673 
2674 static
load_from_home(KConfig * self,const KDirectory * dir,const KfgSettings * ks,char * ncbi_settings,size_t ncbi_settings_size)2675 bool load_from_home ( KConfig * self, const KDirectory * dir,
2676     const KfgSettings * ks, char * ncbi_settings, size_t ncbi_settings_size)
2677 {
2678     char ncbi_home [ PATH_MAX ] = "";
2679 
2680     DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: checking NCBI_HOME\n" ) );
2681 
2682     if ( _KConfigGetNcbiHome ( self, ks, ncbi_home, sizeof ncbi_home ) != 0 )
2683     {
2684         DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG),
2685             ("KFG: cannot read NCBI_HOME from configuration\n"));
2686         return false;
2687     }
2688     else {
2689         bool loaded =
2690             load_from_path ( self, dir, ncbi_home, string_size ( ncbi_home ) );
2691 
2692         if ( loaded )
2693         {
2694             DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG),
2695                 ( "KFG: found from '%s'\n", ncbi_home ) );
2696         }
2697 
2698         _KConfigGetNcbiSettings
2699             ( self, ks, ncbi_settings, ncbi_settings_size, NULL );
2700 
2701         if ( load_user_settings ( self, dir, ncbi_settings ))
2702             loaded = true;
2703 
2704         _KConfigSetNcbiHome    ( self, ks, ncbi_home );
2705         _KConfigSetNcbiSettings( self, ks, ncbi_settings );
2706 
2707         return loaded;
2708     }
2709 }
2710 
2711 static
load_config_files(KConfig * self,const KDirectory * dir,const KfgSettings * ks,bool * loaded_from_dir)2712 rc_t load_config_files ( KConfig * self,
2713     const KDirectory * dir, const KfgSettings * ks, bool * loaded_from_dir )
2714 {
2715     rc_t rc;
2716     bool loaded;
2717     KDirectory * wd;
2718 
2719     char ncbi_settings [ PATH_MAX ] = "";
2720 
2721     assert ( loaded_from_dir );
2722     * loaded_from_dir = false;
2723 
2724     /* if user supplied a starting point, try that */
2725     if ( dir != NULL )
2726     {
2727         char path [ PATH_MAX ] = "";
2728         rc = KDirectoryResolvePath ( dir, true, path, sizeof path, "." );
2729         DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG),
2730             ( "KFG: try load from supplied directory '%s'\n", path ) );
2731 
2732         loaded = scan_config_dir ( self, dir );
2733         if ( loaded )
2734             DBGMSG( DBG_KFG, DBG_FLAG(DBG_KFG), ( "KFG: found from supplied directory\n" ) );
2735 
2736         rc = _KConfigGetNcbiSettings
2737             ( self, ks, ncbi_settings, sizeof ncbi_settings, path );
2738         if (rc == 0) {
2739             if ( load_user_settings ( self, dir, ncbi_settings ))
2740                 loaded = true;
2741         }
2742 
2743         if ( loaded ) {
2744             _KConfigSetNcbiHome    ( self, ks, path );
2745             _KConfigSetNcbiSettings( self, ks, ncbi_settings );
2746             * loaded_from_dir = true;
2747             return rc;
2748         }
2749     }
2750 
2751     /* open up the native directory */
2752     rc = KDirectoryNativeDir ( & wd );
2753     if ( rc != 0 )
2754         return rc;
2755 
2756     /* try to load from environment variable */
2757     rc = load_env_variable_rc ( self, wd, & loaded );
2758     if ( rc != 0 )
2759         return rc;
2760     if ( loaded )
2761         return 0;
2762 
2763     /* load from the other environment variables */
2764     loaded = load_from_env_variable ( self, wd );
2765 
2766     /* try to load from standard locations */
2767     if ( ! loaded )
2768         loaded = load_from_std_location ( self, wd );
2769 
2770     /* check for config as the result of a user install
2771        i.e. not an admin installation */
2772     if ( ! loaded )
2773         loaded = load_from_fs_location ( self, "../etc/ncbi" );
2774     if ( ! loaded )
2775         loaded = load_from_fs_location ( self, "ncbi" );
2776 
2777     if ( ! loaded )
2778         loaded = load_from_default_string ( self );
2779 
2780     if ( ! s_disable_user_settings )
2781         loaded |= load_from_home
2782             ( self, wd, ks, ncbi_settings, sizeof ncbi_settings );
2783     else {
2784         DBGMSG ( DBG_KFG, DBG_FLAG ( DBG_KFG ), (
2785             "KFG: User Settings Are Disables: Skipped Load KFG From Home\n" ) );
2786         _KConfigSetNcbiHome    ( self, ks, NULL );
2787         _KConfigSetNcbiSettings( self, ks, NULL );
2788     }
2789 
2790     KDirectoryRelease ( wd );
2791 
2792     if (self->load_path) {
2793         char* tmp = NULL;
2794         self->load_path_sz_tmp = string_size(self->load_path) + 1;
2795         tmp = realloc(self->load_path, self->load_path_sz_tmp);
2796         if (tmp) {
2797             self->load_path = tmp;
2798         }
2799     }
2800 
2801     return 0;
2802 }
2803 
2804 static
add_predefined_nodes(KConfig * self,const char * appname)2805 void add_predefined_nodes ( KConfig * self, const char * appname )
2806 {
2807     size_t bytes;
2808     char buf [ 4096 ];
2809     const char *value;
2810 
2811     KDirectory *cwd;
2812     const KDirectory *dir;
2813 
2814 #if ! WINDOWS
2815     struct utsname name;
2816 #endif
2817 
2818     /* Path to libkfg.so */
2819     KDyld *dyld;
2820     rc_t rc = KDyldMake ( & dyld );
2821     if ( rc == 0 )
2822     {
2823         rc = find_home_directory ( dyld, & dir, false );
2824         if ( rc == 0 )
2825         {
2826             KDirectoryResolvePath ( dir, true, buf, sizeof buf, "." );
2827             KDirectoryRelease ( dir );
2828         }
2829         KDyldRelease ( dyld );
2830     }
2831     update_node ( self, "vdb/lib/paths/kfg", rc == 0 ? buf : "", true );
2832 
2833     /* Architecture */
2834 #if ! WINDOWS
2835     if (uname(&name) >= 0)
2836         update_node(self, "kfg/arch/name", name.nodename, true);
2837     else
2838 #endif
2839         update_node ( self, "kfg/arch/name", "", true);
2840 
2841     string_printf(buf, sizeof(buf), &bytes, "%u", _ARCH_BITS);
2842     update_node ( self, "kfg/arch/bits", buf, true );
2843 
2844     /* *OS */
2845 #if LINUX
2846     #define OS "linux"
2847 #elif MAC
2848     #define OS "mac"
2849 #elif WINDOWS
2850     #define OS "win"
2851 #elif SUN
2852     #define OS "sun"
2853 #elif BSD
2854     #define OS "bsd"
2855 #else
2856     #error unrecognized OS
2857 #endif
2858     update_node ( self, "OS", OS, true );
2859 #undef OS
2860 
2861 #if 0
2862     /* BUILD_LINKAGE */
2863 #if _STATIC
2864     #define BUILD_LINKAGE "STATIC"
2865 #else
2866     #define BUILD_LINKAGE "DYNAMIC"
2867 #endif
2868     update_node ( self, "BUILD_LINKAGE", BUILD_LINKAGE, true );
2869 #undef BUILD_LINKAGE
2870 #endif
2871 
2872     /* BUILD */
2873 #if _PROFILING
2874     #define BUILD "PROFILE"
2875 #elif _DEBUGGING
2876     #define BUILD "DEBUG"
2877 #else
2878     #define BUILD "RELEASE"
2879 #endif
2880     update_node(self, "BUILD", BUILD, true );
2881 #undef BUILD
2882 
2883     cwd = NULL;
2884 
2885     /* PWD */
2886     rc = KDirectoryNativeDir ( & cwd );
2887     if ( rc == 0 )
2888         rc = KDirectoryResolvePath ( cwd, true, buf, sizeof buf, "." );
2889     update_node(self, "PWD", rc == 0 ? buf : "", true );
2890 
2891     /* APPPATH */
2892     if ( appname != NULL && rc == 0 )
2893     {
2894         bytes = string_size ( appname );
2895         value = string_rchr ( appname, bytes, '/' );
2896         if ( value == NULL )
2897             value = string_rchr ( appname, bytes, '\\' );
2898         if ( value != NULL )
2899             bytes = appname + bytes - value;
2900         rc = KDirectoryResolvePath ( cwd, true, buf, sizeof buf, "%s", appname);
2901         if ( rc == 0 && bytes != 0 )
2902             buf [ string_size(buf) - bytes ] = 0;
2903         update_node(self, "APPPATH", rc == 0 ? buf : "", true );
2904     }
2905 
2906     /* APPNAME */
2907     rc = LogAppName(buf, sizeof(buf), &bytes);
2908     if ( rc == 0 )
2909         buf [ bytes ] = 0;
2910     update_node(self, "APPNAME", rc == 0 ? buf : "", true );
2911 
2912     /* Environment variables */
2913     /* some of the variables may be undefined, create nodes with empty values for them */
2914 #define DEFINE_ENV(name)                                         \
2915     value=getenv(name);                                          \
2916     update_node(self, name, value == NULL ? "" : value, true )
2917 
2918     DEFINE_ENV("HOST");
2919     DEFINE_ENV("USER");
2920 
2921     value = NULL;
2922 #if WINDOWS
2923     value = getenv ( "USERPROFILE" );
2924 #endif
2925     if ( value == NULL ) {
2926         value = getenv ( "HOME" );
2927     }
2928 
2929     if (value == NULL)
2930     {
2931         update_node(self, "HOME", "", true );
2932     }
2933     else
2934     {
2935         rc = KDirectoryResolvePath(cwd, true, buf, sizeof(buf), "%s", value);
2936         if (rc == 0)
2937         {
2938             update_node(self, "HOME", buf, true );
2939         }
2940         else
2941             LOGERR (klogErr, rc, "Unable to create a config item for $HOME");
2942     }
2943 
2944     DEFINE_ENV("VDB_ROOT");
2945     DEFINE_ENV("VDB_CONFIG");
2946 #undef DEFINE_ENV
2947 
2948     KDirectoryRelease ( cwd );
2949 }
2950 
2951 #if WINDOWS
2952 
isexistingdir(const char * path,const KDirectory * dir)2953 static isexistingdir(const char *path, const KDirectory *dir) {
2954     return (KDirectoryPathType(dir, path) & ~kptAlias) == kptDir;
2955 }
2956 
isletter(char c)2957 static bool isletter(char c) {
2958     return ((c >= 'A' && c <= 'Z') ||
2959             (c >= 'a' && c <= 'z'));
2960 }
2961 
sls(const char * b,size_t sz)2962 static bool sls(const char *b, size_t sz) {
2963     if (b == NULL || sz < 3) {
2964         return false;
2965     }
2966 
2967     return (b[0] == '/' && isletter(b[1]) && b[2] == '/');
2968 }
2969 
_DetectRepeatedDrives(const char * buffer,size_t bsize,size_t * fixed,const KDirectory * dir)2970 static bool _DetectRepeatedDrives(const char *buffer,
2971     size_t bsize, size_t *fixed, const KDirectory *dir)
2972 {
2973     assert(fixed);
2974 
2975     if (!sls(buffer, bsize)) {
2976         return false;
2977     }
2978 
2979     if (!sls(buffer + 2, bsize - 2)) {
2980         return false;
2981     }
2982 
2983     if (isexistingdir(buffer, dir)) {
2984         return false;
2985     }
2986 
2987     *fixed = 2;
2988 
2989     while (bsize > *fixed + 2) {
2990         if (isexistingdir(buffer + *fixed, dir)) {
2991             break;
2992         }
2993 
2994         if (!sls(buffer + *fixed + 2, bsize - *fixed - 2)) {
2995             break;
2996         }
2997 
2998         *fixed += 2;
2999     }
3000 
3001     return true;
3002 }
3003 
_KConfigNodeFixRepeatedDrives(KConfigNode * self,bool * updated,const KDirectory * dir)3004 static rc_t _KConfigNodeFixRepeatedDrives(KConfigNode *self,
3005     bool *updated, const KDirectory *dir)
3006 {
3007     rc_t rc = 0;
3008 
3009     char buffer[PATH_MAX];
3010     size_t num_read = 0;
3011     size_t remaining = 0;
3012 
3013     assert(updated);
3014 
3015     rc = KConfigNodeRead(self, 0, buffer, sizeof buffer, &num_read, &remaining);
3016     if (rc == 0) {
3017         size_t fixed = 0;
3018         if (num_read < sizeof buffer) {
3019             buffer[num_read] = '\0';
3020         }
3021         if (_DetectRepeatedDrives(buffer, num_read, &fixed, dir)
3022             && fixed != 0 && fixed < num_read)
3023         {
3024             rc = KConfigNodeWrite(self, buffer + fixed, num_read - fixed);
3025             if (rc == 0) {
3026                 *updated = true;
3027             }
3028         }
3029     }
3030 
3031     return rc;
3032 }
3033 
_KConfigNodeFixChildRepeatedDrives(KConfigNode * self,const KDirectory * dir,bool * updated,const char * name,...)3034 static rc_t _KConfigNodeFixChildRepeatedDrives(KConfigNode *self,
3035     const KDirectory *dir, bool *updated, const char *name, ...)
3036 {
3037     rc_t rc = 0;
3038     KConfigNode *node = NULL;
3039 
3040     va_list args;
3041     va_start(args, name);
3042 
3043     rc = KConfigNodeVOpenNodeUpdate(self, &node, name, args);
3044     if (rc == 0) {
3045         rc_t rc = _KConfigNodeFixRepeatedDrives(node, updated, dir);
3046         KConfigNodeRelease(node);
3047     }
3048 
3049     va_end(args);
3050 
3051     return rc;
3052 }
3053 
_KConfigFixRepeatedDrives(KConfig * self,const KDirectory * pdir,bool * updated)3054 static rc_t _KConfigFixRepeatedDrives(KConfig *self,
3055     const KDirectory *pdir, bool *updated)
3056 {
3057     rc_t rc = 0;
3058     KDirectory * dir = ( KDirectory * ) pdir;
3059     KConfigNode *user = NULL;
3060     if (dir == NULL) {
3061         rc = KDirectoryNativeDir(&dir);
3062     }
3063     rc = KConfigOpenNodeUpdate(self, &user, "/repository/user");
3064     if (rc == 0) {
3065         _KConfigNodeFixChildRepeatedDrives(user, dir, updated, "default-path");
3066     }
3067     if (rc == 0) {
3068         uint32_t i = 0;
3069         uint32_t count = 0;
3070         KNamelist *categories = NULL;
3071         rc_t rc = KConfigNodeListChildren(user, &categories);
3072         if (rc == 0) {     /* main protected ... */
3073             rc = KNamelistCount(categories, &count);
3074         }
3075         for (i = 0; rc == 0 && i < count; ++i) {
3076             const char *nCategory = NULL;
3077             rc_t rc = KNamelistGet(categories, i, &nCategory);
3078             if (rc == 0) { /* main protected ... */
3079                 KConfigNode *category = NULL;
3080                 rc_t rc = KConfigNodeOpenNodeUpdate(user, &category, nCategory);
3081                 if (rc == 0) {
3082                     uint32_t i = 0;
3083                     uint32_t count = 0;
3084                     KNamelist *subcategories = NULL;
3085                     rc_t rc = KConfigNodeListChildren(category, &subcategories);
3086                     if (rc == 0) {     /* main protected ... */
3087                         rc = KNamelistCount(subcategories, &count);
3088                     }
3089                     for (i = 0; rc == 0 && i < count; ++i) {
3090                         const char *name = NULL;
3091                         rc_t rc = KNamelistGet(subcategories, i, &name);
3092                         if (rc == 0) {
3093                             _KConfigNodeFixChildRepeatedDrives(category,
3094                                 dir, updated, "%s/%s", name, "root");
3095                         }
3096                     }
3097                     RELEASE(KNamelist, subcategories);
3098                     RELEASE(KConfigNode, category);
3099                 }
3100             }
3101         }
3102         RELEASE(KNamelist, categories);
3103     }
3104     RELEASE(KConfigNode, user);
3105     if (pdir == NULL) {
3106         RELEASE(KDirectory, dir);
3107     }
3108     return rc;
3109 }
3110 
3111 #endif
3112 
3113 #if CAN_HAVE_CONTAINER_ID
_KConfigGetContainerGUID(KConfig * const self,bool * const updated)3114 static rc_t _KConfigGetContainerGUID(KConfig *const self, bool *const updated)
3115 {
3116     rc_t rc = 0;
3117     KConfigNode const *node = NULL;
3118     struct String *string = NULL;
3119 
3120     *updated = false;
3121     rc = KConfigOpenNodeRead(self, &node, IMAGE_GUID_KEY);
3122     if (rc) {
3123         LOGERR(klogDebug, rc, "no image guid");
3124         return 0; // nothing to do
3125     }
3126 
3127     rc = KConfigNodeReadString(node, &string);
3128     KConfigNodeRelease(node);
3129     if (rc == 0) {
3130         if (0 == KConfig_Get_GUID_Add_Container((char *)string->addr, string->size)) {
3131             KConfigNode *node = NULL;
3132             rc = KConfigOpenNodeUpdate(self, &node, "/LIBS/GUID");
3133             if (rc == 0) {
3134                 rc = KConfigNodeWrite(node, string->addr, string->size);
3135                 KConfigNodeRelease(node);
3136                 if (rc) {
3137                     LOGERR(klogErr, rc, "can't write guid value");
3138                 }
3139                 else {
3140                     *updated = true;
3141                 }
3142             }
3143             else {
3144                 LOGERR(klogErr, rc, "can't update guid node");
3145             }
3146         }
3147         free(string);
3148     }
3149     else {
3150         LOGERR(klogErr, rc, "can't read image guid value");
3151     }
3152     return rc;
3153 }
3154 #endif
3155 
StringRelease(const String * self)3156 static rc_t StringRelease(const String *self) {
3157     StringWhack(self);
3158     return 0;
3159 }
3160 
_KConfigUseWithExtFlatAlg(KConfig * self,bool * updated,const char * old_name,const char * new_name,const char * updated_name)3161 static rc_t _KConfigUseWithExtFlatAlg(KConfig * self, bool * updated,
3162     const char * old_name,
3163     const char * new_name,
3164     const char * updated_name)
3165 {
3166     rc_t rc = 0;
3167 
3168     String * result = NULL;
3169     size_t size = 0;
3170     bool newExists = false;
3171 
3172     assert(updated);
3173     *updated = false;
3174 
3175     rc = KConfigReadString(self, updated_name, &result);
3176     if (rc == 0) { /* was updated already */
3177         RELEASE(String, result);
3178         return rc;
3179     }
3180 
3181     rc = KConfigReadString(self, old_name, &result);
3182     if (rc != 0) /* Bad node was not found. Nothing to do. */
3183         return 0;
3184     assert(result);
3185     size = result->size;
3186     RELEASE(String, result);
3187     if (size == 0) /* Bad node is already empty. Nothing to do. */
3188         return 0;
3189 
3190     rc = KConfigReadString(self, new_name, &result);
3191     if (rc == 0) { /* Good node was found. */
3192         RELEASE(String, result);
3193         newExists = true;
3194     }
3195 
3196     /* Need to create new node. */
3197     if (!newExists)
3198         rc = KConfigWriteString(self, new_name, "sra");
3199 
3200     if (rc == 0) {
3201         /* Clear old node */
3202         rc = KConfigWriteString(self, old_name, "");
3203 
3204         if (rc == 0)
3205             rc = KConfigWriteString(self, updated_name, "updated");
3206 
3207         if (rc == 0)
3208             *updated = true;
3209     }
3210 
3211     return rc;
3212 }
3213 
_KConfigUsePileupAppWithExtFlatAlg(KConfig * self,bool * updated)3214 static rc_t _KConfigUsePileupAppWithExtFlatAlg(KConfig * self,
3215     bool * updated)
3216 {
3217     return _KConfigUseWithExtFlatAlg(self, updated,
3218         "/repository/user/main/public/apps/sraPileup/volumes/flat",
3219         "/repository/user/main/public/apps/sraPileup/volumes/withExtFlat",
3220         "/repository/user/main/public/apps/sraPileup/withExtFlat");
3221 }
3222 
_KConfigUseRealignAppWithExtFlatAlg(KConfig * self,bool * updated)3223 static rc_t _KConfigUseRealignAppWithExtFlatAlg(KConfig * self,
3224     bool * updated)
3225 {
3226     return _KConfigUseWithExtFlatAlg(self, updated,
3227         "/repository/user/main/public/apps/sraRealign/volumes/flat",
3228         "/repository/user/main/public/apps/sraRealign/volumes/withExtFlat",
3229         "/repository/user/main/public/apps/sraRealign/withExtFlat");
3230 }
3231 
3232 #if 0
3233 static rc_t _KConfigUpdateDefault( KConfig * self, bool * updated,
3234     const char * node_name,
3235     const char * node2_name,
3236     const char * old_value,
3237     const char * new_value,
3238     const char * updated_name )
3239 {
3240     rc_t rc = 0;
3241 
3242     String * result = NULL;
3243 
3244     String sOldValue;
3245 
3246     bool update1 = false, update2 = false;
3247 
3248     assert(node_name && old_value && new_value && updated_name);
3249 
3250     StringInitCString(&sOldValue, old_value);
3251 
3252     assert ( updated );
3253     * updated = false;
3254 
3255     rc = KConfigReadString ( self, updated_name, & result );
3256     if ( rc == 0 ) { /* was updated already */
3257         free ( result );
3258         return rc;
3259     }
3260 
3261     rc = KConfigReadString ( self, node_name, & result );
3262     if ( rc == 0 ) { /* when found: update just value = old-value */
3263         if ( StringEqual ( & sOldValue, result ) )
3264             update1 = * updated = true;
3265         free ( result );
3266         result = NULL;
3267     }
3268     else /* don't update when node did not exist */
3269         rc = 0;
3270 
3271     if (node2_name != NULL) {
3272         rc = KConfigReadString(self, node2_name, &result);
3273         if (rc == 0) { /* when found: update just value = old-value */
3274             if (StringEqual(&sOldValue, result))
3275                 update2 = * updated = true;
3276             free(result);
3277             result = NULL;
3278         }
3279         else /* don't update when node did not exist */
3280             rc = 0;
3281     }
3282 
3283     if ( * updated ) {
3284         assert ( rc == 0 );
3285         if (update1)
3286             rc = KConfigWriteString ( self, node_name, new_value);
3287         if (rc == 0 && update2)
3288             rc = KConfigWriteString(self, node2_name, new_value);
3289         if ( rc == 0 )
3290             rc = KConfigWriteString ( self, updated_name, "updated" );
3291     }
3292 
3293     return rc;
3294 }
3295 #endif
3296 
_KConfigLowerAscpRate(KConfig * self,bool * updated)3297 static rc_t _KConfigLowerAscpRate ( KConfig * self, bool * updated ) {
3298     return 0;
3299 /*
3300     return _KConfigUpdateDefault(self, updated,
3301         "/tools/ascp/max_rate", NULL, "1000m", "450m",
3302         "/tools/ascp/max_rate/450m");
3303 */
3304 }
3305 
_KConfigUseTraceCgi(KConfig * self,bool * updated)3306 static rc_t _KConfigUseTraceCgi(KConfig * self, bool * updated) {
3307     return 0;
3308 /*
3309     return _KConfigUpdateDefault(self, updated,
3310         "/repository/remote/main/CGI/resolver-cgi",
3311         "/repository/remote/protected/CGI/resolver-cgi",
3312         "https://www.ncbi.nlm.nih.gov/Traces/names/names.fcgi",
3313         RESOLVER_CGI,
3314         "/repository_remote/CGI/resolver-cgi/trace");
3315 */
3316 }
3317 
3318 /* create Accession as Directory repository when it does not exist */
_KConfigCheckAd(KConfig * self)3319 static rc_t _KConfigCheckAd(KConfig * self) {
3320     const KConfigNode * kfg = NULL;
3321     KConfigNode * flat = NULL;
3322 
3323     const char * name = "/repository/user/ad/public/apps/file/volumes/flat";
3324     rc_t rc = KConfigOpenNodeUpdate(self, &flat, name);
3325     if (rc == 0) {
3326         rc_t r2 = 0;
3327         char buffer[1] = "";
3328         size_t num_read = 0, remaining = 0;
3329         rc = KConfigNodeRead(flat, 0,
3330             buffer, sizeof buffer, &num_read, &remaining);
3331         /* fix invalid app: writing empty string will force to ignore it */
3332         if (rc == 0 && num_read == 1 && remaining == 0 && buffer[0] == '.')
3333             rc = KConfigNodeWrite(flat, "", 0);
3334         r2 = KConfigNodeRelease(flat);
3335         if (r2 != 0 && rc == 0)
3336             rc = r2;
3337     }
3338 
3339     if (rc == 0) {
3340         name = "/repository/user/ad/public/apps/file/volumes/flatAd";
3341         rc = KConfigOpenNodeRead(self, &kfg, name);
3342         if (rc != 0)
3343             rc = KConfigWriteString(self, name, ".");
3344         else
3345             rc = KConfigNodeRelease(kfg);
3346     }
3347 
3348     if (rc == 0) {
3349         name = "/repository/user/ad/public/apps/sra/volumes/sraAd";
3350         rc = KConfigOpenNodeRead(self, &kfg, name);
3351         if (rc != 0)
3352             rc = KConfigWriteString(self, name, ".");
3353         else
3354             rc = KConfigNodeRelease(kfg);
3355     }
3356 
3357     if (rc == 0) {
3358         name = "/repository/user/ad/public/apps/sraPileup/volumes/ad";
3359         rc = KConfigOpenNodeRead(self, &kfg, name);
3360         if (rc != 0)
3361             rc = KConfigWriteString(self, name, ".");
3362         else
3363             rc = KConfigNodeRelease(kfg);
3364     }
3365 
3366     if (rc == 0) {
3367         name = "/repository/user/ad/public/apps/sraRealign/volumes/ad";
3368         rc = KConfigOpenNodeRead(self, &kfg, name);
3369         if (rc != 0)
3370             rc = KConfigWriteString(self, name, ".");
3371         else
3372             rc = KConfigNodeRelease(kfg);
3373     }
3374 
3375     if (rc == 0) {
3376         name = "/repository/user/ad/public/apps/refseq/volumes/refseqAd";
3377         rc = KConfigOpenNodeRead(self, &kfg, name);
3378         if (rc != 0)
3379             rc = KConfigWriteString(self, name, ".");
3380         else
3381             rc = KConfigNodeRelease(kfg);
3382     }
3383 
3384     if (rc == 0) {
3385         name = "/repository/user/ad/public/apps/wgs/volumes/wgsAd";
3386         rc = KConfigOpenNodeRead(self, &kfg, name);
3387         if (rc != 0)
3388             rc = KConfigWriteString(self, name, ".");
3389         else
3390             rc = KConfigNodeRelease(kfg);
3391     }
3392 
3393     if (rc == 0) {
3394         name = "/repository/user/ad/public/root";
3395         rc = KConfigOpenNodeRead(self, &kfg, name);
3396         if (rc != 0)
3397             rc = KConfigWriteString(self, name, ".");
3398         else
3399             rc = KConfigNodeRelease(kfg);
3400     }
3401 
3402     return rc;
3403 }
3404 
3405 static
KConfigFill(KConfig * self,const KDirectory * cfgdir,const char * appname,bool local)3406 rc_t KConfigFill ( KConfig * self, const KDirectory * cfgdir,
3407     const char * appname, bool local )
3408 {
3409     KConfigNode * root;
3410     String empty;
3411     rc_t rc;
3412 
3413     CONST_STRING ( & empty, "" );
3414 
3415     rc = KConfigNodeMake ( & root, & empty );
3416     if (rc == 0)
3417     {
3418         bool loaded_from_dir = false;
3419 
3420         KfgSettings ks;
3421 
3422         KConfigInit ( self, root );
3423 
3424         add_predefined_nodes ( self, appname );
3425 
3426         _KConfigIniKfgSettings ( self, &ks );
3427 
3428         if ( ! self -> disableFileLoadOnKfgCreating )
3429             rc = load_config_files ( self, cfgdir, & ks, & loaded_from_dir );
3430 
3431         if ( rc == 0 ) {
3432          /* commit changes made to magic file nodes
3433             during parsing (e.g. fixed spelling of dbGaP names) */
3434             KConfigCommit ( self );
3435         }
3436     }
3437 
3438     return rc;
3439 }
3440 
3441 
3442 extern rc_t ReportKfg ( const ReportFuncs *f, uint32_t indent,
3443     uint32_t configNodesSkipCount, va_list args );
3444 
3445 /* "cfg" [ OUT ] - return parameter for mgr
3446    if ( "local" == true ) do not initialize G_kfg
3447    if ( cfgdir != NULL ) then initialize G_kfg. It is used in unit tests */
3448 static
KConfigMakeImpl(KConfig ** cfg,const KDirectory * cfgdir,bool local,bool disableFileLoadOnKfgCreating)3449 rc_t KConfigMakeImpl ( KConfig ** cfg, const KDirectory * cfgdir, bool local,
3450     bool disableFileLoadOnKfgCreating )
3451 {
3452     rc_t rc;
3453     static const char * appname = NULL;
3454 
3455     static bool latch;
3456     if ( ! latch )
3457     {
3458         appname = ReportInitConfig ( ReportKfg );
3459         latch = true;
3460     }
3461 
3462     if ( cfg == NULL )
3463         rc = RC ( rcKFG, rcMgr, rcCreating, rcParam, rcNull );
3464     else
3465     {
3466         KConfig * mgr = NULL;
3467 
3468         if ( cfgdir != NULL ) {
3469             /* local = true;
3470             ALWAYS create and/or return a singleton object. */
3471         }
3472 
3473         if ( ! local ) {
3474             if ( G_kfg . ptr ) { /* if already made, just attach */
3475                 rc = KConfigAddRef ( G_kfg.ptr );
3476                 if (rc == 0) {
3477                     * cfg = G_kfg . ptr;
3478                 }
3479                 return rc;
3480             }
3481         }
3482 
3483         mgr = calloc ( 1, sizeof * mgr );
3484         if ( mgr == NULL )
3485             rc = RC ( rcKFG, rcMgr, rcCreating, rcMemory, rcExhausted );
3486         else
3487         {
3488             mgr -> disableFileLoadOnKfgCreating = disableFileLoadOnKfgCreating;
3489             rc = KConfigFill (mgr, cfgdir, appname, local);
3490 
3491             mgr -> initialized = true;
3492 
3493 
3494             if ( rc == 0 ) {
3495                 rc_t rc = 0;
3496 
3497                 bool updated = false;
3498 
3499                 if ( ! s_disable_user_settings ) {
3500                     bool updatd2 = false;
3501 
3502                     rc = _KConfigLowerAscpRate ( mgr,  & updated );
3503                     if (rc == 0) {
3504                         rc = _KConfigUseTraceCgi(mgr, &updatd2);
3505                         updated |= updatd2;
3506                     }
3507 
3508                     if (rc == 0) {
3509                         rc = _KConfigUsePileupAppWithExtFlatAlg(mgr, &updatd2);
3510                         updated |= updatd2;
3511                     }
3512 
3513                     if (rc == 0) {
3514                         rc = _KConfigUseRealignAppWithExtFlatAlg(mgr, &updatd2);
3515                         updated |= updatd2;
3516                     }
3517 
3518                     if ( rc == 0 && updated ) {
3519                         KConfigCommit ( mgr ); /* keep if commit fails: */
3520                         updated = false;       /* ignore rc */
3521                     }
3522                 }
3523 
3524 #if WINDOWS /* VDB-1554: fix incorrect posix paths in configuration nodes */
3525                 rc = _KConfigFixRepeatedDrives ( mgr, cfgdir, & updated );
3526                 if ( rc == 0 && updated )
3527                     rc = KConfigCommit ( mgr );
3528 #endif
3529 #if CAN_HAVE_CONTAINER_ID
3530                 rc = _KConfigGetContainerGUID(mgr, &updated);
3531                 if ( rc == 0 && updated )
3532                     rc = KConfigCommit ( mgr );
3533 #endif
3534                 if ( rc == 0 )
3535                     _KConfigCheckAd ( mgr );
3536             }
3537 
3538             DBGMSG ( DBG_KFG, DBG_FLAG ( DBG_KFG ), ( "\n" ) );
3539 
3540             if ( rc == 0 )
3541             {
3542                 if ( local )
3543                 {
3544                     * cfg = mgr;
3545                 }
3546                 else
3547                 {
3548                     KConfig * prev = atomic_test_and_set_ptr ( & G_kfg, mgr, NULL );
3549                     if ( prev != NULL )
3550                     {
3551                         /* the global singleton was already instantiated: hand out that one */
3552                         rc = KConfigAddRef ( G_kfg.ptr );
3553                         if ( rc == 0 )
3554                         {
3555                             * cfg = G_kfg . ptr;
3556                         }
3557                         /* and we have to deallocate the object we just made! */
3558                         KConfigEmpty ( mgr );
3559                         free( ( void * ) mgr);
3560                     }
3561                     else
3562                     {
3563                         * cfg = mgr;
3564                     }
3565 
3566                 }
3567                 return rc;
3568             }
3569 
3570             KConfigWhack ( mgr );
3571         }
3572 
3573         * cfg = NULL;
3574     }
3575 
3576     return rc;
3577 }
3578 
3579 /* Make
3580  *  create a process-global configuration manager
3581  *
3582  *  "cfg" [ OUT ] - return parameter for mgr
3583  */
KConfigMake(KConfig ** cfg,const KDirectory * cfgdir)3584 LIB_EXPORT rc_t CC KConfigMake(KConfig **cfg, const KDirectory *cfgdir)
3585 {
3586     return KConfigMakeImpl(cfg, cfgdir, false, false);
3587 }
3588 
3589 /* call KConfigMake; do not initialize G_kfg */
3590 LIB_EXPORT
KConfigMakeLocal(KConfig ** cfg,const KDirectory * cfgdir)3591 rc_t CC KConfigMakeLocal(KConfig **cfg, const KDirectory *cfgdir)
3592 {
3593     return KConfigMakeImpl(cfg, cfgdir, true, false);
3594 }
3595 
3596 /* call KConfigMake; do not load any file except user settings ( optionally ) */
3597 LIB_EXPORT
KConfigMakeEmpty(KConfig ** cfg)3598 rc_t CC KConfigMakeEmpty ( KConfig ** cfg )
3599 {
3600     return KConfigMakeImpl ( cfg, NULL, false, true );
3601 }
3602 
3603 /*--------------------------------------------------------------------------
3604  * KNamelist
3605  */
3606 typedef struct KfgConfigNamelist KfgConfigNamelist;
3607 struct KfgConfigNamelist
3608 {
3609     KNamelist dad;
3610     size_t count;
3611     const char *namelist [ 1 ];
3612 };
3613 
3614 /* Whack
3615  */
3616 static
KfgConfigNamelistWhack(KfgConfigNamelist * self)3617 rc_t CC KfgConfigNamelistWhack ( KfgConfigNamelist *self )
3618 {
3619     free ( self );
3620     return 0;
3621 }
3622 
3623 /* Count
3624  */
3625 static
KfgConfigNamelistCount(const KfgConfigNamelist * self,uint32_t * count)3626 rc_t CC KfgConfigNamelistCount ( const KfgConfigNamelist *self,
3627 uint32_t *count )
3628 {
3629     * count = ( uint32_t ) self -> count;
3630     return 0;
3631 }
3632 
3633 /* Get
3634  */
3635 static
KfgConfigNamelistGet(const KfgConfigNamelist * self,uint32_t idx,const char ** name)3636 rc_t CC KfgConfigNamelistGet ( const KfgConfigNamelist *self,
3637     uint32_t idx, const char **name )
3638 {
3639     if ( ( size_t ) idx >= self -> count )
3640         return RC ( rcDB, rcNamelist, rcAccessing, rcParam, rcInvalid );
3641     * name = self -> namelist [ idx ];
3642     return 0;
3643 }
3644 
3645 /* Make
3646  */
3647 static KNamelist_vt_v1 vtKfgConfigNamelist =
3648 {
3649     /* version 1.0 */
3650     1, 0,
3651 
3652     /* start minor version 0 methods */
3653     KfgConfigNamelistWhack,
3654     KfgConfigNamelistCount,
3655     KfgConfigNamelistGet
3656     /* end minor version 0 methods */
3657 };
3658 
3659  static
KfgConfigNamelistMake(KNamelist ** names,uint32_t count)3660  rc_t KfgConfigNamelistMake ( KNamelist **names, uint32_t count )
3661  {
3662      rc_t rc;
3663      KfgConfigNamelist *self = malloc ( sizeof * self -
3664          sizeof self -> namelist + count * sizeof self -> namelist [ 0 ] );
3665      if ( self == NULL )
3666          rc = RC ( rcKFG, rcMetadata, rcListing, rcMemory, rcExhausted );
3667      else
3668      {
3669          self -> count = 0;
3670 
3671          rc = KNamelistInit ( & self -> dad,
3672              ( const KNamelist_vt* ) & vtKfgConfigNamelist );
3673          if ( rc == 0 )
3674          {
3675              * names = & self -> dad;
3676              return 0;
3677          }
3678 
3679          free ( self );
3680      }
3681 
3682      return rc;
3683  }
3684 
3685 /* List
3686  *  create metadata node listings
3687  */
3688 static
BSTNodeCount(BSTNode * n,void * data)3689 void CC BSTNodeCount ( BSTNode *n, void *data )
3690 {
3691     * ( uint32_t* ) data += 1;
3692 }
3693 
3694 static
KConfigNodeGrabName(BSTNode * n,void * data)3695 void CC KConfigNodeGrabName ( BSTNode *n, void *data )
3696 {
3697     KfgConfigNamelist *list = data;
3698     list -> namelist [ list -> count ++ ]
3699         = ( ( const KConfigNode* ) n ) -> name . addr;
3700 }
3701 
3702 /* ListChildren
3703  *  list all named children
3704  */
KConfigNodeListChildren(const KConfigNode * self,KNamelist ** names)3705 LIB_EXPORT rc_t CC KConfigNodeListChildren ( const KConfigNode *self,
3706     KNamelist **names )
3707 {
3708     if ( names == NULL )
3709         return RC ( rcKFG, rcNode, rcListing, rcParam, rcNull );
3710 
3711     * names = NULL;
3712 
3713     if ( self != NULL )
3714     {
3715         rc_t rc;
3716 
3717         uint32_t count = 0;
3718         BSTreeForEach ( & self -> children, 0, BSTNodeCount, & count );
3719 
3720         rc = KfgConfigNamelistMake ( names, count );
3721         if ( rc == 0 )
3722             BSTreeForEach
3723                 ( & self -> children, 0, KConfigNodeGrabName, * names );
3724 
3725         return rc;
3726     }
3727 
3728     return RC ( rcKFG, rcNode, rcListing, rcSelf, rcNull );
3729 }
3730 
3731 static
KConfigGrabName(BSTNode * n,void * data)3732 void CC KConfigGrabName ( BSTNode *n, void *data )
3733 {
3734     KfgConfigNamelist *list = data;
3735     list -> namelist [ list -> count ++ ]
3736         = ( ( const KConfigIncluded* ) n ) -> path;
3737 }
3738 
3739 /* ListIncluded
3740  *  list all included files
3741  */
KConfigListIncluded(const KConfig * self,KNamelist ** names)3742 LIB_EXPORT rc_t CC KConfigListIncluded ( const KConfig *self,
3743     KNamelist **names )
3744 {
3745     if ( names == NULL )
3746         return RC ( rcKFG, rcMgr, rcListing, rcParam, rcNull );
3747 
3748     * names = NULL;
3749 
3750     if ( self != NULL )
3751     {
3752         rc_t rc;
3753 
3754         uint32_t count = 0;
3755         BSTreeForEach ( & self -> included, 0, BSTNodeCount, & count );
3756 
3757         rc = KfgConfigNamelistMake ( names, count );
3758         if ( rc == 0 )
3759             BSTreeForEach
3760                 ( & self -> included, 0, KConfigGrabName, * names );
3761 
3762         return rc;
3763     }
3764 
3765     return RC ( rcKFG, rcMgr, rcListing, rcSelf, rcNull );
3766 }
3767 
3768 /************** Internal node-reading helpers *************/
3769 
3770 /* ReadNodeValueFixed
3771  * copy the node's value into the caller's fixed size buffer and 0-terminate
3772  */
ReadNodeValueFixed(const KConfigNode * self,char * buf,size_t bsize)3773 static rc_t ReadNodeValueFixed ( const KConfigNode* self, char *buf, size_t bsize )
3774 {
3775     size_t num_read, remaining;
3776     rc_t rc = KConfigNodeRead ( self, 0, buf, bsize - 1, &num_read, &remaining);
3777     if (rc == 0)
3778     {
3779         if (remaining != 0)
3780             rc = RC ( rcKFG, rcNode, rcReading, rcBuffer, rcInsufficient );
3781         else
3782             buf[num_read] = '\0';
3783     }
3784     return rc;
3785 }
3786 
3787 /**********************************************************/
3788 
3789 /* ReadBool
3790  *  read a boolean node value
3791  *
3792  * self [ IN ] - KConfigNode object
3793  * result [ OUT ] - return value (true if "TRUE", false if "FALSE"; rc != 0 if neither)
3794  *
3795  */
KConfigNodeReadBool(const KConfigNode * self,bool * result)3796 LIB_EXPORT rc_t CC KConfigNodeReadBool ( const KConfigNode *self, bool *result )
3797 {
3798     rc_t rc;
3799 
3800     if ( result == NULL )
3801         rc = RC ( rcKFG, rcNode, rcReading, rcParam, rcNull );
3802     else
3803     {
3804         * result = false;
3805 
3806         if ( self == NULL )
3807             rc = RC ( rcKFG, rcNode, rcReading, rcSelf, rcNull );
3808         else
3809         {
3810             char buf [ 6 ];
3811             rc = ReadNodeValueFixed ( self, buf, sizeof buf );
3812             if ( rc == 0 )
3813             {
3814                 switch ( tolower ( buf [ 0 ] ) )
3815                 {
3816                 case 'f':
3817                     if ( buf [ 1 ] == 0 )
3818                         return 0;
3819                     if ( strncasecmp ( buf, "false", sizeof buf ) == 0 )
3820                         return 0;
3821                     break;
3822 
3823                 case 'n':
3824                     if ( buf [ 1 ] == 0 )
3825                         return 0;
3826                     if ( strncasecmp ( buf, "no", sizeof buf ) == 0 )
3827                         return 0;
3828                     break;
3829 
3830                 case 't':
3831                     * result = true;
3832                     if ( buf [ 1 ] == 0 )
3833                         return 0;
3834                     if ( strncasecmp ( buf, "true", sizeof buf ) == 0 )
3835                         return 0;
3836                     break;
3837 
3838                 case 'y':
3839                     * result = true;
3840                     if ( buf [ 1 ] == 0 )
3841                         return 0;
3842                     if ( strncasecmp ( buf, "yes", sizeof buf ) == 0 )
3843                         return 0;
3844                     break;
3845                 }
3846 
3847                 * result = false;
3848                 rc = RC ( rcKFG, rcNode, rcReading, rcFormat, rcIncorrect );
3849             }
3850         }
3851     }
3852 
3853     return rc;
3854 }
3855 
3856 /* ReadI64
3857  *  read an integer node value
3858  *
3859  * self [ IN ] - KConfigNode object
3860  * result [ OUT ] - return value (rc != 0 if cannot be converted)
3861  *
3862  */
KConfigNodeReadI64(const KConfigNode * self,int64_t * result)3863 LIB_EXPORT rc_t CC KConfigNodeReadI64 ( const KConfigNode *self, int64_t *result )
3864 {
3865     rc_t rc;
3866 
3867     if ( result == NULL )
3868         rc = RC ( rcKFG, rcNode, rcReading, rcParam, rcNull );
3869     else
3870     {
3871         * result = 0;
3872 
3873         if ( self == NULL )
3874             rc = RC ( rcKFG, rcNode, rcReading, rcSelf, rcNull );
3875         else
3876         {
3877             /* allow for leading zeros */
3878             char buf [ 256 ] = "";
3879 
3880             rc = ReadNodeValueFixed(self, buf, sizeof(buf));
3881             if (rc == 0)
3882             {
3883               if ( buf [ 0 ] == '\0' )
3884                 rc = RC(rcKFG, rcNode, rcReading, rcNode, rcEmpty);
3885               else {
3886                 char* endptr;
3887                 int64_t res = strtoi64(buf, &endptr, 0);
3888                 if ( *endptr == '\0' )
3889                     *result = res;
3890                 else
3891                     rc = RC(rcKFG, rcNode, rcReading, rcFormat, rcIncorrect);
3892               }
3893             }
3894         }
3895     }
3896     return rc;
3897 }
3898 
3899 /* ReadU64
3900  *  read an unsiged node value
3901  *
3902  * self [ IN ] - KConfigNode object
3903  * result [ OUT ] - return value (rc != 0 if cannot be converted)
3904  *
3905  */
KConfigNodeReadU64(const KConfigNode * self,uint64_t * result)3906 LIB_EXPORT rc_t CC KConfigNodeReadU64 ( const KConfigNode *self, uint64_t* result )
3907 {
3908     rc_t rc;
3909 
3910     if ( result == NULL )
3911         rc = RC ( rcKFG, rcNode, rcReading, rcParam, rcNull );
3912     else
3913     {
3914         * result = 0;
3915 
3916         if ( self == NULL )
3917             rc = RC ( rcKFG, rcNode, rcReading, rcSelf, rcNull );
3918         else
3919         {
3920             /* allow for leading zeros */
3921             char buf [ 256 ] = "";
3922 
3923             rc = ReadNodeValueFixed(self, buf, sizeof(buf));
3924             if (rc == 0)
3925             {
3926               if ( buf [ 0 ] == '\0' )
3927                 rc = RC(rcKFG, rcNode, rcReading, rcNode, rcEmpty);
3928               else {
3929                 char* endptr;
3930                 int64_t res = strtou64(buf, &endptr, 0);
3931                 if ( *endptr == '\0' )
3932                     *result = res;
3933                 else
3934                     rc = RC(rcKFG, rcNode, rcReading, rcFormat, rcIncorrect);
3935               }
3936             }
3937         }
3938     }
3939     return rc;
3940 }
3941 
3942 /* ReadF64
3943  *  read a floating point node value
3944  *
3945  * self [ IN ] - KConfigNode object
3946  * result [ OUT ] - return value (rc != 0 if cannot be converted)
3947  *
3948  */
KConfigNodeReadF64(const KConfigNode * self,double * result)3949 LIB_EXPORT rc_t CC KConfigNodeReadF64( const KConfigNode *self, double* result )
3950 {
3951     rc_t rc;
3952 
3953     if ( result == NULL )
3954         rc = RC ( rcKFG, rcNode, rcReading, rcParam, rcNull );
3955     else
3956     {
3957         * result = 0.0;
3958 
3959         if ( self == NULL )
3960             rc = RC ( rcKFG, rcNode, rcReading, rcSelf, rcNull );
3961         else
3962         {
3963             /* allow for leading zeros, trailing digits */
3964             char buf [ 256 ] = "";
3965 
3966             rc = ReadNodeValueFixed(self, buf, sizeof(buf));
3967             if (rc == 0)
3968             {
3969               if ( buf [ 0 ] == '\0' )
3970                 rc = RC(rcKFG, rcNode, rcReading, rcNode, rcEmpty);
3971               else {
3972                 char* endptr;
3973                 double res = strtod(buf, &endptr);
3974                 if ( *endptr == '\0' )
3975                     *result = res;
3976                 else
3977                     rc = RC(rcKFG, rcNode, rcReading, rcFormat, rcIncorrect);
3978               }
3979             }
3980         }
3981     }
3982     return rc;
3983 }
3984 
3985 #if 0
3986 /*** NB - code needs to be located in VFS ***/
3987 /* ReadNodeValueFixed
3988  * Allocate a character buffer of sufficient size, copy the node's value into it, 0-terminate. Caller deallocates.
3989  */
3990 static rc_t ReadNodeValueVariable( const KConfigNode* self, char** buf )
3991 {
3992     size_t num_read, to_read;
3993     /* first we ask about the size to be read */
3994     rc_t rc = KConfigNodeRead ( self, 0, NULL, 0, &num_read, &to_read );
3995     if ( rc == 0 )
3996     {
3997         char* value = malloc( to_read + 1 );
3998         if ( value )
3999         {
4000             rc = ReadNodeValueFixed( self, value, to_read + 1 );
4001             if ( rc == 0 )
4002                 *buf = value;
4003             else
4004                 free (value);
4005         }
4006         else
4007             rc = RC( rcKFG, rcNode, rcReading, rcMemory, rcExhausted );
4008     }
4009     return rc;
4010 }
4011 
4012 /* ReadFloat
4013  *  read a VPath node value
4014  *
4015  * self [ IN ] - KConfigNode object
4016  * result [ OUT ] - return value (rc != 0 if cannot be converted)
4017  *
4018  */
4019 LIB_EXPORT rc_t CC KConfigNodeReadVPath ( const KConfigNode *self, struct VPath** result )
4020 {
4021     rc_t rc;
4022 
4023     if ( result == NULL )
4024         rc = RC ( rcKFG, rcNode, rcReading, rcParam, rcNull );
4025     else
4026     {
4027         * result = NULL;
4028 
4029         if ( self == NULL )
4030             rc = RC ( rcKFG, rcNode, rcReading, rcSelf, rcNull );
4031         else
4032         {
4033             char* buf;
4034             rc = ReadNodeValueVariable ( self, &buf );
4035             if ( rc == 0)
4036             {
4037                 rc = VPathMake(result, buf);
4038                 free(buf);
4039             }
4040         }
4041     }
4042     return rc;
4043 }
4044 #endif
4045 
4046 /* ReadString
4047  *  read a String node value
4048  *
4049  * self [ IN ] - KConfigNode object
4050  * result [ OUT ] - return value (rc != 0 if cannot be converted)
4051  *
4052  */
KConfigNodeReadString(const KConfigNode * self,String ** result)4053 LIB_EXPORT rc_t CC KConfigNodeReadString ( const KConfigNode *self, String** result )
4054 {
4055     rc_t rc;
4056 
4057     if ( result == NULL )
4058         rc = RC ( rcKFG, rcNode, rcReading, rcParam, rcNull );
4059     else
4060     {
4061         * result = NULL;
4062 
4063         if ( self == NULL )
4064             rc = RC ( rcKFG, rcNode, rcReading, rcSelf, rcNull );
4065         else
4066         {
4067             size_t num_read, to_read;
4068 
4069             /* first we ask about the size to be read */
4070             rc = KConfigNodeRead ( self, 0, NULL, 0, &num_read, &to_read );
4071             if ( rc == 0 )
4072             {
4073                 String *value = malloc ( sizeof * value + to_read + 1 );
4074                 if ( value == NULL )
4075                     rc = RC( rcKFG, rcNode, rcReading, rcMemory, rcExhausted );
4076                 else
4077                 {
4078                     /* initialize in absence of data - assume ASCII */
4079                     StringInit ( value, (char*)( value + 1 ), to_read, (uint32_t)to_read );
4080 
4081                     /* read the actual data */
4082                     rc = ReadNodeValueFixed(self, (char*)value->addr, to_read + 1);
4083                     if ( rc == 0 )
4084                     {
4085                         /* measure length of data to handle non-ASCII */
4086                         value -> len = string_len ( value -> addr, value -> size );
4087                         *result = value;
4088                     }
4089                     else
4090                     {
4091                         rc = RC(rcKFG, rcNode, rcReading, rcFormat, rcIncorrect);
4092                         free ( value );
4093                     }
4094                 }
4095             }
4096         }
4097     }
4098     return rc;
4099 }
4100 
KConfigRead(const KConfig * self,const char * path,size_t offset,char * buffer,size_t bsize,size_t * num_read,size_t * remaining)4101 LIB_EXPORT rc_t CC KConfigRead ( const KConfig * self, const char * path,
4102     size_t offset, char * buffer, size_t bsize,
4103     size_t * num_read, size_t * remaining )
4104 {
4105     const KConfigNode * node = NULL;
4106 
4107     rc_t rc = KConfigOpenNodeRead ( self, & node, "%s", path );
4108     if ( rc == 0) {
4109         rc_t rc2 = 0;
4110 
4111         rc = KConfigNodeRead
4112             ( node, offset, buffer, bsize, num_read, remaining );
4113 
4114         rc2 = KConfigNodeRelease ( node );
4115         if ( rc == 0 ) {
4116             rc = rc2;
4117         }
4118     }
4119 
4120     return rc;
4121 }
4122 
4123 /* this macro wraps a call to KConfigNodeGetXXX in a node-accessing
4124    code to implement the corresponding KConfigGetXXX function */
4125 #define NODE_TO_CONFIG_ACCESSOR(fn) \
4126     const KConfigNode* node;                                \
4127     rc_t rc = KConfigOpenNodeRead ( self, &node, "%s", path );   \
4128     if ( rc == 0)                                           \
4129     {                                                       \
4130         rc_t rc2;                                           \
4131         rc = fn(node, result);                              \
4132         rc2 = KConfigNodeRelease(node);                     \
4133         if (rc == 0)                                        \
4134             rc = rc2;                                       \
4135     }                                                       \
4136     return rc;
4137 
4138 /* THESE FUNCTIONS ARE PROTECTED AGAINST BAD "self" AND "path"
4139    BY KConfigOpenNodeRead, BUT THE CONVERSION FUNCTIONS ARE NOT */
KConfigReadBool(const KConfig * self,const char * path,bool * result)4140 LIB_EXPORT rc_t CC KConfigReadBool ( const KConfig* self, const char* path, bool* result )
4141 {
4142     NODE_TO_CONFIG_ACCESSOR(KConfigNodeReadBool);
4143 }
KConfigReadI64(const KConfig * self,const char * path,int64_t * result)4144 LIB_EXPORT rc_t CC KConfigReadI64 ( const KConfig* self, const char* path, int64_t* result )
4145 {
4146     NODE_TO_CONFIG_ACCESSOR(KConfigNodeReadI64);
4147 }
KConfigReadU64(const KConfig * self,const char * path,uint64_t * result)4148 LIB_EXPORT rc_t CC KConfigReadU64 ( const KConfig* self, const char* path, uint64_t* result )
4149 {
4150     NODE_TO_CONFIG_ACCESSOR(KConfigNodeReadU64);
4151 }
4152 
KConfigReadF64(const KConfig * self,const char * path,double * result)4153 LIB_EXPORT rc_t CC KConfigReadF64 ( const KConfig* self, const char* path, double* result )
4154 {
4155     NODE_TO_CONFIG_ACCESSOR(KConfigNodeReadF64);
4156 }
4157 
KConfigReadString(const KConfig * self,const char * path,struct String ** result)4158 LIB_EXPORT rc_t CC KConfigReadString ( const KConfig* self, const char* path, struct String** result )
4159 {
4160     NODE_TO_CONFIG_ACCESSOR(KConfigNodeReadString);
4161 }
4162 
4163 #define DISP_RC(rc, msg) (void)((rc == 0) ? 0 : LOGERR(klogInt, rc, msg))
4164 
KConfigPrintPartial(const KConfig * self,int indent,uint32_t skipCount,va_list args)4165 LIB_EXPORT rc_t CC KConfigPrintPartial
4166     (const KConfig *self, int indent, uint32_t skipCount, va_list args)
4167 {
4168     rc_t rc = 0;
4169 
4170     PrintBuff pb;
4171 
4172     if (rc == 0) {
4173         PrintBuffInit(&pb, NULL);
4174     }
4175 
4176     if (rc == 0) {
4177         rc = KConfigPrintImpl
4178             (self, indent, NULL, false, false, &pb, skipCount, args);
4179     }
4180 
4181     if (rc == 0) {
4182         rc = PrintBuffFlush(&pb);
4183     }
4184 
4185     return rc;
4186 }
4187 
KConfigPrintPartial_noargs(const KConfig * self,int indent,uint32_t skipCount,...)4188 static rc_t KConfigPrintPartial_noargs
4189     (const KConfig *self, int indent, uint32_t skipCount, ...)
4190 {
4191     rc_t rc;
4192     va_list args;
4193 
4194     va_start ( args, skipCount );
4195     rc = KConfigPrintPartial ( self, indent, skipCount, args );
4196     va_end ( args );
4197 
4198     return rc;
4199 }
4200 
KConfigPrint(const KConfig * self,int indent)4201 LIB_EXPORT rc_t CC KConfigPrint(const KConfig* self, int indent) {
4202     return KConfigPrintPartial_noargs(self, indent, 0);
4203 }
4204 
KConfigToFile(const KConfig * self,KFile * file)4205 LIB_EXPORT rc_t CC KConfigToFile(const KConfig* self, KFile *file) {
4206     rc_t rc = 0;
4207     PrintBuff pb;
4208     PrintBuffInit(&pb, file);
4209     if (rc == 0) {
4210         rc = KConfigPrintImpl_noargs(self, 0, NULL, false, true, &pb, 0);
4211     }
4212     if (rc == 0) {
4213         rc = PrintBuffFlush(&pb);
4214     }
4215     return rc;
4216 }
4217 
KConfigDisableUserSettings(void)4218 LIB_EXPORT void CC KConfigDisableUserSettings ( void )
4219 {
4220     s_disable_user_settings = true;
4221 }
4222 
KConfigSetNgcFile(const char * path)4223 LIB_EXPORT void CC KConfigSetNgcFile(const char * path) { s_ngc_file = path; }
KConfigGetNgcFile(void)4224 const char * KConfigGetNgcFile(void) { return s_ngc_file; }
4225 
4226 static
open_file(const KFile ** f,const char * path)4227 rc_t open_file ( const KFile **f, const char *path )
4228 {
4229     /* get current directory */
4230     KDirectory *wd;
4231     rc_t rc = KDirectoryNativeDir ( & wd );
4232     if ( rc == 0 )
4233     {
4234         rc = KDirectoryOpenFileRead ( wd, f, "%s", path );
4235         KDirectoryRelease ( wd );
4236     }
4237 
4238     return rc;
4239 }
4240 
4241 /* KFS_EXTERN rc_t CC KFileMakeGzip2ForRead ( struct KFile const **gz, struct KFile const *src );
4242 #include <stdio.h> aprintf */
4243 #define aprintf( a, b ) ( ( void ) 0 )
4244 static
decode_ncbi_gap(KDataBuffer * mem,const KFile * orig)4245 rc_t decode_ncbi_gap ( KDataBuffer *mem, const KFile *orig )
4246 {
4247     char hdr [ 8 ];
4248     size_t num_read;
4249     rc_t rc = KFileReadAll ( orig, 0, hdr, sizeof hdr, & num_read );
4250 aprintf("decode_ncbi_gap %d\n", __LINE__);
4251     if ( rc == 0 && num_read == sizeof hdr )
4252     {
4253         if (memcmp(hdr, "ncbi_gap", sizeof hdr) != 0) {
4254             rc = RC(rcKFG, rcFile, rcReading, rcFile, rcWrongType);
4255         }
4256         else {
4257             uint64_t eof;
4258 aprintf("decode_ncbi_gap %d\n", __LINE__);
4259             rc = KFileSize ( orig, & eof );
4260 aprintf("decode_ncbi_gap %d\n", __LINE__);
4261             if ( rc == 0 )
4262             {
4263                 const KFile *sub;
4264 aprintf("decode_ncbi_gap %d\n", __LINE__);
4265                 rc = KFileMakeSubRead ( & sub, orig, sizeof hdr,
4266                     eof - sizeof hdr );
4267 aprintf("decode_ncbi_gap %d\n", __LINE__);
4268                 if ( rc == 0 )
4269                 {
4270                     const KFile *gzip;
4271 aprintf("decode_ncbi_gap %d\n", __LINE__);
4272 
4273 /* aprintf          rc = KFileMakeGzip2ForRead ( & gzip, sub ); */
4274                     rc = KFileMakeGzipForRead ( & gzip, sub );
4275 aprintf("decode_ncbi_gap %d\n", __LINE__);
4276                     if ( rc == 0 )
4277                     {
4278 aprintf("decode_ncbi_gap %d\n", __LINE__);
4279                         rc = KDataBufferMakeBytes ( mem, 0 );
4280 aprintf("decode_ncbi_gap %d\n", __LINE__);
4281                         if ( rc == 0 )
4282                         {
4283                             size_t total, to_read;
4284 
4285                             /* after all of that, we're ready to decompress */
4286                             for ( total = 0; ; )
4287                             {
4288                                 char *buff;
4289 
4290 aprintf("decode_ncbi_gap %d\n", __LINE__);
4291                                 rc = KDataBufferResize ( mem,
4292                                     total + 32 * 1024 );
4293 aprintf("decode_ncbi_gap %d\n", __LINE__);
4294                                 if ( rc != 0 )
4295                                     break;
4296 
4297                                 buff = mem -> base;
4298 aprintf("decode_ncbi_gap %d\n", __LINE__);
4299                                 to_read = ( size_t ) mem -> elem_count - total;
4300 aprintf("decode_ncbi_gap %d\n", __LINE__);
4301 
4302                                 rc = KFileReadAll ( gzip, total,
4303                                     & buff [ total ], to_read, & num_read );
4304 aprintf("decode_ncbi_gap %d\n", __LINE__);
4305                                 if ( rc != 0 )
4306                                     break;
4307 
4308                                 total += num_read;
4309 
4310                                 if ( num_read < to_read )
4311                                 {
4312 aprintf("decode_ncbi_gap %d\n", __LINE__);
4313                                     buff [ total ] = 0;
4314 aprintf("decode_ncbi_gap %d\n", __LINE__);
4315                                     mem -> elem_count = total;
4316                                     break;
4317                                 }
4318                             }
4319                         }
4320 
4321 aprintf("decode_ncbi_gap %d\n", __LINE__);
4322                         KFileRelease ( gzip );
4323 aprintf("decode_ncbi_gap %d\n", __LINE__);
4324                     }
4325 
4326 aprintf("decode_ncbi_gap %d\n", __LINE__);
4327                     KFileRelease ( sub );
4328 aprintf("decode_ncbi_gap %d\n", __LINE__);
4329                 }
4330             }
4331         }
4332     }
4333 
4334 aprintf("decode_ncbi_gap %d\n", __LINE__);
4335     return rc;
4336 }
4337 
4338 typedef struct {
4339     const char *projectId;
4340     const char *encryptionKey;
4341     const char *downloadTicket;
4342     const char *description;
4343 } KGapConfig;
4344 
4345 static
_KConfigNncToKGapConfig(const KConfig * self,char * text,KGapConfig * kgc)4346 rc_t _KConfigNncToKGapConfig(const KConfig *self, char *text, KGapConfig *kgc)
4347 {
4348     size_t len = 0;
4349     int i = 0;
4350 
4351     assert(self && text && kgc);
4352 
4353     memset(kgc, 0, sizeof *kgc);
4354     len = string_size(text);
4355 
4356     {
4357         const char version[] = "version ";
4358         size_t l = sizeof version - 1;
4359         if (string_cmp(version, l, text, len, (uint32_t)l) != 0) {
4360             return RC(rcKFG, rcMgr, rcUpdating, rcFormat, rcUnrecognized);
4361         }
4362         text += l;
4363         len -= l;
4364     }
4365 
4366     {
4367         const char version[] = "1.0";
4368         size_t l = sizeof version - 1;
4369         if (string_cmp(version, l, text, l, (uint32_t)l) != 0) {
4370             return RC(rcKFG, rcMgr, rcUpdating, rcFormat, rcUnsupported);
4371         }
4372         text += l;
4373         len -= l;
4374     }
4375 
4376     while (len > 0 && (text[0] == '\r' || text[0] == '\n')) {
4377         ++text;
4378         --len;
4379     }
4380 
4381     for (i = 0; ; ++i) {
4382         const char *p = NULL;
4383         if (i == 0) {
4384             p = strtok(text, "|");
4385         }
4386         else {
4387             p = strtok (NULL, "|");
4388         }
4389         if (p == NULL) {
4390             break;
4391         }
4392         switch (i) {
4393             case 0:
4394                 kgc->projectId = p;
4395                 break;
4396             case 1:
4397                 kgc->encryptionKey = p;
4398                 break;
4399             case 2:
4400                 kgc->downloadTicket = p;
4401                 break;
4402             case 3:
4403                 kgc->description = p;
4404                 break;
4405         }
4406     }
4407 
4408     if (!kgc->projectId || !kgc->encryptionKey || !kgc->downloadTicket ||
4409         !kgc->description)
4410     {
4411         return RC(rcKFG, rcMgr, rcUpdating, rcFile, rcInvalid);
4412     }
4413 
4414     return 0;
4415 }
4416 
KConfigFixMainResolverCgiNode(KConfig * self)4417 LIB_EXPORT rc_t KConfigFixMainResolverCgiNode ( KConfig * self ) {
4418     rc_t rc = 0;
4419 
4420     KConfigNode *node = NULL;
4421     struct String *result = NULL;
4422 
4423     assert(self);
4424 
4425     if (rc == 0) {
4426         rc = KConfigOpenNodeUpdate(self, &node,
4427             "/repository/remote/main/CGI/resolver-cgi");
4428     }
4429 
4430     if (rc == 0) {
4431         rc = KConfigNodeReadString(node, &result);
4432     }
4433 
4434     if (rc == 0) {
4435         String http;
4436         CONST_STRING ( & http,
4437                    "http://www.ncbi.nlm.nih.gov/Traces/names/names.cgi" );
4438         assert(result);
4439         if ( result->size == 0 || StringEqual ( & http, result ) ) {
4440             const char https[] = RESOLVER_CGI;
4441             rc = KConfigNodeWrite ( node, https, sizeof https );
4442         }
4443     }
4444 
4445     free(result);
4446 
4447     KConfigNodeRelease(node);
4448 
4449     return rc;
4450 }
4451 
4452 /* We need to call it from KConfigFixProtectedResolverCgiNode:
4453  * otherwise we call names.cgi, not SDL for dbGaP resolution. */
KConfigFixProtectedSdlCgiNode(KConfig * self)4454 static rc_t KConfigFixProtectedSdlCgiNode(KConfig * self) {
4455     rc_t rc = 0;
4456 
4457     KConfigNode *node = NULL;
4458     struct String *result = NULL;
4459 
4460     assert(self);
4461 
4462     if (rc == 0)
4463         rc = KConfigOpenNodeUpdate(self, &node,
4464             "/repository/remote/protected/SDL.2/resolver-cgi");
4465 
4466     if (rc == 0)
4467         rc = KConfigNodeReadString(node, &result);
4468 
4469     if (rc == 0) {
4470         assert(result);
4471         if (result->size == 0) {
4472             const char https[] = SDL_CGI;
4473             rc = KConfigNodeWrite(node, https, sizeof https);
4474         }
4475     }
4476 
4477     free(result);
4478 
4479     KConfigNodeRelease(node);
4480 
4481     return rc;
4482 }
4483 
KConfigFixProtectedResolverCgiNode(KConfig * self)4484 LIB_EXPORT rc_t KConfigFixProtectedResolverCgiNode ( KConfig * self ) {
4485     rc_t rc = 0;
4486 
4487     KConfigNode *node = NULL;
4488     struct String *result = NULL;
4489 
4490     assert(self);
4491 
4492     if (rc == 0) {
4493         rc = KConfigOpenNodeUpdate(self, &node,
4494             "/repository/remote/protected/CGI/resolver-cgi");
4495     }
4496 
4497     if (rc == 0) {
4498         rc = KConfigNodeReadString(node, &result);
4499     }
4500 
4501     if (rc == 0) {
4502         String http;
4503         CONST_STRING ( & http,
4504                    "http://www.ncbi.nlm.nih.gov/Traces/names/names.cgi" );
4505         assert(result);
4506         if ( result->size == 0 || StringEqual ( & http, result ) ) {
4507             const char https[] = RESOLVER_CGI;
4508             rc = KConfigNodeWrite ( node, https, sizeof https );
4509         }
4510     }
4511 
4512     free(result);
4513 
4514     KConfigNodeRelease(node);
4515 
4516     if (rc == 0)
4517         rc = KConfigFixProtectedSdlCgiNode(self);
4518 
4519     return rc;
4520 }
4521 
_KConfigNodeUpdateChild(KConfigNode * self,const char * name,const char * val)4522 static rc_t _KConfigNodeUpdateChild(KConfigNode *self,
4523     const char *name, const char *val)
4524 {
4525     rc_t rc = 0;
4526 
4527     KConfigNode *node = NULL;
4528 
4529     assert(self && name && val);
4530 
4531     if (rc == 0) {
4532         rc = KConfigNodeOpenNodeUpdate(self, &node, "%s", name);
4533     }
4534 
4535     if (rc == 0) {
4536         rc = KConfigNodeWrite(node, val, string_size(val));
4537     }
4538 
4539     {
4540         rc_t rc2 = KConfigNodeRelease(node);
4541         if (rc2 != 0 && rc == 0) {
4542             rc = rc2;
4543         }
4544     }
4545 
4546     return rc;
4547 }
4548 
_KConfigMkPwdFileAndNode(KConfig * self,KConfigNode * rep,const KGapConfig * kgc)4549 static rc_t _KConfigMkPwdFileAndNode(KConfig *self,
4550     KConfigNode *rep, const KGapConfig *kgc)
4551 {
4552     rc_t rc = 0;
4553     const KConfigNode *ncbiHome = NULL;
4554     KConfigNode *node = NULL;
4555     struct String *result = NULL;
4556     char encryptionKeyPath[PATH_MAX];
4557     KDirectory *dir = NULL;
4558     KFile *encryptionKeyFile = NULL;
4559     size_t num_writ = 0;
4560 
4561     assert(self && kgc && rep);
4562 
4563     if (rc == 0) {
4564         rc = KConfigOpenNodeRead(self, &ncbiHome, "NCBI_HOME");
4565     }
4566     if (rc == 0) {
4567         rc = KConfigNodeReadString(ncbiHome, &result);
4568     }
4569     KConfigNodeRelease(ncbiHome);
4570     ncbiHome = NULL;
4571 
4572     if (rc == 0) {
4573         size_t num_writ = 0;
4574         assert(result && result->addr);
4575         rc = string_printf(encryptionKeyPath, sizeof encryptionKeyPath,
4576             &num_writ, "%s/dbGaP-%s.enc_key", result->addr, kgc->projectId);
4577         if (rc == 0) {
4578             assert(num_writ < sizeof encryptionKeyPath);
4579         }
4580     }
4581     free(result);
4582     result = NULL;
4583 
4584     if (rc == 0) {
4585         rc = KDirectoryNativeDir(&dir);
4586     }
4587 
4588     if (rc == 0) {
4589         rc = KDirectoryCreateFile(dir, &encryptionKeyFile,
4590                                   false, 0600, kcmInit | kcmParents, "%s", encryptionKeyPath);
4591     }
4592 
4593     KDirectoryRelease(dir);
4594 
4595     if (rc == 0) {
4596         assert(kgc->encryptionKey);
4597         rc = KFileWrite(encryptionKeyFile, 0,
4598             kgc->encryptionKey, string_size(kgc->encryptionKey), &num_writ);
4599         if (rc == 0) {
4600             assert(num_writ == string_size(kgc->encryptionKey));
4601         }
4602     }
4603 
4604     if (rc == 0) {
4605         rc = KFileWrite(encryptionKeyFile, string_size(kgc->encryptionKey),
4606             "\n", 1, &num_writ);
4607         if (rc == 0) {
4608             assert(num_writ == 1);
4609         }
4610     }
4611 
4612     {
4613         rc_t rc2 = KFileRelease(encryptionKeyFile);
4614         if (rc2 != 0 && rc == 0) {
4615             rc = rc2;
4616         }
4617     }
4618 
4619     if (rc == 0) {
4620         rc = _KConfigNodeUpdateChild(rep,
4621             "encryption-key-path", encryptionKeyPath);
4622     }
4623 
4624     KConfigNodeRelease(node);
4625 
4626     return rc;
4627 }
4628 
_mkNotFoundDir(const char * repoParentPath)4629 static rc_t _mkNotFoundDir(const char *repoParentPath) {
4630     rc_t rc = 0;
4631 
4632     KPathType type = kptNotFound;
4633 
4634     KDirectory *wd = NULL;
4635     rc = KDirectoryNativeDir(&wd);
4636 
4637     if (rc == 0) {
4638         type = KDirectoryPathType(wd, "%s", repoParentPath);
4639         if (type == kptNotFound) {
4640             rc = KDirectoryCreateDir(wd, 0777, kcmCreate|kcmParents, "%s", repoParentPath);
4641         }
4642     }
4643 
4644     KDirectoryRelease(wd);
4645 
4646     return rc;
4647 }
4648 
_KConfigDBGapRepositoryNodes(KConfig * self,KConfigNode * rep,const KGapConfig * kgc,const char * repoParentPath,const char ** newRepoParentPath)4649 static rc_t _KConfigDBGapRepositoryNodes(KConfig *self,
4650     KConfigNode *rep, const KGapConfig *kgc, const char *repoParentPath,
4651     const char **newRepoParentPath)
4652 {
4653     rc_t rc = 0;
4654 
4655     assert(self && rep && kgc);
4656 
4657     if (rc == 0) {
4658         rc = _KConfigMkPwdFileAndNode(self, rep, kgc);
4659     }
4660 
4661     if (rc == 0) {
4662         assert(kgc->downloadTicket);
4663         rc = _KConfigNodeUpdateChild(rep,
4664             "download-ticket", kgc->downloadTicket);
4665     }
4666 
4667     if (rc == 0) {
4668         rc = _KConfigNodeUpdateChild(rep, "description", kgc->description);
4669     }
4670 
4671     if (rc == 0) {
4672         rc = _KConfigNodeUpdateChild(rep, "apps/file/volumes/flat", "files");
4673     }
4674     if (rc == 0) {
4675         const char name [] = "apps/sra/volumes/sraFlat";
4676         const KConfigNode * node = NULL;
4677         rc = KConfigNodeOpenNodeRead ( rep, & node, name );
4678         if ( rc != 0 )
4679             rc = _KConfigNodeUpdateChild ( rep, name, "sra" );
4680         else
4681             KConfigNodeRelease ( node );
4682     }
4683 
4684     if (rc == 0) {
4685         rc = _KConfigNodeUpdateChild(rep, "cache-enabled", "true");
4686     }
4687 
4688     if (rc == 0) {
4689         static char rootPath[PATH_MAX] = "";
4690         if (repoParentPath == NULL) {
4691             size_t num_writ = 0;
4692             const KConfigNode *home = NULL;
4693             String *result = NULL;
4694 
4695             if (rc == 0) {
4696                 rc = KConfigOpenNodeRead(self, &home, "HOME");
4697             }
4698 
4699             if (rc == 0) {
4700                 rc = KConfigNodeReadString(home, &result);
4701             }
4702 
4703             if (rc == 0) {
4704                 assert(result && result->addr);
4705                 rc = string_printf(rootPath, sizeof rootPath, &num_writ,
4706                     "%s/ncbi/dbGaP-%s", result->addr, kgc->projectId);
4707             }
4708 
4709             if (rc == 0) {
4710                 repoParentPath = rootPath;
4711             }
4712 
4713             free(result);
4714             KConfigNodeRelease(home);
4715         }
4716 
4717         if (rc == 0) {
4718             rc = _KConfigNodeUpdateChild(rep, "root", repoParentPath);
4719         }
4720         if (rc == 0) {
4721             rc = _mkNotFoundDir(repoParentPath);
4722         }
4723         if (rc == 0 && newRepoParentPath != NULL) {
4724             *newRepoParentPath = repoParentPath;
4725         }
4726     }
4727 
4728     return rc;
4729 }
4730 
_KConfigAddDBGapRepository(KConfig * self,const KGapConfig * kgc,const char * repoParentPath,const char ** newRepoParentPath)4731 static rc_t _KConfigAddDBGapRepository(KConfig *self,
4732     const KGapConfig *kgc, const char *repoParentPath,
4733     const char **newRepoParentPath)
4734 {
4735     rc_t rc = 0;
4736 
4737     KConfigNode *rep = NULL;
4738 
4739     char repNodeName[512] = "";
4740 
4741     assert(self && kgc);
4742 
4743     if (rc == 0) {
4744         size_t num_writ = 0;
4745         rc = string_printf(repNodeName, sizeof repNodeName, &num_writ,
4746             "/repository/user/protected/dbGaP-%s", kgc->projectId);
4747         if (rc == 0) {
4748             assert(num_writ < sizeof repNodeName);
4749         }
4750     }
4751 
4752     if (rc == 0) {
4753         rc = KConfigOpenNodeUpdate(self, &rep, "%s", repNodeName);
4754     }
4755 
4756     if (rc == 0) {
4757         rc = _KConfigDBGapRepositoryNodes(self, rep, kgc, repoParentPath,
4758             newRepoParentPath);
4759     }
4760 
4761     KConfigNodeRelease(rep);
4762 
4763     return rc;
4764 }
4765 
KConfigImportNgc(KConfig * self,const char * ngcPath,const char * repoParentPath,const char ** newRepoParentPath)4766 LIB_EXPORT rc_t CC KConfigImportNgc(KConfig *self,
4767     const char *ngcPath, const char *repoParentPath,
4768     const char **newRepoParentPath)
4769 {
4770     if (self == NULL) {
4771         return RC(rcKFG, rcMgr, rcUpdating, rcSelf, rcNull);
4772     }
4773 
4774     if (ngcPath == NULL) {
4775         return RC(rcKFG, rcMgr, rcUpdating, rcParam, rcNull);
4776     }
4777     else {
4778         const KFile *orig = NULL;
4779         rc_t rc = open_file ( & orig, ngcPath );
4780 /*    DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));*/
4781         if (rc != 0) {
4782             return rc;
4783         }
4784         else {
4785             KGapConfig kgc;
4786 
4787             KDataBuffer mem;
4788             memset ( & mem, 0, sizeof mem );
4789 
4790 /*DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));
4791 aprintf("KConfigImportNgc %d\n", __LINE__); */
4792             rc = decode_ncbi_gap ( & mem, orig );
4793 /*DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));
4794 aprintf("KConfigImportNgc %d\n", __LINE__);*/
4795             KFileRelease ( orig );
4796             orig = NULL;
4797 
4798             if (rc == 0) {
4799 /*DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));
4800 aprintf("KConfigImportNgc %d\n", __LINE__);*/
4801                 rc = _KConfigNncToKGapConfig(self, mem.base, &kgc);
4802 /*DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));
4803 aprintf("KConfigImportNgc %d\n", __LINE__);*/
4804             }
4805 
4806             if (rc == 0) {
4807 /*DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));
4808 aprintf("KConfigImportNgc %d\n", __LINE__);*/
4809                 rc = KConfigFixProtectedResolverCgiNode(self);
4810 /*DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));
4811 aprintf("KConfigImportNgc %d\n", __LINE__);*/
4812             }
4813 
4814             if (rc == 0) {
4815 /*DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));
4816 aprintf("KConfigImportNgc %d\n", __LINE__);*/
4817                 rc = _KConfigAddDBGapRepository(self, &kgc, repoParentPath,
4818                     newRepoParentPath);
4819 /*DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));
4820 aprintf("KConfigImportNgc %d\n", __LINE__);*/
4821             }
4822 
4823 /*DBGMSG(DBG_KFG, DBG_FLAG(DBG_KFG), ("KConfigImportNgc %d\n", __LINE__));
4824 aprintf("KConfigImportNgc %d\n", __LINE__);*/
4825             KDataBufferWhack ( & mem );
4826         }
4827 
4828         return rc;
4829     }
4830 }
4831 
4832 
KConfigWriteBool(KConfig * self,const char * path,bool value)4833 LIB_EXPORT rc_t CC KConfigWriteBool( KConfig *self, const char * path, bool value )
4834 {
4835     KConfigNode * node;
4836     rc_t rc = KConfigOpenNodeUpdate ( self, &node, "%s", path );
4837     if ( rc == 0 )
4838     {
4839         rc = KConfigNodeWriteBool ( node, value );
4840         KConfigNodeRelease ( node );
4841     }
4842     return rc;
4843 }
4844 
4845 
KConfigWriteString(KConfig * self,const char * path,const char * value)4846 LIB_EXPORT rc_t CC KConfigWriteString( KConfig *self, const char * path, const char * value )
4847 {
4848     KConfigNode * node;
4849     rc_t rc = KConfigOpenNodeUpdate ( self, &node, "%s", path );
4850     if ( rc == 0 )
4851     {
4852         rc = KConfigNodeWrite ( node, value, string_size( value ) );
4853         KConfigNodeRelease ( node );
4854     }
4855     return rc;
4856 }
4857 
4858 
KConfigWriteSString(KConfig * self,const char * path,struct String const * value)4859 LIB_EXPORT rc_t CC KConfigWriteSString( KConfig *self, const char * path, struct String const * value )
4860 {
4861     KConfigNode * node;
4862     rc_t rc = KConfigOpenNodeUpdate ( self, &node, "%s", path );
4863     if ( rc == 0 )
4864     {
4865         rc = KConfigNodeWrite ( node, value->addr, value->size );
4866         KConfigNodeRelease ( node );
4867     }
4868     return rc;
4869 }
4870