Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MapServer/src/mapserv-config.cpp
Line
Count
Source
1
/**********************************************************************
2
 * $id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Config File Support
6
 * Author:   Steve Lime and the MapServer team.
7
 *
8
 **********************************************************************
9
 * Copyright (c) 1996-2005 Regents of the University of Minnesota.
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a
12
 * copy of this software and associated documentation files (the "Software"),
13
 * to deal in the Software without restriction, including without limitation
14
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
 * and/or sell copies of the Software, and to permit persons to whom the
16
 * Software is furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies of this Software or works derived from this Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
 ****************************************************************************/
28
#include "mapserver.h"
29
#include "mapfile.h" // format shares a couple of tokens
30
31
#include "cpl_conv.h"
32
33
#include <string>
34
35
extern "C" int msyylex(void);
36
extern "C" void msyyrestart(FILE *);
37
38
extern "C" FILE *msyyin;
39
extern "C" int msyystate;
40
extern "C" int msyylineno;
41
extern "C" char *msyystring_buffer;
42
43
2.53k
static int initConfig(configObj *config) {
44
2.53k
  if (config == NULL) {
45
0
    msSetError(MS_MEMERR, "Config object is NULL.", "initConfig()");
46
0
    return MS_FAILURE;
47
0
  }
48
49
2.53k
  if (initHashTable(&(config->env)) != MS_SUCCESS)
50
0
    return MS_FAILURE;
51
2.53k
  if (initHashTable(&(config->maps)) != MS_SUCCESS)
52
0
    return MS_FAILURE;
53
2.53k
  if (initHashTable(&(config->plugins)) != MS_SUCCESS)
54
0
    return MS_FAILURE;
55
56
2.53k
  return MS_SUCCESS;
57
2.53k
}
58
59
2.97k
void msFreeConfig(configObj *config) {
60
2.97k
  if (config == NULL)
61
434
    return;
62
2.53k
  msFreeHashItems(&(config->env));
63
2.53k
  msFreeHashItems(&(config->maps));
64
2.53k
  msFreeHashItems(&(config->plugins));
65
66
2.53k
  msFree(config);
67
2.53k
}
68
69
2.53k
static int loadConfig(configObj *config) {
70
2.53k
  int token;
71
72
2.53k
  if (config == NULL)
73
0
    return MS_FAILURE;
74
75
2.53k
  token = msyylex();
76
2.53k
  if (token != MS_CONFIG_SECTION) {
77
143
    msSetError(MS_IDENTERR,
78
143
               "First token must be CONFIG, this doesn't look like a mapserver "
79
143
               "config file.",
80
143
               "msLoadConfig()");
81
143
    return MS_FAILURE;
82
143
  }
83
84
4.73k
  for (;;) {
85
4.73k
    switch (msyylex()) {
86
2.32k
    case (MS_CONFIG_SECTION_ENV): {
87
2.32k
      if (loadHashTable(&(config->env)) != MS_SUCCESS)
88
112
        return MS_FAILURE;
89
2.21k
      break;
90
2.32k
    }
91
2.21k
    case (MS_CONFIG_SECTION_MAPS):
92
57
      if (loadHashTable(&config->maps) != MS_SUCCESS)
93
9
        return MS_FAILURE;
94
48
      break;
95
93
    case (MS_CONFIG_SECTION_PLUGINS):
96
93
      if (loadHashTable(&config->plugins) != MS_SUCCESS)
97
12
        return MS_FAILURE;
98
81
      break;
99
81
    case (EOF):
100
28
      msSetError(MS_EOFERR, NULL, "msLoadConfig()");
101
28
      return MS_FAILURE;
102
2.10k
    case (END):
103
2.10k
      if (msyyin) {
104
2.10k
        fclose(msyyin);
105
2.10k
        msyyin = NULL;
106
2.10k
      }
107
2.10k
      return MS_SUCCESS;
108
0
      break;
109
130
    default:
110
130
      msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
111
130
                 "msLoadConfig()", msyystring_buffer, msyylineno);
112
130
      return MS_FAILURE;
113
4.73k
    }
114
4.73k
  }
