Save/load: pid_tracker feature.
[lttng-tools.git] / src / common / config / config.c
index 722904772316c0fc0b48f548817a472e051247a1..03601be486deacc189f260251108534156aa0c1c 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #define _GNU_SOURCE
+#define _LGPL_SOURCE
 #include <assert.h>
 #include <ctype.h>
 #include <stdio.h>
@@ -31,6 +32,7 @@
 #include <common/error.h>
 #include <common/macros.h>
 #include <common/utils.h>
+#include <common/compat/getenv.h>
 #include <lttng/lttng-error.h>
 #include <libxml/parser.h>
 #include <libxml/valid.h>
@@ -113,10 +115,19 @@ const char * const config_element_net_output = "net_output";
 const char * const config_element_control_uri = "control_uri";
 const char * const config_element_data_uri = "data_uri";
 const char * const config_element_max_size = "max_size";
+const char * const config_element_pid = "pid";
+const char * const config_element_pids = "pids";
+const char * const config_element_shared_memory_path = "shared_memory_path";
+const char * const config_element_pid_tracker = "pid_tracker";
+const char * const config_element_trackers = "trackers";
+const char * const config_element_targets = "targets";
+const char * const config_element_target_pid = "pid_target";
 
 const char * const config_domain_type_kernel = "KERNEL";
 const char * const config_domain_type_ust = "UST";
 const char * const config_domain_type_jul = "JUL";
+const char * const config_domain_type_log4j = "LOG4J";
+const char * const config_domain_type_python = "PYTHON";
 
 const char * const config_buffer_type_per_pid = "PER_PID";
 const char * const config_buffer_type_per_uid = "PER_UID";
@@ -154,6 +165,7 @@ const char * const config_event_context_vppid = "VPPID";
 const char * const config_event_context_pthread_id = "PTHREAD_ID";
 const char * const config_event_context_hostname = "HOSTNAME";
 const char * const config_event_context_ip = "IP";
+const char * const config_event_context_perf_thread_counter = "PERF_THREAD_COUNTER";
 
 struct consumer_output {
        int enabled;
@@ -191,54 +203,73 @@ int config_get_section_entries(const char *override_path, const char *section,
                config_entry_handler_cb handler, void *user_data)
 {
        int ret = 0;
+       char *path;
        FILE *config_file = NULL;
        struct handler_filter_args filter = { section, handler, user_data };
 
+       /* First, try system-wide conf. file. */
+       path = DEFAULT_DAEMON_SYSTEM_CONFIGPATH;
+
+       config_file = fopen(path, "r");
+       if (config_file) {
+               DBG("Loading daemon conf file at %s", path);
+               /*
+                * Return value is not very important here since error or not, we
+                * continue and try the next possible conf. file.
+                */
+               (void) ini_parse_file(config_file,
+                               (ini_entry_handler) config_entry_handler_filter,
+                               (void *) &filter);
+               fclose(config_file);
+       }
+
+       /* Second is the user local configuration. */
+       path = utils_get_home_dir();
+       if (path) {
+               char fullpath[PATH_MAX];
+
+               ret = snprintf(fullpath, sizeof(fullpath),
+                               DEFAULT_DAEMON_HOME_CONFIGPATH, path);
+               if (ret < 0) {
+                       PERROR("snprintf user conf. path");
+                       goto error;
+               }
+
+               config_file = fopen(fullpath, "r");
+               if (config_file) {
+                       DBG("Loading daemon user conf file at %s", path);
+                       /*
+                        * Return value is not very important here since error or not, we
+                        * continue and try the next possible conf. file.
+                        */
+                       (void) ini_parse_file(config_file,
+                                       (ini_entry_handler) config_entry_handler_filter,
+                                       (void *) &filter);
+                       fclose(config_file);
+               }
+       }
+
+       /* Final path is the one that the user might have provided. */
        if (override_path) {
                config_file = fopen(override_path, "r");
                if (config_file) {
-                       DBG("Loaded daemon configuration file at %s",
-                               override_path);
+                       DBG("Loading daemon command line conf file at %s", override_path);
+                       (void) ini_parse_file(config_file,
+                                       (ini_entry_handler) config_entry_handler_filter,
+                                       (void *) &filter);
+                       fclose(config_file);
                } else {
                        ERR("Failed to open daemon configuration file at %s",
                                override_path);
                        ret = -ENOENT;
-                       goto end;
+                       goto error;
                }
-       } else {
-               char *path = utils_get_home_dir();
-
-               /* Try to open the user's daemon configuration file */
-               if (path) {
-                       ret = asprintf(&path, DEFAULT_DAEMON_HOME_CONFIGPATH, path);
-                       if (ret < 0) {
-                               goto end;
-                       }
-
-                       ret = 0;
-                       config_file = fopen(path, "r");
-                       if (config_file) {
-                               DBG("Loaded daemon configuration file at %s", path);
-                       }
-
-                       free(path);
-               }
-
-               /* Try to open the system daemon configuration file */
-               if (!config_file) {
-                       config_file = fopen(DEFAULT_DAEMON_HOME_CONFIGPATH, "r");
-               }
-       }
-
-       if (!config_file) {
-               DBG("No daemon configuration file found.");
-               goto end;
        }
 
-       ret = ini_parse_file(config_file,
-                       (ini_entry_handler) config_entry_handler_filter, (void *) &filter);
+       /* Everything went well. */
+       ret = 0;
 
-end:
+error:
        return ret;
 }
 
@@ -333,7 +364,7 @@ end:
 }
 
 LTTNG_HIDDEN
