gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/builtin/pwm.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 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 // https://www.kernel.org/doc/Documentation/pwm.txt 34 const pwmSummary = `allows access to specific PWM channel` 35 36 const pwmBaseDeclarationSlots = ` 37 pwm: 38 allow-installation: 39 slot-snap-type: 40 - core 41 - gadget 42 deny-auto-connection: true 43 ` 44 45 var pwmSysfsPwmChipBase = "/sys/class/pwm/pwmchip%d" 46 47 // pwmInterface type 48 type pwmInterface struct { 49 commonInterface 50 } 51 52 // BeforePrepareSlot checks the slot definition is valid 53 func (iface *pwmInterface) BeforePrepareSlot(slot *snap.SlotInfo) error { 54 // must have a PWM channel 55 channel, ok := slot.Attrs["channel"] 56 if !ok { 57 return fmt.Errorf("pwm slot must have a channel attribute") 58 } 59 60 // valid values of channel 61 if _, ok := channel.(int64); !ok { 62 return fmt.Errorf("pwm slot channel attribute must be an int") 63 } 64 65 // must have a PWM chip number 66 chipNum, ok := slot.Attrs["chip-number"] 67 if !ok { 68 return fmt.Errorf("pwm slot must have a chip-number attribute") 69 } 70 71 // valid values of chip number 72 if _, ok := chipNum.(int64); !ok { 73 return fmt.Errorf("pwm slot chip-number attribute must be an int") 74 } 75 76 // slot is good 77 return nil 78 } 79 80 func (iface *pwmInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 81 var chipNum int64 82 if err := slot.Attr("chip-number", &chipNum); err != nil { 83 return err 84 } 85 86 var channel int64 87 if err := slot.Attr("channel", &channel); err != nil { 88 return err 89 } 90 path := fmt.Sprintf(pwmSysfsPwmChipBase, chipNum) 91 // Entries in /sys/class/pwm for PWM chips are just symlinks 92 // to their correct device part in the sysfs tree. Given AppArmor 93 // requires symlinks to be dereferenced, evaluate the PWM 94 // path and add the correct absolute path to the AppArmor snippet. 95 dereferencedPath, err := evalSymlinks(path) 96 if err != nil && os.IsNotExist(err) { 97 // If the specific pwm is not available there is no point 98 // exporting it, we should also not fail because this 99 // will block snapd updates (LP: 1866424) 100 logger.Noticef("cannot find not existing pwm chipbase %s", path) 101 return nil 102 } 103 if err != nil { 104 return err 105 } 106 spec.AddSnippet(fmt.Sprintf("%s/pwm%d/* rwk,", dereferencedPath, channel)) 107 return nil 108 } 109 110 func (iface *pwmInterface) SystemdConnectedSlot(spec *systemd.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 111 var chipNum int64 112 if err := slot.Attr("chip-number", &chipNum); err != nil { 113 return err 114 } 115 116 var channel int64 117 if err := slot.Attr("channel", &channel); err != nil { 118 return err 119 } 120 121 serviceSuffix := fmt.Sprintf("pwmchip%d-pwm%d", chipNum, channel) 122 service := &systemd.Service{ 123 Type: "oneshot", 124 RemainAfterExit: true, 125 ExecStart: fmt.Sprintf("/bin/sh -c 'test -e /sys/class/pwm/pwmchip%[1]d/pwm%[2]d || echo %[2]d > /sys/class/pwm/pwmchip%[1]d/export'", chipNum, channel), 126 ExecStop: fmt.Sprintf("/bin/sh -c 'test ! -e /sys/class/pwm/pwmchip%[1]d/pwm%[2]d || echo %[2]d > /sys/class/pwm/pwmchip%[1]d/unexport'", chipNum, channel), 127 } 128 return spec.AddService(serviceSuffix, service) 129 } 130 131 func (iface *pwmInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool { 132 // allow what declarations allowed 133 return true 134 } 135 136 func init() { 137 registerIface(&pwmInterface{commonInterface{ 138 name: "pwm", 139 summary: pwmSummary, 140 baseDeclarationSlots: pwmBaseDeclarationSlots, 141 }}) 142 }