Skip to content

Commit

Permalink
Merge pull request #783 from rsteube/add-mount
Browse files Browse the repository at this point in the history
added mount
  • Loading branch information
rsteube authored Dec 2, 2021
2 parents be6cb37 + d66e6ae commit 3e97f1d
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 45 deletions.
2 changes: 1 addition & 1 deletion completers/dfc_completer/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func init() {
}),
"q": carapace.ActionValues("name", "type", "mount"),
"t": carapace.ActionMultiParts(",", func(c carapace.Context) carapace.Action {
return fs.ActionFileSystemTypes().Invoke(c).Filter(c.Parts).ToA()
return fs.ActionFilesystemTypes().Invoke(c).Filter(c.Parts).ToA()
}),
"u": carapace.ActionValuesDescribed(
"h", "Human readable",
Expand Down
2 changes: 1 addition & 1 deletion completers/find_completer/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func init() {
"all", "Enable all of the other debug options (but help).",
"help", "Explain the debugging options.",
),
"fstype": fs.ActionFileSystemTypes(),
"fstype": fs.ActionFilesystemTypes(),
"group": os.ActionGroups(),
"perm": fs.ActionFileModes(),
"regextype": carapace.ActionValues("findutils-default", "ed", "emacs", "gnu-awk", "grep", "posix-awk", "awk", "posix-basic", "posix-egrep", "egrep", "posix-extended", "posix-minimal-basic", "sed"),
Expand Down
2 changes: 1 addition & 1 deletion completers/mkfs_completer/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func init() {
rootCmd.Flags().BoolP("version", "V", false, "display version")

carapace.Gen(rootCmd).FlagCompletion(carapace.ActionMap{
"type": fs.ActionFileSystemTypes(),
"type": fs.ActionFilesystemTypes(),
})

carapace.Gen(rootCmd).PositionalCompletion(
Expand Down
71 changes: 71 additions & 0 deletions completers/mount_completer/cmd/action/option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package action

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/pkg/actions/fs"
)

func ActionOptions() carapace.Action {
return carapace.ActionMultiParts("=", func(c carapace.Context) carapace.Action {
switch len(c.Parts) {
case 0:
return carapace.ActionValuesDescribed(
"async", "All I/O to the filesystem should be done asynchronously.",
"atime", "Do not use the noatime feature.",
"noatime", "Do not update inode access times on this filesystem.",
"auto", "Can be mounted with the -a option.",
"noauto", "Can only be mounted explicitly.",
"context=", "Set context",
"fscontext=", "Set context",
"defcontext=", "Set context",
"rootcontext=", "Set context",
"defaults", "Use the default options",
"dev", "Interpret character or block special devices on the filesystem.",
"nodev", "Do not interpret character or block special devices on the filesystem.",
"diratime", "Update directory inode access times on this filesystem.",
"nodiratime", "Do not update directory inode access times on this filesystem.",
"dirsync", "All directory updates within the filesystem should be done synchronously.",
"exec", "Permit execution of binaries.",
"noexec", "Do not permit direct execution of any binaries on the mounted filesystem.",
"group", "Allow an ordinary user to mount the filesystem if one of that user’s groups matches the group of the device.",
"iversion", "Every time the inode is modified, the i_version field will be incremented.",
"noiversion", "Do not increment the i_version inode field.",
"mand", "Allow mandatory locks on this filesystem.",
"nomand", "Do not allow mandatory locks on this filesystem.",
"_netdev", "The filesystem resides on a device that requires network access",
"nofail", "Do not report errors for this device if it does not exist.",
"relatime", "Update inode access times relative to modify or change time.",
"norelatime", "Do not use the relatime feature.",
"strictatime", "Allows to explicitly request full atime updates.",
"nostrictatime", "Use the kernel’s default behavior for inode access time updates.",
"lazytime", "Only update times on the in-memory version of the file inode.",
"nolazytime", "Do not use the lazytime feature.",
"suid", "Honor set-user-ID and set-group-ID bits or file capabilities",
"nosuid", "Do not honor set-user-ID and set-group-ID bits or file capabilities",
"silent", "Turn on the silent flag.",
"loud", "Turn off the silent flag.",
"owner", "Allow an ordinary user to mount the filesystem if that user is the owner of the device.",
"remount", "Attempt to remount an already-mounted filesystem.",
"ro", "Mount the filesystem read-only.",
"rw", "Mount the filesystem read-write.",
"sync", "All I/O to the filesystem should be done synchronously.",
"user", "Allow an ordinary user to mount the filesystem.",
"nouser", "Forbid an ordinary user to mount the filesystem.",
"users", "Allow any user to mount and to unmount the filesystem",
"X-mount.mkdir", "Allow to make a target directory if it does not exist yet.",
"X-mount.subdir=", "Allow mounting sub-directory from a filesystem instead of the root directory.",
"nosymfollow", "Do not follow symlinks when resolving paths.",
)
case 1:
switch c.Parts[0] {
case "X-mount.mkdir":
return fs.ActionFileModesNumeric()

default:
return carapace.ActionValues()
}
default:
return carapace.ActionValues()
}
})
}
48 changes: 48 additions & 0 deletions completers/mount_completer/cmd/action/source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package action

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/pkg/actions/fs"
"github.com/rsteube/carapace-bin/pkg/util"
)

func ActionSources() carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if util.HasPathPrefix(c.CallbackValue) {
return carapace.Batch(
carapace.ActionFiles(),
fs.ActionBlockDevices(),
).ToA()
}
return carapace.ActionMultiParts("=", func(c carapace.Context) carapace.Action {
switch len(c.Parts) {
case 0:
return carapace.ActionValuesDescribed(
"LABEL", "specifies device by filesystem label",
"UUID", "specifies device by filesystem UUID",
"PARTLABEL", "specifies device by partition label",
"PARTUUID", "specifies device by partition UUID",
"ID", "specifies device by udev hardware ID",
).Invoke(c).Suffix("=").ToA()
case 1:
switch c.Parts[0] {
case "LABEL":
return fs.ActionLabels()
case "UUID":
return fs.ActionUuids()
case "PARTLABEL":
return fs.ActionPartLabels()
case "PARTUUID":
return fs.ActionPartUuids()
case "ID":
// TODO
return carapace.ActionValues()
default:
return carapace.ActionValues()
}
default:
return carapace.ActionValues()
}
})
})
}
132 changes: 132 additions & 0 deletions completers/mount_completer/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package cmd

