2 // Copyright (c) 2010-2017 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
19 #include <rte_string_fns.h>
26 #include "parse_utils.h"
29 #include "prox_compat.h"
31 #define UINT32_MAX_STR "4294967295"
34 * Allocate cfg_file structure.
35 * Returns pointer to the allocated structure, NULL otherwise.
37 struct cfg_file *cfg_open(const char *cfg_name)
39 if (cfg_name == NULL) {
40 plog_err("\tNo config file name provided\n");
43 if (access(cfg_name, F_OK)) {
44 plog_err("\tError opening config file '%s': %s\n", cfg_name, strerror(errno));
48 FILE *pf = fopen(cfg_name, "rb");
50 plog_err("\tError opening config file '%s'\n", cfg_name);
54 struct cfg_file *pcfg = calloc(1, sizeof(struct cfg_file));
58 plog_err("\tCouldn't allocate memory for config file struct\n");
63 pcfg->name = strdup(cfg_name);
68 /* Free memory allocated for cfg_file structure.
69 * Returns 0 on success, -1 if the pointer to the pcfg is invalid */
70 int cfg_close(struct cfg_file *pcfg)
76 if (pcfg->name != NULL) {
79 if (pcfg->err_section != NULL) {
80 free(pcfg->err_section);
82 if (pcfg->pfile != NULL) {
90 static int cfg_get_pos(struct cfg_file *pcfg, fpos_t *pos)
92 pcfg->index_line = pcfg->line;
93 return fgetpos(pcfg->pfile, pos);
96 static int cfg_set_pos(struct cfg_file *pcfg, fpos_t *pos)
98 pcfg->line = pcfg->index_line;
99 return fsetpos(pcfg->pfile, pos);
103 * Read a line from the configuration file.
104 * Returns: on success length of the line read from the file is returned,
105 * 0 to indicate End of File,
106 * -1 in case of wrong function parameters
108 static int cfg_get_line(struct cfg_file *pcfg, char *buffer, unsigned len, int raw_lines)
112 if (pcfg == NULL || pcfg->pfile == NULL || buffer == NULL || len == 0) {
117 ptr = fgets(buffer, len, pcfg->pfile);
119 return 0; /* end of file */
127 /* remove comments */
128 ptr = strchr(buffer, ';');
133 ptr = strchr(buffer, '\0');
136 /* remove trailing spaces */
139 while (isspace(*ptr)) {
146 /* remove leading spaces */
147 while (*ptr && isspace(*ptr)) {
155 while (*ptr == '\0'); /* skip empty strings */
157 return strlen(buffer);
161 * Checks if buffer contains section name specified by the cfg_section pointer.
162 * Returns NULL if section name does not match, cfg_section pointer otherwise
164 static struct cfg_section *cfg_check_section(char *buffer, struct cfg_section *psec)
168 static const char *valid = "0123456789,hs- \t";
170 pend = strchr(buffer, ']');
172 return NULL; /* ']' not found: invalid section name */
177 /* check if section is indexed */
178 pend = strchr(psec->name, '#');
180 return (strcmp(buffer, psec->name) == 0) ? psec : NULL;
183 /* get section index */
184 len = pend - psec->name;
185 if (strncmp(buffer, psec->name, len) != 0) {
193 /* only numeric characters are valid for section index */
194 char val[MAX_CFG_STRING_LEN];
195 if (pend[0] == '$') {
196 if (parse_vars(val, sizeof(val), pend))
199 prox_strncpy(val, pend, sizeof(val));
201 for (len = 0; val[len] != '\0'; ++len) {
202 if (strchr(valid, val[len]) == NULL) {
207 psec->nbindex = parse_list_set(psec->indexp, pend, MAX_INDEX);
208 PROX_PANIC(psec->nbindex == -1, "\t\tError in cfg_check_section('%s'): %s\n", buffer, get_parse_err());
210 for (int i = 0; i < psec->nbindex; ++i) {
211 psec->indexp[i] |= CFG_INDEXED;
217 static char *cfg_get_section_name(struct cfg_section *psec)
221 if (!(psec->indexp[0] & CFG_INDEXED)) {
222 return strdup(psec->name);
225 name = malloc(strlen(psec->name) + strlen(UINT32_MAX_STR));
227 strcpy(name, psec->name);
228 char *pidx = strchr(name, '#');
230 sprintf(pidx, "%u", psec->indexp[0] & ~CFG_INDEXED);
237 * Reads configuration file and parses section specified by psec pointer.
238 * Returns 0 on success, -1 otherwise
240 int cfg_parse(struct cfg_file *pcfg, struct cfg_section *psec)
246 struct cfg_section *section = NULL;
247 char buffer[sizeof(pcfg->cur_line)] = {0};
249 if (pcfg == NULL || psec == NULL) {
254 fseek(pcfg->pfile, 0, SEEK_SET);
256 /* read configuration file and parse section specified by psec pointer */
258 if (psec->raw_lines) {
259 /* skip until section starts */
260 char *lines = pcfg->cur_line;
261 size_t max_len = sizeof(pcfg->cur_line);
265 ret = fgets(lines, max_len, pcfg->pfile);
266 if (ret && *ret == '[') {
267 section = cfg_check_section(lines + 1, psec);
269 } while (!section && ret);
276 ret = fgets(buffer, sizeof(buffer), pcfg->pfile);
277 /* remove comments */
282 if (ret && *ret != '[') {
283 size_t l = strlen(buffer);
284 prox_strncpy(lines, buffer, max_len);
288 } while ((ret && *ret != '['));
290 if (section != NULL) {
291 error = section->parser(section->indexp[index_count], pcfg->cur_line, section->data);
293 section->error = error;
294 /* log only the very first error */
295 if (!pcfg->err_section) {
296 pcfg->err_line = pcfg->line;
297 pcfg->err_entry = entry;
298 pcfg->err_section = cfg_get_section_name(section);
307 while (cfg_get_line(pcfg, buffer, MAX_CFG_STRING_LEN, psec->raw_lines) > 0) {
308 prox_strncpy(pcfg->cur_line, buffer, sizeof(pcfg->cur_line));
309 if (*buffer == '[') {
310 if (index_count + 1 < psec->nbindex) {
311 // Need to loop - go back to recorded postion in file
312 cfg_set_pos(pcfg, &pos);
317 section = cfg_check_section(buffer + 1, psec);
320 cfg_get_pos(pcfg, &pos);
324 /* call parser procedure for each line in the section */
325 if (section != NULL) {
326 error = section->parser(section->indexp[index_count], buffer, section->data);
328 section->error = error;
329 /* log only the very first error */
330 if (!pcfg->err_section) {
331 pcfg->err_line = pcfg->line;
332 pcfg->err_entry = entry;
333 pcfg->err_section = cfg_get_section_name(section);
340 if (index_count + 1 < psec->nbindex) {
341 // Last core config contained multiple cores - loop back
342 cfg_set_pos(pcfg, &pos);