:: commit 05db4b937ced3d63db537d806fead0f86f21f95a

mintsuki <mintsuki@protonmail.com> — 2023-12-05 22:17

parents: bc48611f77

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;
 }
tab: 248 wrap: offon