github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/cmd/snaplock/runinhibit/inhibit.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 runinhibit contains operations for establishing, removing and 21 // querying snap run inhibition lock. 22 package runinhibit 23 24 import ( 25 "fmt" 26 "io/ioutil" 27 "os" 28 "path/filepath" 29 30 "github.com/snapcore/snapd/dirs" 31 "github.com/snapcore/snapd/osutil" 32 ) 33 34 // defaultInhibitDir is the directory where inhibition files are stored. 35 const defaultInhibitDir = "/var/lib/snapd/inhibit" 36 37 // InhibitDir is the directory where inhibition files are stored. 38 // This value can be changed by calling dirs.SetRootDir. 39 var InhibitDir = defaultInhibitDir 40 41 func init() { 42 dirs.AddRootDirCallback(func(root string) { 43 InhibitDir = filepath.Join(root, defaultInhibitDir) 44 }) 45 } 46 47 // Hint is a string representing reason for the inhibition of "snap run". 48 type Hint string 49 50 const ( 51 // HintNotInhibited is used when "snap run" is not inhibited. 52 HintNotInhibited Hint = "" 53 // HintInhibitedForRefresh represents inhibition of a "snap run" while a refresh change is being performed. 54 HintInhibitedForRefresh Hint = "refresh" 55 ) 56 57 func openHintFileLock(snapName string) (*osutil.FileLock, error) { 58 fname := filepath.Join(InhibitDir, snapName+".lock") 59 return osutil.NewFileLockWithMode(fname, 0644) 60 } 61 62 // LockWithHint sets a persistent "snap run" inhibition lock, for the given snap, with a given hint. 63 // 64 // The hint cannot be empty. It should be one of the Hint constants defined in 65 // this package. With the hint in place "snap run" will not allow the snap to 66 // start and will block, presenting a user interface if possible. 67 func LockWithHint(snapName string, hint Hint) error { 68 if len(hint) == 0 { 69 return fmt.Errorf("lock hint cannot be empty") 70 } 71 if err := os.MkdirAll(InhibitDir, 0755); err != nil { 72 return err 73 } 74 flock, err := openHintFileLock(snapName) 75 if err != nil { 76 return err 77 } 78 defer flock.Close() 79 80 if err := flock.Lock(); err != nil { 81 return err 82 } 83 f := flock.File() 84 if err := f.Truncate(0); err != nil { 85 return err 86 } 87 _, err = f.WriteString(string(hint)) 88 return err 89 } 90 91 // Unlock truncates the run inhibition lock, for the given snap. 92 // 93 // An empty inhibition lock means uninhibited "snap run". 94 func Unlock(snapName string) error { 95 flock, err := openHintFileLock(snapName) 96 if os.IsNotExist(err) { 97 return nil 98 } 99 if err != nil { 100 return err 101 } 102 defer flock.Close() 103 104 if err := flock.Lock(); err != nil { 105 return err 106 } 107 f := flock.File() 108 return f.Truncate(0) 109 } 110 111 // IsLocked returns the state of the run inhibition lock for the given snap. 112 // 113 // It returns the current, non-empty hit if inhibition is in place. Otherwise 114 // it returns an empty hint. 115 func IsLocked(snapName string) (Hint, error) { 116 fname := filepath.Join(InhibitDir, snapName+".lock") 117 flock, err := osutil.OpenExistingLockForReading(fname) 118 if os.IsNotExist(err) { 119 return "", nil 120 } 121 if err != nil { 122 return "", err 123 } 124 defer flock.Close() 125 126 if err := flock.ReadLock(); err != nil { 127 return "", err 128 } 129 130 buf, err := ioutil.ReadAll(flock.File()) 131 if err != nil { 132 return "", err 133 } 134 return Hint(string(buf)), nil 135 }