Skip to content

Commit

Permalink
'include_file' statement: Re-introduce relative file paths
Browse files Browse the repository at this point in the history
During the preprocessor migration, it seems the support for relative
file paths was lost.  This commit re-introduces all the lost features:

    * allow relative-path imports, e.g. include_file "cgrates.cfg".
      These file paths are considered to be relative to the .cfg file
      that is importing them

    * prioritize any relative-path imports found in the startup
      directory
      (Note: this is different from the "-w" working directory!)

    * detect infinite "include_file" loops

Many thanks to Jonathan Hulme for discovering and reporting this issue!

(cherry picked from commit ecea9b0)
  • Loading branch information
liviuchircu committed Jul 12, 2019
1 parent 3194727 commit eceef3e
Showing 1 changed file with 108 additions and 51 deletions.
159 changes: 108 additions & 51 deletions cfg_pp.c
Expand Up @@ -24,6 +24,8 @@
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <libgen.h>
#include <sys/stat.h>

#include "config.h"
#include "globals.h"
Expand Down Expand Up @@ -79,7 +81,7 @@ int parse_opensips_cfg(const char *cfg_file, const char *preproc_cmdline,

if (flatten_opensips_cfg(cfg_stream,
cfg_stream == stdin ? "stdin" : cfg_file, &cfg_buf) < 0) {
LM_ERR("failed to expand file imports for %s, oom?\n", cfg_file);
LM_ERR("failed to resolve file imports for %s\n", cfg_file);
return -1;
}

Expand Down Expand Up @@ -147,9 +149,14 @@ static int extend_cfg_buf(char **buf, int *sz, int *bytes_left)
}

