From c73f5d3ef35057f11f5d38d03d69db0743a34e08 Mon Sep 17 00:00:00 2001 From: Jared Baur Date: Sat, 22 Jun 2024 09:46:22 -0700 Subject: [PATCH] Fix tboot-bless-boot not working with newline from /proc/cmdline --- build.zig | 1 + flake.lock | 6 +- nixos-module.nix | 4 +- src/client.zig | 2 +- src/cpio/main.zig | 4 +- src/log.zig | 2 +- src/runner.zig | 2 +- src/tboot-bless-boot-generator.zig | 6 +- src/tboot-bless-boot.zig | 109 ++++++++++++++++------------- src/tboot-loader.zig | 2 +- src/tboot-nixos-install.zig | 8 +-- 11 files changed, 78 insertions(+), 68 deletions(-) diff --git a/build.zig b/build.zig index 2002839..b76358c 100644 --- a/build.zig +++ b/build.zig @@ -91,6 +91,7 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, .strip = optimize != std.builtin.OptimizeMode.Debug, }); + tboot_bless_boot.root_module.addImport("clap", clap.module("clap")); b.installArtifact(tboot_bless_boot); const tboot_bless_boot_generator = b.addExecutable(.{ diff --git a/flake.lock b/flake.lock index a0415c5..71977c7 100644 --- a/flake.lock +++ b/flake.lock @@ -21,11 +21,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1718714799, - "narHash": "sha256-FUZpz9rg3gL8NVPKbqU8ei1VkPLsTIfAJ2fdAf5qjak=", + "lastModified": 1718895438, + "narHash": "sha256-k3JqJrkdoYwE3fHE6xGDY676AYmyh4U2Zw+0Bwe5DLU=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c00d587b1a1afbf200b1d8f0b0e4ba9deb1c7f0e", + "rev": "d603719ec6e294f034936c0d0dc06f689d91b6c3", "type": "github" }, "original": { diff --git a/nixos-module.nix b/nixos-module.nix index be7abce..eaffefb 100644 --- a/nixos-module.nix +++ b/nixos-module.nix @@ -77,7 +77,7 @@ in }; systemd.generators.tboot-bless-boot-generator = lib.getExe' pkgs.tinybootTools "tboot-bless-boot-generator"; systemd.services.tboot-bless-boot = { - description = "Mark the Current Boot Loader Entry as Good"; + description = "Mark the current boot loader entry as good"; documentation = [ "https://github.com/jmbaur/tinyboot" ]; requires = [ "boot-complete.target" ]; conflicts = [ "shutdown.target" ]; @@ -91,7 +91,7 @@ in serviceConfig = { Type = "oneshot"; RemainAfterExit = true; - ExecStart = "${lib.getExe' pkgs.tinybootTools "tboot-bless-boot"} ${config.boot.loader.efi.efiSysMountPoint} good"; + ExecStart = "${lib.getExe' pkgs.tinybootTools "tboot-bless-boot"} --esp-mnt=${config.boot.loader.efi.efiSysMountPoint} good"; }; }; } diff --git a/src/client.zig b/src/client.zig index 180bb55..1663aa6 100644 --- a/src/client.zig +++ b/src/client.zig @@ -41,7 +41,7 @@ pub const Client = struct { .stream = try std.net.connectUnixSocket("/run/bus"), .arena = arena, .writer = std.io.bufferedWriter(std.io.getStdOut().writer()), - .log_file = try std.fs.openFileAbsolute("/run/log", .{}), + .log_file = try std.fs.cwd().openFile("/run/log", .{}), }; } diff --git a/src/cpio/main.zig b/src/cpio/main.zig index 8ae3d65..792e165 100644 --- a/src/cpio/main.zig +++ b/src/cpio/main.zig @@ -184,13 +184,13 @@ pub fn main() !void { var archive = try CpioArchive.init(arena.allocator()); defer archive.deinit(); - var init_file = try std.fs.openFileAbsolute(init, .{}); + var init_file = try std.fs.cwd().openFile(init, .{}); defer init_file.close(); var init_source = std.io.StreamSource{ .file = init_file }; try archive.addEntry(&init_source, "./init", .File, 0o755); - var archive_file = try std.fs.createFileAbsolute(outfile, .{}); + var archive_file = try std.fs.cwd().createFile(outfile, .{}); defer archive_file.close(); var archive_file_source = std.io.StreamSource{ .file = archive_file }; diff --git a/src/log.zig b/src/log.zig index 4e85bd0..5a91bba 100644 --- a/src/log.zig +++ b/src/log.zig @@ -8,7 +8,7 @@ pub fn initLogger(t: enum { }) !void { switch (t) { .Server => { - log_file = try std.fs.createFileAbsolute("/run/log", .{ + log_file = try std.fs.cwd().createFile("/run/log", .{ .truncate = true, }); }, diff --git a/src/runner.zig b/src/runner.zig index 6a259fb..5714674 100644 --- a/src/runner.zig +++ b/src/runner.zig @@ -2,7 +2,7 @@ const std = @import("std"); const builtin = @import("builtin"); fn pathExists(p: []const u8) bool { - std.fs.accessAbsolute(p, .{}) catch { + std.fs.cwd().access(p, .{}) catch { return false; }; diff --git a/src/tboot-bless-boot-generator.zig b/src/tboot-bless-boot-generator.zig index 5c74a84..09b3af9 100644 --- a/src/tboot-bless-boot-generator.zig +++ b/src/tboot-bless-boot-generator.zig @@ -32,7 +32,7 @@ pub fn main() !void { return; } - var kernel_cmdline_file = try std.fs.openFileAbsolute("/proc/cmdline", .{}); + var kernel_cmdline_file = try std.fs.cwd().openFile("/proc/cmdline", .{}); defer kernel_cmdline_file.close(); const kernel_cmdline = try kernel_cmdline_file.readToEndAlloc(allocator, 1024); @@ -43,12 +43,12 @@ pub fn main() !void { &.{ early_dir, "basic.target.wants" }, ); - std.fs.makeDirAbsolute(basic_target_path) catch |err| switch (err) { + std.fs.cwd().makeDir(basic_target_path) catch |err| switch (err) { error.PathAlreadyExists => {}, else => return err, }; - var basic_target_dir = try std.fs.openDirAbsolute(basic_target_path, .{}); + var basic_target_dir = try std.fs.cwd().openDir(basic_target_path, .{}); defer basic_target_dir.close(); try basic_target_dir.symLink( diff --git a/src/tboot-bless-boot.zig b/src/tboot-bless-boot.zig index 2c43619..93153b5 100644 --- a/src/tboot-bless-boot.zig +++ b/src/tboot-bless-boot.zig @@ -1,10 +1,10 @@ const std = @import("std"); +const clap = @import("clap"); + const bls = @import("./boot/bls.zig"); const Error = error{ - MissingEfiSysMountPoint, - MissingAction, InvalidAction, MissingBlsEntry, }; @@ -29,44 +29,29 @@ const Action = enum { fn markAsGood( allocator: std.mem.Allocator, - parent_path: []const u8, + parent_dir: std.fs.Dir, original_entry_filename: []const u8, bls_entry_file: bls.BlsEntryFile, ) !void { if (bls_entry_file.tries_left) |tries_left| { _ = tries_left; - const orig_fullpath = try std.fs.path.join( - allocator, - &.{ parent_path, original_entry_filename }, - ); - const new_filename = try std.fmt.allocPrint( allocator, "{s}.conf", .{bls_entry_file.name}, ); - const new_fullpath = try std.fs.path.join( - allocator, - &.{ parent_path, new_filename }, - ); - - try std.fs.renameAbsolute(orig_fullpath, new_fullpath); + try parent_dir.rename(original_entry_filename, new_filename); } } fn markAsBad( allocator: std.mem.Allocator, - parent_path: []const u8, + parent_dir: std.fs.Dir, original_entry_filename: []const u8, bls_entry_file: bls.BlsEntryFile, ) !void { - const orig_fullpath = try std.fs.path.join( - allocator, - &.{ parent_path, original_entry_filename }, - ); - const new_filename = b: { if (bls_entry_file.tries_done) |tries_done| { break :b try std.fmt.allocPrint( @@ -83,28 +68,16 @@ fn markAsBad( } }; - const new_fullpath = try std.fs.path.join( - allocator, - &.{ parent_path, new_filename }, - ); - - try std.fs.renameAbsolute(orig_fullpath, new_fullpath); + try parent_dir.rename(original_entry_filename, new_filename); } fn printStatus( - allocator: std.mem.Allocator, - parent_path: []const u8, original_entry_filename: []const u8, bls_entry_file: bls.BlsEntryFile, ) !void { - const orig_fullpath = try std.fs.path.join( - allocator, - &.{ parent_path, original_entry_filename }, - ); - var stdout = std.io.getStdOut().writer(); - try stdout.print("{s}:\n", .{orig_fullpath}); + try stdout.print("{s}:\n", .{original_entry_filename}); if (bls_entry_file.tries_left) |tries_left| { if (tries_left > 0) { @@ -114,6 +87,10 @@ fn printStatus( } else { try stdout.print("\tentry is bad\n", .{}); } + + if (bls_entry_file.tries_done) |tries_done| { + try stdout.print("\t{} tries done\n", .{tries_done}); + } } else { try stdout.print("\tentry is good\n", .{}); } @@ -121,16 +98,16 @@ fn printStatus( fn findEntry( allocator: std.mem.Allocator, - efi_sys_mount_point: []const u8, + esp_mnt: []const u8, entry_name: []const u8, action: Action, ) !void { const entries_path = try std.fs.path.join( allocator, - &.{ efi_sys_mount_point, "loader", "entries" }, + &.{ esp_mnt, "loader", "entries" }, ); - var entries_dir = try std.fs.openDirAbsolute( + var entries_dir = try std.fs.cwd().openDir( entries_path, .{ .iterate = true }, ); @@ -151,13 +128,15 @@ fn findEntry( }; if (std.mem.eql(u8, bls_entry.name, entry_name)) { - switch (action) { - .good => try markAsGood(allocator, entries_path, dir_entry.name, bls_entry), - .bad => try markAsBad(allocator, entries_path, dir_entry.name, bls_entry), - .status => try printStatus(allocator, entries_path, dir_entry.name, bls_entry), - } + return switch (action) { + .good => try markAsGood(allocator, entries_dir, dir_entry.name, bls_entry), + .bad => try markAsBad(allocator, entries_dir, dir_entry.name, bls_entry), + .status => try printStatus(dir_entry.name, bls_entry), + }; } } + + return Error.MissingBlsEntry; } pub fn main() !void { @@ -165,15 +144,39 @@ pub fn main() !void { defer arena.deinit(); const allocator = arena.allocator(); - var args = std.process.args(); + const params = comptime clap.parseParamsComptime( + \\-h, --help Display this help and exit. + \\--esp-mnt UEFI system partition mountpoint (default /boot). + \\ Action to take against current boot entry (mark as "good"/"bad", or print "status"). + \\ + ); - const argv0 = args.next().?; - _ = argv0; + const parsers = comptime .{ + .ACTION = clap.parsers.string, + .DIR = clap.parsers.string, + }; + + const stderr = std.io.getStdErr().writer(); - const efi_sys_mount_point = args.next() orelse return Error.MissingEfiSysMountPoint; - const action = try Action.fromStr(args.next() orelse return Error.MissingAction); + var diag = clap.Diagnostic{}; + var res = clap.parse(clap.Help, ¶ms, &parsers, .{ + .diagnostic = &diag, + .allocator = arena.allocator(), + }) catch |err| { + try diag.report(stderr, err); + try clap.usage(stderr, clap.Help, ¶ms); + return; + }; + defer res.deinit(); - const kernel_cmdline_file = try std.fs.openFileAbsolute("/proc/cmdline", .{}); + if (res.args.help != 0) { + return clap.help(std.io.getStdErr().writer(), clap.Help, ¶ms, .{}); + } + + const esp_mnt = res.args.@"esp-mnt" orelse std.fs.path.sep_str ++ "boot"; + const action = if (res.positionals.len > 0) try Action.fromStr(res.positionals[0]) else Action.status; + + const kernel_cmdline_file = try std.fs.cwd().openFile("/proc/cmdline", .{}); defer kernel_cmdline_file.close(); const kernel_cmdline = try kernel_cmdline_file.readToEndAlloc(allocator, 1024); @@ -184,7 +187,13 @@ pub fn main() !void { if (std.mem.startsWith(u8, kernel_param, "tboot.bls-entry=")) { var param_split = std.mem.splitScalar(u8, kernel_param, '='); _ = param_split.next().?; - break :b param_split.next() orelse return Error.MissingBlsEntry; + + // /proc/cmdline contains newline at the end of the file + break :b std.mem.trimRight( + u8, + param_split.next() orelse return Error.MissingBlsEntry, + "\n", + ); } } @@ -193,7 +202,7 @@ pub fn main() !void { try findEntry( allocator, - efi_sys_mount_point, + esp_mnt, tboot_bls_entry, action, ); diff --git a/src/tboot-loader.zig b/src/tboot-loader.zig index 60089cd..917b4e3 100644 --- a/src/tboot-loader.zig +++ b/src/tboot-loader.zig @@ -174,7 +174,7 @@ fn pid1() !void { defer log.deinitLogger(); const cmdline = cmdline: { - var cmdline_file = try std.fs.openFileAbsolute("/proc/self/cmdline", .{ .mode = .read_only }); + var cmdline_file = try std.fs.cwd().openFile("/proc/self/cmdline", .{ .mode = .read_only }); defer cmdline_file.close(); const cmdline_raw = try cmdline_file.readToEndAlloc(allocator, 2048); defer allocator.free(cmdline_raw); diff --git a/src/tboot-nixos-install.zig b/src/tboot-nixos-install.zig index eb3288e..b1800b2 100644 --- a/src/tboot-nixos-install.zig +++ b/src/tboot-nixos-install.zig @@ -197,7 +197,7 @@ fn installGeneration( } if (!args.dry_run) { - var entry_file = try std.fs.createFileAbsolute(entry_path, .{}); + var entry_file = try std.fs.cwd().createFile(entry_path, .{}); defer entry_file.close(); try entry_file.writeAll(entry_contents); @@ -227,7 +227,7 @@ fn cleanupDir( if (known_files.get(full_path) == null) { if (!args.dry_run) { - try std.fs.deleteFileAbsolute(full_path); + try std.fs.cwd().deleteFile(full_path); } std.log.info("cleaned up {s}", .{full_path}); } @@ -319,7 +319,7 @@ pub fn main() !void { std.log.warn("running a dry run, no filesystem changes will occur", .{}); } - const esp = try std.fs.openDirAbsolute(args.efi_sys_mount_point, .{ + const esp = try std.fs.cwd().openDir(args.efi_sys_mount_point, .{ .iterate = true, }); @@ -328,7 +328,7 @@ pub fn main() !void { &args, ); - var nixos_system_profile_dir = try std.fs.openDirAbsolute( + var nixos_system_profile_dir = try std.fs.cwd().openDir( "/nix/var/nix/profiles", .{ .iterate = true }, );