/src/netcdf-c/libdispatch/drc.c
Line | Count | Source |
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 | | #include <stddef.h> |
8 | | #ifdef HAVE_UNISTD_H |
9 | | #include <unistd.h> |
10 | | #endif |
11 | | #ifdef HAVE_STDARG_H |
12 | | #include <stdarg.h> |
13 | | #endif |
14 | | #include <stdio.h> |
15 | | #include <stdlib.h> |
16 | | #include <string.h> |
17 | | #include <assert.h> |
18 | | |
19 | | #include "netcdf.h" |
20 | | #include "ncbytes.h" |
21 | | #include "ncuri.h" |
22 | | #include "ncrc.h" |
23 | | #include "nclog.h" |
24 | | #include "ncauth.h" |
25 | | #include "ncpathmgr.h" |
26 | | #include "nc4internal.h" |
27 | | #include "ncs3sdk.h" |
28 | | #include "ncdispatch.h" |
29 | | #include "ncutil.h" |
30 | | |
31 | | #undef NOREAD |
32 | | |
33 | | #undef DRCDEBUG |
34 | | #undef LEXDEBUG |
35 | | #undef PARSEDEBUG |
36 | | |
37 | 0 | #define RTAG ']' |
38 | 0 | #define LTAG '[' |
39 | | |
40 | | #undef MEMCHECK |
41 | | #define MEMCHECK(x) if((x)==NULL) {goto nomem;} else {} |
42 | | |
43 | | /* Forward */ |
44 | | static int NC_rcload(void); |
45 | | static char* rcreadline(char** nextlinep); |
46 | | static void rctrim(char* text); |
47 | | static void rcorder(NClist* rc); |
48 | | static int rccompile(const char* path); |
49 | | static int rcequal(NCRCentry* e1, NCRCentry* e2); |
50 | | static int rclocatepos(const char* key, const char* hostport, const char* urlpath); |
51 | | static struct NCRCentry* rclocate(const char* key, const char* hostport, const char* urlpath); |
52 | | static int rcsearch(const char* prefix, const char* rcname, char** pathp); |
53 | | static void rcfreeentries(NClist* rc); |
54 | | static void rcfreeentry(NCRCentry* t); |
55 | | #ifdef DRCDEBUG |
56 | | static void storedump(char* msg, NClist* entrys); |
57 | | #endif |
58 | | |
59 | | /* Define default rc files and aliases, also defines load order*/ |
60 | | static const char* rcfilenames[] = {".ncrc", ".daprc", ".dodsrc", NULL}; |
61 | | |
62 | | static int NCRCinitialized = 0; |
63 | | |
64 | | /**************************************************/ |
65 | | /* User API */ |
66 | | |
67 | | /** |
68 | | The most common case is to get the most general value for a key, |
69 | | where most general means that the urlpath and hostport are null |
70 | | So this function returns the value associated with the key |
71 | | where the .rc entry has the simple form "key=value". |
72 | | If that entry is not found, then return NULL. |
73 | | |
74 | | @param key table entry key field |
75 | | @param table entry key field |
76 | | @return value matching the key -- caller frees |
77 | | @return NULL if no entry of the form key=value exists |
78 | | */ |
79 | | char* |
80 | | nc_rc_get(const char* key) |
81 | 0 | { |
82 | 0 | NCglobalstate* ncg = NULL; |
83 | 0 | char* value = NULL; |
84 | |
|
85 | 0 | if(!NC_initialized) nc_initialize(); |
86 | |
|
87 | 0 | ncg = NC_getglobalstate(); |
88 | 0 | assert(ncg != NULL && ncg->rcinfo != NULL && ncg->rcinfo->entries != NULL); |
89 | 0 | if(ncg->rcinfo->ignore) goto done; |
90 | 0 | value = NC_rclookup(key,NULL,NULL); |
91 | 0 | done: |
92 | 0 | value = nulldup(value); |
93 | 0 | return value; |
94 | 0 | } |
95 | | |
96 | | /** |
97 | | Set simple key=value in .rc table. |
98 | | Will overwrite any existing value. |
99 | | |
100 | | @param key |
101 | | @param value |
102 | | @return NC_NOERR if success |
103 | | @return NC_EINVAL if fail |
104 | | */ |
105 | | int |
106 | | nc_rc_set(const char* key, const char* value) |
107 | 0 | { |
108 | 0 | int stat = NC_NOERR; |
109 | 0 | NCglobalstate* ncg = NULL; |
110 | |
|
111 | 0 | if(!NC_initialized) nc_initialize(); |
112 | |
|
113 | 0 | ncg = NC_getglobalstate(); |
114 | 0 | assert(ncg != NULL && ncg->rcinfo != NULL && ncg->rcinfo->entries != NULL); |
115 | 0 | if(ncg->rcinfo->ignore) goto done;; |
116 | 0 | stat = NC_rcfile_insert(key,NULL,NULL,value); |
117 | 0 | done: |
118 | 0 | return stat; |
119 | 0 | } |
120 | | |
121 | | /**************************************************/ |
122 | | /* External Entry Points */ |
123 | | |
124 | | /* |
125 | | Initialize defaults and load: |
126 | | * .ncrc |
127 | | * .dodsrc |
128 | | * ${HOME}/.aws/config |
129 | | * ${HOME}/.aws/credentials |
130 | | |
131 | | For debugging support, it is possible |
132 | | to change where the code looks for the .aws directory. |
133 | | This is set by the environment variable NC_TEST_AWS_DIR. |
134 | | |
135 | | */ |
136 | | |
137 | | void |
138 | | ncrc_initialize(void) |
139 | 1 | { |
140 | 1 | if(NCRCinitialized) return; |
141 | 1 | NCRCinitialized = 1; /* prevent recursion */ |
142 | | |
143 | 1 | #ifndef NOREAD |
144 | 1 | { |
145 | 1 | int stat = NC_NOERR; |
146 | 1 | NCglobalstate* ncg = NC_getglobalstate(); |
147 | | /* Load entrys */ |
148 | 1 | if((stat = NC_rcload())) { |
149 | 0 | nclog(NCLOGWARN,".rc loading failed"); |
150 | 0 | } |
151 | | /* Load .aws/config &/ credentials */ |
152 | 1 | if((stat = NC_aws_load_credentials(ncg))) { |
153 | 1 | nclog(NCLOGWARN,"AWS config file not loaded"); |
154 | 1 | } |
155 | 1 | } |
156 | 1 | #endif |
157 | 1 | } |
158 | | |
159 | | static void |
160 | | ncrc_setrchome(void) |
161 | 1 | { |
162 | 1 | const char* tmp = NULL; |
163 | 1 | NCglobalstate* ncg = NC_getglobalstate(); |
164 | 1 | assert(ncg && ncg->home); |
165 | 1 | if(ncg->rcinfo->rchome) return; |
166 | 1 | tmp = getenv(NCRCENVHOME); |
167 | 1 | if(tmp == NULL || strlen(tmp) == 0) |
168 | 1 | tmp = ncg->home; |
169 | 1 | ncg->rcinfo->rchome = strdup(tmp); |
170 | | #ifdef DRCDEBUG |
171 | | fprintf(stderr,"ncrc_setrchome: %s\n",ncg->rcinfo->rchome); |
172 | | #endif |
173 | 1 | } |
174 | | |
175 | | void |
176 | | NC_rcclear(NCRCinfo* info) |
177 | 1 | { |
178 | 1 | if(info == NULL) return; |
179 | 1 | nullfree(info->rcfile); |
180 | 1 | nullfree(info->rchome); |
181 | 1 | rcfreeentries(info->entries); |
182 | 1 | NC_s3freeprofilelist(info->s3profiles); |
183 | 1 | } |
184 | | |
185 | | static void |
186 | | rcfreeentry(NCRCentry* t) |
187 | 0 | { |
188 | 0 | nullfree(t->host); |
189 | 0 | nullfree(t->urlpath); |
190 | 0 | nullfree(t->key); |
191 | 0 | nullfree(t->value); |
192 | 0 | free(t); |
193 | 0 | } |
194 | | |
195 | | static void |
196 | | rcfreeentries(NClist* rc) |
197 | 1 | { |
198 | 1 | size_t i; |
199 | 1 | for(i=0;i<nclistlength(rc);i++) { |
200 | 0 | NCRCentry* t = (NCRCentry*)nclistget(rc,i); |
201 | 0 | rcfreeentry(t); |
202 | 0 | } |
203 | 1 | nclistfree(rc); |
204 | 1 | } |
205 | | |
206 | | /* locate, read and compile the rc files, if any */ |
207 | | static int |
208 | | NC_rcload(void) |
209 | 1 | { |
210 | 1 | size_t i; |
211 | 1 | int ret = NC_NOERR; |
212 | 1 | char* path = NULL; |
213 | 1 | NCglobalstate* globalstate = NULL; |
214 | 1 | NClist* rcfileorder = nclistnew(); |
215 | | |
216 | 1 | if(!NCRCinitialized) ncrc_initialize(); |
217 | 1 | globalstate = NC_getglobalstate(); |
218 | | |
219 | 1 | if(globalstate->rcinfo->ignore) { |
220 | 0 | nclog(NCLOGNOTE,".rc file loading suppressed"); |
221 | 0 | goto done; |
222 | 0 | } |
223 | 1 | if(globalstate->rcinfo->loaded) goto done; |
224 | | |
225 | | /* locate the configuration files in order of use: |
226 | | 1. Specified by NCRCENV_RC environment variable. |
227 | | 2. If NCRCENV_RC is not set then merge the set of rc files in this order: |
228 | | 1. $HOME/.ncrc |
229 | | 2. $HOME/.dodsrc |
230 | | 3. $CWD/.ncrc |
231 | | 4. $CWD/.dodsrc |
232 | | Entries in later files override any of the earlier files |
233 | | */ |
234 | 1 | if(globalstate->rcinfo->rcfile != NULL) { /* always use this */ |
235 | 0 | nclistpush(rcfileorder,strdup(globalstate->rcinfo->rcfile)); |
236 | 1 | } else { |
237 | 1 | const char** rcname; |
238 | 1 | const char* dirnames[3]; |
239 | 1 | const char** dir; |
240 | | |
241 | | /* Make sure rcinfo.rchome is defined */ |
242 | 1 | ncrc_setrchome(); |
243 | 1 | dirnames[0] = globalstate->rcinfo->rchome; |
244 | 1 | dirnames[1] = globalstate->cwd; |
245 | 1 | dirnames[2] = NULL; |
246 | | |
247 | 3 | for(dir=dirnames;*dir;dir++) { |
248 | 8 | for(rcname=rcfilenames;*rcname;rcname++) { |
249 | 6 | ret = rcsearch(*dir,*rcname,&path); |
250 | 6 | if(ret == NC_NOERR && path != NULL) |
251 | 0 | nclistpush(rcfileorder,path); |
252 | 6 | path = NULL; |
253 | 6 | } |
254 | 2 | } |
255 | 1 | } |
256 | 1 | for(i=0;i<nclistlength(rcfileorder);i++) { |
257 | 0 | path = (char*)nclistget(rcfileorder,i); |
258 | 0 | if((ret=rccompile(path))) { |
259 | 0 | nclog(NCLOGWARN, "Error parsing %s\n",path); |
260 | 0 | ret = NC_NOERR; /* ignore it */ |
261 | 0 | goto done; |
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | 1 | done: |
266 | 1 | globalstate->rcinfo->loaded = 1; /* even if not exists */ |
267 | 1 | nclistfreeall(rcfileorder); |
268 | 1 | return (ret); |
269 | 1 | } |
270 | | |
271 | | /** |
272 | | * Locate a entry by property key. |
273 | | * If duplicate keys, first takes precedence. |
274 | | * @param key to lookup |
275 | | * @param hostport to use for lookup |
276 | | * @param urlpath to use for lookup |
277 | | * @return the value of the key or NULL if not found. |
278 | | */ |
279 | | char* |
280 | | NC_rclookup(const char* key, const char* hostport, const char* urlpath) |
281 | 1 | { |
282 | 1 | struct NCRCentry* entry = NULL; |
283 | 1 | if(!NCRCinitialized) ncrc_initialize(); |
284 | 1 | entry = rclocate(key,hostport,urlpath); |
285 | 1 | return (entry == NULL ? NULL : entry->value); |
286 | 1 | } |
287 | | |
288 | | /** |
289 | | * Locate a entry by property key and uri. |
290 | | * If duplicate keys, first takes precedence. |
291 | | */ |
292 | | char* |
293 | | NC_rclookupx(NCURI* uri, const char* key) |
294 | 0 | { |
295 | 0 | char* hostport = NULL; |
296 | 0 | char* result = NULL; |
297 | |
|
298 | 0 | hostport = NC_combinehostport(uri); |
299 | 0 | result = NC_rclookup(key,hostport,uri->path); |
300 | 0 | nullfree(hostport); |
301 | 0 | return result; |
302 | 0 | } |
303 | | |
304 | | #if 0 |
305 | | /*! |
306 | | Set the absolute path to use for the rc file. |
307 | | WARNING: this MUST be called before any other |
308 | | call in order for this to take effect. |
309 | | |
310 | | \param[in] rcfile The path to use. If NULL then do not use any rcfile. |
311 | | |
312 | | \retval OC_NOERR if the request succeeded. |
313 | | \retval OC_ERCFILE if the file failed to load |
314 | | */ |
315 | | |
316 | | int |
317 | | NC_set_rcfile(const char* rcfile) |
318 | | { |
319 | | int stat = NC_NOERR; |
320 | | FILE* f = NULL; |
321 | | NCglobalstate* globalstate = NC_getglobalstate(); |
322 | | |
323 | | if(rcfile != NULL && strlen(rcfile) == 0) |
324 | | rcfile = NULL; |
325 | | f = NCfopen(rcfile,"r"); |
326 | | if(f == NULL) { |
327 | | stat = NC_ERCFILE; |
328 | | goto done; |
329 | | } |
330 | | fclose(f); |
331 | | NC_rcclear(globalstate->rcinfo); |
332 | | globalstate->rcinfo->rcfile = strdup(rcfile); |
333 | | /* Clear globalstate->rcinfo */ |
334 | | NC_rcclear(&globalstate->rcinfo); |
335 | | /* (re) load the rcfile and esp the entriestore*/ |
336 | | stat = NC_rcload(); |
337 | | done: |
338 | | return stat; |
339 | | } |
340 | | #endif |
341 | | |
342 | | /**************************************************/ |
343 | | /* RC processing functions */ |
344 | | |
345 | | static char* |
346 | | rcreadline(char** nextlinep) |
347 | 0 | { |
348 | 0 | char* line; |
349 | 0 | char* p; |
350 | |
|
351 | 0 | line = (p = *nextlinep); |
352 | 0 | if(*p == '\0') return NULL; /*signal done*/ |
353 | 0 | for(;*p;p++) { |
354 | 0 | if(*p == '\r' && p[1] == '\n') *p = '\0'; |
355 | 0 | else if(*p == '\n') break; |
356 | 0 | } |
357 | 0 | *p++ = '\0'; /* null terminate line; overwrite newline */ |
358 | 0 | *nextlinep = p; |
359 | 0 | return line; |
360 | 0 | } |
361 | | |
362 | | /* Trim TRIMCHARS from both ends of text; */ |
363 | | static void |
364 | | rctrim(char* text) |
365 | 0 | { |
366 | 0 | char* p; |
367 | 0 | char* q; |
368 | 0 | size_t len = 0; |
369 | |
|
370 | 0 | if(text == NULL || *text == '\0') return; |
371 | | |
372 | 0 | len = strlen(text); |
373 | | |
374 | | /* elide upto first non-trimchar */ |
375 | 0 | for(q=text,p=text;*p;p++) { |
376 | 0 | if(*p != ' ' && *p != '\t' && *p != '\r') {*q++ = *p;} |
377 | 0 | } |
378 | 0 | len = strlen(p); |
379 | | /* locate last non-trimchar */ |
380 | 0 | if(len > 0) { |
381 | 0 | for(size_t i = len; i-->0;) { |
382 | 0 | p = &text[i]; |
383 | 0 | if(*p != ' ' && *p != '\t' && *p != '\r') {break;} |
384 | 0 | *p = '\0'; /* elide trailing trimchars */ |
385 | 0 | } |
386 | 0 | } |
387 | 0 | } |
388 | | |
389 | | /* Order the entries: those with urls must be first, |
390 | | but otherwise relative order does not matter. |
391 | | */ |
392 | | static void |
393 | | rcorder(NClist* rc) |
394 | 0 | { |
395 | 0 | size_t i; |
396 | 0 | size_t len = nclistlength(rc); |
397 | 0 | NClist* tmprc = NULL; |
398 | 0 | if(rc == NULL || len == 0) return; |
399 | 0 | tmprc = nclistnew(); |
400 | | /* Two passes: 1) pull entries with host */ |
401 | 0 | for(i=0;i<len;i++) { |
402 | 0 | NCRCentry* ti = nclistget(rc,i); |
403 | 0 | if(ti->host == NULL) continue; |
404 | 0 | nclistpush(tmprc,ti); |
405 | 0 | } |
406 | | /* pass 2 pull entries without host*/ |
407 | 0 | for(i=0;i<len;i++) { |
408 | 0 | NCRCentry* ti = nclistget(rc,i); |
409 | 0 | if(ti->host != NULL) continue; |
410 | 0 | nclistpush(tmprc,ti); |
411 | 0 | } |
412 | | /* Move tmp to rc */ |
413 | 0 | nclistsetlength(rc,0); |
414 | 0 | for(i=0;i<len;i++) { |
415 | 0 | NCRCentry* ti = nclistget(tmprc,i); |
416 | 0 | nclistpush(rc,ti); |
417 | 0 | } |
418 | | #ifdef DRCDEBUG |
419 | | storedump("reorder:",rc); |
420 | | #endif |
421 | 0 | nclistfree(tmprc); |
422 | 0 | } |
423 | | |
424 | | /* Merge a entry store from a file*/ |
425 | | static int |
426 | | rccompile(const char* filepath) |
427 | 0 | { |
428 | 0 | int ret = NC_NOERR; |
429 | 0 | NClist* rc = NULL; |
430 | 0 | char* contents = NULL; |
431 | 0 | NCbytes* tmp = ncbytesnew(); |
432 | 0 | NCURI* uri = NULL; |
433 | 0 | char* nextline = NULL; |
434 | 0 | NCglobalstate* globalstate = NC_getglobalstate(); |
435 | 0 | NCS3INFO s3; |
436 | |
|
437 | 0 | memset(&s3,0,sizeof(s3)); |
438 | |
|
439 | 0 | if((ret=NC_readfile(filepath,tmp))) { |
440 | 0 | nclog(NCLOGWARN, "Could not open configuration file: %s",filepath); |
441 | 0 | goto done; |
442 | 0 | } |
443 | 0 | contents = ncbytesextract(tmp); |
444 | 0 | if(contents == NULL) contents = strdup(""); |
445 | | /* Either reuse or create new */ |
446 | 0 | rc = globalstate->rcinfo->entries; |
447 | 0 | if(rc == NULL) { |
448 | 0 | rc = nclistnew(); |
449 | 0 | globalstate->rcinfo->entries = rc; |
450 | 0 | } |
451 | 0 | nextline = contents; |
452 | 0 | for(;;) { |
453 | 0 | char* line; |
454 | 0 | char* key = NULL; |
455 | 0 | char* value = NULL; |
456 | 0 | char* host = NULL; |
457 | 0 | char* urlpath = NULL; |
458 | 0 | size_t llen; |
459 | 0 | NCRCentry* entry; |
460 | |
|
461 | 0 | line = rcreadline(&nextline); |
462 | 0 | if(line == NULL) break; /* done */ |
463 | 0 | rctrim(line); /* trim leading and trailing blanks */ |
464 | 0 | if(line[0] == '#') continue; /* comment */ |
465 | 0 | if((llen=strlen(line)) == 0) continue; /* empty line */ |
466 | 0 | if(line[0] == LTAG) { |
467 | 0 | char* url = ++line; |
468 | 0 | char* rtag = strchr(line,RTAG); |
469 | 0 | if(rtag == NULL) { |
470 | 0 | nclog(NCLOGERR, "Malformed [url] in %s entry: %s",filepath,line); |
471 | 0 | continue; |
472 | 0 | } |
473 | 0 | line = rtag + 1; |
474 | 0 | *rtag = '\0'; |
475 | | /* compile the url and pull out the host, port, and path */ |
476 | 0 | if(uri) ncurifree(uri); |
477 | 0 | if(ncuriparse(url,&uri)) { |
478 | 0 | nclog(NCLOGERR, "Malformed [url] in %s entry: %s",filepath,line); |
479 | 0 | continue; |
480 | 0 | } |
481 | 0 | if(NC_iss3(uri,NULL)) { |
482 | 0 | NCURI* newuri = NULL; |
483 | | /* Rebuild the url to S3 "path" format */ |
484 | 0 | NC_s3clear(&s3); |
485 | 0 | if((ret = NC_s3urlrebuild(uri,&s3,&newuri))) goto done; |
486 | 0 | ncurifree(uri); |
487 | 0 | uri = newuri; |
488 | 0 | newuri = NULL; |
489 | 0 | } |
490 | | /* Get the host+port */ |
491 | 0 | ncbytesclear(tmp); |
492 | 0 | ncbytescat(tmp,uri->host); |
493 | 0 | if(uri->port != NULL) { |
494 | 0 | ncbytesappend(tmp,':'); |
495 | 0 | ncbytescat(tmp,uri->port); |
496 | 0 | } |
497 | 0 | ncbytesnull(tmp); |
498 | 0 | host = ncbytesextract(tmp); |
499 | 0 | if(strlen(host)==0) /* nullify host */ |
500 | 0 | {free(host); host = NULL;} |
501 | | /* Get the url path part */ |
502 | 0 | urlpath = uri->path; |
503 | 0 | if(urlpath && strlen(urlpath)==0) urlpath = NULL; /* nullify */ |
504 | 0 | } |
505 | | /* split off key and value */ |
506 | 0 | key=line; |
507 | 0 | value = strchr(line, '='); |
508 | 0 | if(value == NULL) |
509 | 0 | value = line + strlen(line); |
510 | 0 | else { |
511 | 0 | *value = '\0'; |
512 | 0 | value++; |
513 | 0 | } |
514 | | /* See if key already exists */ |
515 | 0 | entry = rclocate(key,host,urlpath); |
516 | 0 | if(entry == NULL) { |
517 | 0 | entry = (NCRCentry*)calloc(1,sizeof(NCRCentry)); |
518 | 0 | if(entry == NULL) {ret = NC_ENOMEM; goto done;} |
519 | 0 | nclistpush(rc,entry); |
520 | 0 | entry->host = host; host = NULL; |
521 | 0 | entry->urlpath = nulldup(urlpath); |
522 | 0 | entry->key = nulldup(key); |
523 | 0 | rctrim(entry->host); |
524 | 0 | rctrim(entry->urlpath); |
525 | 0 | rctrim(entry->key); |
526 | 0 | } |
527 | 0 | nullfree(entry->value); |
528 | 0 | entry->value = nulldup(value); |
529 | 0 | rctrim(entry->value); |
530 | |
|
531 | | #ifdef DRCDEBUG |
532 | | fprintf(stderr,"rc: host=%s urlpath=%s key=%s value=%s\n", |
533 | | (entry->host != NULL ? entry->host : "<null>"), |
534 | | (entry->urlpath != NULL ? entry->urlpath : "<null>"), |
535 | | entry->key,entry->value); |
536 | | #endif |
537 | 0 | entry = NULL; |
538 | 0 | } |
539 | | #ifdef DRCDEBUG |
540 | | fprintf(stderr,"reorder.path=%s\n",filepath); |
541 | | #endif |
542 | 0 | rcorder(rc); |
543 | |
|
544 | 0 | done: |
545 | 0 | NC_s3clear(&s3); |
546 | 0 | if(contents) free(contents); |
547 | 0 | ncurifree(uri); |
548 | 0 | ncbytesfree(tmp); |
549 | 0 | return (ret); |
550 | 0 | } |
551 | | |
552 | | /** |
553 | | Encapsulate equality comparison: return 1|0 |
554 | | */ |
555 | | static int |
556 | | rcequal(NCRCentry* e1, NCRCentry* e2) |
557 | 0 | { |
558 | 0 | int nulltest; |
559 | 0 | if(e1->key == NULL || e2->key == NULL) return 0; |
560 | 0 | if(strcmp(e1->key,e2->key) != 0) return 0; |
561 | | /* test hostport; take NULL into account*/ |
562 | 0 | nulltest = 0; |
563 | 0 | if(e1->host == NULL) nulltest |= 1; |
564 | 0 | if(e2->host == NULL) nulltest |= 2; |
565 | | /* Use host to decide if entry applies */ |
566 | 0 | switch (nulltest) { |
567 | 0 | case 0: if(strcmp(e1->host,e2->host) != 0) {return 0;} break; |
568 | 0 | case 1: break; /* .rc->host == NULL && candidate->host != NULL */ |
569 | 0 | case 2: return 0; /* .rc->host != NULL && candidate->host == NULL */ |
570 | 0 | case 3: break; /* .rc->host == NULL && candidate->host == NULL */ |
571 | 0 | default: return 0; |
572 | 0 | } |
573 | | /* test urlpath take NULL into account*/ |
574 | 0 | nulltest = 0; |
575 | 0 | if(e1->urlpath == NULL) nulltest |= 1; |
576 | 0 | if(e2->urlpath == NULL) nulltest |= 2; |
577 | 0 | switch (nulltest) { |
578 | 0 | case 0: if(strcmp(e1->urlpath,e2->urlpath) != 0) {return 0;} break; |
579 | 0 | case 1: break; /* .rc->urlpath == NULL && candidate->urlpath != NULL */ |
580 | 0 | case 2: return 0; /* .rc->urlpath != NULL && candidate->urlpath == NULL */ |
581 | 0 | case 3: break; /* .rc->urlpath == NULL && candidate->urlpath == NULL */ |
582 | 0 | default: return 0; |
583 | 0 | } |
584 | 0 | return 1; |
585 | 0 | } |
586 | | |
587 | | /** |
588 | | * (Internal) Locate a entry by property key and host+port (may be null) and urlpath (may be null) |
589 | | * If duplicate keys, first takes precedence. |
590 | | */ |
591 | | static int |
592 | | rclocatepos(const char* key, const char* hostport, const char* urlpath) |
593 | 1 | { |
594 | 1 | size_t i; |
595 | 1 | NCglobalstate* globalstate = NC_getglobalstate(); |
596 | 1 | struct NCRCinfo* info = globalstate->rcinfo; |
597 | 1 | NCRCentry* entry = NULL; |
598 | 1 | NCRCentry candidate; |
599 | 1 | NClist* rc = info->entries; |
600 | | |
601 | 1 | if(info->ignore) return -1; |
602 | | |
603 | 1 | candidate.key = (char*)key; |
604 | 1 | candidate.value = (char*)NULL; |
605 | 1 | candidate.host = (char*)hostport; |
606 | 1 | candidate.urlpath = (char*)urlpath; |
607 | | |
608 | 1 | for(i=0;i<nclistlength(rc);i++) { |
609 | 0 | entry = (NCRCentry*)nclistget(rc,i); |
610 | 0 | if(rcequal(entry,&candidate)) return (int)i; |
611 | 0 | } |
612 | 1 | return -1; |
613 | 1 | } |
614 | | |
615 | | /** |
616 | | * (Internal) Locate a entry by property key and host+port (may be null or ""). |
617 | | * If duplicate keys, first takes precedence. |
618 | | */ |
619 | | static struct NCRCentry* |
620 | | rclocate(const char* key, const char* hostport, const char* urlpath) |
621 | 1 | { |
622 | 1 | int pos; |
623 | 1 | NCglobalstate* globalstate = NC_getglobalstate(); |
624 | 1 | struct NCRCinfo* info = globalstate->rcinfo; |
625 | | |
626 | 1 | if(globalstate->rcinfo->ignore) return NULL; |
627 | 1 | if(key == NULL || info == NULL) return NULL; |
628 | 1 | pos = rclocatepos(key,hostport,urlpath); |
629 | 1 | if(pos < 0) return NULL; |
630 | 0 | return NC_rcfile_ith(info,(size_t)pos); |
631 | 1 | } |
632 | | |
633 | | /** |
634 | | * Locate rc file by searching in directory prefix. |
635 | | */ |
636 | | static |
637 | | int |
638 | | rcsearch(const char* prefix, const char* rcname, char** pathp) |
639 | 6 | { |
640 | 6 | char* path = NULL; |
641 | 6 | FILE* f = NULL; |
642 | 6 | size_t plen = (prefix?strlen(prefix):0); |
643 | 6 | size_t rclen = strlen(rcname); |
644 | 6 | int ret = NC_NOERR; |
645 | | |
646 | 6 | size_t pathlen = plen+rclen+1+1; /*+1 for '/' +1 for nul */ |
647 | 6 | path = (char*)malloc(pathlen); /* +1 for nul*/ |
648 | 6 | if(path == NULL) {ret = NC_ENOMEM; goto done;} |
649 | 6 | snprintf(path, pathlen, "%s/%s", prefix, rcname); |
650 | | /* see if file is readable */ |
651 | 6 | f = NCfopen(path,"r"); |
652 | 6 | if(f != NULL) |
653 | 0 | nclog(NCLOGNOTE, "Found rc file=%s",path); |
654 | 6 | done: |
655 | 6 | if(f == NULL || ret != NC_NOERR) { |
656 | 6 | nullfree(path); |
657 | 6 | path = NULL; |
658 | 6 | } |
659 | 6 | if(f != NULL) |
660 | 0 | fclose(f); |
661 | 6 | if(pathp != NULL) |
662 | 6 | *pathp = path; |
663 | 0 | else { |
664 | 0 | nullfree(path); |
665 | 0 | path = NULL; |
666 | 0 | } |
667 | 6 | errno = 0; /* silently ignore errors */ |
668 | 6 | return (ret); |
669 | 6 | } |
670 | | |
671 | | int |
672 | | NC_rcfile_insert(const char* key, const char* hostport, const char* urlpath, const char* value) |
673 | 0 | { |
674 | 0 | int ret = NC_NOERR; |
675 | | /* See if this key already defined */ |
676 | 0 | struct NCRCentry* entry = NULL; |
677 | 0 | NCglobalstate* globalstate = NULL; |
678 | 0 | NClist* rc = NULL; |
679 | |
|
680 | 0 | if(!NCRCinitialized) ncrc_initialize(); |
681 | |
|
682 | 0 | if(key == NULL || value == NULL) |
683 | 0 | {ret = NC_EINVAL; goto done;} |
684 | | |
685 | 0 | globalstate = NC_getglobalstate(); |
686 | 0 | rc = globalstate->rcinfo->entries; |
687 | |
|
688 | 0 | if(rc == NULL) { |
689 | 0 | rc = nclistnew(); |
690 | 0 | globalstate->rcinfo->entries = rc; |
691 | 0 | if(rc == NULL) {ret = NC_ENOMEM; goto done;} |
692 | 0 | } |
693 | 0 | entry = rclocate(key,hostport,urlpath); |
694 | 0 | if(entry == NULL) { |
695 | 0 | entry = (NCRCentry*)calloc(1,sizeof(NCRCentry)); |
696 | 0 | if(entry == NULL) {ret = NC_ENOMEM; goto done;} |
697 | 0 | entry->key = strdup(key); |
698 | 0 | entry->value = NULL; |
699 | 0 | rctrim(entry->key); |
700 | 0 | entry->host = nulldup(hostport); |
701 | 0 | rctrim(entry->host); |
702 | 0 | entry->urlpath = nulldup(urlpath); |
703 | 0 | rctrim(entry->urlpath); |
704 | 0 | nclistpush(rc,entry); |
705 | 0 | } |
706 | 0 | if(entry->value != NULL) free(entry->value); |
707 | 0 | entry->value = strdup(value); |
708 | 0 | rctrim(entry->value); |
709 | | #ifdef DRCDEBUG |
710 | | storedump("NC_rcfile_insert",rc); |
711 | | #endif |
712 | 0 | done: |
713 | 0 | return ret; |
714 | 0 | } |
715 | | |
716 | | /* Obtain the count of number of entries */ |
717 | | size_t |
718 | | NC_rcfile_length(NCRCinfo* info) |
719 | 0 | { |
720 | 0 | return nclistlength(info->entries); |
721 | 0 | } |
722 | | |
723 | | /* Obtain the ith entry; return NULL if out of range */ |
724 | | NCRCentry* |
725 | | NC_rcfile_ith(NCRCinfo* info, size_t i) |
726 | 0 | { |
727 | 0 | if(i >= nclistlength(info->entries)) |
728 | 0 | return NULL; |
729 | 0 | return (NCRCentry*)nclistget(info->entries,i); |
730 | 0 | } |
731 | | |
732 | | |
733 | | #ifdef DRCDEBUG |
734 | | static void |
735 | | storedump(char* msg, NClist* entries) |
736 | | { |
737 | | int i; |
738 | | |
739 | | if(msg != NULL) fprintf(stderr,"%s\n",msg); |
740 | | if(entries == NULL || nclistlength(entries)==0) { |
741 | | fprintf(stderr,"<EMPTY>\n"); |
742 | | return; |
743 | | } |
744 | | for(i=0;i<nclistlength(entries);i++) { |
745 | | NCRCentry* t = (NCRCentry*)nclistget(entries,i); |
746 | | fprintf(stderr,"\t%s\t%s\t%s\n", |
747 | | ((t->host == NULL || strlen(t->host)==0)?"--":t->host),t->key,t->value); |
748 | | } |
749 | | fflush(stderr); |
750 | | } |
751 | | #endif |