-struct config_writer *config_writer_create(int fd_output)
+struct config_writer *config_writer_create(int fd_output, int indent)
 {
        int ret;
        struct config_writer *writer;
@@ -359,12 +390,12 @@ struct config_writer *config_writer_create(int fd_output)
 
        ret = xmlTextWriterSetIndentString(writer->writer,
                BAD_CAST config_xml_indent_string);
-       if (ret)  {
+       if (ret) {
                goto error_destroy;
        }
 
-       ret = xmlTextWriterSetIndent(writer->writer, 1);
-       if (ret)  {
+       ret = xmlTextWriterSetIndent(writer->writer, indent);
+       if (ret) {
                goto error_destroy;
        }
 
@@ -568,13 +599,50 @@ void fini_session_config_validation_ctx(
        memset(ctx, 0, sizeof(struct session_config_validation_ctx));
 }
 
+static
+char *get_session_config_xsd_path()
+{
+       char *xsd_path;
+       const char *base_path = lttng_secure_getenv(DEFAULT_SESSION_CONFIG_XSD_PATH_ENV);
+       size_t base_path_len;
+       size_t max_path_len;
+
+       if (!base_path) {
+               base_path = DEFAULT_SESSION_CONFIG_XSD_PATH;
+       }
+
+       base_path_len = strlen(base_path);
+       max_path_len = base_path_len +
+               sizeof(DEFAULT_SESSION_CONFIG_XSD_FILENAME) + 1;
+       xsd_path = zmalloc(max_path_len);
+       if (!xsd_path) {
+               goto end;
+       }
+
+       strncpy(xsd_path, base_path, max_path_len);
+       if (xsd_path[base_path_len - 1] != '/') {
+               xsd_path[base_path_len++] = '/';
+       }
+
+       strncpy(xsd_path + base_path_len, DEFAULT_SESSION_CONFIG_XSD_FILENAME,
+               max_path_len - base_path_len);
+end:
+       return xsd_path;
+}
+
 static
 int init_session_config_validation_ctx(
        struct session_config_validation_ctx *ctx)
 {
        int ret;
+       char *xsd_path = get_session_config_xsd_path();
 
-       ctx->parser_ctx = xmlSchemaNewParserCtxt(DEFAULT_SESSION_CONFIG_XSD_PATH);
+       if (!xsd_path) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       ctx->parser_ctx = xmlSchemaNewParserCtxt(xsd_path);
        if (!ctx->parser_ctx) {
                ERR("XSD parser context creation failed");
                ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
@@ -606,6 +674,7 @@ end:
                fini_session_config_validation_ctx(ctx);
        }
 
+       free(xsd_path);
        return ret;
 }
 
@@ -691,6 +760,10 @@ int get_domain_type(xmlChar *domain)
                ret = LTTNG_DOMAIN_UST;
        } else if (!strcmp((char *) domain, config_domain_type_jul)) {
                ret = LTTNG_DOMAIN_JUL;
+       } else if (!strcmp((char *) domain, config_domain_type_log4j)) {
+               ret = LTTNG_DOMAIN_LOG4J;
+       } else if (!strcmp((char *) domain, config_domain_type_python)) {
+               ret = LTTNG_DOMAIN_PYTHON;
        } else {
                goto error;
        }
@@ -1178,6 +1251,7 @@ int create_session(const char *name,
        struct lttng_domain *kernel_domain,
        struct lttng_domain *ust_domain,
        struct lttng_domain *jul_domain,
+       struct lttng_domain *log4j_domain,
        xmlNodePtr output_node,
        uint64_t live_timer_interval)
 {
@@ -1218,7 +1292,7 @@ int create_session(const char *name,
                int i;
                struct lttng_domain *domain;
                struct lttng_domain *domains[] =
-                       { kernel_domain, ust_domain, jul_domain };
+                       { kernel_domain, ust_domain, jul_domain, log4j_domain };
 
                /* network destination */
                if (live_timer_interval && live_timer_interval != UINT64_MAX) {
@@ -1574,6 +1648,24 @@ int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle,
 
        ret = lttng_enable_event_with_exclusions(handle, &event, channel_name,
                        filter_expression, exclusion_count, exclusions);
+       if (ret) {
+               goto end;
+       }
+
+       if (!event.enabled) {
+               /*
+                * Note that we should use lttng_disable_event_ext() (2.6+) to
+                * eliminate the risk of clashing on events of the same
+                * name (with different event types and loglevels).
+                *
+                * Unfortunately, lttng_disable_event_ext() only performs a
+                * match on the name and event type and errors out if any other
+                * event attribute is not set to its default value.
+                *
+                * This will disable all events that match this name.
+                */
+               ret = lttng_disable_event(handle, event.name, channel_name);
+       }
 end:
        for (i = 0; i < exclusion_count; i++) {
                free(exclusions[i]);
@@ -1898,7 +1990,9 @@ int process_context_node(xmlNodePtr context_node,
                xmlNodePtr perf_attr_node;
 
                /* perf */
-               context.ctx = LTTNG_EVENT_CONTEXT_PERF_COUNTER;
+               context.ctx = handle->domain.type == LTTNG_DOMAIN_KERNEL ?
+                       LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER :
+                       LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER;
                for (perf_attr_node = xmlFirstElementChild(context_child_node);
                        perf_attr_node; perf_attr_node =
                                xmlNextElementSibling(perf_attr_node)) {
@@ -1998,6 +2092,79 @@ end:
        return ret;
 }
 
+static
+int process_pid_tracker_node(xmlNodePtr pid_tracker_node,
+       struct lttng_handle *handle)
+{
+       int ret, child;
+       xmlNodePtr targets_node = NULL;
+       xmlNodePtr node;
+
+       assert(handle);
+       assert(pid_tracker_node);
+       /* get the targets node */
+       for (node = xmlFirstElementChild(pid_tracker_node); node;
+               node = xmlNextElementSibling(node)) {
+               if (!strcmp((const char *) node->name,
+                               config_element_targets)) {
+                       targets_node = node;
+                       break;
+               }
+       }
+
+       if (!targets_node) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       /* Go through all pid_target node */
+       child = xmlChildElementCount(targets_node);
+       if (child == 0) {
+               /* The session is explicitly set to target nothing. */
+               ret = lttng_untrack_pid(handle, -1);
+               if (ret) {
+                       goto end;
+               }
+       }
+       for (node = xmlFirstElementChild(targets_node); node;
+                       node = xmlNextElementSibling(node)) {
+               xmlNodePtr pid_target_node = node;
+
+               /* get pid node and track it */
+               for (node = xmlFirstElementChild(pid_target_node); node;
+                       node = xmlNextElementSibling(node)) {
+                       if (!strcmp((const char *) node->name,
+                                       config_element_pid)) {
+                               int64_t pid;
+                               xmlChar *content = NULL;
+
+                               content = xmlNodeGetContent(node);
+                               if (!content) {
+                                       ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
+                                       goto end;
+                               }
+
+                               ret = parse_int(content, &pid);
+                               free(content);
+                               if (ret) {
+                                       ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
+                                       goto end;
+                               }
+
+                               ret = lttng_track_pid(handle, (int) pid);
+                               if (ret) {
+                                       goto end;
+                               }
+                       }
+               }
+               node = pid_target_node;
+       }
+
+end:
+       return ret;
+}
+
+
 static
 int process_domain_node(xmlNodePtr domain_node, const char *session_name)
 {
@@ -2005,6 +2172,8 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name)
        struct lttng_domain domain = { 0 };
        struct lttng_handle *handle = NULL;
        xmlNodePtr channels_node = NULL;
+       xmlNodePtr trackers_node = NULL;
+       xmlNodePtr pid_tracker_node = NULL;
        xmlNodePtr node;
 
        assert(session_name);
@@ -2071,6 +2240,36 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name)
                        goto end;
                }
        }
+
+       /* get the trackers node */
+       for (node = xmlFirstElementChild(domain_node); node;
+                       node = xmlNextElementSibling(node)) {
+               if (!strcmp((const char *) node->name,
+                                       config_element_trackers)) {
+                       trackers_node = node;
+                       break;
+               }
+       }
+
+       if (!trackers_node) {
+               goto end;
+       }
+
+       for (node = xmlFirstElementChild(trackers_node); node;
+                       node = xmlNextElementSibling(node)) {
+               if (!strcmp((const char *)node->name,config_element_pid_tracker)) {
+                       pid_tracker_node = node;
+                       ret = process_pid_tracker_node(pid_tracker_node, handle);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+       }
+
+       if (!pid_tracker_node) {
+               lttng_track_pid(handle, -1);
+       }
+
 end:
        lttng_destroy_handle(handle);
        return ret;
@@ -2082,13 +2281,16 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
 {
        int ret, started = -1, snapshot_mode = -1;
        uint64_t live_timer_interval = UINT64_MAX;
-       char *name = NULL;
+       xmlChar *name = NULL;
+       xmlChar *shm_path = NULL;
        xmlNodePtr domains_node = NULL;
        xmlNodePtr output_node = NULL;
        xmlNodePtr node;
        struct lttng_domain *kernel_domain = NULL;
        struct lttng_domain *ust_domain = NULL;
        struct lttng_domain *jul_domain = NULL;
+       struct lttng_domain *log4j_domain = NULL;
+       struct lttng_domain *python_domain = NULL;
 
        for (node = xmlFirstElementChild(session_node); node;
                node = xmlNextElementSibling(node)) {
@@ -2098,10 +2300,10 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
                        xmlChar *node_content = xmlNodeGetContent(node);
                        if (!node_content) {
                                ret = -LTTNG_ERR_NOMEM;
-                               goto end;
+                               goto error;
                        }
 
-                       name = (char *) node_content;
+                       name = node_content;
                } else if (!domains_node && !strcmp((const char *) node->name,
                        config_element_domains)) {
                        /* domains */
@@ -2112,19 +2314,29 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
                        xmlChar *node_content = xmlNodeGetContent(node);
                        if (!node_content) {
                                ret = -LTTNG_ERR_NOMEM;
-                               goto end;
+                               goto error;
                        }
 
                        ret = parse_bool(node_content, &started);
                        free(node_content);
                        if (ret) {
                                ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
-                               goto end;
+                               goto error;
                        }
                } else if (!output_node && !strcmp((const char *) node->name,
                        config_element_output)) {
                        /* output */
                        output_node = node;
+               } else if (!shm_path && !strcmp((const char *) node->name,
+                       config_element_shared_memory_path)) {
+                       /* shared memory path */
+                       xmlChar *node_content = xmlNodeGetContent(node);
+                       if (!node_content) {
+                               ret = -LTTNG_ERR_NOMEM;
+                               goto error;
+                       }
+
+                       shm_path = node_content;
                } else {
                        /* attributes, snapshot_mode or live_timer_interval */
                        xmlNodePtr attributes_child =
@@ -2137,14 +2349,14 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
                                        xmlNodeGetContent(attributes_child);
                                if (!snapshot_mode_content) {
                                        ret = -LTTNG_ERR_NOMEM;
-                                       goto end;
+                                       goto error;
                                }
 
                                ret = parse_bool(snapshot_mode_content, &snapshot_mode);
                                free(snapshot_mode_content);
                                if (ret) {
                                        ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
-                                       goto end;
+                                       goto error;
                                }
                        } else {
                                /* live_timer_interval */
@@ -2152,14 +2364,14 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
                                        xmlNodeGetContent(attributes_child);
                                if (!timer_interval_content) {
                                        ret = -LTTNG_ERR_NOMEM;
-                                       goto end;
+                                       goto error;
                                }
 
                                ret = parse_uint(timer_interval_content, &live_timer_interval);
                                free(timer_interval_content);
                                if (ret) {
                                        ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
-                                       goto end;
+                                       goto error;
                                }
                        }
                }
@@ -2168,13 +2380,13 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
        if (!name) {
                /* Mandatory attribute, as defined in the session XSD */
                ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
-               goto end;
+               goto error;
        }
 
-       if (session_name && strcmp(name, session_name)) {
+       if (session_name && strcmp((char *) name, session_name)) {
                /* This is not the session we are looking for */
-               ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
-               goto end;
+               ret = -LTTNG_ERR_NO_SESSION;
+               goto error;
        }
 
        /* Init domains to create the session handles */
@@ -2185,7 +2397,7 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
                domain = zmalloc(sizeof(*domain));
                if (!domain) {
                        ret = -LTTNG_ERR_NOMEM;
-                       goto end;
+                       goto error;
                }
 
                ret = init_domain(node, domain);
@@ -2215,6 +2427,20 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
                        }
                        jul_domain = domain;
                        break;
+               case LTTNG_DOMAIN_LOG4J:
+                       if (log4j_domain) {
+                               /* Same domain seen twice, invalid! */
+                               goto domain_init_error;
+                       }
+                       log4j_domain = domain;
+                       break;
+               case LTTNG_DOMAIN_PYTHON:
+                       if (python_domain) {
+                               /* Same domain seen twice, invalid! */
+                               goto domain_init_error;
+                       }
+                       python_domain = domain;
+                       break;
                default:
                        WARN("Invalid domain type");
                        goto domain_init_error;
@@ -2223,57 +2449,102 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
 domain_init_error:
                free(domain);
                ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
-               goto end;
+               goto error;
        }
 
        if (override) {
                /* Destroy session if it exists */
-               ret = lttng_destroy_session(name);
+               ret = lttng_destroy_session((const char *) name);
                if (ret && ret != -LTTNG_ERR_SESS_NOT_FOUND) {
                        ERR("Failed to destroy existing session.");
-                       goto end;
+                       goto error;
                }
        }
 
        /* Create session type depending on output type */
        if (snapshot_mode && snapshot_mode != -1) {
-               ret = create_snapshot_session(name, output_node);
+               ret = create_snapshot_session((const char *) name, output_node);
        } else if (live_timer_interval &&
                live_timer_interval != UINT64_MAX) {
-               ret = create_session(name, kernel_domain, ust_domain, jul_domain,
+               ret = create_session((const char *) name, kernel_domain,
+                               ust_domain, jul_domain, log4j_domain,
                                output_node, live_timer_interval);
        } else {
                /* regular session */
-               ret = create_session(name, kernel_domain, ust_domain, jul_domain,
+               ret = create_session((const char *) name, kernel_domain,
+                               ust_domain, jul_domain, log4j_domain,
                                output_node, UINT64_MAX);
        }
-
        if (ret) {
-               goto end;
+               goto error;
+       }
+
+       if (shm_path) {
+               ret = lttng_set_session_shm_path((const char *) name,
+                               (const char *) shm_path);
+               if (ret) {
+                       goto error;
+               }
        }
 
        for (node = xmlFirstElementChild(domains_node); node;
                node = xmlNextElementSibling(node)) {
-               ret = process_domain_node(node, name);
+               ret = process_domain_node(node, (const char *) name);
                if (ret) {
                        goto end;
                }
        }
 
        if (started) {
-               ret = lttng_start_tracing(name);
+               ret = lttng_start_tracing((const char *) name);
                if (ret) {
                        goto end;
                }
        }
+
 end:
+       if (ret < 0) {
+               ERR("Failed to load session %s: %s", (const char *) name,
+                       lttng_strerror(ret));
+               lttng_destroy_session((const char *) name);
+       }
+
+error:
        free(kernel_domain);
        free(ust_domain);
        free(jul_domain);
-       free(name);
+       free(log4j_domain);
+       free(python_domain);
+       xmlFree(name);
+       xmlFree(shm_path);
        return ret;
 }
 
+/*
+ * Return 1 if the given path is readable by the current UID or 0 if not.
+ * Return -1 if the path is EPERM.
+ */
+static int validate_file_read_creds(const char *path)
+{
+       int ret;
+
+       assert(path);
+
+       /* Can we read the file. */
+       ret = access(path, R_OK);
+       if (!ret) {
+               goto valid;
+       }
+       if (errno == EACCES) {
+               return -1;
+       } else {
+               /* Invalid. */
+               return 0;
+       }
+valid:
+       return 1;
+}
+
 static
 int load_session_from_file(const char *path, const char *session_name,
        struct session_config_validation_ctx *validation_ctx, int override)
@@ -2282,14 +2553,17 @@ int load_session_from_file(const char *path, const char *session_name,
        xmlDocPtr doc = NULL;
        xmlNodePtr sessions_node;
        xmlNodePtr session_node;
-       struct stat sb;
 
        assert(path);
        assert(validation_ctx);
 
-       ret = stat(path, &sb);
-       if (ret) {
-               ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
+       ret = validate_file_read_creds(path);
+       if (ret != 1) {
+               if (ret == -1) {
+                       ret = -LTTNG_ERR_EPERM;
+               } else {
+                       ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
+               }
                goto end;
        }
 
@@ -2330,6 +2604,23 @@ end:
        return ret;
 }
 
+/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
+static
+struct dirent *alloc_dirent(const char *path)
+{
+       size_t len;
+       long name_max;
+       struct dirent *entry;
+
+       name_max = pathconf(path, _PC_NAME_MAX);
+       if (name_max == -1) {
+               name_max = PATH_MAX;
+       }
+       len = offsetof(struct dirent, d_name) + name_max + 1;
+       entry = zmalloc(len);
+       return entry;
+}
+
 static
 int load_session_from_path(const char *path, const char *session_name,
        struct session_config_validation_ctx *validation_ctx, int override)
@@ -2342,7 +2633,14 @@ int load_session_from_path(const char *path, const char *session_name,
 
        directory = opendir(path);
        if (!directory) {
-               if (errno != ENOTDIR) {
+               switch (errno) {
+               case ENOTDIR:
+                       /* Try the file loading. */
+                       break;
+               case ENOENT:
+                       ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
+                       goto end;
+               default:
                        ret = -LTTNG_ERR_LOAD_IO_FAIL;
                        goto end;
                }
@@ -2358,7 +2656,7 @@ int load_session_from_path(const char *path, const char *session_name,
                        goto end;
                }
 
-               entry = zmalloc(sizeof(*entry));
+               entry = alloc_dirent(path);
                if (!entry) {
                        ret = -LTTNG_ERR_NOMEM;
                        goto end;
@@ -2386,7 +2684,7 @@ int load_session_from_path(const char *path, const char *session_name,
                                continue;
                        }
 
-                       if (path_len + file_name_len > PATH_MAX) {
+                       if (path_len + file_name_len >= PATH_MAX) {
                                continue;
                        }
 
@@ -2433,11 +2731,46 @@ end:
        return ret;
 }
 
+/*
+ * Validate that the given path's credentials and the current process have the
+ * same UID. If so, return 1 else return 0 if it does NOT match.
+ */
+static int validate_path_creds(const char *path)
+{
+       int ret, uid = getuid();
+       struct stat buf;
+
+       assert(path);
+
+       if (uid == 0) {
+               goto valid;
+       }
+
+       ret = stat(path, &buf);
+       if (ret < 0) {
+               if (errno != ENOENT) {
+                       PERROR("stat");
+               }
+               ret = -LTTNG_ERR_INVALID;
+               goto valid;
+       }
+
+       if (buf.st_uid != uid) {
+               goto invalid;
+       }
+
+valid:
+       return 1;
+invalid:
+       return 0;
+}
+
 LTTNG_HIDDEN
 int config_load_session(const char *path, const char *session_name,
-               int override)
+               int override, unsigned int autoload)
 {
        int ret;
+       const char *path_ptr = NULL;
        struct session_config_validation_ctx validation_ctx = { 0 };
 
        ret = init_session_config_validation_ctx(&validation_ctx);
@@ -2446,34 +2779,77 @@ int config_load_session(const char *path, const char *session_name,
        }
 
        if (!path) {
+               char *home_path;
+               const char *sys_path;
+
                /* Try home path */
-               char *home_path = utils_get_home_dir();
+               home_path = utils_get_home_dir();
                if (home_path) {
-                       char *path;
+                       char path[PATH_MAX];
 
-                       ret = asprintf(&path, DEFAULT_SESSION_HOME_CONFIGPATH,
-                               home_path);
-                       if (ret < 0) {
-                               goto end;
-                       }
+                       /*
+                        * Try user session configuration path. Ignore error here so we can
+                        * continue loading the system wide sessions.
+                        */
+                       if (autoload) {
+                               ret = snprintf(path, sizeof(path),
+                                               DEFAULT_SESSION_HOME_CONFIGPATH "/"
+                                               DEFAULT_SESSION_CONFIG_AUTOLOAD, home_path);
+                               if (ret < 0) {
+                                       PERROR("snprintf session autoload home config path");
+                                       goto end;
+                               }
 
-                       ret = load_session_from_path(path, session_name,
-                               &validation_ctx, 0);
-                       if (!ret || (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT)) {
-                               /* Session found or an error occured */
-                               free(path);
-                               goto end;
+                               /*
+                                * Credentials are only validated for the autoload in order to
+                                * avoid any user session daemon to try to load kernel sessions
+                                * automatically and failing all the times.
+                                */
+                               ret = validate_path_creds(path);
+                               if (ret) {
+                                       path_ptr = path;
+                               }
+                       } else {
+                               ret = snprintf(path, sizeof(path),
+                                               DEFAULT_SESSION_HOME_CONFIGPATH, home_path);
+                               if (ret < 0) {
+                                       PERROR("snprintf session home config path");
+                                       goto end;
+                               }
+                               path_ptr = path;
                        }
+                       if (path_ptr) {
+                               ret = load_session_from_path(path_ptr, session_name,
+                                               &validation_ctx, override);
+                               if (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT) {
+                                       goto end;
+                               }
+                               /*
+                                * Continue even if the session was found since we have to try
+                                * the system wide sessions.
+                                */
+                       }
+               }
 
-                       free(path);
+               /* Reset path pointer for the system wide dir. */
+               path_ptr = NULL;
+
+               /* Try system wide configuration directory. */
+               if (autoload) {
+                       sys_path = DEFAULT_SESSION_SYSTEM_CONFIGPATH "/"
+                               DEFAULT_SESSION_CONFIG_AUTOLOAD;
+                       ret = validate_path_creds(sys_path);
+                       if (ret) {
+                               path_ptr = sys_path;
+                       }
+               } else {
+                       sys_path = DEFAULT_SESSION_SYSTEM_CONFIGPATH;
+                       path_ptr = sys_path;
                }
 
-               /* Try system session configuration path */
-               ret = load_session_from_path(DEFAULT_SESSION_SYSTEM_CONFIGPATH,
-                       session_name, &validation_ctx, 0);
-               if (!ret || (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT)) {
-                       /* Session found or an error occured */
-                       goto end;
+               if (path_ptr) {
+                       ret = load_session_from_path(path_ptr, session_name,
+                                       &validation_ctx, override);
                }
        } else {
                ret = access(path, F_OK);
@@ -2499,5 +2875,12 @@ int config_load_session(const char *path, const char *session_name,
        }
 end:
        fini_session_config_validation_ctx(&validation_ctx);
+       if (ret == -LTTNG_ERR_LOAD_SESSION_NOENT && !session_name && !path) {
+               /*
+                * Don't report an error if no sessions are found when called
+                * without a session_name or a search path.
+                */
+               ret = 0;
+       }
        return ret;
 }
This page took 0.034436 seconds and 4 git commands to generate.