Coverage Report

Created: 2025-06-09 07:43

/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