gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/builtin/gpio.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-2021 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 builtin 21 22 import ( 23 "fmt" 24 "os" 25 26 "gitee.com/mysnapcore/mysnapd/interfaces" 27 "gitee.com/mysnapcore/mysnapd/interfaces/apparmor" 28 "gitee.com/mysnapcore/mysnapd/interfaces/systemd" 29 "gitee.com/mysnapcore/mysnapd/logger" 30 "gitee.com/mysnapcore/mysnapd/snap" 31 ) 32 33 const gpioSummary = `allows access to specific GPIO pin` 34 35 const gpioBaseDeclarationSlots = ` 36 gpio: 37 allow-installation: 38 slot-snap-type: 39 - core 40 - gadget 41 deny-auto-connection: true 42 ` 43 44 var gpioSysfsGpioBase = "/sys/class/gpio/gpio" 45 46 // gpioInterface type 47 type gpioInterface struct{} 48 49 // String returns the same value as Name(). 50 func (iface *gpioInterface) String() string { 51 return iface.Name() 52 } 53 54 // Name of the gpioInterface 55 func (iface *gpioInterface) Name() string { 56 return "gpio" 57 } 58 59 func (iface *gpioInterface) StaticInfo() interfaces.StaticInfo { 60 return interfaces.StaticInfo{ 61 Summary: gpioSummary, 62 BaseDeclarationSlots: gpioBaseDeclarationSlots, 63 } 64 } 65 66 // BeforePrepareSlot checks the slot definition is valid 67 func (iface *gpioInterface) BeforePrepareSlot(slot *snap.SlotInfo) error { 68 // Must have a GPIO number 69 number, ok := slot.Attrs["number"] 70 if !ok { 71 return fmt.Errorf("gpio slot must have a number attribute") 72 } 73 74 // Valid values of number 75 if _, ok := number.(int64); !ok { 76 return fmt.Errorf("gpio slot number attribute must be an int") 77 } 78 79 // Slot is good 80 return nil 81 } 82 83 func (iface *gpioInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 84 var number int64 85 if err := slot.Attr("number", &number); err != nil { 86 return err 87 } 88 path := fmt.Sprint(gpioSysfsGpioBase, number) 89 // Entries in /sys/class/gpio for single GPIO's are just symlinks 90 // to their correct device part in the sysfs tree. Given AppArmor 91 // requires symlinks to be dereferenced, evaluate the GPIO 92 // path and add the correct absolute path to the AppArmor snippet. 93 dereferencedPath, err := evalSymlinks(path) 94 if err != nil && os.IsNotExist(err) { 95 // If the specific gpio is not available there is no point 96 // exporting it, we should also not fail because this 97 // will block snapd updates (LP: 1866424) 98 logger.Noticef("cannot export not existing gpio %s", path) 99 return nil 100 } 101 if err != nil { 102 return err 103 } 104 spec.AddSnippet(fmt.Sprintf("%s/* rwk,", dereferencedPath)) 105 return nil 106 } 107 108 func (iface *gpioInterface) SystemdConnectedSlot(spec *systemd.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 109 var gpioNum int64 110 if err := slot.Attr("number", &gpioNum); err != nil { 111 return err 112 } 113 114 serviceSuffix := fmt.Sprintf("gpio-%d", gpioNum) 115 service := &systemd.Service{ 116 Type: "oneshot", 117 RemainAfterExit: true, 118 ExecStart: fmt.Sprintf("/bin/sh -c 'test -e /sys/class/gpio/gpio%d || echo %d > /sys/class/gpio/export'", gpioNum, gpioNum), 119 ExecStop: fmt.Sprintf("/bin/sh -c 'test ! -e /sys/class/gpio/gpio%d || echo %d > /sys/class/gpio/unexport'", gpioNum, gpioNum), 120 } 121 return spec.AddService(serviceSuffix, service) 122 } 123 124 func (iface *gpioInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool { 125 // allow what declarations allowed 126 return true 127 } 128 129 func init() { 130 registerIface(&gpioInterface{}) 131 }