@@ -2,13 +2,16 @@ package main
2
2
3
3
import (
4
4
"fmt"
5
+ "os"
6
+ "os/exec"
5
7
"path/filepath"
6
8
"strings"
7
9
"syscall"
8
10
9
11
"github.com/urfave/cli"
10
12
"golang.org/x/sys/unix"
11
13
satomfs "stackerbuild.io/stacker/pkg/atomfs"
14
+ "stackerbuild.io/stacker/pkg/squashfs"
12
15
)
13
16
14
17
var mountCmd = cli.Command {
@@ -42,20 +45,39 @@ func findImage(ctx *cli.Context) (string, string, error) {
42
45
}
43
46
44
47
func doMount (ctx * cli.Context ) error {
45
- if ctx .NArg () != 2 {
46
- return fmt .Errorf ("source and destination required" )
48
+ if ! amPrivileged () {
49
+ fmt .Println ("Please run as root, or in a user namespace" )
50
+ fmt .Println (" You could try:" )
51
+ fmt .Println ("\t lxc-usernsexec -s -- /bin/bash" )
52
+ fmt .Println (" or" )
53
+ fmt .Println ("\t unshare -Umr -- /bin/bash" )
54
+ fmt .Println ("then run from that shell" )
55
+ os .Exit (1 )
47
56
}
48
-
49
57
ocidir , tag , err := findImage (ctx )
50
58
if err != nil {
51
59
return err
52
60
}
53
61
54
62
target := ctx .Args ()[1 ]
55
63
metadir := filepath .Join (target , "meta" )
64
+
65
+ complete := false
66
+
67
+ defer func () {
68
+ if ! complete {
69
+ cleanupDest (metadir )
70
+ }
71
+ }()
72
+
73
+ if PathExists (metadir ) {
74
+ return fmt .Errorf ("%q exists: cowardly refusing to mess with it" , metadir )
75
+ }
76
+
56
77
if err := EnsureDir (metadir ); err != nil {
57
78
return err
58
79
}
80
+
59
81
rodest := filepath .Join (metadir , "ro" )
60
82
if err = EnsureDir (rodest ); err != nil {
61
83
return err
@@ -84,13 +106,71 @@ func doMount(ctx *cli.Context) error {
84
106
err = overlay (target , rodest , metadir )
85
107
}
86
108
109
+ complete = true
110
+ return nil
111
+ }
112
+
113
+ func cleanupDest (metadir string ) {
114
+ fmt .Printf ("Failure detected: cleaning up %q" , metadir )
115
+ rodest := filepath .Join (metadir , "ro" )
116
+ if PathExists (rodest ) {
117
+ if err := unix .Unmount (rodest , 0 ); err != nil {
118
+ fmt .Printf ("Failed unmounting %q: %v" , rodest , err )
119
+ }
120
+ }
121
+
122
+ mountsdir := filepath .Join (metadir , "mounts" )
123
+ entries , err := os .ReadDir (mountsdir )
87
124
if err != nil {
88
- satomfs .Umount (rodest )
89
- return err
125
+ fmt .Printf ("Failed reading contents of %q: %v" , mountsdir , err )
126
+ os .RemoveAll (metadir )
127
+ return
128
+ }
129
+
130
+ wd , err := os .Getwd ()
131
+ if err != nil {
132
+ fmt .Printf ("Failed getting working directory" )
133
+ os .RemoveAll (metadir )
134
+ }
135
+ for _ , e := range entries {
136
+ n := filepath .Base (e .Name ())
137
+ if n == "workaround" {
138
+ continue
139
+ }
140
+ if strings .HasSuffix (n , ".log" ) {
141
+ continue
142
+ }
143
+ p := filepath .Join (wd , mountsdir , e .Name ())
144
+ if err := squashUmount (p ); err != nil {
145
+ fmt .Printf ("Failed unmounting %q: %v\n " , p , err )
146
+ }
147
+ }
148
+ os .RemoveAll (metadir )
149
+ }
150
+
151
+ func RunCommand (args ... string ) error {
152
+ cmd := exec .Command (args [0 ], args [1 :]... )
153
+ output , err := cmd .CombinedOutput ()
154
+ if err != nil {
155
+ return fmt .Errorf ("%s: %s: %s" , strings .Join (args , " " ), err , string (output ))
90
156
}
91
157
return nil
92
158
}
93
159
160
+ func amPrivileged () bool {
161
+ if os .Geteuid () == 0 {
162
+ return true
163
+ }
164
+ return false
165
+ }
166
+
167
+ func squashUmount (p string ) error {
168
+ if amPrivileged () {
169
+ return squashfs .Umount (p )
170
+ }
171
+ return RunCommand ("fusermount" , "-u" , p )
172
+ }
173
+
94
174
func overlay (target , rodest , metadir string ) error {
95
175
workdir := filepath .Join (metadir , "work" )
96
176
if err := EnsureDir (workdir ); err != nil {
0 commit comments