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 #195 from tri-adam/mount
Experimental Mount Command
- Loading branch information
Showing
24 changed files
with
325 additions
and
26 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright (c) 2022, Sylabs Inc. All rights reserved. | ||
// This software is licensed under a 3-clause BSD license. Please consult the | ||
// LICENSE file distributed with the sources of this project regarding your | ||
// rights to use or distribute this software. | ||
|
||
package siftool | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/sylabs/sif/v2/internal/pkg/exp" | ||
) | ||
|
||
// Mount mounts the primary system partition of the SIF file at path into mountPath. | ||
func (a *App) Mount(ctx context.Context, path, mountPath string) error { | ||
return exp.Mount(ctx, path, mountPath, | ||
exp.OptMountStdout(a.opts.out), | ||
exp.OptMountStderr(a.opts.err), | ||
) | ||
} |
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,104 @@ | ||
// Copyright (c) 2022, Sylabs Inc. All rights reserved. | ||
// This software is licensed under a 3-clause BSD license. Please consult the | ||
// LICENSE file distributed with the sources of this project regarding your | ||
// rights to use or distribute this software. | ||
|
||
// Package exp contains experimental functionality that is not sufficiently mature to be exported | ||
// as part of the module API. | ||
package exp | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
|
||
"github.com/sylabs/sif/v2/pkg/sif" | ||
) | ||
|
||
// mountSquashFS mounts the SquashFS filesystem from path at offset into mountPath. | ||
func mountSquashFS(ctx context.Context, offset int64, path, mountPath string, mo mountOpts) error { | ||
args := []string{ | ||
"-o", fmt.Sprintf("ro,offset=%d", offset), | ||
filepath.Clean(path), | ||
filepath.Clean(mountPath), | ||
} | ||
|
||
cmd := exec.CommandContext(ctx, "squashfuse", args...) | ||
cmd.Stdout = mo.stdout | ||
cmd.Stderr = mo.stderr | ||
|
||
if err := cmd.Run(); err != nil { | ||
return fmt.Errorf("failed to mount: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// mountOpts accumulates mount options. | ||
type mountOpts struct { | ||
stdout io.Writer | ||
stderr io.Writer | ||
} | ||
|
||
// MountOpt are used to specify mount options. | ||
type MountOpt func(*mountOpts) error | ||
|
||
// OptMountStdout writes standard output to w. | ||
func OptMountStdout(w io.Writer) MountOpt { | ||
return func(mo *mountOpts) error { | ||
mo.stdout = w | ||
return nil | ||
} | ||
} | ||
|
||
// OptMountStderr writes standard error to w. | ||
func OptMountStderr(w io.Writer) MountOpt { | ||
return func(mo *mountOpts) error { | ||
mo.stderr = w | ||
return nil | ||
} | ||
} | ||
|
||
var errUnsupportedFSType = errors.New("unrecognized filesystem type") | ||
|
||
// Mount mounts the primary system partition of the SIF file at path into mountPath. | ||
// | ||
// Mount may start one or more underlying processes. By default, stdout and stderr of these | ||
// processes is discarded. To modify this behavior, consider using OptMountStdout and/or | ||
// OptMountStderr. | ||
func Mount(ctx context.Context, path, mountPath string, opts ...MountOpt) error { | ||
mo := mountOpts{} | ||
|
||
for _, opt := range opts { | ||
if err := opt(&mo); err != nil { | ||
return fmt.Errorf("%w", err) | ||
} | ||
} | ||
|
||
f, err := sif.LoadContainerFromPath(path, sif.OptLoadWithFlag(os.O_RDONLY)) | ||
if err != nil { | ||
return fmt.Errorf("failed to load image: %w", err) | ||
} | ||
defer func() { _ = f.UnloadContainer() }() | ||
|
||
d, err := f.GetDescriptor(sif.WithPartitionType(sif.PartPrimSys)) | ||
if err != nil { | ||
return fmt.Errorf("failed to get partition descriptor: %w", err) | ||
} | ||
|
||
fs, _, _, err := d.PartitionMetadata() | ||
if err != nil { | ||
return fmt.Errorf("failed to get partition metadata: %w", err) | ||
} | ||
|
||
switch fs { | ||
case sif.FsSquash: | ||
return mountSquashFS(ctx, d.Offset(), path, mountPath, mo) | ||
default: | ||
return errUnsupportedFSType | ||
} | ||
} |
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
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,27 @@ | ||
// Copyright (c) 2022, Sylabs Inc. All rights reserved. | ||
// This software is licensed under a 3-clause BSD license. Please consult the | ||
// LICENSE file distributed with the sources of this project regarding your | ||
// rights to use or distribute this software. | ||
|
||
package siftool | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// getMount returns a command that mounts the primary system partition of a SIF image. | ||
func (c *command) getMount() *cobra.Command { | ||
return &cobra.Command{ | ||
Use: "mount <sif_path> <mount_path>", | ||
Short: "Mount primary system partition", | ||
Long: "Mount the primary system partition of a SIF image", | ||
Example: c.opts.rootPath + " mount image.sif path/", | ||
Args: cobra.ExactArgs(2), | ||
PreRunE: c.initApp, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
return c.app.Mount(cmd.Context(), args[0], args[1]) | ||
}, | ||
DisableFlagsInUseLine: true, | ||
Hidden: true, // hide while command is experimental | ||
} | ||
} |
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,61 @@ | ||
// Copyright (c) 2022, Sylabs Inc. All rights reserved. | ||
// This software is licensed under a 3-clause BSD license. Please consult the | ||
// LICENSE file distributed with the sources of this project regarding your | ||
// rights to use or distribute this software. | ||
|
||
package siftool | ||
|
||
import ( | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/sylabs/sif/v2/pkg/sif" | ||
) | ||
|
||
func Test_command_getMount(t *testing.T) { | ||
if _, err := exec.LookPath("squashfuse"); err != nil { | ||
t.Skip("squashfuse not found, skipping mount tests") | ||
} | ||
|
||
tests := []struct { | ||
name string | ||
opts commandOpts | ||
path string | ||
wantErr error | ||
}{ | ||
{ | ||
name: "Empty", | ||
path: filepath.Join(corpus, "empty.sif"), | ||
wantErr: sif.ErrNoObjects, | ||
}, | ||
{ | ||
name: "OneGroup", | ||
path: filepath.Join(corpus, "one-group.sif"), | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
path, err := os.MkdirTemp("", "siftool-mount-*") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
t.Cleanup(func() { | ||
cmd := exec.Command("fusermount", "-u", path) | ||
|
||
if err := cmd.Run(); err != nil { | ||
t.Log(err) | ||
} | ||
|
||
os.RemoveAll(path) | ||
}) | ||
|
||
c := &command{opts: tt.opts} | ||
|
||
cmd := c.getMount() | ||
|
||
runCommand(t, cmd, []string{tt.path, path}, tt.wantErr) | ||
}) | ||
} | ||
} |
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
Oops, something went wrong.