package cmd import ( "fmt" "os" "git.wntrmute.dev/kyle/arca/internal/config" "git.wntrmute.dev/kyle/arca/internal/udisks" "github.com/godbus/dbus/v5" "github.com/spf13/cobra" ) var ( forceInit bool mergeInit bool ) var initCmd = &cobra.Command{ Use: "init", Short: "Generate config from detected LUKS devices", Long: "Scans for LUKS-encrypted devices, excludes the root filesystem, and writes a config file with passphrase as the default unlock method.", RunE: runInit, } func init() { initCmd.Flags().BoolVarP(&forceInit, "force", "f", false, "overwrite existing config file") initCmd.Flags().BoolVar(&mergeInit, "merge", false, "add new devices to existing config without overwriting") initCmd.MarkFlagsMutuallyExclusive("force", "merge") rootCmd.AddCommand(initCmd) } func runInit(cmd *cobra.Command, args []string) error { cfgPath := config.Path() // Load existing config for merge, or start fresh. var cfg *config.Config if mergeInit { cfg = config.Load() } else { if !forceInit { if _, err := os.Stat(cfgPath); err == nil { return fmt.Errorf("config already exists at %s (use --force to overwrite or --merge to add new devices)", cfgPath) } } cfg = &config.Config{Devices: make(map[string]config.DeviceConfig)} } client, err := udisks.NewClient() if err != nil { return fmt.Errorf("connecting to udisks2: %w", err) } defer client.Close() encrypted, err := client.ListEncryptedDevices() if err != nil { return err } rootBacking, err := client.RootBackingDevices() if err != nil { return fmt.Errorf("detecting root device: %w", err) } added := 0 for _, dev := range encrypted { if isRootBacking(dev.ObjectPath, rootBacking) { fmt.Fprintf(os.Stderr, "Skipping %s (root filesystem)\n", dev.DevicePath) continue } if cfg.HasUUID(dev.UUID) { fmt.Fprintf(os.Stderr, "Skipping %s (already configured)\n", dev.DevicePath) continue } alias := aliasFromUUID(dev.UUID) cfg.Devices[alias] = config.DeviceConfig{ UUID: dev.UUID, Methods: []string{"passphrase"}, } fmt.Fprintf(os.Stderr, "Found %s (UUID %s) -> alias %q\n", dev.DevicePath, dev.UUID, alias) added++ } if added == 0 && !mergeInit { fmt.Println("No non-root LUKS devices found.") return nil } if added == 0 && mergeInit { fmt.Println("No new devices to add.") return nil } if err := cfg.Save(); err != nil { return fmt.Errorf("saving config: %w", err) } fmt.Printf("Config written to %s (%d device(s) added)\n", cfgPath, added) return nil } func isRootBacking(path dbus.ObjectPath, rootDevices []dbus.ObjectPath) bool { for _, r := range rootDevices { if path == r { return true } } return false }