/*
- * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
+ * SPDX-License-Identifier: LGPL-2.1-only
*
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <assert.h>
-#include <common/defaults.h>
-#include <common/error.h>
-#include <common/macros.h>
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/uri.h>
-#include <lttng/tracker-internal.h>
-#include <stdio.h>
-#include <time.h>
-
-struct lttng_tracker_id *lttng_tracker_id_create(void)
-{
- struct lttng_tracker_id *id;
+#include <lttng/domain.h>
+#include <lttng/lttng-error.h>
+#include <lttng/tracker.h>
- id = zmalloc(sizeof(*id));
- if (!id) {
- goto error;
+#include <common/dynamic-array.h>
+#include <common/error.h>
+#include <common/hashtable/hashtable.h>
+#include <common/hashtable/utils.h>
+#include <common/tracker.h>
+
+#include <stdbool.h>
+
+struct process_attr_tracker_values_comm_header {
+ uint32_t count;
+};
+
+struct process_attr_tracker_value_comm {
+ /* enum lttng_process_attr_value_type */
+ int32_t type;
+ union {
+ struct process_attr_integral_value_comm integral;
+ /* Includes the '\0' terminator. */
+ uint32_t name_len;
+ } value;
+};
+
+#define GET_INTEGRAL_COMM_VALUE(value_ptr, as_type) \
+ ((as_type)(is_signed(as_type) ? (value_ptr)->u._signed : \
+ (value_ptr)->u._unsigned))
+
+#define SET_INTEGRAL_COMM_VALUE(comm_value, value) \
+ if (is_signed(typeof(value))) { \
+ (comm_value)->u._signed = \
+ (typeof((comm_value)->u._signed)) value; \
+ } else { \
+ (comm_value)->u._unsigned = \
+ (typeof((comm_value)->u._unsigned)) value; \
}
- id->type = LTTNG_ID_UNKNOWN;
- id->string = NULL;
- id->value = -1;
- return id;
-error:
- lttng_tracker_id_destroy(id);
- return NULL;
+static inline bool is_virtual_process_attr(enum lttng_process_attr process_attr)
+{
+ return process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID ||
+ process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID ||
+ process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID;
+}
+
+static inline bool is_value_type_name(
+ enum lttng_process_attr_value_type value_type)
+{
+ return value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ||
+ value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME;
}
-enum lttng_tracker_id_status lttng_tracker_id_set_value(
- struct lttng_tracker_id *id, int value)
+enum lttng_error_code process_attr_value_from_comm(
+ enum lttng_domain_type domain,
+ enum lttng_process_attr process_attr,
+ enum lttng_process_attr_value_type value_type,
+ const struct process_attr_integral_value_comm *integral_value,
+ const struct lttng_buffer_view *value_view,
+ struct process_attr_value **_value)
{
- assert(id);
+ char *name = NULL;
+ enum lttng_error_code ret = LTTNG_OK;
+ struct process_attr_value *value = zmalloc(sizeof(*value));
- if (value < 0) {
- return LTTNG_TRACKER_ID_STATUS_INVALID;
+ if (!value) {
+ ret = LTTNG_ERR_NOMEM;
+ goto error;
}
- id->type = LTTNG_ID_VALUE;
- id->value = value;
- return LTTNG_TRACKER_ID_STATUS_OK;
-}
+ if (value_view && value_view->size > 0) {
+ if (value_view->data[value_view->size - 1] != '\0') {
+ ret = LTTNG_ERR_INVALID;
+ goto error;
+ }
+ name = strdup(value_view->data);
+ if (!name) {
+ ret = LTTNG_ERR_NOMEM;
+ goto error;
+ }
+ }
-enum lttng_tracker_id_status lttng_tracker_id_set_string(
- struct lttng_tracker_id *id, const char *value)
-{
- assert(id);
- assert(value);
+ if (domain != LTTNG_DOMAIN_UST && domain != LTTNG_DOMAIN_KERNEL) {
+ ERR("Only the user space and kernel space domains may be specified to configure process attribute trackers");
+ ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
+ goto error;
+ }
+
+ if (!is_virtual_process_attr(process_attr) &&
+ domain != LTTNG_DOMAIN_KERNEL) {
+ ERR("Non-virtual process attributes can only be used in the kernel domain");
+ ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
+ goto error;
+ }
- id->type = LTTNG_ID_STRING;
- id->string = strdup(value);
- if (id->string == NULL) {
- /* No memory left */
+ /* Only expect a payload for name value types. */
+ if (is_value_type_name(value_type) &&
+ (!value_view || value_view->size == 0)) {
+ ret = LTTNG_ERR_INVALID_PROTOCOL;
+ goto error;
+ } else if (!is_value_type_name(value_type) && value_view &&
+ value_view->size != 0) {
+ ret = LTTNG_ERR_INVALID_PROTOCOL;
+ goto error;
+ }
+
+ value->type = value_type;
+ switch (process_attr) {
+ case LTTNG_PROCESS_ATTR_PROCESS_ID:
+ case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
+ if (value_type != LTTNG_PROCESS_ATTR_VALUE_TYPE_PID) {
+ ERR("Invalid value type used for process ID process attribute");
+ ret = LTTNG_ERR_INVALID;
+ goto error;
+ }
+ value->value.pid =
+ GET_INTEGRAL_COMM_VALUE(integral_value, pid_t);
+ break;
+ case LTTNG_PROCESS_ATTR_USER_ID:
+ case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+ switch (value_type) {
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
+ value->value.uid = GET_INTEGRAL_COMM_VALUE(
+ integral_value, uid_t);
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
+ if (!name) {
+ ret = LTTNG_ERR_INVALID;
+ goto error;
+ }
+
+ value->value.user_name = name;
+ name = NULL;
+ break;
+ default:
+ ERR("Invalid value type used for user ID process attribute");
+ ret = LTTNG_ERR_INVALID;
+ goto error;
+ }
+ break;
+ case LTTNG_PROCESS_ATTR_GROUP_ID:
+ case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+ switch (value_type) {
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
+ value->value.gid = GET_INTEGRAL_COMM_VALUE(
+ integral_value, gid_t);
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
+ if (!name) {
+ ret = LTTNG_ERR_INVALID;
+ goto error;
+ }
+
+ value->value.group_name = name;
+ name = NULL;
+ break;
+ default:
+ ERR("Invalid value type used for group ID process attribute");
+ ret = LTTNG_ERR_INVALID;
+ goto error;
+ }
+ break;
+ default:
+ ret = LTTNG_ERR_INVALID_PROTOCOL;
goto error;
}
- return LTTNG_TRACKER_ID_STATUS_OK;
+ *_value = value;
+ value = NULL;
+ free(name);
+ return LTTNG_OK;
error:
- return LTTNG_TRACKER_ID_STATUS_INVALID;
+ free(name);
+ process_attr_value_destroy(value);
+ return ret;
}
-enum lttng_tracker_id_status lttng_tracker_id_set_all(
- struct lttng_tracker_id *id)
+const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr)
{
- assert(id);
+ switch (process_attr) {
+ case LTTNG_PROCESS_ATTR_PROCESS_ID:
+ return "process ID";
+ case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
+ return "virtual process ID";
+ case LTTNG_PROCESS_ATTR_USER_ID:
+ return "user ID";
+ case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+ return "virtual user ID";
+ case LTTNG_PROCESS_ATTR_GROUP_ID:
+ return "group ID";
+ case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+ return "virtual group ID";
+ default:
+ return "unknown process attribute";
+ }
+}
- id->type = LTTNG_ID_ALL;
+static void process_attr_tracker_value_destructor(void *ptr)
+{
+ struct process_attr_value *value = (typeof(value)) ptr;
- return LTTNG_TRACKER_ID_STATUS_OK;
+ process_attr_value_destroy(value);
}
-static void lttng_tracker_id_reset(struct lttng_tracker_id *id)
+struct lttng_process_attr_values *lttng_process_attr_values_create(void)
{
- if (id == NULL) {
- return;
- }
+ struct lttng_process_attr_values *values = zmalloc(sizeof(*values));
- if (id->string != NULL) {
- free(id->string);
- id->string = NULL;
+ if (!values) {
+ goto end;
}
- id->type = LTTNG_ID_UNKNOWN;
- id->value = -1;
+ lttng_dynamic_pointer_array_init(
+ &values->array, process_attr_tracker_value_destructor);
+end:
+ return values;
}
-void lttng_tracker_id_destroy(struct lttng_tracker_id *id)
+unsigned int _lttng_process_attr_values_get_count(
+ const struct lttng_process_attr_values *values)
{
- if (id == NULL) {
- return;
- }
-
- lttng_tracker_id_reset(id);
-
- free(id);
+ return (unsigned int) lttng_dynamic_pointer_array_get_count(
+ &values->array);
}
-enum lttng_tracker_id_type lttng_tracker_id_get_type(
- const struct lttng_tracker_id *id)
+const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index(
+ const struct lttng_process_attr_values *values,
+ unsigned int index)
{
- assert(id);
- return id->type;
+ return lttng_dynamic_pointer_array_get_pointer(&values->array, index);
}
-enum lttng_tracker_id_status lttng_tracker_id_get_value(
- const struct lttng_tracker_id *id, int *value)
+static
+int process_attr_tracker_value_serialize(const struct process_attr_value *value,
+ struct lttng_dynamic_buffer *buffer)
{
- assert(id);
- if (id->type == LTTNG_ID_UNKNOWN) {
- return LTTNG_TRACKER_ID_STATUS_UNSET;
+ int ret;
+ struct process_attr_tracker_value_comm value_comm = {
+ .type = (int32_t) value->type,
+ };
+ const char *name = NULL;
+
+ switch (value->type) {
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
+ SET_INTEGRAL_COMM_VALUE(
+ &value_comm.value.integral, value->value.pid);
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
+ SET_INTEGRAL_COMM_VALUE(
+ &value_comm.value.integral, value->value.uid);
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
+ SET_INTEGRAL_COMM_VALUE(
+ &value_comm.value.integral, value->value.gid);
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
+ name = value->value.user_name;
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
+ name = value->value.group_name;
+ break;
+ default:
+ abort();
}
- if (id->type != LTTNG_ID_VALUE) {
- return LTTNG_TRACKER_ID_STATUS_INVALID;
+ if (name) {
+ value_comm.value.name_len = strlen(name) + 1;
}
- *value = id->value;
- return LTTNG_TRACKER_ID_STATUS_OK;
-}
-
-bool lttng_tracker_id_is_equal(const struct lttng_tracker_id *left,
- const struct lttng_tracker_id *right)
-{
- if (left->type != right->type) {
- return 0;
+ ret = lttng_dynamic_buffer_append(
+ buffer, &value_comm, sizeof(value_comm));
+ if (ret) {
+ goto end;
}
- switch (left->type) {
- case LTTNG_ID_ALL:
- return 1;
- case LTTNG_ID_VALUE:
- if (left->value != right->value) {
- return 0;
- }
- break;
- case LTTNG_ID_STRING:
- if (strcmp(left->string, right->string) != 0) {
- return 0;
- }
- break;
- default:
- /*
- * Normally this should return true, but comparing unset tracker
- * id is "invalid".
- */
- return 0;
+ if (name) {
+ ret = lttng_dynamic_buffer_append(
+ buffer, name, value_comm.value.name_len);
}
- return 1;
+end:
+ return ret;
}
-int lttng_tracker_id_copy(struct lttng_tracker_id *dest,
- const struct lttng_tracker_id *orig)
+int lttng_process_attr_values_serialize(
+ const struct lttng_process_attr_values *values,
+ struct lttng_dynamic_buffer *buffer)
{
- int ret = 0;
- enum lttng_tracker_id_status status;
+ int ret;
+ unsigned int count, i;
+ struct process_attr_tracker_values_comm_header header = {};
- assert(dest);
- assert(orig);
+ count = _lttng_process_attr_values_get_count(values);
+ header.count = (uint32_t) count;
- switch (orig->type) {
- case LTTNG_ID_ALL:
- status = lttng_tracker_id_set_all(dest);
- break;
- case LTTNG_ID_VALUE:
- status = lttng_tracker_id_set_value(dest, orig->value);
- break;
- case LTTNG_ID_STRING:
- status = lttng_tracker_id_set_string(dest, orig->string);
- break;
- default:
- status = LTTNG_TRACKER_ID_STATUS_OK;
- break;
+ ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header));
+ if (ret) {
+ goto end;
}
- if (status != LTTNG_TRACKER_ID_STATUS_OK) {
- ret = -1;
- goto error;
+ for (i = 0; i < count; i++) {
+ const struct process_attr_value *value =
+ lttng_process_attr_tracker_values_get_at_index(
+ values, i);
+
+ ret = process_attr_tracker_value_serialize(value, buffer);
+ if (ret) {
+ goto end;
+ }
}
-error:
+end:
return ret;
}
-struct lttng_tracker_id *lttng_tracker_id_duplicate(
- const struct lttng_tracker_id *orig)
+ssize_t lttng_process_attr_values_create_from_buffer(
+ enum lttng_domain_type domain,
+ enum lttng_process_attr process_attr,
+ const struct lttng_buffer_view *buffer_view,
+ struct lttng_process_attr_values **_values)
{
- int ret;
- struct lttng_tracker_id *copy = NULL;
+ ssize_t offset;
+ unsigned int i;
+ struct lttng_process_attr_values *values;
+ struct lttng_buffer_view header_view;
+ const struct process_attr_tracker_values_comm_header *header;
+
+ values = lttng_process_attr_values_create();
+ if (!values) {
+ goto error;
+ }
- copy = lttng_tracker_id_create();
- if (copy == NULL) {
+ header_view = lttng_buffer_view_from_view(
+ buffer_view, 0, sizeof(*header));
+ if (!lttng_buffer_view_is_valid(&header_view)) {
goto error;
}
- ret = lttng_tracker_id_copy(copy, orig);
- if (ret) {
+ offset = header_view.size;
+ header = (typeof(header)) header_view.data;
+
+ /*
+ * Check that the number of values is not absurdly large with respect to
+ * the received buffer's size.
+ */
+ if (buffer_view->size <
+ header->count * sizeof(struct process_attr_tracker_value_comm)) {
goto error;
}
+ for (i = 0; i < (unsigned int) header->count; i++) {
+ int ret;
+ enum lttng_error_code ret_code;
+ const struct process_attr_tracker_value_comm *value_comm;
+ struct process_attr_value *value;
+ enum lttng_process_attr_value_type type;
+ struct lttng_buffer_view value_view;
+ struct lttng_buffer_view value_name_view = {};
+
+ value_view = lttng_buffer_view_from_view(
+ buffer_view, offset, sizeof(*value_comm));
+ if (!lttng_buffer_view_is_valid(&value_view)) {
+ goto error;
+ }
+
+ offset += value_view.size;
+ value_comm = (typeof(value_comm)) value_view.data;
+ type = (typeof(type)) value_comm->type;
+
+ if (is_value_type_name(type)) {
+ value_name_view = lttng_buffer_view_from_view(
+ buffer_view, offset,
+ value_comm->value.name_len);
+ if (!lttng_buffer_view_is_valid(&value_name_view)) {
+ goto error;
+ }
+
+ offset += value_name_view.size;
+ }
+
+ ret_code = process_attr_value_from_comm(domain, process_attr,
+ type, &value_comm->value.integral,
+ &value_name_view, &value);
+ if (ret_code != LTTNG_OK) {
+ goto error;
+ }
+
+ ret = lttng_dynamic_pointer_array_add_pointer(
+ &values->array, value);
+ if (ret) {
+ process_attr_value_destroy(value);
+ goto error;
+ }
+ }
- return copy;
+ *_values = values;
+ return offset;
error:
- lttng_tracker_id_destroy(copy);
- return NULL;
+ lttng_process_attr_values_destroy(values);
+ return -1;
}
-enum lttng_tracker_id_status lttng_tracker_id_get_string(
- const struct lttng_tracker_id *id, const char **value)
+void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values)
{
- assert(id);
- if (id->type == LTTNG_ID_UNKNOWN) {
- *value = NULL;
- return LTTNG_TRACKER_ID_STATUS_UNSET;
- }
-
- if (id->type != LTTNG_ID_STRING) {
- *value = NULL;
- return LTTNG_TRACKER_ID_STATUS_INVALID;
+ if (!values) {
+ return;
}
-
- *value = id->string;
- return LTTNG_TRACKER_ID_STATUS_OK;
+ lttng_dynamic_pointer_array_reset(&values->array);
+ free(values);
}
-struct lttng_tracker_ids *lttng_tracker_ids_create(unsigned int count)
+struct process_attr_value *process_attr_value_copy(
+ const struct process_attr_value *value)
{
- struct lttng_tracker_ids *ids = NULL;
+ struct process_attr_value *new_value = NULL;
- ids = zmalloc(sizeof(*ids));
- if (!ids) {
- goto error;
+ if (!value) {
+ goto end;
}
- ids->id_array = zmalloc(sizeof(struct lttng_tracker_id) * count);
- if (!ids->id_array) {
- goto error;
+ new_value = zmalloc(sizeof(*new_value));
+ if (!new_value) {
+ goto end;
}
-
- ids->count = count;
-
- return ids;
+ if (is_value_type_name(value->type)) {
+ const char *src =
+ value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
+ value->value.user_name :
+ value->value.group_name;
+ char **dst = value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
+ &new_value->value.user_name :
+ &new_value->value.group_name;
+
+ new_value->type = value->type;
+ *dst = strdup(src);
+ if (!*dst) {
+ goto error;
+ }
+ } else {
+ *new_value = *value;
+ }
+end:
+ return new_value;
error:
- free(ids);
+ free(new_value);
return NULL;
}
-LTTNG_HIDDEN
-struct lttng_tracker_id *lttng_tracker_ids_get_pointer_of_index(
- const struct lttng_tracker_ids *ids, unsigned int index)
+unsigned long process_attr_value_hash(const struct process_attr_value *a)
{
- assert(ids);
- if (index >= ids->count) {
- return NULL;
- }
+ unsigned long hash = hash_key_ulong((void *) a->type, lttng_ht_seed);
- return &ids->id_array[index];
-}
+ switch (a->type) {
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
+ hash ^= hash_key_ulong((void *) (unsigned long) a->value.pid,
+ lttng_ht_seed);
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
+ hash ^= hash_key_ulong((void *) (unsigned long) a->value.uid,
+ lttng_ht_seed);
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
+ hash ^= hash_key_ulong((void *) (unsigned long) a->value.gid,
+ lttng_ht_seed);
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
+ hash ^= hash_key_str(a->value.user_name, lttng_ht_seed);
+ break;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
+ hash ^= hash_key_str(a->value.group_name, lttng_ht_seed);
+ break;
+ default:
+ abort();
+ }
-const struct lttng_tracker_id *lttng_tracker_ids_get_at_index(
- const struct lttng_tracker_ids *ids, unsigned int index)
-{
- assert(ids);
- return lttng_tracker_ids_get_pointer_of_index(ids, index);
+ return hash;
}
-int lttng_tracker_ids_get_count(const struct lttng_tracker_ids *ids)
+bool process_attr_tracker_value_equal(const struct process_attr_value *a,
+ const struct process_attr_value *b)
{
- assert(ids);
- return ids->count;
+ if (a->type != b->type) {
+ return false;
+ }
+ switch (a->type) {
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
+ return a->value.pid == b->value.pid;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
+ return a->value.uid == b->value.uid;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
+ return a->value.gid == b->value.gid;
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
+ return !strcmp(a->value.user_name, b->value.user_name);
+ case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
+ return !strcmp(a->value.group_name, b->value.group_name);
+ default:
+ abort();
+ }
}
-void lttng_tracker_ids_destroy(struct lttng_tracker_ids *ids)
+void process_attr_value_destroy(struct process_attr_value *value)
{
- if (!ids) {
+ if (!value) {
return;
}
-
- for (int i = 0; i < ids->count; i++) {
- lttng_tracker_id_reset(&ids->id_array[i]);
+ if (is_value_type_name(value->type)) {
+ free(value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
+ value->value.user_name :
+ value->value.group_name);
}
- free(ids->id_array);
- free(ids);
+ free(value);
}