github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/overlord/ifacestate/implicit.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2017 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 ifacestate
    21  
    22  import (
    23  	"fmt"
    24  
    25  	"github.com/snapcore/snapd/interfaces"
    26  	"github.com/snapcore/snapd/interfaces/builtin"
    27  	"github.com/snapcore/snapd/overlord/state"
    28  	"github.com/snapcore/snapd/release"
    29  	"github.com/snapcore/snapd/snap"
    30  )
    31  
    32  func shouldSnapdHostImplicitSlots(mapper SnapMapper) bool {
    33  	_, ok := mapper.(*CoreSnapdSystemMapper)
    34  	return ok
    35  }
    36  
    37  // addImplicitSlots adds implicitly defined slots and hotplug slots to a given snap.
    38  //
    39  // Only the OS snap has implicit and hotplug slots.
    40  //
    41  // It is assumed that slots have names matching the interface name. Existing
    42  // slots are not changed, only missing slots are added.
    43  func addImplicitSlots(st *state.State, snapInfo *snap.Info) error {
    44  	// Implicit slots can be added to the special "snapd" snap or to snaps with
    45  	// type "os". Currently there are no other snaps that gain implicit
    46  	// interfaces.
    47  	if snapInfo.Type() != snap.TypeOS && snapInfo.Type() != snap.TypeSnapd {
    48  		return nil
    49  	}
    50  
    51  	// If the manager has chosen to put implicit slots on the "snapd" snap
    52  	// then stop adding them to any other core snaps.
    53  	if shouldSnapdHostImplicitSlots(mapper) && snapInfo.Type() != snap.TypeSnapd {
    54  		return nil
    55  	}
    56  
    57  	hotplugSlots, err := getHotplugSlots(st)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	// Ask each interface if it wants to be implicitly added.
    63  	for _, iface := range builtin.Interfaces() {
    64  		si := interfaces.StaticInfoOf(iface)
    65  		if (release.OnClassic && si.ImplicitOnClassic) || (!release.OnClassic && si.ImplicitOnCore) {
    66  			ifaceName := iface.Name()
    67  			if _, ok := snapInfo.Slots[ifaceName]; !ok {
    68  				snapInfo.Slots[ifaceName] = makeImplicitSlot(snapInfo, ifaceName)
    69  			}
    70  		}
    71  	}
    72  
    73  	// Add hotplug slots
    74  	for _, hslotInfo := range hotplugSlots {
    75  		if _, ok := snapInfo.Slots[hslotInfo.Name]; ok {
    76  			return fmt.Errorf("cannot add hotplug slot %s: slot already exists", hslotInfo.Name)
    77  		}
    78  		if hslotInfo.HotplugGone {
    79  			continue
    80  		}
    81  		snapInfo.Slots[hslotInfo.Name] = &snap.SlotInfo{
    82  			Name:       hslotInfo.Name,
    83  			Snap:       snapInfo,
    84  			Interface:  hslotInfo.Interface,
    85  			Attrs:      hslotInfo.StaticAttrs,
    86  			HotplugKey: hslotInfo.HotplugKey,
    87  		}
    88  	}
    89  
    90  	return nil
    91  }
    92  
    93  func makeImplicitSlot(snapInfo *snap.Info, ifaceName string) *snap.SlotInfo {
    94  	return &snap.SlotInfo{
    95  		Name:      ifaceName,
    96  		Snap:      snapInfo,
    97  		Interface: ifaceName,
    98  	}
    99  }