| // SPDX-License-Identifier: GPL-2.0-only |
| /* Copyright (C) 2019 Daniel Borkmann <daniel@iogearbox.net> */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <sys/syscall.h> |
| |
| #include "l2md.h" |
| |
| bool verbose_enabled; |
| |
| void *xmalloc(size_t size) |
| { |
| void *ptr; |
| |
| if (!size) |
| panic("xmalloc: zero size\n"); |
| ptr = malloc(size); |
| if (ptr == NULL) |
| panic("xmalloc: out of memory (allocating %zu bytes)\n", size); |
| return ptr; |
| } |
| |
| void *xzmalloc(size_t size) |
| { |
| void *ptr = xmalloc(size); |
| |
| memset(ptr, 0, size); |
| return ptr; |
| } |
| |
| void *xrealloc(void *old, size_t size) |
| { |
| void *new; |
| |
| if (size == 0) |
| panic("xrealloc: zero size\n"); |
| new = realloc(old, size); |
| if (new == NULL) |
| panic("xrealloc: out of memory (allocating %zu bytes)\n", size); |
| return new; |
| } |
| |
| void xfree(void *ptr) |
| { |
| free(ptr); |
| } |
| |
| void xmkdir1(const char *path) |
| { |
| struct stat sb = {}; |
| int ret; |
| |
| ret = stat(path, &sb); |
| if (ret) { |
| ret = mkdir(path, S_IRWXU); |
| if (ret) |
| panic("mkdir %s failed: %s\n", path, strerror(errno)); |
| } |
| } |
| |
| void xmkdir1_with_subdirs(const char *path) |
| { |
| char tmp[PATH_MAX], *ptr; |
| size_t len; |
| |
| slprintf(tmp, sizeof(tmp),"%s", path); |
| len = strlen(tmp); |
| if (tmp[len - 1] == '/') |
| tmp[len - 1] = 0; |
| for (ptr = tmp + 1; *ptr; ptr++) { |
| if (*ptr == '/') { |
| *ptr = 0; |
| xmkdir1(tmp); |
| *ptr = '/'; |
| } |
| } |
| xmkdir1(tmp); |
| } |
| |
| void xmkdir2(const char *base, const char *name) |
| { |
| char path[PATH_MAX]; |
| |
| slprintf(path, sizeof(path), "%s/%s", base, name); |
| xmkdir1(path); |
| } |
| |
| int xread_file(const char *file, char *to, size_t len, bool fatal) |
| { |
| loff_t ret; |
| int fd; |
| |
| fd = open(file, O_RDONLY); |
| if (fd < 0) { |
| if (fatal) |
| panic("Cannot open %s: %s\n", file, strerror(errno)); |
| else |
| return fd; |
| } |
| |
| do { |
| ret = read(fd, to, len); |
| if (ret <= 0) { |
| if (fatal) { |
| if (ret) |
| panic("Cannot read file %s: %s\n", |
| file, strerror(errno)); |
| else |
| panic("Unexpected end of file %s\n", |
| file); |
| } else { |
| if (!ret) |
| warn("Unexpected end of file %s\n", |
| file); |
| close(fd); |
| return -1; |
| } |
| } |
| to += ret; |
| len -= ret; |
| } while (len > 0); |
| |
| close(fd); |
| return 0; |
| } |
| |
| int xwrite_file(const char *file, const char *to, size_t len, bool fatal) |
| { |
| loff_t ret; |
| int fd; |
| |
| fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0600); |
| if (fd < 0) { |
| if (fatal) |
| panic("Cannot open %s: %s\n", file, strerror(errno)); |
| else |
| return fd; |
| } |
| |
| do { |
| ret = write(fd, to, len); |
| if (ret < 0) { |
| if (fatal) { |
| panic("Cannot write file %s: %s\n", file, |
| strerror(errno)); |
| } else { |
| close(fd); |
| return -1; |
| } |
| } |
| to += ret; |
| len -= ret; |
| } while (len > 0); |
| |
| close(fd); |
| return 0; |
| } |
| |
| void xpipe(int pipefd[2]) |
| { |
| if (pipe(pipefd) < 0) |
| panic("Cannot create pipe: %s\n", strerror(errno)); |
| } |
| |
| void xwrite(int fd, const char *to, size_t len) |
| { |
| loff_t ret; |
| |
| do { |
| ret = write(fd, to, len); |
| if (ret < 0) |
| panic("Cannot write to file descriptor %d: %s", |
| fd, strerror(errno)); |
| to += ret; |
| len -= ret; |
| } while (len > 0); |
| } |
| |
| int timeval_sub(struct timeval *res, struct timeval *x, |
| struct timeval *y) |
| { |
| if (x->tv_usec < y->tv_usec) { |
| int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; |
| |
| y->tv_usec -= 1000000 * nsec; |
| y->tv_sec += nsec; |
| } |
| |
| if (x->tv_usec - y->tv_usec > 1000000) { |
| int nsec = (x->tv_usec - y->tv_usec) / 1000000; |
| |
| y->tv_usec += 1000000 * nsec; |
| y->tv_sec -= nsec; |
| } |
| |
| res->tv_sec = x->tv_sec - y->tv_sec; |
| res->tv_usec = x->tv_usec - y->tv_usec; |
| |
| return x->tv_sec < y->tv_sec; |
| } |
| |
| size_t strlcpy(char *dest, const char *src, size_t size) |
| { |
| size_t ret = strlen(src); |
| |
| if (size) { |
| size_t len = (ret >= size) ? size - 1 : ret; |
| |
| memcpy(dest, src, len); |
| dest[len] = '\0'; |
| } |
| |
| return ret; |
| } |
| |
| static inline int vslprintf(char *dst, size_t size, const char *fmt, va_list ap) |
| { |
| int ret; |
| |
| ret = vsnprintf(dst, size, fmt, ap); |
| dst[size - 1] = '\0'; |
| |
| return ret; |
| } |
| |
| int slprintf(char *dst, size_t size, const char *fmt, ...) |
| { |
| va_list ap; |
| int ret; |
| |
| va_start(ap, fmt); |
| ret = vslprintf(dst, size, fmt, ap); |
| va_end(ap); |
| |
| return ret; |
| } |
| |
| void die(void) |
| { |
| exit(EXIT_FAILURE); |
| } |
| |
| void panic(const char *format, ...) |
| { |
| va_list vl; |
| |
| va_start(vl, format); |
| vfprintf(stderr, format, vl); |
| va_end(vl); |
| |
| die(); |
| } |
| |
| void warn(const char *format, ...) |
| { |
| va_list vl; |
| |
| va_start(vl, format); |
| vfprintf(stderr, format, vl); |
| va_end(vl); |
| } |
| |
| void verbose(const char *format, ...) |
| { |
| va_list vl; |
| |
| if (verbose_enabled) { |
| va_start(vl, format); |
| vfprintf(stderr, format, vl); |
| va_end(vl); |
| } |
| } |