github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/cmd/snap-preseed/reset.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 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 main 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 28 "github.com/snapcore/snapd/dirs" 29 "github.com/snapcore/snapd/osutil" 30 apparmor_sandbox "github.com/snapcore/snapd/sandbox/apparmor" 31 ) 32 33 func resetPreseededChroot(preseedChroot string) error { 34 exists, isDir, err := osutil.DirExists(preseedChroot) 35 if err != nil { 36 return fmt.Errorf("cannot reset %q: %v", preseedChroot, err) 37 } 38 if !exists { 39 return fmt.Errorf("cannot reset non-existing directory %q", preseedChroot) 40 } 41 if !isDir { 42 return fmt.Errorf("cannot reset %q, it is not a directory", preseedChroot) 43 } 44 45 // globs that yield individual files 46 globs := []string{ 47 dirs.SnapStateFile, 48 dirs.SnapSystemKeyFile, 49 filepath.Join(dirs.SnapBlobDir, "*.snap"), 50 filepath.Join(dirs.SnapUdevRulesDir, "*-snap.*.rules"), 51 filepath.Join(dirs.SnapDBusSystemPolicyDir, "snap.*.*.conf"), 52 filepath.Join(dirs.SnapServicesDir, "snap.*.service"), 53 filepath.Join(dirs.SnapServicesDir, "snap.*.timer"), 54 filepath.Join(dirs.SnapServicesDir, "snap.*.socket"), 55 filepath.Join(dirs.SnapServicesDir, "snap-*.mount"), 56 filepath.Join(dirs.SnapServicesDir, "multi-user.target.wants", "snap-*.mount"), 57 filepath.Join(dirs.SnapUserServicesDir, "snap.*.service"), 58 filepath.Join(dirs.SnapUserServicesDir, "snap.*.socket"), 59 filepath.Join(dirs.SnapUserServicesDir, "snap.*.timer"), 60 filepath.Join(dirs.SnapUserServicesDir, "default.target.wants", "snap.*.service"), 61 filepath.Join(dirs.SnapUserServicesDir, "sockets.target.wants", "snap.*.socket"), 62 filepath.Join(dirs.SnapUserServicesDir, "timers.target.wants", "snap.*.timer"), 63 } 64 65 for _, gl := range globs { 66 matches, err := filepath.Glob(filepath.Join(preseedChroot, gl)) 67 if err != nil { 68 // the only possible error from Glob() is ErrBadPattern 69 return err 70 } 71 for _, path := range matches { 72 if err := os.Remove(path); err != nil { 73 return fmt.Errorf("error removing %s: %v", path, err) 74 } 75 } 76 } 77 78 // directories that need to be removed recursively (but 79 // leaving parent directory intact). 80 globs = []string{ 81 filepath.Join(dirs.SnapDataDir, "*"), 82 filepath.Join(dirs.SnapCacheDir, "*"), 83 filepath.Join(apparmor_sandbox.CacheDir, "*"), 84 filepath.Join(dirs.SnapDesktopFilesDir, "*"), 85 } 86 87 for _, gl := range globs { 88 matches, err := filepath.Glob(filepath.Join(preseedChroot, gl)) 89 if err != nil { 90 // the only possible error from Glob() is ErrBadPattern 91 return err 92 } 93 for _, path := range matches { 94 if err := os.RemoveAll(path); err != nil { 95 return fmt.Errorf("error removing %s: %v", path, err) 96 } 97 } 98 } 99 100 // directories removed entirely 101 paths := []string{ 102 dirs.SnapAssertsDBDir, 103 dirs.FeaturesDir, 104 dirs.SnapDesktopIconsDir, 105 dirs.SnapDeviceDir, 106 dirs.SnapCookieDir, 107 dirs.SnapMountPolicyDir, 108 dirs.SnapAppArmorDir, 109 dirs.SnapSeqDir, 110 dirs.SnapMountDir, 111 dirs.SnapSeccompBase, 112 } 113 114 for _, path := range paths { 115 if err := os.RemoveAll(filepath.Join(preseedChroot, path)); err != nil { 116 // report the error and carry on 117 return fmt.Errorf("error removing %s: %v", path, err) 118 } 119 } 120 121 // bash-completion symlinks; note there are symlinks that point at 122 // completer, and symlinks that point at the completer symlinks. 123 // e.g. 124 // lxd.lxc -> /snap/core/current/usr/lib/snapd/complete.sh 125 // lxc -> lxd.lxc 126 files, err := ioutil.ReadDir(filepath.Join(preseedChroot, dirs.CompletersDir)) 127 if err != nil && !os.IsNotExist(err) { 128 return fmt.Errorf("error reading %s: %v", dirs.CompletersDir, err) 129 } 130 completeShSymlinks := make(map[string]string) 131 var otherSymlinks []string 132 133 // pass 1: find all symlinks pointing at complete.sh 134 for _, fileInfo := range files { 135 if fileInfo.Mode()&os.ModeSymlink == 0 { 136 continue 137 } 138 fullPath := filepath.Join(preseedChroot, dirs.CompletersDir, fileInfo.Name()) 139 if dirs.IsCompleteShSymlink(fullPath) { 140 if err := os.Remove(fullPath); err != nil { 141 return fmt.Errorf("error removing symlink %s: %v", fullPath, err) 142 } 143 completeShSymlinks[fileInfo.Name()] = fullPath 144 } else { 145 otherSymlinks = append(otherSymlinks, fullPath) 146 } 147 } 148 // pass 2: find all symlinks that point at the symlinks found in pass 1. 149 for _, other := range otherSymlinks { 150 target, err := os.Readlink(other) 151 if err != nil { 152 return fmt.Errorf("error reading symlink target of %s: %v", other, err) 153 } 154 if _, ok := completeShSymlinks[target]; ok { 155 if err := os.Remove(other); err != nil { 156 return fmt.Errorf("error removing symlink %s: %v", other, err) 157 } 158 } 159 } 160 161 return nil 162 }