github.com/rigado/snapd@v2.42.5-go-mod+incompatible/features/features.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2018 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 features 21 22 import ( 23 "fmt" 24 "path/filepath" 25 26 "github.com/snapcore/snapd/dirs" 27 "github.com/snapcore/snapd/osutil" 28 ) 29 30 // SnapdFeature is a named feature that may be on or off. 31 type SnapdFeature int 32 33 const ( 34 // Layouts controls availability of snap layouts. 35 Layouts SnapdFeature = iota 36 // ParallelInstances controls availability installing a snap multiple times. 37 ParallelInstances 38 // Hotplug controls availability of dynamically creating slots based on system hardware. 39 Hotplug 40 // SnapdSnap controls possibility of installing the snapd snap. 41 SnapdSnap 42 // PerUserMountNamespace controls the persistence of per-user mount namespaces. 43 PerUserMountNamespace 44 // RefreshAppAwareness controls refresh being aware of running applications. 45 RefreshAppAwareness 46 // RobustMountNamespaceUpdates controls how snap-update-ns updates existing mount namespaces. 47 RobustMountNamespaceUpdates 48 // lastFeature is the final known feature, it is only used for testing. 49 lastFeature 50 ) 51 52 // KnownFeatures returns the list of all known features. 53 func KnownFeatures() []SnapdFeature { 54 features := make([]SnapdFeature, int(lastFeature)) 55 for i := range features { 56 features[i] = SnapdFeature(i) 57 } 58 return features 59 } 60 61 // featureNames maps feature constant to stable string representation. 62 // The constants here must be synchronized with cmd/libsnap-confine-private/feature.c 63 var featureNames = map[SnapdFeature]string{ 64 Layouts: "layouts", 65 ParallelInstances: "parallel-instances", 66 Hotplug: "hotplug", 67 SnapdSnap: "snapd-snap", 68 PerUserMountNamespace: "per-user-mount-namespace", 69 RefreshAppAwareness: "refresh-app-awareness", 70 71 RobustMountNamespaceUpdates: "robust-mount-namespace-updates", 72 } 73 74 // featuresEnabledWhenUnset contains a set of features that are enabled when not explicitly configured. 75 var featuresEnabledWhenUnset = map[SnapdFeature]bool{ 76 Layouts: true, 77 } 78 79 // featuresExported contains a set of features that are exported outside of snapd. 80 var featuresExported = map[SnapdFeature]bool{ 81 PerUserMountNamespace: true, 82 RefreshAppAwareness: true, 83 ParallelInstances: true, 84 85 RobustMountNamespaceUpdates: true, 86 } 87 88 // String returns the name of a snapd feature. 89 // The function panics for bogus feature values. 90 func (f SnapdFeature) String() string { 91 if name, ok := featureNames[f]; ok { 92 return name 93 } 94 panic(fmt.Sprintf("unknown feature flag code %d", f)) 95 } 96 97 // IsEnabledWhenUnset returns true if a feature is enabled when not set. 98 // 99 // A feature may be enabled or disabled with explicit state in snapd. If 100 // explicit state is absent the effective value is the implicit default 101 // computed by this function. 102 func (f SnapdFeature) IsEnabledWhenUnset() bool { 103 return featuresEnabledWhenUnset[f] 104 } 105 106 // IsExported returns true if a feature is copied from snapd state to a feature file. 107 // 108 // Certain features are available outside of snapd internal state and visible as control 109 // files in a dedicated directory. Such features can be queried for, via IsEnabled, outside 110 // of snapd. 111 func (f SnapdFeature) IsExported() bool { 112 return featuresExported[f] 113 } 114 115 // ControlFile returns the path of the file controlling the exported feature. 116 // 117 // Snapd considers the feature enabled if the file is present. 118 // The contents of the file are not important. 119 // 120 // The function panics for features that are not exported. 121 func (f SnapdFeature) ControlFile() string { 122 if !f.IsExported() { 123 panic(fmt.Sprintf("cannot compute the control file of feature %q because that feature is not exported", f)) 124 } 125 return filepath.Join(dirs.FeaturesDir, f.String()) 126 } 127 128 // ConfigOption returns the snap name and configuration option associated with this feature. 129 func (f SnapdFeature) ConfigOption() (snapName, confName string) { 130 return "core", "experimental." + f.String() 131 } 132 133 // IsEnabled checks if a given exported snapd feature is enabled. 134 // 135 // The function panics for features that are not exported. 136 func (f SnapdFeature) IsEnabled() bool { 137 if !f.IsExported() { 138 panic(fmt.Sprintf("cannot check if feature %q is enabled because that feature is not exported", f)) 139 } 140 return osutil.FileExists(f.ControlFile()) 141 }