github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/cmd/snap-update-ns/update.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 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 "github.com/snapcore/snapd/logger" 24 "github.com/snapcore/snapd/osutil" 25 ) 26 27 // MountProfileUpdateContext provides the context of a mount namespace update. 28 // The context provides a way to synchronize the operation with other users of 29 // the snap system, to load and save the mount profiles and to provide the file 30 // system assumptions with which the mount namespace will be modified. 31 type MountProfileUpdateContext interface { 32 // Lock obtains locks appropriate for the update. 33 Lock() (unlock func(), err error) 34 // Assumptions computes filesystem assumptions under which the update shall operate. 35 Assumptions() *Assumptions 36 // LoadDesiredProfile loads the mount profile that should be constructed. 37 LoadDesiredProfile() (*osutil.MountProfile, error) 38 // LoadCurrentProfile loads the mount profile that is currently applied. 39 LoadCurrentProfile() (*osutil.MountProfile, error) 40 // SaveCurrentProfile saves the mount profile that is currently applied. 41 SaveCurrentProfile(*osutil.MountProfile) error 42 } 43 44 func executeMountProfileUpdate(upCtx MountProfileUpdateContext) error { 45 unlock, err := upCtx.Lock() 46 if err != nil { 47 return err 48 } 49 defer unlock() 50 51 desired, err := upCtx.LoadDesiredProfile() 52 if err != nil { 53 return err 54 } 55 56 currentBefore, err := upCtx.LoadCurrentProfile() 57 if err != nil { 58 return err 59 } 60 61 // Synthesize mount changes that were applied before for the purpose of the tmpfs detector. 62 as := upCtx.Assumptions() 63 for _, entry := range currentBefore.Entries { 64 as.AddChange(&Change{Action: Mount, Entry: entry}) 65 } 66 67 // Compute the needed changes and perform each change if 68 // needed, collecting those that we managed to perform or that 69 // were performed already. 70 changesNeeded := NeededChanges(currentBefore, desired) 71 72 var changesMade []*Change 73 for _, change := range changesNeeded { 74 synthesised, err := change.Perform(as) 75 changesMade = append(changesMade, synthesised...) 76 if err != nil { 77 // We may have done something even if Perform itself has 78 // failed. We need to collect synthesized changes and 79 // store them. 80 origin := change.Entry.XSnapdOrigin() 81 if origin == "layout" || origin == "overname" { 82 // TODO: convert the test to a method over origin. 83 return err 84 } else if err != ErrIgnoredMissingMount { 85 logger.Noticef("cannot change mount namespace according to change %s: %s", change, err) 86 } 87 continue 88 } 89 90 changesMade = append(changesMade, change) 91 } 92 93 // Compute the new current profile so that it contains only changes that were made 94 // and save it back for next runs. 95 var currentAfter osutil.MountProfile 96 for _, change := range changesMade { 97 if change.Action == Mount || change.Action == Keep { 98 currentAfter.Entries = append(currentAfter.Entries, change.Entry) 99 } 100 } 101 return upCtx.SaveCurrentProfile(¤tAfter) 102 }