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  }