github.com/rigado/snapd@v2.42.5-go-mod+incompatible/overlord/snapstate/backend/setup.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014-2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package backend 21 22 import ( 23 "fmt" 24 "os" 25 "path/filepath" 26 27 "github.com/snapcore/snapd/boot" 28 "github.com/snapcore/snapd/progress" 29 "github.com/snapcore/snapd/release" 30 "github.com/snapcore/snapd/snap" 31 ) 32 33 // SetupSnap does prepare and mount the snap for further processing. 34 func (b Backend) SetupSnap(snapFilePath, instanceName string, sideInfo *snap.SideInfo, meter progress.Meter) (snapType snap.Type, err error) { 35 // This assumes that the snap was already verified or --dangerous was used. 36 37 s, snapf, oErr := OpenSnapFile(snapFilePath, sideInfo) 38 if oErr != nil { 39 return snapType, oErr 40 } 41 42 // update instance key to what was requested 43 _, s.InstanceKey = snap.SplitInstanceName(instanceName) 44 45 instdir := s.MountDir() 46 47 defer func() { 48 if err == nil { 49 return 50 } 51 // XXX: this will also remove the snap from /var/lib/snapd/snaps 52 if e := b.RemoveSnapFiles(s, s.GetType(), meter); e != nil { 53 meter.Notify(fmt.Sprintf("while trying to clean up due to previous failure: %v", e)) 54 } 55 }() 56 57 if err := os.MkdirAll(instdir, 0755); err != nil { 58 return snapType, err 59 } 60 61 if s.InstanceKey != "" { 62 err := os.MkdirAll(snap.BaseDir(s.SnapName()), 0755) 63 if err != nil && !os.IsExist(err) { 64 return snapType, err 65 } 66 } 67 68 if err := snapf.Install(s.MountFile(), instdir); err != nil { 69 return snapType, err 70 } 71 72 // generate the mount unit for the squashfs 73 if err := addMountUnit(s, meter); err != nil { 74 return snapType, err 75 } 76 77 t := s.GetType() 78 // TODO: maybe look into passing the model 79 if err := boot.Kernel(s, t, nil, release.OnClassic).ExtractKernelAssets(snapf); err != nil { 80 return snapType, fmt.Errorf("cannot install kernel: %s", err) 81 } 82 83 return t, nil 84 } 85 86 // RemoveSnapFiles removes the snap files from the disk after unmounting the snap. 87 func (b Backend) RemoveSnapFiles(s snap.PlaceInfo, typ snap.Type, meter progress.Meter) error { 88 mountDir := s.MountDir() 89 90 // this also ensures that the mount unit stops 91 if err := removeMountUnit(mountDir, meter); err != nil { 92 return err 93 } 94 95 if err := os.RemoveAll(mountDir); err != nil { 96 return err 97 } 98 99 // snapPath may either be a file or a (broken) symlink to a dir 100 snapPath := s.MountFile() 101 if _, err := os.Lstat(snapPath); err == nil { 102 // remove the kernel assets (if any) 103 // TODO: maybe look into passing the model 104 if err := boot.Kernel(s, typ, nil, release.OnClassic).RemoveKernelAssets(); err != nil { 105 return err 106 } 107 108 // remove the snap 109 if err := os.RemoveAll(snapPath); err != nil { 110 return err 111 } 112 } 113 114 return nil 115 } 116 117 func (b Backend) RemoveSnapDir(s snap.PlaceInfo, hasOtherInstances bool) error { 118 mountDir := s.MountDir() 119 120 snapName, instanceKey := snap.SplitInstanceName(s.InstanceName()) 121 if instanceKey != "" { 122 // always ok to remove instance specific one, failure to remove 123 // is ok, there may be other revisions 124 os.Remove(filepath.Dir(mountDir)) 125 } 126 if !hasOtherInstances { 127 // remove only if not used by other instances of the same snap, 128 // failure to remove is ok, there may be other revisions 129 os.Remove(snap.BaseDir(snapName)) 130 } 131 return nil 132 } 133 134 // UndoSetupSnap undoes the work of SetupSnap using RemoveSnapFiles. 135 func (b Backend) UndoSetupSnap(s snap.PlaceInfo, typ snap.Type, meter progress.Meter) error { 136 return b.RemoveSnapFiles(s, typ, meter) 137 }