/* search for '(include|import)_file "filepath"' patterns */
int extract_included_file(char *line, int line_len, char **out_path)
int mk_included_file_path(char *line, int line_len, const char *current_dir,
char **out_path)
{
#define MAX_INCLUDE_FNAME 256
static char full_path[MAX_INCLUDE_FNAME];
struct stat _;
char *p = NULL, enclose = 0;
int len1, len2, fplen;

if (line_len > include_v1.len &&
!memcmp(line, include_v1.s, include_v1.len)) {
Expand All @@ -162,7 +169,7 @@ int extract_included_file(char *line, int line_len, char **out_path)
}

if (!p)
return -1;
return 1;

while (line_len > 0 && isspace(*p)) {
line_len--;
Expand All @@ -189,11 +196,94 @@ int extract_included_file(char *line, int line_len, char **out_path)
return -1;

*p = '\0';

/* is it a relative-path import? */
if (**out_path != '/' && stat(*out_path, &_) < 0) {
LM_DBG("%s not found (%d, %s), assuming it's relative to source cfg\n",
*out_path, errno, strerror(errno));

/* this relative path is not inside the startup dir,
* so maybe it's relative to the importing file */
len1 = strlen(current_dir);
len2 = strlen(*out_path);

if (len1 + 1 + len2 + 1 > MAX_INCLUDE_FNAME) {
LM_ERR("file path too long (max %d): '%s' + '%s'\n",
MAX_INCLUDE_FNAME, current_dir, *out_path);
return -1;
}

memcpy(full_path, current_dir, len1);
fplen = len1;

/* this test can only fail when opensips runs from '/' */
if (current_dir[len1 - 1] != '/')
full_path[fplen++] = '/';

memcpy(full_path + fplen, *out_path, len2);
fplen += len2;

full_path[fplen] = '\0';
*out_path = full_path;
}

LM_DBG("preparing to include %s\n", *out_path);
return 0;
}

static struct cfg_context {
const char *path;
const char *dirname; /* useful for relative path includes */
int loc;
char **lines;
int bufsz;
struct cfg_context *next;
} *__ccon;

static struct cfg_context *cfg_context_new_file(const char *path)
{
struct cfg_context *con, *it;
char *cpy;

for (it = __ccon; it; it = it->next)
if (!strcmp(it->path, path))
return it;

con = malloc(sizeof *con);
memset(con, 0, sizeof *con);

con->path = strdup(path);

cpy = strdup(path);
con->dirname = strdup(dirname(cpy));
free(cpy);

con->lines = malloc(32 * sizeof *con->lines);
con->bufsz = 32;

add_last(con, __ccon);
return con;
}

static void cfg_context_append_line(struct cfg_context *con,
char *line, int len)
{
if (con->loc == con->bufsz) {
con->bufsz *= 2;
con->lines = realloc(con->lines, con->bufsz * sizeof *con->lines);
if (!con->lines)
return;
}

con->lines[con->loc] = malloc(len + 1);
memcpy(con->lines[con->loc], line, len);
con->lines[con->loc][len] = '\0';

con->loc++;
}

static int __flatten_opensips_cfg(FILE *cfg, const char *cfg_path,
char **flattened, int *sz, int *bytes_left)
char **flattened, int *sz, int *bytes_left, int reclev)
{
FILE *included_cfg;
ssize_t line_len;
Expand All @@ -203,6 +293,12 @@ static int __flatten_opensips_cfg(FILE *cfg, const char *cfg_path,
int line_counter = 1, printed;
struct cfg_context *con = NULL;

if (reclev > 50) {
LM_ERR("Maximum import depth reached (50) or "
"you have an infinite include_file loop!\n");
goto out_err;
}

if (cfg_path_len >= 2048) {
LM_ERR("file path too large: %.*s...\n", 2048, cfg_path);
goto out_err;
Expand Down Expand Up @@ -277,19 +373,22 @@ static int __flatten_opensips_cfg(FILE *cfg, const char *cfg_path,
cfg_context_append_line(con, line, line_len);

/* if it's an include, skip printing the line, but do print the file */
if (extract_included_file(line, line_len, &included_cfg_path) == 0) {
if (mk_included_file_path(line, line_len, con->dirname, &included_cfg_path) == 0) {
included_cfg = fopen(included_cfg_path, "r");
if (!included_cfg) {
LM_ERR("failed to open %s: %d (%s)\n", included_cfg_path,
errno, strerror(errno));
goto out_err;
}

included_cfg_path = strdup(included_cfg_path);
if (__flatten_opensips_cfg(included_cfg, included_cfg_path,
flattened, sz, bytes_left)) {
LM_ERR("failed to flatten cfg file (internal err), oom?\n");
flattened, sz, bytes_left, reclev + 1)) {
free(included_cfg_path);
LM_ERR("failed to flatten cfg file %s\n", cfg_path);
goto out_err;
}
free(included_cfg_path);
} else {
if (*bytes_left < line_len) {
if (extend_cfg_buf(flattened, sz, bytes_left) < 0) {
Expand Down Expand Up @@ -336,8 +435,8 @@ static int flatten_opensips_cfg(FILE *cfg, const char *cfg_path, str *out)
int sz = 0, bytes_left = 0;
char *flattened = NULL;

if (__flatten_opensips_cfg(cfg, cfg_path, &flattened, &sz, &bytes_left)) {
LM_ERR("failed to flatten cfg file (internal err), out of memory?\n");
if (__flatten_opensips_cfg(cfg, cfg_path, &flattened, &sz, &bytes_left, 0)) {
LM_ERR("failed to flatten cfg file %s\n", cfg_path);
return -1;
}

Expand Down Expand Up @@ -397,48 +496,6 @@ int cfg_pop(void)
return 0;
}

static struct cfg_context {
const char *path;
int loc;
char **lines;
int bufsz;
struct cfg_context *next;
} *__ccon;

static struct cfg_context *cfg_context_new_file(const char *path)
{
struct cfg_context *con, *it;

for (it = __ccon; it; it = it->next)
if (!strcmp(it->path, path))
return NULL;

con = malloc(sizeof *con);
memset(con, 0, sizeof *con);

con->path = strdup(path);
con->lines = malloc(32 * sizeof *con->lines);
con->bufsz = 32;

add_last(con, __ccon);
return con;
}

static void cfg_context_append_line(struct cfg_context *con,
char *line, int len)
{
if (con->loc == con->bufsz) {
con->bufsz *= 2;
con->lines = realloc(con->lines, con->bufsz * sizeof *con->lines);
}

con->lines[con->loc] = malloc(len + 1);
memcpy(con->lines[con->loc], line, len);
con->lines[con->loc][len] = '\0';

con->loc++;
}

void cfg_dump_context(const char *file, int line, int colstart, int colend)
{
static int called_before;
Expand Down

0 comments on commit eceef3e

Please sign in to comment.