mirror of
https://github.com/samba-team/samba.git
synced 2025-01-22 22:04:08 +03:00
lib: Add tevent_req_profile helpers
Print and marshall/unmarshall tevent_req_profile structs Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
parent
9847848cca
commit
1e206553eb
519
lib/util/tevent_req_profile.c
Normal file
519
lib/util/tevent_req_profile.c
Normal file
@ -0,0 +1,519 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
int tevent_req_profile_print(const struct tevent_req_profile *profile,
|
||||
FILE *fp,
|
||||
unsigned indent,
|
||||
unsigned max_indent)
|
||||
{
|
||||
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;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ret = fprintf(
|
||||
fp,
|
||||
"%*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 (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
indent += 1;
|
||||
|
||||
if (indent >= max_indent) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (sub = tevent_req_profile_get_subprofiles(profile);
|
||||
sub != NULL;
|
||||
sub = tevent_req_profile_next(sub)) {
|
||||
int subret;
|
||||
|
||||
subret = tevent_req_profile_print(sub, fp, indent, max_indent);
|
||||
if (subret < 0) {
|
||||
return subret;
|
||||
}
|
||||
|
||||
ret += subret;
|
||||
|
||||
if (ret < subret) {
|
||||
/* overflow */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *tevent_req_profile_string(const struct tevent_req_profile *profile,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
unsigned indent,
|
||||
unsigned max_indent)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char *buf = NULL;
|
||||
size_t buflen = 0;
|
||||
char *result = NULL;
|
||||
int ret;
|
||||
|
||||
fp = open_memstream(&buf, &buflen);
|
||||
if (fp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = tevent_req_profile_print(profile, fp, 0, max_indent);
|
||||
if (ret < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = fclose(fp);
|
||||
if (ret != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* A FILE* from open_memstream maintains the 0-byte at the end
|
||||
* beyond the reported length.
|
||||
*/
|
||||
result = talloc_memdup(mem_ctx, buf, buflen+1);
|
||||
|
||||
done:
|
||||
SAFE_FREE(buf);
|
||||
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;
|
||||
}
|
50
lib/util/tevent_req_profile.h
Normal file
50
lib/util/tevent_req_profile.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __LIB_UTIL_TEVENT_REQ_PROFILE_UNPACK
|
||||
#define __LIB_UTIL_TEVENT_REQ_PROFILE_UNPACK
|
||||
|
||||
#include "replace.h"
|
||||
#include <tevent.h>
|
||||
|
||||
int tevent_req_profile_print(const struct tevent_req_profile *profile,
|
||||
FILE *fp,
|
||||
unsigned indent,
|
||||
unsigned max_indent);
|
||||
char *tevent_req_profile_string(const struct tevent_req_profile *profile,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
unsigned indent,
|
||||
unsigned max_indent);
|
||||
ssize_t tevent_req_profile_pack(
|
||||
const struct tevent_req_profile *profile,
|
||||
uint8_t *buf,
|
||||
size_t buflen);
|
||||
ssize_t tevent_req_profile_unpack(
|
||||
const uint8_t *buf,
|
||||
size_t buflen,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tevent_req_profile **p_profile);
|
||||
|
||||
#endif
|
@ -166,6 +166,7 @@ else:
|
||||
tevent_unix.c
|
||||
tevent_ntstatus.c
|
||||
tevent_werror.c
|
||||
tevent_req_profile.c
|
||||
''',
|
||||
local_include=False,
|
||||
public_deps='tevent samba-errors',
|
||||
|
Loading…
x
Reference in New Issue
Block a user