-
-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #783 from rsteube/add-mount
added mount
- Loading branch information
Showing
11 changed files
with
393 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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...) | ||
}) | ||
} |
Oops, something went wrong.