Files
arca/cmd/status.go
Kyle Isom e9247c720a Add config validation, remove command, status filtering, and unlock method display
config check: validates UUID format, recognized methods, keyfile
consistency and existence. Reports all issues with alias context.

remove: deletes a device from config by alias. Inverse of add.

status: --mounted, --unlocked, --locked flags filter the device table.
Flags combine as OR.

mount/unlock: display which method succeeded and key slot used, e.g.
"(fido2, key slot 1)". cryptsetup Open now runs with -v and parses
"Key slot N unlocked" from stderr via io.MultiWriter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:22:52 -07:00

88 lines
1.8 KiB
Go

package cmd
import (
"fmt"
"os"
"text/tabwriter"
"git.wntrmute.dev/kyle/arca/internal/config"
"git.wntrmute.dev/kyle/arca/internal/udisks"
"github.com/spf13/cobra"
)
var (
filterMounted bool
filterUnlocked bool
filterLocked bool
)
var statusCmd = &cobra.Command{
Use: "status",
Short: "Show LUKS volume status",
RunE: runStatus,
}
func init() {
statusCmd.Flags().BoolVar(&filterMounted, "mounted", false, "show only mounted devices")
statusCmd.Flags().BoolVar(&filterUnlocked, "unlocked", false, "show only unlocked (but not mounted) devices")
statusCmd.Flags().BoolVar(&filterLocked, "locked", false, "show only locked devices")
rootCmd.AddCommand(statusCmd)
}
func runStatus(cmd *cobra.Command, args []string) error {
cfg := config.Load()
client, err := udisks.NewClient()
if err != nil {
return fmt.Errorf("connecting to udisks2: %w", err)
}
defer client.Close()
devices, err := client.ListEncryptedDevices()
if err != nil {
return err
}
filtering := filterMounted || filterUnlocked || filterLocked
w := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', 0)
fmt.Fprintln(w, "DEVICE\tUUID\tALIAS\tSTATE\tMOUNTPOINT")
for _, dev := range devices {
alias := cfg.AliasFor(dev.UUID)
state := "locked"
mountpoint := ""
if ct, err := client.CleartextDevice(&dev); err == nil {
state = "unlocked"
if mp, err := client.MountPoint(ct); err == nil && mp != "" {
mountpoint = mp
state = "mounted"
}
}
if filtering {
switch state {
case "mounted":
if !filterMounted {
continue
}
case "unlocked":
if !filterUnlocked {
continue
}
case "locked":
if !filterLocked {
continue
}
}
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
dev.DevicePath, dev.UUID, alias, state, mountpoint)
}
w.Flush()
return nil
}