#include "common.h" noreturn void fatal_error(const char* fmt, ...) { va_list args; va_start(args, fmt); fprintf(stderr, "ERROR: "); vfprintf(stderr, fmt, args); va_end(args); exit(-1); } void setup() { // set output to line-buffered for easier debugging setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stderr, NULL, _IOLBF, 0); unsigned int seed = time(NULL); printf("Random seed: %u\n", seed); srand(seed); } int open_input_fd(const char* path) { int fd = open(path, O_RDONLY); if (fd < 0) fatal_error("Failed to open input file %s: %s\n", path, strerror(errno)); return fd; } void read_fd(const char* path, int fd, void* buffer, size_t size) { off_t offset = 0; while (size > 0) { ssize_t ret = read(fd, buffer + offset, size); if (ret == -EINTR) continue; if (ret <= 0) fatal_error("Failed to read file %s: %s\n", path, strerror(errno)); size -= ret; offset += ret; } } void seek_fd(const char* path, int fd, ssize_t offset, int mode) { off_t ret = lseek(fd, offset, mode); if (ret == -1) fatal_error("Failed to lseek(%zd, %d) file %s: %s\n", offset, mode, path, strerror(errno)); } off_t tell_fd(const char* path, int fd) { off_t pos = lseek(fd, 0, SEEK_CUR); if (pos == -1) fatal_error("Failed to lseek(0, SEEK_CUR) file %s: %s\n", path, strerror(errno)); return pos; } int open_output_fd(const char* path, bool rdwr) { int fd = open(path, rdwr ? O_RDWR|O_CREAT : O_WRONLY|O_CREAT, 0664); if (fd < 0) fatal_error("Failed to open output file %s: %s\n", path, strerror(errno)); return fd; } void write_fd(const char* path, int fd, const void* buffer, size_t size) { off_t offset = 0; while (size > 0) { ssize_t ret = write(fd, buffer + offset, size); if (ret == -EINTR) continue; if (ret <= 0) fatal_error("Failed to write file %s: %s\n", path, strerror(errno)); size -= ret; offset += ret; } } void close_fd(const char* path, int fd) { if (fd >= 0 && close(fd) != 0) fatal_error("Failed to close file %s: %s\n", path, strerror(errno)); } void* mmap_fd(const char* path, int fd, int protection, size_t offset, size_t size) { void* address = mmap(NULL, size, protection, MAP_SHARED, fd, offset); if (address == MAP_FAILED) fatal_error("Failed to mmap file %s: %s\n", path, strerror(errno)); return address; } void munmap_fd(const char* path, void* address, size_t size) { if (munmap(address, size) < 0) fatal_error("Failed to munmap file %s: %s\n", path, strerror(errno)); } FILE* open_input_stdio(const char* path) { FILE* f = fopen(path, "r"); if (!f) fatal_error("Failed to fopen input file %s: %s\n", path, strerror(errno)); return f; } void read_stdio(const char* path, FILE* f, void* buffer, size_t size) { if (size > 0) { size_t ret = fread(buffer, size, 1, f); if (ret != 1) fatal_error("Failed to fread file %s: %s\n", path, strerror(errno)); } } void seek_stdio(const char* path, FILE* f, off_t offset, int mode) { if (offset > LONG_MAX) fatal_error("Failed to fseek file %s(%zd): offset too big\n", path, offset); int ret = fseek(f, (long)offset, mode); if (ret < 0) fatal_error("Failed to fseek file %s(%zd): %s\n", path, offset, strerror(errno)); } off_t tell_stdio(const char* path, FILE* f) { long pos = ftell(f); if (pos < 0) fatal_error("Failed to ftell file %s: %s\n", path, strerror(errno)); return pos; } void close_stdio(const char* path, FILE* f) { if (f && fclose(f) != 0) fatal_error("Failed to fclose file %s: %s\n", path, strerror(errno)); } FILE* open_output_stdio(const char* path, bool rdwr) { FILE* f = fopen(path, rdwr ? "r+" : "w"); if (!f) fatal_error("Failed to fopen output file %s: %s\n", path, strerror(errno)); return f; } void write_stdio(const char* path, FILE* f, const void* buffer, size_t size) { if (size > 0) { size_t ret = fwrite(buffer, size, 1, f); if (ret != 1) fatal_error("Failed to fwrite file %s: %s\n", path, strerror(errno)); } } void* alloc_buffer(size_t size) { void* buffer = malloc(size); if (!buffer) fatal_error("No memory\n"); return buffer; } void fill_random(void* buffer, size_t size) { for (size_t i = 0; i < size; i++) ((uint8_t*)buffer)[i] = rand() % 256; }