import (
"strings"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/completers/mount_completer/cmd/action"
"github.com/rsteube/carapace-bin/pkg/actions/fs"
"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: "mount",
Short: "mount a filesystem",
Run: func(cmd *cobra.Command, args []string) {},
}

func Execute() error {
return rootCmd.Execute()
}
func init() {
carapace.Gen(rootCmd).Standalone()

rootCmd.Flags().BoolP("all", "a", false, "mount all filesystems mentioned in fstab")
rootCmd.Flags().BoolP("bind", "B", false, "mount a subtree somewhere else (same as -o bind)")
rootCmd.Flags().BoolP("fake", "f", false, "dry run; skip the mount(2) syscall")
rootCmd.Flags().BoolP("fork", "F", false, "fork off for each device (use with -a)")
rootCmd.Flags().StringP("fstab", "T", "", "alternative file to /etc/fstab")
rootCmd.Flags().BoolP("help", "h", false, "display this help")
rootCmd.Flags().BoolP("internal-only", "i", false, "don't call the mount.<type> helpers")
rootCmd.Flags().StringP("label", "L", "", "synonym for LABEL=<label>")
rootCmd.Flags().Bool("make-private", false, "mark a subtree as private")
rootCmd.Flags().Bool("make-rprivate", false, "recursively mark a whole subtree as private")
rootCmd.Flags().Bool("make-rshared", false, "recursively mark a whole subtree as shared")
rootCmd.Flags().Bool("make-rslave", false, "recursively mark a whole subtree as slave")
rootCmd.Flags().Bool("make-runbindable", false, "recursively mark a whole subtree as unbindable")
rootCmd.Flags().Bool("make-shared", false, "mark a subtree as shared")
rootCmd.Flags().Bool("make-slave", false, "mark a subtree as slave")
rootCmd.Flags().Bool("make-unbindable", false, "mark a subtree as unbindable")
rootCmd.Flags().BoolP("move", "M", false, "move a subtree to some other place")
rootCmd.Flags().StringP("namespace", "N", "", "perform mount in another namespace")
rootCmd.Flags().BoolP("no-canonicalize", "c", false, "don't canonicalize paths")
rootCmd.Flags().BoolP("no-mtab", "n", false, "don't write to /etc/mtab")
rootCmd.Flags().StringP("options", "o", "", "comma-separated list of mount options")
rootCmd.Flags().String("options-mode", "", "what to do with options loaded from fstab")
rootCmd.Flags().String("options-source", "", "mount options source")
rootCmd.Flags().Bool("options-source-force", false, "force use of options from fstab/mtab")
rootCmd.Flags().BoolP("rbind", "R", false, "mount a subtree and all submounts somewhere else")
rootCmd.Flags().BoolP("read-only", "r", false, "mount the filesystem read-only (same as -o ro)")
rootCmd.Flags().StringP("rw", "w", "", "mount the filesystem read-write (default)")
rootCmd.Flags().BoolP("show-labels", "l", false, "show also filesystem labels")
rootCmd.Flags().String("source", "", "explicitly specifies source (path, label, uuid)")
rootCmd.Flags().String("target", "", "explicitly specifies mountpoint")
rootCmd.Flags().String("target-prefix", "", "specifies path used for all mountpoints")
rootCmd.Flags().StringP("test-opts", "O", "", "limit the set of filesystems (use with -a)")
rootCmd.Flags().StringP("types", "t", "", "limit the set of filesystem types")
rootCmd.Flags().StringP("uuid", "U", "", "synonym for UUID=<uuid>")
rootCmd.Flags().BoolP("verbose", "v", false, "say what is being done")
rootCmd.Flags().BoolP("version", "V", false, "display version")

carapace.Gen(rootCmd).FlagCompletion(carapace.ActionMap{
"fstab": carapace.ActionFiles(),
"label": fs.ActionLabels(),
"options": carapace.ActionMultiParts(",", func(c carapace.Context) carapace.Action {
keys := make([]string, 0)
for _, part := range c.Parts {
keys = append(keys, strings.Split(part, "=")[0])
}
return action.ActionOptions().Invoke(c).Filter(keys).ToA()
}),
"options-mode": carapace.ActionValues("ignore", "append", "prepend", "replace"),
"options-source": carapace.ActionMultiParts(",", func(c carapace.Context) carapace.Action {
return carapace.ActionValues("fstab", "mtab", "disable").Invoke(c).Filter(c.Parts).ToA()
}),
"source": action.ActionSources(),
"target": carapace.ActionDirectories(),
"target-prefix": carapace.ActionDirectories(),
"types": carapace.ActionMultiParts(",", func(c carapace.Context) carapace.Action {
return fs.ActionFilesystemTypes().Invoke(c).Filter(c.Parts).ToA()
}),
"uuid": fs.ActionUuids(),
})

carapace.Gen(rootCmd).PositionalCompletion(
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if rootCmd.Flag("all").Changed {
return carapace.ActionValues()
}
if isOperation(rootCmd) {
return fs.ActionMounts()
}
if rootCmd.Flag("source").Changed {
if rootCmd.Flag("target").Changed {
return carapace.ActionValues()
}
return carapace.ActionDirectories()
}
return action.ActionSources()
}),
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if rootCmd.Flag("all").Changed {
return carapace.ActionValues()
}
if isOperation(rootCmd) {
if rootCmd.Flag("bind").Changed ||
rootCmd.Flag("rbind").Changed ||
rootCmd.Flag("move").Changed {
return carapace.ActionDirectories()
}
}

