summaryrefslogtreecommitdiffstats
path: root/lib/util/tevent_req_profile.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/util/tevent_req_profile.c')
-rw-r--r--lib/util/tevent_req_profile.c506
1 files changed, 506 insertions, 0 deletions
diff --git a/lib/util/tevent_req_profile.c b/lib/util/tevent_req_profile.c
new file mode 100644
index 0000000..2d280f7
--- /dev/null
+++ b/lib/util/tevent_req_profile.c
@@ -0,0 +1,506 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Helpers around tevent_req_profile
+ *
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * ** NOTE! The following LGPL license applies to the tevent
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <tevent.h>
+#include "lib/util/tevent_req_profile.h"
+#include "lib/util/time_basic.h"
+#include "lib/util/memory.h"
+
+static bool tevent_req_profile_string_internal(
+ const struct tevent_req_profile *profile,
+ unsigned indent,
+ unsigned max_indent,
+ char **string)
+{
+ struct timeval start, stop, diff;
+ struct timeval_buf start_buf, stop_buf;
+ const char *req_name = NULL;
+ const char *start_location = NULL;
+ const char *stop_location = NULL;
+ pid_t pid;
+ enum tevent_req_state state;
+ const char *state_buf = NULL;
+ uint64_t user_error;
+ const struct tevent_req_profile *sub = NULL;
+ char *result;
+
+ tevent_req_profile_get_name(profile, &req_name);
+
+ tevent_req_profile_get_start(profile, &start_location, &start);
+ timeval_str_buf(&start, false, true, &start_buf);
+
+ tevent_req_profile_get_stop(profile, &stop_location, &stop);
+ timeval_str_buf(&stop, false, true, &stop_buf);
+
+ diff = tevent_timeval_until(&start, &stop);
+
+ tevent_req_profile_get_status(profile, &pid, &state, &user_error);
+
+ switch(state) {
+ case TEVENT_REQ_INIT:
+ state_buf = "TEVENT_REQ_INIT";
+ break;
+ case TEVENT_REQ_IN_PROGRESS:
+ state_buf = "TEVENT_REQ_IN_PROGRESS";
+ break;
+ case TEVENT_REQ_DONE:
+ state_buf = "TEVENT_REQ_DONE";
+ break;
+ case TEVENT_REQ_USER_ERROR:
+ state_buf = "TEVENT_REQ_USER_ERROR";
+ break;
+ case TEVENT_REQ_TIMED_OUT:
+ state_buf = "TEVENT_REQ_TIMED_OUT";
+ break;
+ case TEVENT_REQ_NO_MEMORY:
+ state_buf = "TEVENT_REQ_NO_MEMORY";
+ break;
+ case TEVENT_REQ_RECEIVED:
+ state_buf = "TEVENT_REQ_RECEIVED";
+ break;
+ default:
+ state_buf = "unknown";
+ break;
+ }
+
+ result = talloc_asprintf_append_buffer(
+ *string,
+ "%*s[%s] %s [%s] %s [%s] [%ju.%.6ju] -> %s (%d %"PRIu64"))\n",
+ indent,
+ "",
+ req_name,
+ start_location,
+ start_buf.buf,
+ stop_location,
+ stop_buf.buf,
+ (uintmax_t)diff.tv_sec,
+ (uintmax_t)diff.tv_usec,
+ state_buf,
+ (int)state,
+ user_error);
+ if (result == NULL) {
+ return false;
+ }
+ *string = result;
+
+ indent += 1;
+
+ if (indent >= max_indent) {
+ return true;
+ }
+
+ for (sub = tevent_req_profile_get_subprofiles(profile);
+ sub != NULL;
+ sub = tevent_req_profile_next(sub)) {
+ bool ret;
+
+ ret = tevent_req_profile_string_internal(
+ sub,
+ indent,
+ max_indent,
+ string);
+ if (!ret) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+char *tevent_req_profile_string(TALLOC_CTX *mem_ctx,
+ const struct tevent_req_profile *profile,
+ unsigned indent,
+ unsigned max_indent)
+{
+ char *result;
+ bool ret;
+
+ result = talloc_strdup(mem_ctx, "");
+ if (result == NULL) {
+ return NULL;
+ }
+
+ ret = tevent_req_profile_string_internal(
+ profile,
+ indent,
+ max_indent,
+ &result);
+ if (!ret) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static ssize_t tevent_req_profile_pack_one(
+ const struct tevent_req_profile *profile,
+ uint8_t *buf,
+ size_t buflen)
+{
+ const char *req_name = NULL;
+ const char *start_location = NULL;
+ const char *stop_location = NULL;
+ struct timeval start_time, stop_time;
+ pid_t pid;
+ enum tevent_req_state state;
+ uint64_t user_error;
+ size_t pack_len, len;
+ int ret;
+
+ tevent_req_profile_get_name(profile, &req_name);
+ tevent_req_profile_get_start(profile, &start_location, &start_time);
+ tevent_req_profile_get_stop(profile, &stop_location, &stop_time);
+ tevent_req_profile_get_status(profile, &pid, &state, &user_error);
+
+ len = strlen(req_name)+1;
+ if (buflen >= len) {
+ memcpy(buf, req_name, len);
+ buf += len;
+ buflen -= len;
+ }
+
+ pack_len = len;
+
+ len = strlen(start_location)+1;
+ pack_len += len;
+ if (pack_len < len) {
+ return -1; /* overflow */
+ }
+
+ if (buflen >= len) {
+ memcpy(buf, start_location, len);
+ buf += len;
+ buflen -= len;
+ }
+
+ len = strlen(stop_location)+1;
+ pack_len += len;
+ if (pack_len < len) {
+ return -1; /* overflow */
+ }
+
+ if (buflen >= len) {
+ memcpy(buf, stop_location, len);
+ buf += len;
+ buflen -= len;
+ }
+
+ ret = snprintf((char *)buf,
+ buflen,
+ "%ju %ju %ju %ju %d %d %"PRIu64"",
+ (uintmax_t)start_time.tv_sec,
+ (uintmax_t)start_time.tv_usec,
+ (uintmax_t)stop_time.tv_sec,
+ (uintmax_t)stop_time.tv_usec,
+ (int)pid,
+ (int)state,
+ user_error);
+ if (ret < 0) {
+ return -1;
+ }
+
+ /*
+ * Take care of the trailing 0. No overflow check, this would
+ * be a VERY small number of bits for "int".
+ */
+ ret += 1;
+
+ pack_len += ret;
+
+ return pack_len;
+}
+
+ssize_t tevent_req_profile_pack(
+ const struct tevent_req_profile *profile,
+ uint8_t *buf,
+ size_t buflen)
+{
+ const struct tevent_req_profile *sub = NULL;
+ size_t num_sub;
+ ssize_t pack_len, profile_len;
+ int ret;
+
+ num_sub = 0;
+ pack_len = 0;
+
+ for (sub = tevent_req_profile_get_subprofiles(profile);
+ sub != NULL;
+ sub = tevent_req_profile_next(sub)) {
+ num_sub += 1;
+ }
+
+ ret = snprintf((char *)buf, buflen, "%zu ", num_sub);
+ if (ret < 0) {
+ return -1;
+ }
+
+ if (buflen > (size_t)ret) {
+ buf += ret;
+ buflen -= ret;
+ }
+
+ pack_len = ret;
+
+ profile_len = tevent_req_profile_pack_one(profile, buf, buflen);
+ if (profile_len == -1) {
+ return -1;
+ }
+
+ if (buflen >= (size_t)profile_len) {
+ buf += profile_len;
+ buflen -= profile_len;
+ }
+
+ pack_len += profile_len;
+ if (pack_len < profile_len) {
+ return -1; /* overflow */
+ }
+
+ for (sub = tevent_req_profile_get_subprofiles(profile);
+ sub != NULL;
+ sub = tevent_req_profile_next(sub)) {
+
+ profile_len = tevent_req_profile_pack(sub, buf, buflen);
+ if (profile_len == -1) {
+ return -1;
+ }
+
+ if (buflen >= (size_t)profile_len) {
+ buf += profile_len;
+ buflen -= profile_len;
+ }
+
+ pack_len += profile_len;
+ if (pack_len < profile_len) {
+ return -1; /* overflow */
+ }
+ }
+
+ return pack_len;
+}
+
+static bool parse_uintmax(const char *buf,
+ char delimiter,
+ uintmax_t *presult,
+ char **p_endptr)
+{
+ uintmax_t result;
+ char *endptr;
+
+ result = strtoumax(buf, &endptr, 10);
+ if ((result == UINTMAX_MAX) && (errno == ERANGE)) {
+ return false;
+ }
+ if (*endptr != delimiter) {
+ return false;
+ }
+
+ *presult = result;
+ *p_endptr = endptr+1;
+
+ return true;
+}
+
+static ssize_t tevent_req_profile_unpack_one(
+ const uint8_t *buf,
+ size_t buflen,
+ struct tevent_req_profile *profile)
+{
+ const char *orig_buf = (const char *)buf;
+ const char *req_name = NULL;
+ const char *start_location = NULL;
+ const char *stop_location = NULL;
+ uintmax_t start_sec, start_usec, stop_sec, stop_usec, pid, state;
+ uintmax_t user_error;
+ char *next = NULL;
+ size_t len;
+ bool ok;
+
+ if (buflen == 0) {
+ return -1;
+ }
+ if (buf[buflen-1] != '\0') {
+ return -1;
+ }
+
+ req_name = (const char *)buf;
+ len = strlen(req_name)+1;
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) {
+ return -1;
+ }
+
+ start_location = (const char *)buf;
+ len = strlen(start_location)+1;
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) {
+ return -1;
+ }
+
+ stop_location = (const char *)buf;
+ len = strlen(stop_location)+1;
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) {
+ return -1;
+ }
+
+ ok = parse_uintmax((const char *)buf, ' ', &start_sec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &start_usec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &stop_sec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &stop_usec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &pid, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &state, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, '\0', &user_error, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = tevent_req_profile_set_name(profile, req_name);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = tevent_req_profile_set_start(
+ profile,
+ start_location,
+ (struct timeval){ .tv_sec=start_sec, .tv_usec=start_usec });
+ if (!ok) {
+ return -1;
+ }
+
+ ok = tevent_req_profile_set_stop(
+ profile,
+ stop_location,
+ (struct timeval){ .tv_sec=stop_sec, .tv_usec=stop_usec });
+ if (!ok) {
+ return -1;
+ }
+
+ tevent_req_profile_set_status(
+ profile,
+ pid,
+ (enum tevent_req_state)state,
+ user_error);
+
+ return next - orig_buf;
+}
+
+ssize_t tevent_req_profile_unpack(
+ const uint8_t *buf,
+ size_t buflen,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_req_profile **p_profile)
+{
+ const uint8_t *orig_buf = buf;
+ struct tevent_req_profile *profile = NULL;
+ uintmax_t i, num_subprofiles;
+ char *next = NULL;
+ bool ok;
+ ssize_t len;
+
+ errno = 0;
+
+ if (buf[buflen-1] != '\0') {
+ return -1;
+ }
+
+ ok = parse_uintmax((const char *)buf, ' ', &num_subprofiles, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ len = (next - (const char *)buf);
+
+ buf += len;
+ buflen -= len;
+
+ profile = tevent_req_profile_create(mem_ctx);
+ if (profile == NULL) {
+ return -1;
+ }
+
+ len = tevent_req_profile_unpack_one(buf, buflen, profile);
+ if (len == -1) {
+ TALLOC_FREE(profile);
+ return -1;
+ }
+
+ buf += len;
+ buflen -= len;
+
+ for (i=0; i<num_subprofiles; i++) {
+ struct tevent_req_profile *subprofile;
+
+ len = tevent_req_profile_unpack(
+ buf,
+ buflen,
+ profile,
+ &subprofile);
+ if (len == -1) {
+ TALLOC_FREE(profile);
+ return -1;
+ }
+ buf += len;
+ buflen -= len;
+
+ tevent_req_profile_append_sub(profile, &subprofile);
+ }
+
+ *p_profile = profile;
+
+ return buf - orig_buf;
+}