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 #include #include +#include #include +#include #include #include @@ -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 [GPT partition index]\n", name); + printf("usage: %s bios-install [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) { // - 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 \n", name); + printf("usage: %s enroll-config \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 \n", name); +static void general_usage(void) { + printf("usage: %s \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; }