diff options
Diffstat (limited to 'logsrvd/logsrv_util.c')
-rw-r--r-- | logsrvd/logsrv_util.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/logsrvd/logsrv_util.c b/logsrvd/logsrv_util.c new file mode 100644 index 0000000..e5d54f1 --- /dev/null +++ b/logsrvd/logsrv_util.c @@ -0,0 +1,159 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2019-2020 Todd C. Miller <Todd.Miller@sudo.ws> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include <sys/types.h> + +#include <errno.h> +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ +#if defined(HAVE_STDINT_H) +# include <stdint.h> +#elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "sudo_compat.h" +#include "sudo_debug.h" +#include "sudo_fatal.h" +#include "sudo_gettext.h" +#include "sudo_iolog.h" +#include "sudo_util.h" + +#include "logsrv_util.h" + +/* + * Expand buf as needed or just reset it. + */ +bool +expand_buf(struct connection_buffer *buf, unsigned int needed) +{ + void *newdata; + debug_decl(expand_buf, SUDO_DEBUG_UTIL); + + if (buf->size < needed) { + /* Expand buffer. */ + needed = sudo_pow2_roundup(needed); + if ((newdata = malloc(needed)) == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO, + "%s: unable to malloc %u", __func__, needed); + debug_return_bool(false); + } + if (buf->off > 0) + memcpy(newdata, buf->data + buf->off, buf->len - buf->off); + free(buf->data); + buf->data = newdata; + buf->size = needed; + } else { + /* Just reset existing buffer. */ + if (buf->off > 0) { + memmove(buf->data, buf->data + buf->off, + buf->len - buf->off); + } + } + buf->len -= buf->off; + buf->off = 0; + + debug_return_bool(true); +} + +/* + * Open any I/O log files that are present. + * The timing file must always exist. + */ +bool +iolog_open_all(int dfd, const char *iolog_dir, struct iolog_file *iolog_files, + const char *mode) +{ + int iofd; + debug_decl(iolog_open_all, SUDO_DEBUG_UTIL); + + for (iofd = 0; iofd < IOFD_MAX; iofd++) { + iolog_files[iofd].enabled = true; + if (!iolog_open(&iolog_files[iofd], dfd, iofd, mode)) { + if (errno != ENOENT) { + sudo_warn(U_("unable to open %s/%s"), iolog_dir, + iolog_fd_to_name(iofd)); + debug_return_bool(false); + } + } + } + if (!iolog_files[IOFD_TIMING].enabled) { + sudo_warn(U_("unable to open %s/%s"), iolog_dir, + iolog_fd_to_name(IOFD_TIMING)); + debug_return_bool(false); + } + debug_return_bool(true); +} + +/* + * Seek to the specified point in time in the I/O logs. + */ +bool +iolog_seekto(int iolog_dir_fd, const char *iolog_path, + struct iolog_file *iolog_files, struct timespec *elapsed_time, + const struct timespec *target) +{ + struct timing_closure timing; + off_t pos; + debug_decl(iolog_seekto, SUDO_DEBUG_UTIL); + + /* Parse timing file until we reach the target point. */ + for (;;) { + if (iolog_read_timing_record(&iolog_files[IOFD_TIMING], &timing) != 0) + goto bad; + sudo_timespecadd(&timing.delay, elapsed_time, elapsed_time); + if (timing.event < IOFD_TIMING) { + if (!iolog_files[timing.event].enabled) { + /* Missing log file. */ + sudo_warn(U_("missing I/O log file %s/%s"), iolog_path, + iolog_fd_to_name(timing.event)); + goto bad; + } + pos = iolog_seek(&iolog_files[timing.event], timing.u.nbytes, + SEEK_CUR); + if (pos == -1) { + sudo_warn(U_("%s/%s: unable to seek forward %zu"), iolog_path, + iolog_fd_to_name(timing.event), timing.u.nbytes); + goto bad; + } + } + if (sudo_timespeccmp(elapsed_time, target, >=)) { + if (sudo_timespeccmp(elapsed_time, target, ==)) + break; + + /* Mismatch between resume point and stored log. */ + sudo_warnx(U_("unable to find resume point [%lld, %ld] in %s/%s"), + (long long)target->tv_sec, target->tv_nsec, iolog_path, + "timing"); + goto bad; + } + } + debug_return_bool(true); +bad: + debug_return_bool(false); +} |