115
2.39k
}
116
117
7.23k
static void msConfigSetConfigOption(const char *key, const char *value) {
118
7.23k
  CPLSetConfigOption(key, value);
119
7.23k
  if (strcasecmp(key, "PROJ_DATA") == 0 || strcasecmp(key, "PROJ_LIB") == 0) {
120
351
    msSetPROJ_DATA(value, nullptr);
121
351
  }
122
7.23k
}
123
124
0
std::string msGetMapserverConfigFilePath() {
125
126
0
  const char *config_path = CPLGetConfigOption("MAPSERVER_CONFIG_FILE", NULL);
127
0
  if (config_path != nullptr) {
128
0
    return std::string(config_path);
129
0
  }
130
131
0
  const char *env_file = getenv("MAPSERVER_CONFIG_FILE");
132
0
  if (env_file != nullptr) {
133
    // get config filename from environment
134
0
    return std::string(env_file);
135
0
  }
136
137
0
  if (MAPSERVER_CONFIG_FILE[0] != '\0') {
138
    // fallback to hardcoded file name
139
0
    return std::string(MAPSERVER_CONFIG_FILE);
140
0
  }
141
0
  return std::string();
142
0
}
143
144
2.53k
configObj *msLoadConfig(const char *ms_config_file) {
145
2.53k
  configObj *config = NULL;
146
147
2.53k
  std::string config_path;
148
149
2.53k
  if (ms_config_file == NULL) {
150
0
    config_path = msGetMapserverConfigFilePath();
151
0
    if (config_path.empty()) {
152
0
      msSetError(MS_MISCERR, "No config file set.", "msLoadConfig()");
153
0
      return NULL;
154
0
    }
155
0
    ms_config_file = config_path.c_str();
156
0
  }
157
158
2.53k
  config = (configObj *)calloc(1, sizeof(configObj));
159
2.53k
  MS_CHECK_ALLOC(config, sizeof(configObj), NULL);
160
161
2.53k
  if (initConfig(config) != MS_SUCCESS) {
162
0
    msFreeConfig(config);
163
0
    return NULL;
164
0
  }
165
166
2.53k
  msAcquireLock(TLOCK_PARSER);
167
168
2.53k
  if ((msyyin = fopen(ms_config_file, "r")) == NULL) {
169
0
    msDebug("Cannot open configuration file %s.\n", ms_config_file);
170
0
    msSetError(MS_IOERR,
171
0
               "See mapserver.org/mapfile/config.html for more information.",
172
0
               "msLoadConfig()");
173
0
    msReleaseLock(TLOCK_PARSER);
174
0
    msFreeConfig(config);
175
0
    return NULL;
176
0
  }
177
178
2.53k
  msyystate = MS_TOKENIZE_CONFIG;
179
2.53k
  msyylex(); // sets things up, but doesn't process any tokens
180
181
2.53k
  msyyrestart(msyyin); // start at line 1
182
2.53k
  msyylineno = 1;
183
184
2.53k
  if (loadConfig(config) != MS_SUCCESS) {
185
434
    msFreeConfig(config);
186
434
    msReleaseLock(TLOCK_PARSER);
187
434
    if (msyyin) {
188
434
      fclose(msyyin);
189
434
      msyyin = NULL;
190
434
    }
191
434
    return NULL;
192
434
  }
193
2.10k
  msReleaseLock(TLOCK_PARSER);
194
195
  // load all env key/values using CPLSetConfigOption() - only do this *after*
196
  // we have a good config
197
2.10k
  const char *key = msFirstKeyFromHashTable(&config->env);
198
2.10k
  if (key != NULL) {
199
2.09k
    msConfigSetConfigOption(key, msLookupHashTable(&config->env, key));
200
201
2.09k
    const char *last_key = key;
202
5.13k
    while ((key = msNextKeyFromHashTable(&config->env, last_key)) != NULL) {
203
3.03k
      msConfigSetConfigOption(key, msLookupHashTable(&config->env, key));
204
3.03k
      last_key = key;
205
3.03k
    }
206
2.09k
  }
207
208
  // also store the path to the CONFIG file
209
2.10k
  msConfigSetConfigOption("MAPSERVER_CONFIG_FILE", ms_config_file);
210
211
2.10k
  return config;
212
2.53k
}
213
214
0
const char *msConfigGetEnv(const configObj *config, const char *key) {
215
0
  if (config == NULL || key == NULL)
216
0
    return NULL;
217
0
  return msLookupHashTable(&config->env, key);
218
0
}
219
220
/**
221
 * Get the path to a Mapfile, from the MapServer CONFIG file using
222
 * its key. If the path is relative then the CONFIG file location
223
 * is used to determine the absolute path.
224
 * The provided pszReturnPath must be at least MS_MAXPATHLEN long.
225
 */
226
const char *msConfigGetMap(const configObj *config, const char *key,
227
0
                           char *pszReturnPath) {
228
0
  if (config == NULL || key == NULL || pszReturnPath == NULL)
229
0
    return NULL;
230
231
0
  const char *mapFile = msLookupHashTable(&config->maps, key);
232
0
  if (!mapFile)
233
0
    return NULL;
234
235
  // check for relative Mapfile paths
236
0
  if (CPLIsFilenameRelative(mapFile)) {
237
238
0
    std::string config_path = msGetMapserverConfigFilePath();
239
0
    if (config_path.empty()) {
240
0
      return NULL;
241
0
    }
242
0
    char *configPath = msGetPath(config_path.c_str());
243
244
0
    if (!configPath)
245
0
      return NULL;
246
247
0
    if (msBuildPath(pszReturnPath, configPath, mapFile) == NULL) {
248
0
      free(configPath);
249
0
      return NULL;
250
0
    }
251
0
    free(configPath);
252
0
  } else {
253
    // just copy absolute path directly
254
0
    strlcpy(pszReturnPath, mapFile, MS_MAXPATHLEN);
255
0
  }
256
0
  return pszReturnPath;
257
0
}
258
259
0
const char *msConfigGetPlugin(const configObj *config, const char *key) {
260
0
  if (config == NULL || key == NULL)
261
0
    return NULL;
262
0
  return msLookupHashTable(&config->plugins, key);
263
0
}