if !rootCmd.Flag("source").Changed &&
!rootCmd.Flag("target").Changed {
return carapace.ActionDirectories()
}
return carapace.ActionValues()
}),
)
}

func isOperation(cmd *cobra.Command) bool {
return cmd.Flag("bind").Changed ||
cmd.Flag("move").Changed ||
cmd.Flag("rbind").Changed ||
cmd.Flag("make-shared").Changed ||
cmd.Flag("make-slave").Changed ||
cmd.Flag("make-private").Changed ||
cmd.Flag("make-unbindable").Changed ||
cmd.Flag("make-rshared").Changed ||
cmd.Flag("make-rslave").Changed ||
cmd.Flag("make-rprivate").Changed
}
7 changes: 7 additions & 0 deletions completers/mount_completer/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "github.com/rsteube/carapace-bin/completers/mount_completer/cmd"

func main() {
cmd.Execute()
}
99 changes: 99 additions & 0 deletions pkg/actions/fs/blockdevice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package fs

import (
"encoding/json"
"fmt"

"github.com/rsteube/carapace"
)

type blockdevice struct {
Kname string
Label string
Partlabel string
Partuuid string
Parttypename string
Path string
Size string
Type string
Uuid string
}

func actionBlockdevices(f func(blockdevices []blockdevice) carapace.Action) carapace.Action {
return carapace.ActionExecCommand("lsblk", "--json", "-o", "KNAME,LABEL,PARTLABEL,PARTUUID,PATH,SIZE,PARTTYPENAME,TYPE,UUID")(func(output []byte) carapace.Action {
var b struct {
Blockdevices []blockdevice
}
if err := json.Unmarshal(output, &b); err != nil {
return carapace.ActionMessage(err.Error())
}
return f(b.Blockdevices)
})
}

