host/limine: Improve error reporting
diff --git a/host/limine.c b/host/limine.c
index 3a0768a6..939d2cfc 100644
--- a/host/limine.c
+++ b/host/limine.c
@@ -8,7 +8,9 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
+#include <stdarg.h>
#include <string.h>
+#include <errno.h>
#include <inttypes.h>
#include <limits.h>
@@ -16,6 +18,23 @@
#include "limine-bios-hdd.h"
#endif
+static const char *program_name = NULL;
+
+static void perror_wrap(const char *fmt, ...) {
+ int old_errno = errno;
+
+ fprintf(stderr, "%s: ", program_name);
+
+ va_list args;
+ va_start(args, fmt);
+
+ vfprintf(stderr, fmt, args);
+
+ va_end(args);
+
+ fprintf(stderr, ": %s\n", strerror(old_errno));
+}
+
static void remove_arg(int *argc, char *argv[], int index) {
for (int i = index; i < *argc - 1; i++) {
argv[i] = argv[i + 1];
@@ -216,7 +235,7 @@ static bool device_init(void) {
for (size_t i = 0; i < sizeof(guesses) / sizeof(size_t); i++) {
void *tmp = realloc(cache, guesses[i]);
if (tmp == NULL) {
- perror("ERROR");
+ perror_wrap("error: device_init(): realloc()");
return false;
}
cache = tmp;
@@ -239,7 +258,7 @@ static bool device_init(void) {
return true;
}
- fprintf(stderr, "ERROR: Couldn't determine block size of device.\n");
+ fprintf(stderr, "%s: error: device_init(): Couldn't determine block size of device.\n", program_name);
return false;
}
@@ -248,14 +267,14 @@ static bool device_flush_cache(void) {
return true;
if (set_pos(device, cached_block * block_size) != 0) {
- perror("ERROR");
+ perror_wrap("error: device_flush_cache(): set_pos()");
return false;
}
size_t ret = fwrite(cache, block_size, 1, device);
if (ret != 1) {
if (ferror(device)) {
- perror("ERROR");
+ perror_wrap("error: device_flush_cache(): fwrite()");
}
return false;
}
@@ -274,14 +293,14 @@ static bool device_cache_block(uint64_t block) {
}
if (set_pos(device, block * block_size) != 0) {
- perror("ERROR");
+ perror_wrap("error: device_cache_block(): set_pos()");
return false;
}
size_t ret = fread(cache, block_size, 1, device);
if (ret != 1) {
if (ferror(device)) {
- perror("ERROR");
+ perror_wrap("error: device_cache_block(): fread()");
}
return false;
}
@@ -326,30 +345,33 @@ static bool store_uninstall_data(const char *filename) {
FILE *udfile = fopen(filename, "wb");
if (udfile == NULL) {
+ perror_wrap("error: `%s`", filename);
goto error;
}
if (fwrite(&uninstall_data_i, sizeof(uint64_t), 1, udfile) != 1) {
- goto error;
+ goto fwrite_error;
}
for (size_t i = 0; i < uninstall_data_i; i++) {
if (fwrite(&uninstall_data[i].loc, sizeof(uint64_t), 1, udfile) != 1) {
- goto error;
+ goto fwrite_error;
}
if (fwrite(&uninstall_data[i].count, sizeof(uint64_t), 1, udfile) != 1) {
- goto error;
+ goto fwrite_error;
}
if (fwrite(uninstall_data[i].data, uninstall_data[i].count, 1, udfile) != 1) {
- goto error;
+ goto fwrite_error;
}
}
fclose(udfile);
return true;
+fwrite_error:
+ perror_wrap("error: store_uninstall_data(): fwrite()");
+
error:
- perror("ERROR");
if (udfile != NULL) {
fclose(udfile);
}
@@ -363,34 +385,38 @@ static bool load_uninstall_data(const char *filename) {
FILE *udfile = fopen(filename, "rb");
if (udfile == NULL) {
+ perror_wrap("error: `%s`", filename);
goto error;
}
if (fread(&uninstall_data_i, sizeof(uint64_t), 1, udfile) != 1) {
- goto error;
+ goto fread_error;
}
for (size_t i = 0; i < uninstall_data_i; i++) {
if (fread(&uninstall_data[i].loc, sizeof(uint64_t), 1, udfile) != 1) {
- goto error;
+ goto fread_error;
}
if (fread(&uninstall_data[i].count, sizeof(uint64_t), 1, udfile) != 1) {
- goto error;
+ goto fread_error;
}
uninstall_data[i].data = malloc(uninstall_data[i].count);
if (uninstall_data[i].data == NULL) {
+ perror_wrap("error: load_uninstall_data(): malloc()");
goto error;
}
if (fread(uninstall_data[i].data, uninstall_data[i].count, 1, udfile) != 1) {
- goto error;
+ goto fread_error;
}
}
fclose(udfile);
return true;
+fread_error:
+ perror_wrap("error: load_uninstall_data(): fread()");
+
error:
- perror("ERROR");
if (udfile != NULL) {
fclose(udfile);
}
@@ -404,7 +430,6 @@ static bool _device_read(void *_buffer, uint64_t loc, size_t count) {
uint64_t block = (loc + progress) / block_size;
if (!device_cache_block(block)) {
- fprintf(stderr, "ERROR: Read error.\n");
return false;
}
@@ -426,7 +451,7 @@ static bool _device_write(const void *_buffer, uint64_t loc, size_t count) {
}
if (uninstall_data_i >= UNINSTALL_DATA_MAX) {
- fprintf(stderr, "Internal error: Too many uninstall data entries!\n");
+ fprintf(stderr, "%s: error: Too many uninstall data entries! Please report this bug upstream.\n", program_name);
return false;
}
@@ -434,12 +459,11 @@ static bool _device_write(const void *_buffer, uint64_t loc, size_t count) {
ud->data = malloc(count);
if (ud->data == NULL) {
- fprintf(stderr, "ERROR: Memory allocation failure.\n");
+ perror_wrap("error: _device_write(): malloc()");
return false;
}
if (!_device_read(ud->data, loc, count)) {
- fprintf(stderr, "ERROR: Device read failure.\n");
return false;
}
@@ -453,7 +477,6 @@ skip_save:;
uint64_t block = (loc + progress) / block_size;
if (!device_cache_block(block)) {
- fprintf(stderr, "ERROR: Write error.\n");
return false;
}
@@ -484,14 +507,14 @@ static void uninstall(void) {
bool retry = false;
while (!_device_write(ud->data, ud->loc, ud->count)) {
if (retry) {
- fprintf(stderr, "ERROR: Uninstall data index %zu failed to write. Uninstall may be incomplete!\n", i);
+ fprintf(stderr, "%s: error: Uninstall data index %zu failed to write. Uninstall may be incomplete!\n", program_name, i);
break;
}
if (!quiet) {
- fprintf(stderr, "Warning: Uninstall data index %zu failed to write, retrying...\n", i);
+ fprintf(stderr, "%s: warning: Uninstall data index %zu failed to write, retrying...\n", program_name, i);
}
if (!device_flush_cache()) {
- fprintf(stderr, "ERROR: Device cache flush failure. Uninstall may be incomplete!\n");
+ fprintf(stderr, "%s: error: Device cache flush failure. Uninstall may be incomplete!\n", program_name);
}
cache_state = CACHE_CLEAN;
cached_block = (uint64_t)-1;
@@ -500,7 +523,7 @@ static void uninstall(void) {
}
if (!device_flush_cache()) {
- fprintf(stderr, "ERROR: Device cache flush failure. Uninstall may be incomplete!\n");
+ fprintf(stderr, "%s: error: Device cache flush failure. Uninstall may be incomplete!\n", program_name);
}
if (!quiet) {
@@ -521,7 +544,7 @@ static void uninstall(void) {
} while (0)
static void bios_install_usage(const char *name) {
- printf("Usage: %s bios-install <device> [GPT partition index]\n", name);
+ printf("usage: %s bios-install <device> [GPT partition index]\n", name);
printf("\n");
printf(" --force-mbr Force MBR detection to work even if the\n");
printf(" safety checks fail (DANGEROUS!)\n");
@@ -569,35 +592,35 @@ static int bios_install(int argc, char *argv[]) {
quiet = true;
} else if (strcmp(argv[i], "--force-mbr") == 0) {
if (force_mbr && !quiet) {
- fprintf(stderr, "Warning: --force-mbr already set.\n");
+ fprintf(stderr, "%s: warning: --force-mbr already set.\n", program_name);
}
force_mbr = 1;
} else if (strcmp(argv[i], "--uninstall") == 0) {
if (uninstall_mode && !quiet) {
- fprintf(stderr, "Warning: --uninstall already set.\n");
+ fprintf(stderr, "%s: warning: --uninstall already set.\n", program_name);
}
uninstall_mode = true;
} else if (memcmp(argv[i], "--uninstall-data-file=", 21) == 0) {
if (uninstall_file != NULL && !quiet) {
- fprintf(stderr, "Warning: --uninstall-data-file already set. Overriding...\n");
+ fprintf(stderr, "%s: warning: --uninstall-data-file already set. Overriding...\n", program_name);
}
uninstall_file = argv[i] + 21;
if (strlen(uninstall_file) == 0) {
- fprintf(stderr, "ERROR: Uninstall data file has a zero-length name!\n");
+ fprintf(stderr, "%s: error: Uninstall data file has a zero-length name!\n", program_name);
return EXIT_FAILURE;
}
} else {
if (device != NULL) { // [GPT partition index]
part_ndx = argv[i]; // TODO: Make this non-positional?
} else if ((device = fopen(argv[i], "r+b")) == NULL) { // <device>
- perror("ERROR");
+ perror_wrap("error: `%s`", argv[i]);
return EXIT_FAILURE;
}
}
}
if (device == NULL) {
- fprintf(stderr, "ERROR: No device specified\n");
+ fprintf(stderr, "%s: error: No device specified\n", program_name);
bios_install_usage(argv[-1]);
return EXIT_FAILURE;
}
@@ -608,7 +631,7 @@ static int bios_install(int argc, char *argv[]) {
if (uninstall_mode) {
if (uninstall_file == NULL) {
- fprintf(stderr, "ERROR: Uninstall mode set but no --uninstall-data-file=... passed.\n");
+ fprintf(stderr, "%s: error: Uninstall mode set but no --uninstall-data-file=... passed.\n", program_name);
goto uninstall_mode_cleanup;
}
@@ -638,7 +661,7 @@ static int bios_install(int argc, char *argv[]) {
lb_guesses[i]);
}
} else {
- fprintf(stderr, "ERROR: Device has a valid GPT, refusing to force MBR.\n");
+ fprintf(stderr, "%s: error: Device has a valid GPT, refusing to force MBR.\n", program_name);
goto cleanup;
}
break;
@@ -658,7 +681,7 @@ static int bios_install(int argc, char *argv[]) {
fprintf(stderr, "Secondary header valid.\n");
}
} else {
- fprintf(stderr, "ERROR: Secondary header not valid, aborting.\n");
+ fprintf(stderr, "%s: error: Secondary header not valid, aborting.\n", program_name);
goto cleanup;
}
}
@@ -783,7 +806,7 @@ static int bios_install(int argc, char *argv[]) {
}
if (gpt == 0 && mbr == 0) {
- fprintf(stderr, "ERROR: Could not determine if the device has a valid partition table.\n");
+ fprintf(stderr, "error: Could not determine if the device has a valid partition table.\n");
fprintf(stderr, " Please ensure the device has a valid MBR or GPT.\n");
fprintf(stderr, " Alternatively, pass `--force-mbr` to override these checks.\n");
fprintf(stderr, " **ONLY DO THIS AT YOUR OWN RISK, DATA LOSS MAY OCCUR!**\n");
@@ -807,7 +830,7 @@ static int bios_install(int argc, char *argv[]) {
sscanf(part_ndx, "%" SCNu32, &partition_num);
partition_num--;
if (partition_num > ENDSWAP(gpt_header.number_of_partition_entries)) {
- fprintf(stderr, "ERROR: Partition number is too large.\n");
+ fprintf(stderr, "%s: error: Partition number is too large.\n", program_name);
goto cleanup;
}
@@ -819,7 +842,7 @@ static int bios_install(int argc, char *argv[]) {
if (gpt_entry.unique_partition_guid[0] == 0 &&
gpt_entry.unique_partition_guid[1] == 0) {
- fprintf(stderr, "ERROR: No such partition.\n");
+ fprintf(stderr, "%s: error: No such partition: `%s`.\n", program_name, part_ndx);
goto cleanup;
}
@@ -866,7 +889,7 @@ static int bios_install(int argc, char *argv[]) {
new_partition_array_lba_size * partition_entries_per_lb;
if ((int64_t)new_partition_entry_count <= max_partition_entry_used) {
- fprintf(stderr, "ERROR: Cannot embed because there are too many used partition entries.\n");
+ fprintf(stderr, "%s: error: Cannot embed because there are too many used partition entries.\n", program_name);
goto cleanup;
}
@@ -891,7 +914,7 @@ static int bios_install(int argc, char *argv[]) {
uint8_t *partition_array =
malloc(new_partition_entry_count * ENDSWAP(gpt_header.size_of_partition_entry));
if (partition_array == NULL) {
- perror("ERROR");
+ perror_wrap("error: bios_install(): malloc()");
goto cleanup;
}
@@ -1000,7 +1023,7 @@ uninstall_mode_cleanup:
#define CONFIG_B2SUM_SIGNATURE "++CONFIG_B2SUM_SIGNATURE++"
static void enroll_config_usage(const char *name) {
- printf("Usage: %s enroll-config <Limine executable> <BLAKE2B of config file>\n", name);
+ printf("usage: %s enroll-config <Limine executable> <BLAKE2B of config file>\n", name);
printf("\n");
printf(" --reset Remove enrolled BLAKE2B, will not check config integrity\n");
printf("\n");
@@ -1040,18 +1063,18 @@ static int enroll_config(int argc, char *argv[]) {
}
if (!reset && strlen(argv[2]) != 128) {
- fprintf(stderr, "ERROR: BLAKE2B specified is not 128 characters long\n");
+ fprintf(stderr, "%s: error: BLAKE2B specified is not 128 characters long.\n", program_name);
goto cleanup;
}
bootloader_file = fopen(argv[1], "r+b");
if (bootloader_file == NULL) {
- perror("ERROR");
- goto cleanup;;
+ perror_wrap("error: `%s`", argv[1]);
+ goto cleanup;
}
if (fseek(bootloader_file, 0, SEEK_END) != 0) {
- perror("ERROR");
+ perror_wrap("error: enroll_config(): fseek()");
goto cleanup;
}
size_t bootloader_size = ftell(bootloader_file);
@@ -1059,12 +1082,12 @@ static int enroll_config(int argc, char *argv[]) {
bootloader = malloc(bootloader_size);
if (bootloader == NULL) {
- perror("ERROR");
+ perror_wrap("error: enroll_config(): malloc()");
goto cleanup;
}
if (fread(bootloader, bootloader_size, 1, bootloader_file) != 1) {
- perror("ERROR");
+ perror_wrap("error: enroll_config(): fread()");
goto cleanup;
}
@@ -1086,7 +1109,7 @@ static int enroll_config(int argc, char *argv[]) {
}
if (checksum_loc == NULL) {
- fprintf(stderr, "ERROR: Checksum location not found in provided executable\n");
+ fprintf(stderr, "%s: error: Checksum location not found in provided executable.\n", program_name);
goto cleanup;
}
@@ -1097,11 +1120,11 @@ static int enroll_config(int argc, char *argv[]) {
}
if (fseek(bootloader_file, 0, SEEK_SET) != 0) {
- perror("ERROR");
+ perror_wrap("error: enroll_config(): fseek()");
goto cleanup;
}
if (fwrite(bootloader, bootloader_size, 1, bootloader_file) != 1) {
- perror("ERROR");
+ perror_wrap("error: enroll_config(): fwrite()");
goto cleanup;
}
@@ -1131,28 +1154,30 @@ static int version(void) {
return EXIT_SUCCESS;
}
-static void general_usage(const char *name) {
- printf("Usage: %s <command> <args...>\n", name);
+static void general_usage(void) {
+ printf("usage: %s <command> <args...>\n", program_name);
printf("\n");
printf("Valid commands: help, version, bios-install, enroll-config\n");
}
int main(int argc, char *argv[]) {
+ program_name = argv[0];
+
if (argc <= 1) {
- general_usage(argv[0]);
+ general_usage();
return EXIT_FAILURE;
}
if (strcmp(argv[1], "help") == 0
|| strcmp(argv[1], "--help") == 0
|| strcmp(argv[1], "-h") == 0) {
- general_usage(argv[0]);
+ general_usage();
return EXIT_SUCCESS;
} else if (strcmp(argv[1], "bios-install") == 0) {
#ifndef LIMINE_NO_BIOS
return bios_install(argc - 1, &argv[1]);
#else
- fprintf(stderr, "ERROR: Limine has been compiled without BIOS support.\n");
+ fprintf(stderr, "%s: error: Limine has been compiled without BIOS support.\n", program_name);
return EXIT_FAILURE;
#endif
} else if (strcmp(argv[1], "enroll-config") == 0) {
@@ -1162,6 +1187,6 @@ int main(int argc, char *argv[]) {
return version();
}
- general_usage(argv[0]);
+ general_usage();
return EXIT_FAILURE;
}
