@@ -14,13 +14,16 @@ package core
1414*/
1515
1616import (
17+ "bufio"
1718 "encoding/json"
18- "errors"
1919 "fmt"
2020 "os"
2121 "os/exec"
22+ "path/filepath"
2223 "strings"
2324 "syscall"
25+
26+ "golang.org/x/sys/unix"
2427)
2528
2629// DiskManager exposes functions to interact with the system's disks
@@ -192,33 +195,97 @@ func (p *Partition) Mount(destination string) error {
192195 return nil
193196}
194197
195- // Unmount unmounts a partition
196- func (p * Partition ) Unmount () error {
197- PrintVerboseInfo ("Partition.Unmount" , "running..." )
198+ // Returns whether the partition is a device-mapper virtual partition
199+ func (p * Partition ) IsDevMapper () bool {
200+ return p .Parent != nil
201+ }
202+
203+ // IsEncrypted returns whether the partition is encrypted
204+ func (p * Partition ) IsEncrypted () bool {
205+ return strings .HasPrefix (p .FsType , "crypto_" )
206+ }
198207
199- if p .MountPoint == "" {
200- PrintVerboseErr ("Partition.Unmount" , 0 , errors .New ("no mount point" ))
201- return errors .New ("no mount point" )
208+ func UnmountRecursive (mountPoint string , flags int ) error {
209+ mountPointOld := mountPoint
210+ mountPoint , err := filepath .EvalSymlinks (mountPoint )
211+ if err != nil {
212+ return fmt .Errorf ("could not find real path for %s: %w" , mountPointOld , err )
202213 }
203214
204- err := syscall . Unmount ( p . MountPoint , 0 )
215+ systemMountpoints , err := readMountPoints ( )
205216 if err != nil {
206- PrintVerboseErr ("Partition.Unmount" , 1 , err )
217+ fmt .Errorf ("Could not load system mounts: %w" , err )
218+ }
219+
220+ mountId := ""
221+
222+ for id , systemMount := range systemMountpoints {
223+ if systemMount .mountPoint == mountPoint {
224+ mountId = id
225+ }
226+ }
227+
228+ if mountId == "" {
229+ err := unix .Unmount (mountPoint , flags )
207230 return err
208231 }
209232
210- PrintVerboseInfo ("Partition.Unmount" , "successfully unmounted" , p .MountPoint )
211- p .MountPoint = ""
233+ err = unmountRecursive (mountId , systemMountpoints , flags , 0 )
234+ if err != nil {
235+ return fmt .Errorf ("could not recursively unmount %s: %w" , mountPoint , err )
236+ }
212237
213238 return nil
214239}
215240
216- // Returns whether the partition is a device-mapper virtual partition
217- func (p * Partition ) IsDevMapper () bool {
218- return p .Parent != nil
241+ func unmountRecursive (mountPointId string , systemMountpoints map [string ]mount , flags int , depth int ) error {
242+ if depth >= 1000 {
243+ return fmt .Errorf ("too many layers when trying to recursively unmount" )
244+ }
245+
246+ mount , ok := systemMountpoints [mountPointId ]
247+ if ! ok {
248+ return fmt .Errorf ("could not find mountpoint with id %s" , mountPointId )
249+ }
250+
251+ for childMountId , childMount := range systemMountpoints {
252+ if childMount .parentId == mountPointId {
253+ err := unmountRecursive (childMountId , systemMountpoints , flags , depth + 1 )
254+ if err != nil {
255+ fmt .Errorf ("could not unmount %s: %w" , childMount .mountPoint )
256+ }
257+ }
258+ }
259+
260+ return unix .Unmount (mount .mountPoint , flags )
219261}
220262
221- // IsEncrypted returns whether the partition is encrypted
222- func (p * Partition ) IsEncrypted () bool {
223- return strings .HasPrefix (p .FsType , "crypto_" )
263+ type mount struct {
264+ id string
265+ parentId string
266+ mountPoint string
267+ }
268+
269+ func readMountPoints () (map [string ]mount , error ) {
270+ f , err := os .Open ("/proc/self/mountinfo" )
271+ if err != nil {
272+ return nil , err
273+ }
274+ defer f .Close ()
275+
276+ mounts := make (map [string ]mount )
277+ scanner := bufio .NewScanner (f )
278+
279+ for scanner .Scan () {
280+ fields := strings .Fields (scanner .Text ())
281+ if len (fields ) < 5 {
282+ continue
283+ }
284+
285+ id := fields [0 ]
286+
287+ mounts [id ] = mount {id : id , parentId : fields [1 ], mountPoint : fields [4 ]}
288+ }
289+
290+ return mounts , scanner .Err ()
224291}
0 commit comments