diff options
Diffstat (limited to 'src/boot')
-rw-r--r-- | src/boot/bootctl.c | 44 | ||||
-rw-r--r-- | src/boot/efi/boot.c | 89 | ||||
-rw-r--r-- | src/boot/efi/disk.c | 51 | ||||
-rw-r--r-- | src/boot/efi/disk.h | 21 | ||||
-rw-r--r-- | src/boot/efi/graphics.c | 3 | ||||
-rw-r--r-- | src/boot/efi/stub.c | 6 |
6 files changed, 146 insertions, 68 deletions
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index faab82dbb8..f991e30cfa 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -20,28 +20,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <getopt.h> -#include <stdlib.h> #include <assert.h> -#include <sys/statfs.h> -#include <sys/stat.h> -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <sys/mman.h> -#include <dirent.h> +#include <blkid/blkid.h> #include <ctype.h> -#include <limits.h> +#include <dirent.h> +#include <errno.h> #include <ftw.h> +#include <getopt.h> +#include <limits.h> #include <stdbool.h> -#include <blkid/blkid.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <unistd.h> +#include "blkid-util.h" #include "efivars.h" -#include "build.h" -#include "util.h" #include "rm-rf.h" -#include "blkid-util.h" +#include "util.h" static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) { struct statfs sfs; @@ -294,6 +293,8 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) { else if (r < 0) return r; + printf("\n"); + return 0; } @@ -487,9 +488,9 @@ static int copy_file(const char *from, const char *to, bool force) { } } while (!feof(f)); - fflush(g); - if (ferror(g)) { - r = log_error_errno(EIO, "Failed to write \"%s\": %m", to); + r = fflush_and_check(g); + if (r < 0) { + log_error_errno(r, "Failed to write \"%s\": %m", to); goto error; } @@ -517,7 +518,7 @@ static int copy_file(const char *from, const char *to, bool force) { return 0; error: - unlink(p); + (void) unlink(p); return r; } @@ -816,7 +817,7 @@ static int remove_boot_efi(const char *esp_path) { if (r < 0) return log_error_errno(errno, "Failed to remove \"%s/%s\": %m", p, de->d_name); - log_info("Removed \"%s/\%s\".", p, de->d_name); + log_info("Removed \"%s/%s\".", p, de->d_name); } c++; @@ -965,8 +966,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - printf(VERSION "\n"); - return 0; + return version(); case ARG_PATH: arg_path = optarg; diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 827c11844c..38b79da886 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -22,6 +22,7 @@ #include "console.h" #include "graphics.h" #include "pefile.h" +#include "disk.h" #include "linux.h" #ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI @@ -69,16 +70,14 @@ typedef struct { BOOLEAN no_editor; } Config; -static VOID cursor_left(UINTN *cursor, UINTN *first) -{ +static VOID cursor_left(UINTN *cursor, UINTN *first) { if ((*cursor) > 0) (*cursor)--; else if ((*first) > 0) (*first)--; } -static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) -{ +static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) { if ((*cursor)+1 < x_max) (*cursor)++; else if ((*first) + (*cursor) < len) @@ -855,13 +854,11 @@ static VOID config_entry_free(ConfigEntry *entry) { FreePool(entry->options); } -static BOOLEAN is_digit(CHAR16 c) -{ +static BOOLEAN is_digit(CHAR16 c) { return (c >= '0') && (c <= '9'); } -static UINTN c_order(CHAR16 c) -{ +static UINTN c_order(CHAR16 c) { if (c == '\0') return 0; if (is_digit(c)) @@ -872,8 +869,7 @@ static UINTN c_order(CHAR16 c) return c + 0x10000; } -static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) -{ +static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) { CHAR16 *os1 = s1; CHAR16 *os2 = s2; @@ -1139,13 +1135,11 @@ static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR1 config_add_entry(config, entry); } -static VOID config_load(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path) { - EFI_FILE_HANDLE entries_dir; - EFI_STATUS err; +static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) { CHAR8 *content = NULL; UINTN sec; UINTN len; - UINTN i; + EFI_STATUS err; len = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content); if (len > 0) @@ -1158,6 +1152,11 @@ static VOID config_load(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, config->timeout_sec = sec; } else config->timeout_sec_efivar = -1; +} + +static VOID config_load_entries(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path) { + EFI_FILE_HANDLE entries_dir; + EFI_STATUS err; err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &entries_dir, L"\\loader\\entries", EFI_FILE_MODE_READ, 0ULL); if (!EFI_ERROR(err)) { @@ -1194,8 +1193,11 @@ static VOID config_load(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, } uefi_call_wrapper(entries_dir->Close, 1, entries_dir); } +} + +static VOID config_sort_entries(Config *config) { + UINTN i; - /* sort entries after version number */ for (i = 1; i < config->entry_count; i++) { BOOLEAN more; UINTN k; @@ -1495,6 +1497,7 @@ static VOID config_entry_add_osx(Config *config) { static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_image, EFI_FILE *root_dir) { EFI_FILE_HANDLE linux_dir; EFI_STATUS err; + ConfigEntry *entry; err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &linux_dir, L"\\EFI\\Linux", EFI_FILE_MODE_READ, 0ULL); if (!EFI_ERROR(err)) { @@ -1504,6 +1507,7 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima EFI_FILE_INFO *f; CHAR8 *sections[] = { (UINT8 *)".osrel", + (UINT8 *)".cmdline", NULL }; UINTN offs[ELEMENTSOF(sections)-1] = {}; @@ -1535,7 +1539,7 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima if (StriCmp(f->FileName + len - 4, L".efi") != 0) continue; - /* look for an .osrel section in the .efi binary */ + /* look for .osrel and .cmdline sections in the .efi binary */ err = pefile_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs); if (EFI_ERROR(err)) continue; @@ -1575,10 +1579,21 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima if (os_name && os_id && (os_version || os_build)) { CHAR16 *conf; CHAR16 *path; + CHAR16 *cmdline; conf = PoolPrint(L"%s-%s", os_id, os_version ? : os_build); path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName); - config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path); + entry = config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path); + + FreePool(content); + /* read the embedded cmdline file */ + len = file_read(linux_dir, f->FileName, offs[1], szs[1] - 1 , &content); + if (len > 0) { + cmdline = stra_to_str(content); + entry->options = cmdline; + cmdline = NULL; + } + FreePool(cmdline); FreePool(conf); FreePool(path); } @@ -1683,11 +1698,11 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { EFI_LOADED_IMAGE *loaded_image; EFI_FILE *root_dir; CHAR16 *loaded_image_path; - EFI_DEVICE_PATH *device_path; EFI_STATUS err; Config config; UINT64 init_usec; BOOLEAN menu = FALSE; + CHAR16 uuid[37]; InitializeLib(image, sys_table); init_usec = time_usec(); @@ -1709,29 +1724,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { } /* export the device path this image is started from */ - device_path = DevicePathFromHandle(loaded_image->DeviceHandle); - if (device_path) { - EFI_DEVICE_PATH *path, *paths; - - paths = UnpackDevicePath(device_path); - for (path = paths; !IsDevicePathEnd(path); path = NextDevicePathNode(path)) { - HARDDRIVE_DEVICE_PATH *drive; - CHAR16 uuid[37]; - - if (DevicePathType(path) != MEDIA_DEVICE_PATH) - continue; - if (DevicePathSubType(path) != MEDIA_HARDDRIVE_DP) - continue; - drive = (HARDDRIVE_DEVICE_PATH *)path; - if (drive->SignatureType != SIGNATURE_TYPE_GUID) - continue; - - GuidToString(uuid, (EFI_GUID *)&drive->Signature); - efivar_set(L"LoaderDevicePartUUID", uuid, FALSE); - break; - } - FreePool(paths); - } + if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS) + efivar_set(L"LoaderDevicePartUUID", uuid, FALSE); root_dir = LibOpenRoot(loaded_image->DeviceHandle); if (!root_dir) { @@ -1745,12 +1739,19 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { loaded_image_path = DevicePathToStr(loaded_image->FilePath); efivar_set(L"LoaderImageIdentifier", loaded_image_path, FALSE); - /* scan "\loader\entries\*.conf" files */ ZeroMem(&config, sizeof(Config)); - config_load(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path); + config_load_defaults(&config, root_dir); - /* if we find some well-known loaders, add them to the end of the list */ + /* scan /EFI/Linux/ directory */ config_entry_add_linux(&config, loaded_image, root_dir); + + /* scan /loader/entries/\*.conf files */ + config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path); + + /* sort entries after version number */ + config_sort_entries(&config); + + /* if we find some well-known loaders, add them to the end of the list */ config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path, L"auto-windows", 'w', L"Windows Boot Manager", L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi"); config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path, diff --git a/src/boot/efi/disk.c b/src/boot/efi/disk.c new file mode 100644 index 0000000000..96063fbc28 --- /dev/null +++ b/src/boot/efi/disk.c @@ -0,0 +1,51 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * Copyright (C) 2015 Kay Sievers <kay@vrfy.org> + */ + +#include <efi.h> +#include <efilib.h> + +#include "util.h" + +EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[37]) { + EFI_DEVICE_PATH *device_path; + EFI_STATUS r = EFI_NOT_FOUND; + + /* export the device path this image is started from */ + device_path = DevicePathFromHandle(handle); + if (device_path) { + EFI_DEVICE_PATH *path, *paths; + + paths = UnpackDevicePath(device_path); + for (path = paths; !IsDevicePathEnd(path); path = NextDevicePathNode(path)) { + HARDDRIVE_DEVICE_PATH *drive; + + if (DevicePathType(path) != MEDIA_DEVICE_PATH) + continue; + if (DevicePathSubType(path) != MEDIA_HARDDRIVE_DP) + continue; + drive = (HARDDRIVE_DEVICE_PATH *)path; + if (drive->SignatureType != SIGNATURE_TYPE_GUID) + continue; + + GuidToString(uuid, (EFI_GUID *)&drive->Signature); + r = EFI_SUCCESS; + break; + } + FreePool(paths); + } + + return r; +} diff --git a/src/boot/efi/disk.h b/src/boot/efi/disk.h new file mode 100644 index 0000000000..1b25343a00 --- /dev/null +++ b/src/boot/efi/disk.h @@ -0,0 +1,21 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * Copyright (C) 2015 Kay Sievers <kay@vrfy.org> + */ + +#ifndef __SDBOOT_DISK_H +#define __SDBOOT_DISK_H + +EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[37]); +#endif diff --git a/src/boot/efi/graphics.c b/src/boot/efi/graphics.c index 2e9c11f5a0..f732428216 100644 --- a/src/boot/efi/graphics.c +++ b/src/boot/efi/graphics.c @@ -67,10 +67,9 @@ EFI_STATUS graphics_mode(BOOLEAN on) { EFI_STATUS err; err = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **)&ConsoleControl); - if (EFI_ERROR(err)) { + if (EFI_ERROR(err)) /* console control protocol is nonstandard and might not exist. */ return err == EFI_NOT_FOUND ? EFI_SUCCESS : err; - } /* check current mode */ err = uefi_call_wrapper(ConsoleControl->GetMode, 4, ConsoleControl, ¤t, &uga_exists, &stdin_locked); diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 0b1bc491ed..0c5ee4e9ff 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -18,6 +18,7 @@ #include "util.h" #include "pefile.h" +#include "disk.h" #include "graphics.h" #include "splash.h" #include "linux.h" @@ -46,6 +47,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { UINTN szs[ELEMENTSOF(sections)-1] = {}; CHAR8 *cmdline = NULL; UINTN cmdline_len; + CHAR16 uuid[37]; EFI_STATUS err; InitializeLib(image, sys_table); @@ -99,6 +101,10 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { cmdline = line; } + /* export the device path this image is started from */ + if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS) + efivar_set(L"LoaderDevicePartUUID", uuid, FALSE); + if (szs[3] > 0) graphics_splash((UINT8 *)((UINTN)loaded_image->ImageBase + addrs[3]), szs[3], NULL); |