/src/gdal/netcdf-c-4.7.4/libdispatch/drc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata |
3 | | See COPYRIGHT for license information. |
4 | | */ |
5 | | |
6 | | #include "config.h" |
7 | | #ifdef HAVE_UNISTD_H |
8 | | #include <unistd.h> |
9 | | #endif |
10 | | #ifdef HAVE_STDARG_H |
11 | | #include <stdarg.h> |
12 | | #endif |
13 | | #include <stdio.h> |
14 | | #include <stdlib.h> |
15 | | #include <string.h> |
16 | | #include "netcdf.h" |
17 | | #include "ncbytes.h" |
18 | | #include "ncuri.h" |
19 | | #include "ncrc.h" |
20 | | #include "nclog.h" |
21 | | #include "ncwinpath.h" |
22 | | |
23 | 1 | #define RCFILEENV "DAPRCFILE" |
24 | | |
25 | 0 | #define RTAG ']' |
26 | 0 | #define LTAG '[' |
27 | | |
28 | 0 | #define TRIMCHARS " \t\r\n" |
29 | | |
30 | | #undef MEMCHECK |
31 | | #define MEMCHECK(x) if((x)==NULL) {goto nomem;} else {} |
32 | | |
33 | | /* Forward */ |
34 | | static char* rcreadline(char** nextlinep); |
35 | | static void rctrim(char* text); |
36 | | static void rcorder(NClist* rc); |
37 | | static int rccompile(const char* path); |
38 | | static struct NCTriple* rclocate(const char* key, const char* hostport); |
39 | | static int rcsearch(const char* prefix, const char* rcname, char** pathp); |
40 | | static void rcfreetriples(NClist* rc); |
41 | | #ifdef D4DEBUG |
42 | | static void storedump(char* msg, NClist* triples); |
43 | | #endif |
44 | | |
45 | | /* Define default rc files and aliases, also defines search order*/ |
46 | | static const char* rcfilenames[] = {".daprc",".dodsrc",".ncrc",NULL}; |
47 | | |
48 | | /**************************************************/ |
49 | | /* External Entry Points */ |
50 | | |
51 | | static NCRCglobalstate* ncrc_globalstate = NULL; |
52 | | |
53 | | /* Get global state */ |
54 | | NCRCglobalstate* |
55 | | ncrc_getglobalstate(void) |
56 | 2 | { |
57 | 2 | if(ncrc_globalstate == NULL) { |
58 | 1 | ncrc_globalstate = calloc(1,sizeof(NCRCglobalstate)); |
59 | 1 | } |
60 | 2 | return ncrc_globalstate; |
61 | 2 | } |
62 | | |
63 | | void |
64 | | ncrc_freeglobalstate(void) |
65 | 0 | { |
66 | 0 | if(ncrc_globalstate != NULL) { |
67 | 0 | nullfree(ncrc_globalstate->tempdir); |
68 | 0 | nullfree(ncrc_globalstate->home); |
69 | 0 | NC_rcclear(&ncrc_globalstate->rcinfo); |
70 | 0 | free(ncrc_globalstate); |
71 | 0 | ncrc_globalstate = NULL; |
72 | 0 | } |
73 | 0 | } |
74 | | |
75 | | void |
76 | | NC_rcclear(NCRCinfo* info) |
77 | 0 | { |
78 | 0 | if(info == NULL) return; |
79 | 0 | nullfree(info->rcfile); |
80 | 0 | rcfreetriples(info->triples); |
81 | 0 | } |
82 | | |
83 | | void |
84 | | rcfreetriples(NClist* rc) |
85 | 0 | { |
86 | 0 | int i; |
87 | 0 | for(i=0;i<nclistlength(rc);i++) { |
88 | 0 | NCTriple* t = (NCTriple*)nclistget(rc,i); |
89 | 0 | nullfree(t->host); |
90 | 0 | nullfree(t->key); |
91 | 0 | nullfree(t->value); |
92 | 0 | free(t); |
93 | 0 | } |
94 | 0 | nclistfree(rc); |
95 | 0 | } |
96 | | |
97 | | /* locate, read and compile the rc file, if any */ |
98 | | int |
99 | | NC_rcload(void) |
100 | 1 | { |
101 | 1 | int ret = NC_NOERR; |
102 | 1 | char* path = NULL; |
103 | 1 | NCRCglobalstate* globalstate = ncrc_getglobalstate(); |
104 | | |
105 | 1 | if(globalstate->rcinfo.ignore) { |
106 | 0 | nclog(NCLOGDBG,"No runtime configuration file specified; continuing"); |
107 | 0 | return (NC_NOERR); |
108 | 0 | } |
109 | 1 | if(globalstate->rcinfo.loaded) return (NC_NOERR); |
110 | | |
111 | | /* locate the configuration files in the following order: |
112 | | 1. specified by NC_set_rcfile |
113 | | 2. set by DAPRCFILE env variable |
114 | | 3. ./<rcfile> (current directory) |
115 | | 4. $HOME/<rcfile> |
116 | | */ |
117 | 1 | if(globalstate->rcinfo.rcfile != NULL) { /* always use this */ |
118 | 0 | path = strdup(globalstate->rcinfo.rcfile); |
119 | 1 | } else if(getenv(RCFILEENV) != NULL && strlen(getenv(RCFILEENV)) > 0) { |
120 | 0 | path = strdup(getenv(RCFILEENV)); |
121 | 1 | } else { |
122 | 1 | const char** rcname; |
123 | 1 | int found = 0; |
124 | 4 | for(rcname=rcfilenames;!found && *rcname;rcname++) { |
125 | 3 | ret = rcsearch(".",*rcname,&path); |
126 | 3 | if(ret == NC_NOERR && path == NULL) /* try $HOME */ |
127 | 3 | ret = rcsearch(globalstate->home,*rcname,&path); |
128 | 3 | if(ret != NC_NOERR) |
129 | 0 | goto done; |
130 | 3 | if(path != NULL) |
131 | 0 | found = 1; |
132 | 3 | } |
133 | 1 | } |
134 | 1 | if(path == NULL) { |
135 | 1 | nclog(NCLOGDBG,"Cannot find runtime configuration file; continuing"); |
136 | 1 | } else { |
137 | | #ifdef D4DEBUG |
138 | | fprintf(stderr, "RC file: %s\n", path); |
139 | | #endif |
140 | 0 | if((ret=rccompile(path))) { |
141 | 0 | nclog(NCLOGERR, "Error parsing %s\n",path); |
142 | 0 | goto done; |
143 | 0 | } |
144 | 0 | } |
145 | 1 | done: |
146 | 1 | globalstate->rcinfo.loaded = 1; /* even if not exists */ |
147 | 1 | nullfree(path); |
148 | 1 | return (ret); |
149 | 1 | } |
150 | | |
151 | | /** |
152 | | * Locate a triple by property key and host+port (may be null|"") |
153 | | * If duplicate keys, first takes precedence. |
154 | | */ |
155 | | char* |
156 | | NC_rclookup(const char* key, const char* hostport) |
157 | 0 | { |
158 | 0 | struct NCTriple* triple = rclocate(key,hostport); |
159 | 0 | return (triple == NULL ? NULL : triple->value); |
160 | 0 | } |
161 | | |
162 | | /*! |
163 | | Set the absolute path to use for the rc file. |
164 | | WARNING: this MUST be called before any other |
165 | | call in order for this to take effect. |
166 | | |
167 | | \param[in] rcfile The path to use. If NULL, or "", |
168 | | then do not use any rcfile. |
169 | | |
170 | | \retval OC_NOERR if the request succeeded. |
171 | | \retval OC_ERCFILE if the file failed to load |
172 | | */ |
173 | | |
174 | | int |
175 | | NC_set_rcfile(const char* rcfile) |
176 | 0 | { |
177 | 0 | int stat = NC_NOERR; |
178 | 0 | FILE* f = NULL; |
179 | 0 | NCRCglobalstate* globalstate = ncrc_getglobalstate(); |
180 | |
|
181 | 0 | if(rcfile != NULL && strlen(rcfile) == 0) |
182 | 0 | rcfile = NULL; |
183 | 0 | f = NCfopen(rcfile,"r"); |
184 | 0 | if(f == NULL) { |
185 | 0 | stat = NC_ERCFILE; |
186 | 0 | goto done; |
187 | 0 | } |
188 | 0 | fclose(f); |
189 | 0 | nullfree(globalstate->rcinfo.rcfile); |
190 | 0 | globalstate->rcinfo.rcfile = strdup(rcfile); |
191 | | /* Clear globalstate->rcinfo */ |
192 | 0 | NC_rcclear(&globalstate->rcinfo); |
193 | | /* (re) load the rcfile and esp the triplestore*/ |
194 | 0 | stat = NC_rcload(); |
195 | 0 | done: |
196 | 0 | return stat; |
197 | 0 | } |
198 | | |
199 | | /**************************************************/ |
200 | | /* RC processing functions */ |
201 | | |
202 | | static char* |
203 | | rcreadline(char** nextlinep) |
204 | 0 | { |
205 | 0 | char* line; |
206 | 0 | char* p; |
207 | |
|
208 | 0 | line = (p = *nextlinep); |
209 | 0 | if(*p == '\0') return NULL; /*signal done*/ |
210 | 0 | for(;*p;p++) { |
211 | 0 | if(*p == '\r' && p[1] == '\n') *p = '\0'; |
212 | 0 | else if(*p == '\n') break; |
213 | 0 | } |
214 | 0 | *p++ = '\0'; /* null terminate line; overwrite newline */ |
215 | 0 | *nextlinep = p; |
216 | 0 | return line; |
217 | 0 | } |
218 | | |
219 | | /* Trim TRIMCHARS from both ends of text; */ |
220 | | static void |
221 | | rctrim(char* text) |
222 | 0 | { |
223 | 0 | char* p = text; |
224 | 0 | size_t len = 0; |
225 | 0 | int i; |
226 | | |
227 | | /* locate first non-trimchar */ |
228 | 0 | for(;*p;p++) { |
229 | 0 | if(strchr(TRIMCHARS,*p) == NULL) break; /* hit non-trim char */ |
230 | 0 | } |
231 | 0 | memmove(text,p,strlen(p)+1); |
232 | 0 | len = strlen(text); |
233 | | /* locate last non-trimchar */ |
234 | 0 | if(len > 0) { |
235 | 0 | for(i=(len-1);i>=0;i--) { |
236 | 0 | if(strchr(TRIMCHARS,text[i]) == NULL) { |
237 | 0 | text[i+1] = '\0'; /* elide trailing trimchars */ |
238 | 0 | break; |
239 | 0 | } |
240 | 0 | } |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | | /* Order the triples: those with urls must be first, |
245 | | but otherwise relative order does not matter. |
246 | | */ |
247 | | static void |
248 | | rcorder(NClist* rc) |
249 | 0 | { |
250 | 0 | int i; |
251 | 0 | int len = nclistlength(rc); |
252 | 0 | NClist* tmprc = NULL; |
253 | 0 | if(rc == NULL || len == 0) return; |
254 | 0 | tmprc = nclistnew(); |
255 | | /* Copy rc into tmprc and clear rc */ |
256 | 0 | for(i=0;i<len;i++) { |
257 | 0 | NCTriple* ti = nclistget(rc,i); |
258 | 0 | nclistpush(tmprc,ti); |
259 | 0 | } |
260 | 0 | nclistclear(rc); |
261 | | /* Two passes: 1) pull triples with host */ |
262 | 0 | for(i=0;i<len;i++) { |
263 | 0 | NCTriple* ti = nclistget(tmprc,i); |
264 | 0 | if(ti->host == NULL) continue; |
265 | 0 | nclistpush(rc,ti); |
266 | 0 | } |
267 | | /* pass 2 pull triples without host*/ |
268 | 0 | for(i=0;i<len;i++) { |
269 | 0 | NCTriple* ti = nclistget(tmprc,i); |
270 | 0 | if(ti->host != NULL) continue; |
271 | 0 | nclistpush(rc,ti); |
272 | 0 | } |
273 | | #ifdef D4DEBUG |
274 | | storedump("reorder:",rc); |
275 | | #endif |
276 | 0 | nclistfree(tmprc); |
277 | 0 | } |
278 | | |
279 | | /* Create a triple store from a file */ |
280 | | static int |
281 | | rccompile(const char* path) |
282 | 0 | { |
283 | 0 | int ret = NC_NOERR; |
284 | 0 | NClist* rc = NULL; |
285 | 0 | char* contents = NULL; |
286 | 0 | NCbytes* tmp = ncbytesnew(); |
287 | 0 | NCURI* uri = NULL; |
288 | 0 | char* nextline = NULL; |
289 | 0 | NCRCglobalstate* globalstate = ncrc_getglobalstate(); |
290 | |
|
291 | 0 | if((ret=NC_readfile(path,tmp))) { |
292 | 0 | nclog(NCLOGERR, "Could not open configuration file: %s",path); |
293 | 0 | goto done; |
294 | 0 | } |
295 | 0 | contents = ncbytesextract(tmp); |
296 | 0 | if(contents == NULL) contents = strdup(""); |
297 | | /* Either reuse or create new */ |
298 | 0 | rc = globalstate->rcinfo.triples; |
299 | 0 | if(rc != NULL) |
300 | 0 | rcfreetriples(rc); /* clear out any old data */ |
301 | 0 | else { |
302 | 0 | rc = nclistnew(); |
303 | 0 | globalstate->rcinfo.triples = rc; |
304 | 0 | } |
305 | 0 | nextline = contents; |
306 | 0 | for(;;) { |
307 | 0 | char* line; |
308 | 0 | char* key; |
309 | 0 | char* value; |
310 | 0 | size_t llen; |
311 | 0 | NCTriple* triple; |
312 | |
|
313 | 0 | line = rcreadline(&nextline); |
314 | 0 | if(line == NULL) break; /* done */ |
315 | 0 | rctrim(line); /* trim leading and trailing blanks */ |
316 | 0 | if(line[0] == '#') continue; /* comment */ |
317 | 0 | if((llen=strlen(line)) == 0) continue; /* empty line */ |
318 | 0 | triple = (NCTriple*)calloc(1,sizeof(NCTriple)); |
319 | 0 | if(triple == NULL) {ret = NC_ENOMEM; goto done;} |
320 | 0 | if(line[0] == LTAG) { |
321 | 0 | char* url = ++line; |
322 | 0 | char* rtag = strchr(line,RTAG); |
323 | 0 | if(rtag == NULL) { |
324 | 0 | nclog(NCLOGERR, "Malformed [url] in %s entry: %s",path,line); |
325 | 0 | free(triple); |
326 | 0 | continue; |
327 | 0 | } |
328 | 0 | line = rtag + 1; |
329 | 0 | *rtag = '\0'; |
330 | | /* compile the url and pull out the host */ |
331 | 0 | if(uri) ncurifree(uri); |
332 | 0 | if(ncuriparse(url,&uri)) { |
333 | 0 | nclog(NCLOGERR, "Malformed [url] in %s entry: %s",path,line); |
334 | 0 | free(triple); |
335 | 0 | continue; |
336 | 0 | } |
337 | 0 | ncbytesclear(tmp); |
338 | 0 | ncbytescat(tmp,uri->host); |
339 | 0 | if(uri->port != NULL) { |
340 | 0 | ncbytesappend(tmp,':'); |
341 | 0 | ncbytescat(tmp,uri->port); |
342 | 0 | } |
343 | 0 | ncbytesnull(tmp); |
344 | 0 | triple->host = ncbytesextract(tmp); |
345 | 0 | if(strlen(triple->host)==0) |
346 | 0 | {free(triple->host); triple->host = NULL;} |
347 | 0 | } |
348 | | /* split off key and value */ |
349 | 0 | key=line; |
350 | 0 | value = strchr(line, '='); |
351 | 0 | if(value == NULL) |
352 | 0 | value = line + strlen(line); |
353 | 0 | else { |
354 | 0 | *value = '\0'; |
355 | 0 | value++; |
356 | 0 | } |
357 | 0 | triple->key = strdup(key); |
358 | 0 | triple->value = strdup(value); |
359 | 0 | rctrim(triple->key); |
360 | 0 | rctrim(triple->value); |
361 | | #ifdef D4DEBUG |
362 | | fprintf(stderr,"rc: host=%s key=%s value=%s\n", |
363 | | (triple->host != NULL ? triple->host : "<null>"), |
364 | | triple->key,triple->valu); |
365 | | #endif |
366 | 0 | nclistpush(rc,triple); |
367 | 0 | triple = NULL; |
368 | 0 | } |
369 | 0 | rcorder(rc); |
370 | |
|
371 | 0 | done: |
372 | 0 | if(contents) free(contents); |
373 | 0 | ncurifree(uri); |
374 | 0 | ncbytesfree(tmp); |
375 | 0 | return (ret); |
376 | 0 | } |
377 | | |
378 | | /** |
379 | | * (Internal) Locate a triple by property key and host+port (may be null or ""). |
380 | | * If duplicate keys, first takes precedence. |
381 | | */ |
382 | | static struct NCTriple* |
383 | | rclocate(const char* key, const char* hostport) |
384 | 0 | { |
385 | 0 | int i,found; |
386 | 0 | NCRCglobalstate* globalstate = ncrc_getglobalstate(); |
387 | 0 | NClist* rc = globalstate->rcinfo.triples; |
388 | 0 | NCTriple* triple = NULL; |
389 | |
|
390 | 0 | if(globalstate->rcinfo.ignore) |
391 | 0 | return NULL; |
392 | | |
393 | 0 | if(key == NULL || rc == NULL) return NULL; |
394 | 0 | if(hostport == NULL) hostport = ""; |
395 | |
|
396 | 0 | for(found=0,i=0;i<nclistlength(rc);i++) { |
397 | 0 | int t; |
398 | 0 | size_t hplen; |
399 | 0 | triple = (NCTriple*)nclistget(rc,i); |
400 | |
|
401 | 0 | hplen = (triple->host == NULL ? 0 : strlen(triple->host)); |
402 | |
|
403 | 0 | if(strcmp(key,triple->key) != 0) continue; /* keys do not match */ |
404 | | /* If the triple entry has no url, then use it |
405 | | (because we have checked all other cases)*/ |
406 | 0 | if(hplen == 0) {found=1;break;} |
407 | | /* do hostport match */ |
408 | 0 | t = 0; |
409 | 0 | if(triple->host != NULL) |
410 | 0 | t = strcmp(hostport,triple->host); |
411 | 0 | if(t == 0) {found=1; break;} |
412 | 0 | } |
413 | 0 | return (found?triple:NULL); |
414 | 0 | } |
415 | | |
416 | | /** |
417 | | * Locate rc file by searching in directory prefix. |
418 | | */ |
419 | | static |
420 | | int |
421 | | rcsearch(const char* prefix, const char* rcname, char** pathp) |
422 | 6 | { |
423 | 6 | char* path = NULL; |
424 | 6 | FILE* f = NULL; |
425 | 6 | size_t plen = (prefix?strlen(prefix):0); |
426 | 6 | size_t rclen = strlen(rcname); |
427 | 6 | int ret = NC_NOERR; |
428 | | |
429 | 6 | size_t pathlen = plen+rclen+1; /*+1 for '/' */ |
430 | 6 | path = (char*)malloc(pathlen+1); /* +1 for nul*/ |
431 | 6 | if(path == NULL) {ret = NC_ENOMEM; goto done;} |
432 | 6 | strncpy(path,prefix,pathlen); |
433 | 6 | strncat(path,"/",pathlen); |
434 | 6 | strncat(path,rcname,pathlen); |
435 | | /* see if file is readable */ |
436 | 6 | f = fopen(path,"r"); |
437 | 6 | if(f != NULL) |
438 | 0 | nclog(NCLOGDBG, "Found rc file=%s",path); |
439 | 6 | done: |
440 | 6 | if(f == NULL || ret != NC_NOERR) { |
441 | 6 | nullfree(path); |
442 | 6 | path = NULL; |
443 | 6 | } |
444 | 6 | if(f != NULL) |
445 | 0 | fclose(f); |
446 | 6 | if(pathp != NULL) |
447 | 6 | *pathp = path; |
448 | 0 | else { |
449 | 0 | nullfree(path); |
450 | 0 | path = NULL; |
451 | 0 | } |
452 | 6 | return (ret); |
453 | 6 | } |
454 | | |
455 | | int |
456 | | NC_rcfile_insert(const char* key, const char* value, const char* hostport) |
457 | 0 | { |
458 | 0 | int ret = NC_NOERR; |
459 | | /* See if this key already defined */ |
460 | 0 | struct NCTriple* triple = NULL; |
461 | 0 | NCRCglobalstate* globalstate = ncrc_getglobalstate(); |
462 | 0 | NClist* rc = globalstate->rcinfo.triples; |
463 | |
|
464 | 0 | if(rc == NULL) { |
465 | 0 | rc = nclistnew(); |
466 | 0 | if(rc == NULL) {ret = NC_ENOMEM; goto done;} |
467 | 0 | } |
468 | 0 | triple = rclocate(key,hostport); |
469 | 0 | if(triple == NULL) { |
470 | 0 | triple = (NCTriple*)calloc(1,sizeof(NCTriple)); |
471 | 0 | if(triple == NULL) {ret = NC_ENOMEM; goto done;} |
472 | 0 | triple->key = strdup(key); |
473 | 0 | triple->value = NULL; |
474 | 0 | rctrim(triple->key); |
475 | 0 | triple->host = (hostport == NULL ? NULL : strdup(hostport)); |
476 | 0 | nclistpush(rc,triple); |
477 | 0 | } |
478 | 0 | if(triple->value != NULL) free(triple->value); |
479 | 0 | triple->value = strdup(value); |
480 | 0 | rctrim(triple->value); |
481 | 0 | done: |
482 | 0 | return ret; |
483 | 0 | } |
484 | | |
485 | | /* Obtain the count of number of triples */ |
486 | | size_t |
487 | | NC_rcfile_length(NCRCinfo* info) |
488 | 0 | { |
489 | 0 | return nclistlength(info->triples); |
490 | 0 | } |
491 | | |
492 | | /* Obtain the ith triple; return NULL if out of range */ |
493 | | NCTriple* |
494 | | NC_rcfile_ith(NCRCinfo* info, size_t i) |
495 | 0 | { |
496 | 0 | if(i >= nclistlength(info->triples)) |
497 | 0 | return NULL; |
498 | 0 | return (NCTriple*)nclistget(info->triples,i); |
499 | 0 | } |
500 | | |
501 | | |
502 | | #ifdef D4DEBUG |
503 | | static void |
504 | | storedump(char* msg, NClist* triples) |
505 | | { |
506 | | int i; |
507 | | |
508 | | if(msg != NULL) fprintf(stderr,"%s\n",msg); |
509 | | if(triples == NULL || nclistlength(triples)==0) { |
510 | | fprintf(stderr,"<EMPTY>\n"); |
511 | | return; |
512 | | } |
513 | | for(i=0;i<nclistlength(triples);i++) { |
514 | | NCTriple* t = (NCTriple*)nclistget(triples,i); |
515 | | fprintf(stderr,"\t%s\t%s\t%s\n", |
516 | | ((t->host == NULL || strlen(t->host)==0)?"--":t->host),t->key,t->value); |
517 | | } |
518 | | fflush(stderr); |
519 | | } |
520 | | #endif |