X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Ftracker.c;h=29249d528bc8da1f1a7b71e00381cc24b65d1678;hp=312d7bce07601ee26a87ae82a5cd6821d8d16285;hb=b78dab175fd5d80ca3a851e17660b776414332a6;hpb=ab5be9fa2eb5ba9600a82cd18fd3cfcbac69169a diff --git a/src/common/tracker.c b/src/common/tracker.c index 312d7bce0..29249d528 100644 --- a/src/common/tracker.c +++ b/src/common/tracker.c @@ -1,367 +1,523 @@ /* - * Copyright (C) 2019 Jonathan Rajotte-Julien + * Copyright (C) 2019 Jonathan Rajotte + * Copyright (C) 2020 Jérémie Galarneau * * SPDX-License-Identifier: LGPL-2.1-only * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct lttng_tracker_id *lttng_tracker_id_create(void) -{ - struct lttng_tracker_id *id; +#include +#include +#include - id = zmalloc(sizeof(*id)); - if (!id) { - goto error; +#include +#include +#include +#include +#include + +#include + +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; } -enum lttng_tracker_id_status lttng_tracker_id_set_value( - struct lttng_tracker_id *id, int value) +static inline bool is_value_type_name( + enum lttng_process_attr_value_type value_type) { - assert(id); - - if (value < 0) { - return LTTNG_TRACKER_ID_STATUS_INVALID; - } - - id->type = LTTNG_ID_VALUE; - id->value = value; - return LTTNG_TRACKER_ID_STATUS_OK; + 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_string( - struct lttng_tracker_id *id, const char *value) +LTTNG_HIDDEN +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); - assert(value); + char *name = NULL; + enum lttng_error_code ret = LTTNG_OK; + struct process_attr_value *value = zmalloc(sizeof(*value)); - id->type = LTTNG_ID_STRING; - id->string = strdup(value); - if (id->string == NULL) { - /* No memory left */ + if (!value) { + ret = LTTNG_ERR_NOMEM; goto error; } - return LTTNG_TRACKER_ID_STATUS_OK; -error: - return LTTNG_TRACKER_ID_STATUS_INVALID; -} - -enum lttng_tracker_id_status lttng_tracker_id_set_all( - struct lttng_tracker_id *id) -{ - assert(id); + 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; + } + } - id->type = LTTNG_ID_ALL; + 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; + } - return LTTNG_TRACKER_ID_STATUS_OK; -} + 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; + } -static void lttng_tracker_id_reset(struct lttng_tracker_id *id) -{ - if (id == NULL) { - return; + /* 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; } - if (id->string != NULL) { - free(id->string); - id->string = NULL; + 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; } - id->type = LTTNG_ID_UNKNOWN; - id->value = -1; + *_value = value; + value = NULL; + free(name); + return LTTNG_OK; +error: + free(name); + process_attr_value_destroy(value); + return ret; } -void lttng_tracker_id_destroy(struct lttng_tracker_id *id) +LTTNG_HIDDEN +const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr) { - if (id == NULL) { - return; + 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"; } - - lttng_tracker_id_reset(id); - - free(id); } -enum lttng_tracker_id_type lttng_tracker_id_get_type( - const struct lttng_tracker_id *id) +static void process_attr_tracker_value_destructor(void *ptr) { - assert(id); - return id->type; + struct process_attr_value *value = (typeof(value)) ptr; + + process_attr_value_destroy(value); } -enum lttng_tracker_id_status lttng_tracker_id_get_value( - const struct lttng_tracker_id *id, int *value) +LTTNG_HIDDEN +struct lttng_process_attr_values *lttng_process_attr_values_create(void) { - assert(id); - if (id->type == LTTNG_ID_UNKNOWN) { - return LTTNG_TRACKER_ID_STATUS_UNSET; - } + struct lttng_process_attr_values *values = zmalloc(sizeof(*values)); - if (id->type != LTTNG_ID_VALUE) { - return LTTNG_TRACKER_ID_STATUS_INVALID; + if (!values) { + goto end; } - *value = id->value; - return LTTNG_TRACKER_ID_STATUS_OK; + lttng_dynamic_pointer_array_init( + &values->array, process_attr_tracker_value_destructor); +end: + return values; } -bool lttng_tracker_id_is_equal(const struct lttng_tracker_id *left, - const struct lttng_tracker_id *right) +LTTNG_HIDDEN +unsigned int _lttng_process_attr_values_get_count( + const struct lttng_process_attr_values *values) { - if (left->type != right->type) { - return 0; - } - - 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; - } - return 1; + return (unsigned int) lttng_dynamic_pointer_array_get_count( + &values->array); } -int lttng_tracker_id_copy(struct lttng_tracker_id *dest, - const struct lttng_tracker_id *orig) +LTTNG_HIDDEN +const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index( + const struct lttng_process_attr_values *values, + unsigned int index) { - int ret = 0; - enum lttng_tracker_id_status status; - - assert(dest); - assert(orig); + return lttng_dynamic_pointer_array_get_pointer(&values->array, index); +} - switch (orig->type) { - case LTTNG_ID_ALL: - status = lttng_tracker_id_set_all(dest); +static +int process_attr_tracker_value_serialize(const struct process_attr_value *value, + struct lttng_dynamic_buffer *buffer) +{ + 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_ID_VALUE: - status = lttng_tracker_id_set_value(dest, orig->value); + case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID: + SET_INTEGRAL_COMM_VALUE( + &value_comm.value.integral, value->value.uid); break; - case LTTNG_ID_STRING: - status = lttng_tracker_id_set_string(dest, orig->string); + case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID: + SET_INTEGRAL_COMM_VALUE( + &value_comm.value.integral, value->value.gid); break; - default: - status = LTTNG_TRACKER_ID_STATUS_OK; + 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 (status != LTTNG_TRACKER_ID_STATUS_OK) { - ret = -1; - goto error; + if (name) { + value_comm.value.name_len = strlen(name) + 1; } -error: + + ret = lttng_dynamic_buffer_append( + buffer, &value_comm, sizeof(value_comm)); + if (ret) { + goto end; + } + + if (name) { + ret = lttng_dynamic_buffer_append( + buffer, name, value_comm.value.name_len); + } +end: return ret; } -struct lttng_tracker_id *lttng_tracker_id_duplicate( - const struct lttng_tracker_id *orig) +LTTNG_HIDDEN +int lttng_process_attr_values_serialize( + const struct lttng_process_attr_values *values, + struct lttng_dynamic_buffer *buffer) { int ret; - struct lttng_tracker_id *copy = NULL; + unsigned int count, i; + struct process_attr_tracker_values_comm_header header = {}; - copy = lttng_tracker_id_create(); - if (copy == NULL) { - goto error; - } + count = _lttng_process_attr_values_get_count(values); + header.count = (uint32_t) count; - ret = lttng_tracker_id_copy(copy, orig); + ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header)); if (ret) { - goto error; + goto end; } - return copy; -error: - lttng_tracker_id_destroy(copy); - return NULL; -} - -enum lttng_tracker_id_status lttng_tracker_id_get_string( - const struct lttng_tracker_id *id, const char **value) -{ - assert(id); - if (id->type == LTTNG_ID_UNKNOWN) { - *value = NULL; - return LTTNG_TRACKER_ID_STATUS_UNSET; - } + for (i = 0; i < count; i++) { + const struct process_attr_value *value = + lttng_process_attr_tracker_values_get_at_index( + values, i); - if (id->type != LTTNG_ID_STRING) { - *value = NULL; - return LTTNG_TRACKER_ID_STATUS_INVALID; + ret = process_attr_tracker_value_serialize(value, buffer); + if (ret) { + goto end; + } } - - *value = id->string; - return LTTNG_TRACKER_ID_STATUS_OK; +end: + return ret; } -struct lttng_tracker_ids *lttng_tracker_ids_create(unsigned int count) +LTTNG_HIDDEN +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) { - struct lttng_tracker_ids *ids = NULL; - - ids = zmalloc(sizeof(*ids)); - if (!ids) { + 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; } - ids->id_array = zmalloc(sizeof(struct lttng_tracker_id) * count); - if (!ids->id_array) { + header_view = lttng_buffer_view_from_view( + buffer_view, 0, sizeof(*header)); + if (!header_view.data) { goto error; } + 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 (!value_view.data) { + goto error; + } - ids->count = count; + offset += value_view.size; + value_comm = (typeof(value_comm)) value_view.data; + type = (typeof(type)) value_comm->type; - return ids; -error: - free(ids); - return NULL; -} + if (is_value_type_name(type)) { + value_name_view = lttng_buffer_view_from_view( + buffer_view, offset, + value_comm->value.name_len); + 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; + } -LTTNG_HIDDEN -struct lttng_tracker_id *lttng_tracker_ids_get_pointer_of_index( - const struct lttng_tracker_ids *ids, unsigned int index) -{ - assert(ids); - if (index >= ids->count) { - return NULL; + ret = lttng_dynamic_pointer_array_add_pointer( + &values->array, value); + if (ret) { + process_attr_value_destroy(value); + goto error; + } } - return &ids->id_array[index]; + *_values = values; + return offset; +error: + lttng_process_attr_values_destroy(values); + return -1; } -const struct lttng_tracker_id *lttng_tracker_ids_get_at_index( - const struct lttng_tracker_ids *ids, unsigned int index) +LTTNG_HIDDEN +void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values) { - assert(ids); - return lttng_tracker_ids_get_pointer_of_index(ids, index); + if (!values) { + return; + } + lttng_dynamic_pointer_array_reset(&values->array); + free(values); } -enum lttng_tracker_id_status lttng_tracker_ids_get_count(const struct lttng_tracker_ids *ids, unsigned int *count) +LTTNG_HIDDEN +struct process_attr_value *process_attr_value_copy( + const struct process_attr_value *value) { + struct process_attr_value *new_value = NULL; - enum lttng_tracker_id_status status = LTTNG_TRACKER_ID_STATUS_OK; - - if (!ids || !count) { - status = LTTNG_TRACKER_ID_STATUS_INVALID; + if (!value) { goto end; } - *count = ids->count; + new_value = zmalloc(sizeof(*new_value)); + if (!new_value) { + goto end; + } + 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 status; + return new_value; +error: + free(new_value); + return NULL; } -void lttng_tracker_ids_destroy(struct lttng_tracker_ids *ids) +LTTNG_HIDDEN +unsigned long process_attr_value_hash(const struct process_attr_value *a) { - if (!ids) { - return; - } + unsigned long hash = hash_key_ulong((void *) a->type, lttng_ht_seed); - for (int i = 0; i < ids->count; i++) { - lttng_tracker_id_reset(&ids->id_array[i]); + 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(); } - free(ids->id_array); - free(ids); + + return hash; } -int lttng_tracker_ids_serialize(const struct lttng_tracker_ids *ids, - struct lttng_dynamic_buffer *buffer) +LTTNG_HIDDEN +bool process_attr_tracker_value_equal(const struct process_attr_value *a, + const struct process_attr_value *b) { - int ret; - int value; - const char *string; - unsigned int count; - enum lttng_tracker_id_status status; - const struct lttng_tracker_id *id; - - status = lttng_tracker_ids_get_count(ids, &count); - if (status != LTTNG_TRACKER_ID_STATUS_OK) { - ret = LTTNG_ERR_INVALID; - goto error; + 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(); + } +} - for (unsigned int i = 0; i < count; i++) { - struct lttcomm_tracker_id_header id_hdr; - size_t var_data_len = 0; - - id = lttng_tracker_ids_get_at_index(ids, i); - if (!id) { - ret = -LTTNG_ERR_INVALID; - goto error; - } - - memset(&id_hdr, 0, sizeof(id_hdr)); - id_hdr.type = lttng_tracker_id_get_type(id); - switch (id_hdr.type) { - case LTTNG_ID_ALL: - break; - case LTTNG_ID_VALUE: - status = lttng_tracker_id_get_value(id, &value); - id_hdr.u.value = value; - if (status != LTTNG_TRACKER_ID_STATUS_OK) { - ret = -LTTNG_ERR_INVALID; - goto error; - } - break; - case LTTNG_ID_STRING: - status = lttng_tracker_id_get_string( - id, &string); - if (status != LTTNG_TRACKER_ID_STATUS_OK) { - ret = -LTTNG_ERR_INVALID; - goto error; - } - - id_hdr.u.var_data_len = var_data_len = - strlen(string) + 1; - break; - default: - ret = -LTTNG_ERR_INVALID; - goto error; - } - ret = lttng_dynamic_buffer_append( - buffer, &id_hdr, sizeof(id_hdr)); - if (ret) { - ret = -LTTNG_ERR_NOMEM; - goto error; - } - ret = lttng_dynamic_buffer_append( - buffer, string, var_data_len); - if (ret) { - ret = -LTTNG_ERR_NOMEM; - goto error; - } +LTTNG_HIDDEN +void process_attr_value_destroy(struct process_attr_value *value) +{ + if (!value) { + return; } -error: - return ret; + 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(value); }