// ActionBlockDevices completes block devices
// /dev/sda (10G)
// /dev/sda1 (2G Linux swap)
func ActionBlockDevices() carapace.Action {
return actionBlockdevices(func(blockdevices []blockdevice) carapace.Action {
vals := make([]string, 0)
for _, b := range blockdevices {
vals = append(vals, b.Path, fmt.Sprintf("%v %v", b.Size, b.Parttypename))
}
return carapace.ActionValuesDescribed(vals...)
})
}

// TODO add examples to actions

// ActionLabels completes disk labels
func ActionLabels() carapace.Action {
return actionBlockdevices(func(blockdevices []blockdevice) carapace.Action {
vals := make([]string, 0)
for _, b := range blockdevices {
if b.Label != "" {
vals = append(vals, b.Label, b.Kname)
}
}
return carapace.ActionValuesDescribed(vals...)
})
}

// ActionPartLabels completes partition labels
func ActionPartLabels() carapace.Action {
return actionBlockdevices(func(blockdevices []blockdevice) carapace.Action {
vals := make([]string, 0)
for _, b := range blockdevices {
if b.Label != "" {
vals = append(vals, b.Partlabel, b.Kname)
}
}
return carapace.ActionValuesDescribed(vals...)
})
}

// ActionUuids completes disk uuids
func ActionUuids() carapace.Action {
return actionBlockdevices(func(blockdevices []blockdevice) carapace.Action {
vals := make([]string, 0)
for _, b := range blockdevices {
if b.Uuid != "" {
vals = append(vals, b.Uuid, b.Kname)
}
}
return carapace.ActionValuesDescribed(vals...)
})
}

// ActionPartUuids completes partition uuids
func ActionPartUuids() carapace.Action {
return actionBlockdevices(func(blockdevices []blockdevice) carapace.Action {
vals := make([]string, 0)
for _, b := range blockdevices {
if b.Partuuid != "" {
vals = append(vals, b.Partuuid, b.Kname)
}
}
return carapace.ActionValuesDescribed(vals...)
})
}
Loading

0 comments on commit 3e97f1d

Please sign in to comment.