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