From e21ff8039bdf73e3d895805bc8a11bcec66d4805 Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Tue, 24 Mar 2026 08:01:57 -0700 Subject: [PATCH] =?UTF-8?q?M4:=20CLI=20polish=20=E2=80=94=20version=20flag?= =?UTF-8?q?,=20mountpoint=20override,=20stable=20aliases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add --version flag with build-time injection via ldflags. Add --mountpoint/-m flag to mount for one-off mount point override. Change init aliases from device path basename (sda1) to UUID prefix (b8b2f8e3) for stability across boots. Add .gitignore. Update flake.nix with version injection. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 2 ++ cmd/init.go | 15 ++++++++++----- cmd/mount.go | 39 ++++++++++++++++++++++++++++++--------- cmd/root.go | 4 ++++ flake.nix | 6 +++++- main.go | 3 +++ 6 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71b1c64 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/arca +result diff --git a/cmd/init.go b/cmd/init.go index 6e73bf7..b7bc116 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -6,6 +6,7 @@ import ( "path/filepath" "strings" + "git.wntrmute.dev/kyle/arca/internal/config" "git.wntrmute.dev/kyle/arca/internal/udisks" "github.com/godbus/dbus/v5" @@ -62,7 +63,7 @@ func runInit(cmd *cobra.Command, args []string) error { continue } - alias := aliasFromPath(dev.DevicePath) + alias := aliasFromUUID(dev.UUID) cfg.Devices[alias] = config.DeviceConfig{ UUID: dev.UUID, Methods: []string{"passphrase"}, @@ -101,8 +102,12 @@ func isRootBacking(path dbus.ObjectPath, rootDevices []dbus.ObjectPath) bool { return false } -func aliasFromPath(devPath string) string { - // "/dev/sda1" -> "sda1", "/dev/nvme0n1p2" -> "nvme0n1p2" - base := filepath.Base(devPath) - return strings.TrimPrefix(base, "dm-") +func aliasFromUUID(uuid string) string { + // Use first 8 chars of UUID as a stable alias. + // "b8b2f8e3-4cde-4aca-a96e-df9274019f9f" -> "b8b2f8e3" + clean := strings.ReplaceAll(uuid, "-", "") + if len(clean) > 8 { + clean = clean[:8] + } + return clean } diff --git a/cmd/mount.go b/cmd/mount.go index 6f6c9ef..5de2e61 100644 --- a/cmd/mount.go +++ b/cmd/mount.go @@ -12,6 +12,8 @@ import ( "golang.org/x/term" ) +var mountpoint string + var mountCmd = &cobra.Command{ Use: "mount ", Short: "Unlock and mount a LUKS volume", @@ -20,6 +22,7 @@ var mountCmd = &cobra.Command{ } func init() { + mountCmd.Flags().StringVarP(&mountpoint, "mountpoint", "m", "", "mount point override (privileged path only)") rootCmd.AddCommand(mountCmd) } @@ -35,6 +38,12 @@ func runMount(cmd *cobra.Command, args []string) error { devCfg := cfg.ResolveDevice(target) + // CLI flag overrides config mountpoint. + mp := devCfg.Mountpoint + if mountpoint != "" { + mp = mountpoint + } + dev, err := client.FindDevice(devCfg.UUID, target) if err != nil { return err @@ -43,12 +52,12 @@ func runMount(cmd *cobra.Command, args []string) error { // Check if already unlocked. if cleartext, err := client.CleartextDevice(dev); err == nil { // Already unlocked — check if mounted too. - if mp, mounted := client.IsMounted(cleartext); mounted { - fmt.Println(mp) + if existing, mounted := client.IsMounted(cleartext); mounted { + fmt.Println(existing) return nil } // Unlocked but not mounted — just mount it. - return doMount(client, cleartext, devCfg) + return doMount(client, cleartext, mp) } // Need to unlock. @@ -63,23 +72,35 @@ func runMount(cmd *cobra.Command, args []string) error { } if result.Privileged { - mountpoint, err := cryptsetup.Mount(result.Device.DevicePath, devCfg.Mountpoint) + mnt, err := cryptsetup.Mount(result.Device.DevicePath, mp) if err != nil { return fmt.Errorf("mounting: %w", err) } - fmt.Println(mountpoint) + fmt.Println(mnt) return nil } - return doMount(client, result.Device, devCfg) + if mp != "" { + fmt.Fprintf(os.Stderr, "warning: --mountpoint is ignored for udisks2 mounts (passphrase/keyfile path)\n") + } + return doMount(client, result.Device, "") } -func doMount(client *udisks.Client, cleartext *udisks.BlockDevice, devCfg config.ResolvedDevice) error { - mountpoint, err := client.Mount(cleartext) +func doMount(client *udisks.Client, cleartext *udisks.BlockDevice, mp string) error { + if mp != "" { + // udisks2 doesn't support custom mount points; use privileged mount. + mnt, err := cryptsetup.Mount(cleartext.DevicePath, mp) + if err != nil { + return fmt.Errorf("mounting: %w", err) + } + fmt.Println(mnt) + return nil + } + mnt, err := client.Mount(cleartext) if err != nil { return fmt.Errorf("mounting: %w", err) } - fmt.Println(mountpoint) + fmt.Println(mnt) return nil } diff --git a/cmd/root.go b/cmd/root.go index 0da7431..b3f14b1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -12,6 +12,10 @@ var rootCmd = &cobra.Command{ Short: "Mount and unmount LUKS-encrypted volumes", } +func SetVersion(v string) { + rootCmd.Version = v +} + func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) diff --git a/flake.nix b/flake.nix index 98bee68..623092c 100644 --- a/flake.nix +++ b/flake.nix @@ -10,13 +10,17 @@ let system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; + version = "1.0.0"; in { packages.${system}.default = pkgs.buildGoModule { pname = "arca"; - version = "0.1.0"; + inherit version; src = ./.; vendorHash = null; + ldflags = [ + "-X main.version=${version}" + ]; }; }; } diff --git a/main.go b/main.go index 12ab116..7d2febd 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,9 @@ package main import "git.wntrmute.dev/kyle/arca/cmd" +var version = "dev" + func main() { + cmd.SetVersion(version) cmd.Execute() }