From 29ecb55d0fbe468a33b1868da998707cd60246cb Mon Sep 17 00:00:00 2001 From: Patrick Stephens Date: Wed, 4 Dec 2024 12:02:49 +0000 Subject: [PATCH] calyptia: generate machine id for fleet agents Signed-off-by: Patrick Stephens --- include/CMakeLists.txt | 6 + include/fluent-bit/flb_utils.h | 1 + plugins/custom_calyptia/calyptia.c | 191 +++++++++++++++++- plugins/custom_calyptia/calyptia.h | 12 ++ plugins/in_calyptia_fleet/in_calyptia_fleet.c | 95 ++------- plugins/out_calyptia/calyptia.c | 36 ++-- plugins/out_calyptia/calyptia.h | 26 +-- src/flb_utils.c | 52 +++++ 8 files changed, 289 insertions(+), 130 deletions(-) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 38f1b0dccd5..30ec68744a8 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -10,6 +10,12 @@ install(FILES ${headers} COMPONENT headers PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) +file(GLOB headers "fluent-bit/calyptia/*.h") +install(FILES ${headers} + DESTINATION ${FLB_INSTALL_INCLUDEDIR}/fluent-bit + COMPONENT headers + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + file(GLOB headers "fluent-bit/config_format/*.h") install(FILES ${headers} DESTINATION ${FLB_INSTALL_INCLUDEDIR}/fluent-bit/config_format/ diff --git a/include/fluent-bit/flb_utils.h b/include/fluent-bit/flb_utils.h index b1f06592278..a0719c53e50 100644 --- a/include/fluent-bit/flb_utils.h +++ b/include/fluent-bit/flb_utils.h @@ -74,5 +74,6 @@ int flb_utils_get_machine_id(char **out_id, size_t *out_size); void flb_utils_set_plugin_string_property(const char *name, flb_sds_t *field_storage, flb_sds_t new_value); +int flb_utils_mkdir(const char *dir, int perms); #endif diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index bfbb42f4767..44052812fb7 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -27,11 +27,16 @@ #include #include #include - +#include +#include +#include +#include #include #include "calyptia.h" +#define UUID_BUFFER_SIZE 38 /* Maximum length of UUID string + null terminator */ + /* * Check if the key belongs to a sensitive data field, if so report it. We never * share any sensitive data. @@ -217,16 +222,13 @@ int set_fleet_input_properties(struct calyptia *ctx, struct flb_input_instance * flb_input_set_property(fleet, "api_key", ctx->api_key); flb_input_set_property(fleet, "host", ctx->cloud_host); flb_input_set_property(fleet, "port", ctx->cloud_port); + flb_input_set_property(fleet, "config_dir", ctx->fleet_config_dir); /* Set TLS properties */ flb_input_set_property(fleet, "tls", ctx->cloud_tls == 1 ? "on" : "off"); flb_input_set_property(fleet, "tls.verify", ctx->cloud_tls_verify == 1 ? "on" : "off"); /* Optional configurations */ - if (ctx->fleet_config_dir) { - flb_input_set_property(fleet, "config_dir", ctx->fleet_config_dir); - } - if (ctx->fleet_max_http_buffer_size) { flb_input_set_property(fleet, "max_http_buffer_size", ctx->fleet_max_http_buffer_size); } @@ -376,15 +378,182 @@ static flb_sds_t sha256_to_hex(unsigned char *sha256) return hex; } +static flb_sds_t generate_base_agent_directory(struct calyptia *ctx, flb_sds_t *fleet_dir) +{ + flb_sds_t ret = NULL; + + if (ctx == NULL || fleet_dir == NULL) { + return NULL; + } + + if (*fleet_dir == NULL) { + *fleet_dir = flb_sds_create_size(CALYPTIA_MAX_DIR_SIZE); + if (*fleet_dir == NULL) { + return NULL; + } + } + + ret = flb_sds_printf(fleet_dir, "%s", ctx->fleet_config_dir); + if (ret == NULL) { + flb_sds_destroy(*fleet_dir); + return NULL; + } + + return ret; +} + +static flb_sds_t agent_config_filename(struct calyptia *ctx, char *fname) +{ + flb_sds_t cfgname = NULL; + flb_sds_t ret; + + if (ctx == NULL || fname == NULL) { + return NULL; + } + + if (generate_base_agent_directory(ctx, &cfgname) == NULL) { + return NULL; + } + + ret = flb_sds_printf(&cfgname, PATH_SEPARATOR "%s.conf", fname); + if (ret == NULL) { + flb_sds_destroy(cfgname); + return NULL; + } + + return cfgname; +} + +static char* generate_uuid() { + char* uuid = flb_malloc(UUID_BUFFER_SIZE); + if (!uuid) { + flb_errno(); + return NULL; + } + + /* create new UUID for fleet */ + if (flb_utils_uuid_v4_gen(uuid) != 0 || strlen(uuid) == 0) { + flb_free(uuid); + return NULL; + } + return uuid; +} + +static int write_uuid_to_file(flb_sds_t fleet_machine_id, char* uuid) { + int fd; + size_t uuid_len; + + if (fleet_machine_id == NULL || uuid == NULL) { + return FLB_FALSE; + } + + /* write uuid to file */ + fd = flb_open(fleet_machine_id, O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (fd == -1) { + return FLB_FALSE; + } + + uuid_len = strlen(uuid); + + if (flb_write(fd, uuid, uuid_len) != uuid_len) { + flb_close(fd); + return FLB_FALSE; + } + + flb_close(fd); + return FLB_TRUE; +} + +static int create_agent_directory(struct calyptia *ctx) +{ + if( ctx == NULL ) { + return -1; + } + + /* If it exists just return */ + if (access(ctx->fleet_config_dir, F_OK) == 0) { + return 0; + } + + /* Create the directory if it does not exist */ + if (flb_utils_mkdir(ctx->fleet_config_dir, 0700) != 0) { + flb_plg_error(ctx->ins, "failed to create directory: %s", ctx->fleet_config_dir); + return -1; + } + + return 0; +} + static flb_sds_t get_machine_id(struct calyptia *ctx) { - int ret; - char *buf; - size_t blen; + int ret = -1; + char *buf = NULL; + size_t blen = 0; unsigned char sha256_buf[64] = {0}; +#if defined(FLB_SYSTEM_WINDOWS) /* retrieve raw machine id */ ret = flb_utils_get_machine_id(&buf, &blen); +#else + /* /etc/machine-id is not guaranteed to be unique so we generate one */ + flb_sds_t fleet_machine_id = NULL; + + /** ensure we have the directory created */ + if (create_agent_directory(ctx) != 0) { + return NULL; + } + + /** now get the agent filename */ + fleet_machine_id = machine_id_fleet_config_filename(ctx); + if (fleet_machine_id == NULL) { + flb_plg_error(ctx->ins, "unable to allocate machine id file"); + return NULL; + } + + /* check if the file exists first, if it does not we generate a UUID */ + if (flb_access(fleet_machine_id, F_OK) != 0) { + + /* create new UUID for fleet */ + buf = generate_uuid(); + if( buf == NULL ) { + flb_plg_error(ctx->ins, "failed to create uuid for fleet machine id"); + flb_sds_destroy(fleet_machine_id); + return NULL; + } + flb_plg_info(ctx->ins, "generated UUID for machine ID: %s", buf); + + /* write uuid to file */ + if (write_uuid_to_file(fleet_machine_id, buf ) != FLB_TRUE) { + flb_plg_error(ctx->ins, "failed to write fleet machine id file: %s", fleet_machine_id); + flb_free(buf); + flb_sds_destroy(fleet_machine_id); + return NULL; + } + + flb_free(buf); + buf = NULL; + + flb_plg_info(ctx->ins, "written machine ID to file: %s", fleet_machine_id); + } + + /* now check file exists (it always should) and read from it */ + if (flb_access(fleet_machine_id, F_OK) == 0) { + ret = flb_utils_read_file_wrapper(fleet_machine_id, &buf, &blen); + if (ret != 0) { + flb_plg_error(ctx->ins, "failed to read fleet machine id file: %s", fleet_machine_id); + flb_sds_destroy(fleet_machine_id); + return NULL; + } + flb_plg_info(ctx->ins, "read UUID (%s) from file: %s", buf, fleet_machine_id); + } + else { /* fall back to machine-id */ + flb_plg_warn(ctx->ins, "unable to get uuid from file (%s) so falling back to machine id", fleet_machine_id); + ret = flb_utils_get_machine_id(&buf, &blen); + } + + /* Clean up no longer required filename */ + flb_sds_destroy(fleet_machine_id); +#endif if (ret == -1) { flb_plg_error(ctx->ins, "could not obtain machine id"); @@ -520,13 +689,13 @@ static struct flb_config_map config_map[] = { }, { - FLB_CONFIG_MAP_STR, "calyptia_host", "cloud-api.calyptia.com", + FLB_CONFIG_MAP_STR, "calyptia_host", DEFAULT_CALYPTIA_HOST, 0, FLB_TRUE, offsetof(struct calyptia, cloud_host), "" }, { - FLB_CONFIG_MAP_STR, "calyptia_port", "443", + FLB_CONFIG_MAP_STR, "calyptia_port", DEFAULT_CALYPTIA_PORT, 0, FLB_TRUE, offsetof(struct calyptia, cloud_port), "" }, @@ -559,7 +728,7 @@ static struct flb_config_map config_map[] = { "Fleet id to be used when registering agent in a fleet" }, { - FLB_CONFIG_MAP_STR, "fleet.config_dir", NULL, + FLB_CONFIG_MAP_STR, "fleet.config_dir", FLEET_DEFAULT_CONFIG_DIR, 0, FLB_TRUE, offsetof(struct calyptia, fleet_config_dir), "Base path for the configuration directory." }, diff --git a/plugins/custom_calyptia/calyptia.h b/plugins/custom_calyptia/calyptia.h index b4313f51182..0a2e61abad6 100644 --- a/plugins/custom_calyptia/calyptia.h +++ b/plugins/custom_calyptia/calyptia.h @@ -57,4 +57,16 @@ struct calyptia { }; int set_fleet_input_properties(struct calyptia *ctx, struct flb_input_instance *fleet); +static flb_sds_t agent_config_filename(struct calyptia *ctx, char *fname); + +/* These are unique to the agent rather than the fleet */ +#define machine_id_fleet_config_filename(a) agent_config_filename((a), "machine-id") + +/* Function wrappers to enable mocking for unit test filesystem access */ +int (*flb_access)(const char *pathname, int mode) = access; +int (*flb_open)(const char *pathname, int flags, ...) = open; +ssize_t (*flb_write)(int fd, const void *buf, size_t count) = write; +int (*flb_close)(int fd) = close; +int (*flb_utils_read_file_wrapper)(char *path, char **out_buf, size_t *out_size) = flb_utils_read_file; + #endif /* FLB_CALYPTIA_H */ diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 28e3fc8719c..5a423856c32 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -38,6 +38,9 @@ #include #include #include +#include + +#include /* Glob support */ #ifndef _MSC_VER @@ -50,26 +53,15 @@ #define PATH_MAX MAX_PATH #endif -#define CALYPTIA_H_PROJECT "X-Project-Token" -#define CALYPTIA_H_CTYPE "Content-Type" -#define CALYPTIA_H_CTYPE_JSON "application/json" +#define CALYPTIA_HEADERS_PROJECT "X-Project-Token" +#define CALYPTIA_HEADERS_CTYPE "Content-Type" +#define CALYPTIA_HEADERS_CTYPE_JSON "application/json" #define DEFAULT_INTERVAL_SEC "15" #define DEFAULT_INTERVAL_NSEC "0" #define DEFAULT_MAX_HTTP_BUFFER_SIZE "10485760" -#define CALYPTIA_HOST "cloud-api.calyptia.com" -#define CALYPTIA_PORT "443" - -#ifndef _WIN32 -#define PATH_SEPARATOR "/" -#define DEFAULT_CONFIG_DIR "/tmp/calyptia-fleet" -#else -#define DEFAULT_CONFIG_DIR NULL -#define PATH_SEPARATOR "\\" -#endif - struct flb_in_calyptia_fleet_config { /* Time interval check */ int interval_sec; @@ -920,7 +912,7 @@ static struct flb_http_client *fleet_http_do(struct flb_in_calyptia_fleet_config flb_http_buffer_size(client, ctx->max_http_buffer_size); flb_http_add_header(client, - CALYPTIA_H_PROJECT, sizeof(CALYPTIA_H_PROJECT) - 1, + CALYPTIA_HEADERS_PROJECT, sizeof(CALYPTIA_HEADERS_PROJECT) - 1, ctx->api_key, flb_sds_len(ctx->api_key)); ret = flb_http_do(client, &b_sent); @@ -1087,56 +1079,6 @@ static int get_calyptia_file(struct flb_in_calyptia_fleet_config *ctx, return ret; } -#ifdef FLB_SYSTEM_WINDOWS -#define _mkdir(a, b) mkdir(a) -#else -#define _mkdir(a, b) mkdir(a, b) -#endif - -/* recursively create directories, based on: - * https://stackoverflow.com/a/2336245 - * who found it at: - * http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html - */ -static int __mkdir(const char *dir, int perms) { - char tmp[255]; - char *ptr = NULL; - size_t len; - int ret; - - ret = snprintf(tmp, sizeof(tmp),"%s",dir); - if (ret > sizeof(tmp)) { - flb_error("directory too long for __mkdir: %s", dir); - return -1; - } - - len = strlen(tmp); - - if (tmp[len - 1] == PATH_SEPARATOR[0]) { - tmp[len - 1] = 0; - } - -#ifndef FLB_SYSTEM_WINDOWS - for (ptr = tmp + 1; *ptr; ptr++) { -#else - for (ptr = tmp + 3; *ptr; ptr++) { -#endif - - if (*ptr == PATH_SEPARATOR[0]) { - *ptr = 0; - if (access(tmp, F_OK) != 0) { - ret = _mkdir(tmp, perms); - if (ret != 0) { - return ret; - } - } - *ptr = PATH_SEPARATOR[0]; - } - } - - return _mkdir(tmp, perms); -} - #ifndef _WIN32 static struct cfl_array *read_glob(const char *path) { @@ -1839,7 +1781,7 @@ static int get_calyptia_fleet_config(struct flb_in_calyptia_fleet_config *ctx) return -1; } - flb_sds_printf(&ctx->fleet_url, "/v1/fleets/%s/config?format=ini", ctx->fleet_id); + flb_sds_printf(&ctx->fleet_url, CALYPTIA_ENDPOINT_FLEET_CONFIG_INI, ctx->fleet_id); } if (ctx->fleet_files_url == NULL) { @@ -1849,7 +1791,7 @@ static int get_calyptia_fleet_config(struct flb_in_calyptia_fleet_config *ctx) return -1; } - flb_sds_printf(&ctx->fleet_files_url, "/v1/fleets/%s/files", ctx->fleet_id); + flb_sds_printf(&ctx->fleet_files_url, CALYPTIA_ENDPOINT_FLEET_FILES, ctx->fleet_id); } create_fleet_header(ctx); @@ -1920,7 +1862,7 @@ static int create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) flb_sds_t myfleetdir = NULL; if (access(ctx->config_dir, F_OK) != 0) { - if (__mkdir(ctx->config_dir, 0700) != 0) { + if (flb_utils_mkdir(ctx->config_dir, 0700) != 0) { return -1; } } @@ -1931,7 +1873,7 @@ static int create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) } if (access(myfleetdir, F_OK) != 0) { - if (__mkdir(myfleetdir, 0700) !=0) { + if (flb_utils_mkdir(myfleetdir, 0700) !=0) { return -1; } } @@ -1970,18 +1912,19 @@ static flb_sds_t fleet_gendir(struct flb_in_calyptia_fleet_config *ctx, time_t t static int fleet_mkdir(struct flb_in_calyptia_fleet_config *ctx, time_t timestamp) { + int ret = -1; flb_sds_t fleetcurdir; fleetcurdir = fleet_gendir(ctx, timestamp); - if (fleetcurdir == NULL) { - return -1; + if (fleetcurdir != NULL) { + if (flb_utils_mkdir(fleetcurdir, 0700) == 0) { + ret = 0; + } + flb_sds_destroy(fleetcurdir); } - __mkdir(fleetcurdir, 0700); - flb_sds_destroy(fleetcurdir); - - return 0; + return ret; } static int fleet_cur_chdir(struct flb_in_calyptia_fleet_config *ctx) @@ -2378,7 +2321,7 @@ static struct flb_config_map config_map[] = { "Calyptia Cloud API Key." }, { - FLB_CONFIG_MAP_STR, "config_dir", DEFAULT_CONFIG_DIR, + FLB_CONFIG_MAP_STR, "config_dir", FLEET_DEFAULT_CONFIG_DIR, 0, FLB_TRUE, offsetof(struct flb_in_calyptia_fleet_config, config_dir), "Base path for the configuration directory." }, diff --git a/plugins/out_calyptia/calyptia.c b/plugins/out_calyptia/calyptia.c index c16fd31d6ee..5f145075c1e 100644 --- a/plugins/out_calyptia/calyptia.c +++ b/plugins/out_calyptia/calyptia.c @@ -341,43 +341,43 @@ static int calyptia_http_do(struct flb_calyptia *ctx, struct flb_http_client *c, return FLB_ERROR; } flb_http_add_header(c, - CALYPTIA_H_CTYPE, sizeof(CALYPTIA_H_CTYPE) - 1, - CALYPTIA_H_CTYPE_JSON, sizeof(CALYPTIA_H_CTYPE_JSON) - 1); + CALYPTIA_HEADERS_CTYPE, sizeof(CALYPTIA_HEADERS_CTYPE) - 1, + CALYPTIA_HEADERS_CTYPE_JSON, sizeof(CALYPTIA_HEADERS_CTYPE_JSON) - 1); flb_http_add_header(c, - CALYPTIA_H_PROJECT, sizeof(CALYPTIA_H_PROJECT) - 1, + CALYPTIA_HEADERS_PROJECT, sizeof(CALYPTIA_HEADERS_PROJECT) - 1, ctx->api_key, flb_sds_len(ctx->api_key)); } else if (type == CALYPTIA_ACTION_PATCH) { flb_http_add_header(c, - CALYPTIA_H_CTYPE, sizeof(CALYPTIA_H_CTYPE) - 1, - CALYPTIA_H_CTYPE_JSON, sizeof(CALYPTIA_H_CTYPE_JSON) - 1); + CALYPTIA_HEADERS_CTYPE, sizeof(CALYPTIA_HEADERS_CTYPE) - 1, + CALYPTIA_HEADERS_CTYPE_JSON, sizeof(CALYPTIA_HEADERS_CTYPE_JSON) - 1); flb_http_add_header(c, - CALYPTIA_H_AGENT_TOKEN, - sizeof(CALYPTIA_H_AGENT_TOKEN) - 1, + CALYPTIA_HEADERS_AGENT_TOKEN, + sizeof(CALYPTIA_HEADERS_AGENT_TOKEN) - 1, ctx->agent_token, flb_sds_len(ctx->agent_token)); } else if (type == CALYPTIA_ACTION_METRICS) { flb_http_add_header(c, - CALYPTIA_H_CTYPE, sizeof(CALYPTIA_H_CTYPE) - 1, - CALYPTIA_H_CTYPE_MSGPACK, - sizeof(CALYPTIA_H_CTYPE_MSGPACK) - 1); + CALYPTIA_HEADERS_CTYPE, sizeof(CALYPTIA_HEADERS_CTYPE) - 1, + CALYPTIA_HEADERS_CTYPE_MSGPACK, + sizeof(CALYPTIA_HEADERS_CTYPE_MSGPACK) - 1); flb_http_add_header(c, - CALYPTIA_H_AGENT_TOKEN, - sizeof(CALYPTIA_H_AGENT_TOKEN) - 1, + CALYPTIA_HEADERS_AGENT_TOKEN, + sizeof(CALYPTIA_HEADERS_AGENT_TOKEN) - 1, ctx->agent_token, flb_sds_len(ctx->agent_token)); } #ifdef FLB_HAVE_CHUNK_TRACE else if (type == CALYPTIA_ACTION_TRACE) { flb_http_add_header(c, - CALYPTIA_H_CTYPE, sizeof(CALYPTIA_H_CTYPE) - 1, - CALYPTIA_H_CTYPE_JSON, sizeof(CALYPTIA_H_CTYPE_JSON) - 1); + CALYPTIA_HEADERS_CTYPE, sizeof(CALYPTIA_HEADERS_CTYPE) - 1, + CALYPTIA_HEADERS_CTYPE_JSON, sizeof(CALYPTIA_HEADERS_CTYPE_JSON) - 1); flb_http_add_header(c, - CALYPTIA_H_AGENT_TOKEN, - sizeof(CALYPTIA_H_AGENT_TOKEN) - 1, + CALYPTIA_HEADERS_AGENT_TOKEN, + sizeof(CALYPTIA_HEADERS_AGENT_TOKEN) - 1, ctx->agent_token, flb_sds_len(ctx->agent_token)); } #endif @@ -1059,13 +1059,13 @@ static void cb_calyptia_flush(struct flb_event_chunk *event_chunk, /* Configuration properties map */ static struct flb_config_map config_map[] = { { - FLB_CONFIG_MAP_STR, "cloud_host", CALYPTIA_HOST, + FLB_CONFIG_MAP_STR, "cloud_host", DEFAULT_CALYPTIA_HOST, 0, FLB_TRUE, offsetof(struct flb_calyptia, cloud_host), "", }, { - FLB_CONFIG_MAP_INT, "cloud_port", CALYPTIA_PORT, + FLB_CONFIG_MAP_INT, "cloud_port", DEFAULT_CALYPTIA_PORT, 0, FLB_TRUE, offsetof(struct flb_calyptia, cloud_port), "", }, diff --git a/plugins/out_calyptia/calyptia.h b/plugins/out_calyptia/calyptia.h index 0532e4a2b01..4da215d2206 100644 --- a/plugins/out_calyptia/calyptia.h +++ b/plugins/out_calyptia/calyptia.h @@ -25,31 +25,7 @@ #include #include -/* End point */ -#define CALYPTIA_HOST "cloud-api.calyptia.com" -#define CALYPTIA_PORT "443" - -/* HTTP action types */ -#define CALYPTIA_ACTION_REGISTER 0 -#define CALYPTIA_ACTION_PATCH 1 -#define CALYPTIA_ACTION_METRICS 2 -#define CALYPTIA_ACTION_TRACE 3 - -/* Endpoints */ -#define CALYPTIA_ENDPOINT_CREATE "/v1/agents" -#define CALYPTIA_ENDPOINT_PATCH "/v1/agents/%s" -#define CALYPTIA_ENDPOINT_METRICS "/v1/agents/%s/metrics" -#define CALYPTIA_ENDPOINT_TRACE "/v1/traces/%s" - -/* Storage */ -#define CALYPTIA_SESSION_FILE "session.CALYPTIA" - -/* Headers */ -#define CALYPTIA_H_PROJECT "X-Project-Token" -#define CALYPTIA_H_AGENT_TOKEN "X-Agent-Token" -#define CALYPTIA_H_CTYPE "Content-Type" -#define CALYPTIA_H_CTYPE_JSON "application/json" -#define CALYPTIA_H_CTYPE_MSGPACK "application/x-msgpack" +#include struct flb_calyptia { /* config map */ diff --git a/src/flb_utils.c b/src/flb_utils.c index 211632260e3..3aa4412086b 100644 --- a/src/flb_utils.c +++ b/src/flb_utils.c @@ -37,6 +37,8 @@ #include #include +#include + #ifdef FLB_HAVE_AWS_ERROR_REPORTER #include @@ -1636,3 +1638,53 @@ void flb_utils_set_plugin_string_property(const char *name, *field_storage = new_value; } + +#ifdef FLB_SYSTEM_WINDOWS +#define _mkdir(a, b) mkdir(a) +#else +#define _mkdir(a, b) mkdir(a, b) +#endif + +/* recursively create directories, based on: + * https://stackoverflow.com/a/2336245 + * who found it at: + * http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html + */ +int flb_utils_mkdir(const char *dir, int perms) { + char tmp[CALYPTIA_MAX_DIR_SIZE]; + char *ptr = NULL; + size_t len; + int ret; + + ret = snprintf(tmp, sizeof(tmp),"%s",dir); + if (ret < 0 || ret >= sizeof(tmp)) { + flb_error("directory too long for flb_utils_mkdir: %s", dir); + return -1; + } + + len = strlen(tmp); + /* len == ret but verifying index is valid */ + if ( len > 0 && tmp[len - 1] == PATH_SEPARATOR[0]) { + tmp[len - 1] = 0; + } + +#ifndef FLB_SYSTEM_WINDOWS + for (ptr = tmp + 1; *ptr; ptr++) { +#else + for (ptr = tmp + 3; *ptr; ptr++) { +#endif + + if (*ptr == PATH_SEPARATOR[0]) { + *ptr = 0; + if (access(tmp, F_OK) != 0) { + ret = _mkdir(tmp, perms); + if (ret != 0) { + return ret; + } + } + *ptr = PATH_SEPARATOR[0]; + } + } + + return _mkdir(tmp, perms); +}