/
iio.go
151 lines (124 loc) · 4.65 KB
/
iio.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2016-2017 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package builtin
import (
"fmt"
"path/filepath"
"regexp"
"strings"
"github.com/snapcore/snapd/interfaces"
"github.com/snapcore/snapd/interfaces/apparmor"
"github.com/snapcore/snapd/interfaces/udev"
"github.com/snapcore/snapd/snap"
)
const iioSummary = `allows access to a specific IIO device`
const iioBaseDeclarationSlots = `
iio:
allow-installation:
slot-snap-type:
- gadget
- core
deny-auto-connection: true
`
const iioConnectedPlugAppArmor = `
# Description: Give access to a specific IIO device on the system.
###IIO_DEVICE_PATH### rw,
/sys/bus/iio/devices/###IIO_DEVICE_NAME###/ r,
/sys/bus/iio/devices/###IIO_DEVICE_NAME###/** rwk,
`
// The type for iio interface
type iioInterface struct{}
// Getter for the name of the iio interface
func (iface *iioInterface) Name() string {
return "iio"
}
func (iface *iioInterface) StaticInfo() interfaces.StaticInfo {
return interfaces.StaticInfo{
Summary: iioSummary,
BaseDeclarationSlots: iioBaseDeclarationSlots,
}
}
func (iface *iioInterface) String() string {
return iface.Name()
}
// Pattern to match allowed iio device nodes. It is going to be used to check the
// validity of the path attributes in case the udev is not used for
// identification
var iioControlDeviceNodePattern = regexp.MustCompile("^/dev/iio:device[0-9]+$")
// Check validity of the defined slot
func (iface *iioInterface) BeforePrepareSlot(slot *snap.SlotInfo) error {
// Validate the path
path, ok := slot.Attrs["path"].(string)
if !ok || path == "" {
return fmt.Errorf("%s slot must have a path attribute", iface.Name())
}
// XXX: this interface feeds the cleaned path into the regex and is
// left unchanged here for historical reasons. New interfaces (eg,
// like raw-volume) should instead use verifySlotPathAttribute() which
// performs additional verification.
path = filepath.Clean(path)
if !iioControlDeviceNodePattern.MatchString(path) {
return fmt.Errorf("%s path attribute must be a valid device node", iface.Name())
}
return nil
}
func (iface *iioInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
var path string
if err := slot.Attr("path", &path); err != nil {
return nil
}
cleanedPath := filepath.Clean(path)
snippet := strings.Replace(iioConnectedPlugAppArmor, "###IIO_DEVICE_PATH###", cleanedPath, -1)
// The path is already verified against a regular expression
// in BeforePrepareSlot so we can rely on its structure here and
// safely strip the '/dev/' prefix to get the actual name of
// the IIO device.
deviceName := strings.TrimPrefix(path, "/dev/")
snippet = strings.Replace(snippet, "###IIO_DEVICE_NAME###", deviceName, -1)
// Add a snippet for various device specific rules, except for sysfs write
// access that are specialized below.
spec.AddSnippet(snippet)
// Because all deviceName values have the prefix of "iio:device" enforced
// by the sanitization logic above, we can trim that prefix and provide a
// shorter expansion expression.
deviceNum := strings.TrimPrefix(deviceName, "iio:device")
// Use parametric snippets to avoid parser slowdown.
spec.AddParametricSnippet([]string{
"/sys/devices/**/iio:device" /* ###PARAM### */, "/** rwk, # Add any condensed parametric rules",
}, deviceNum)
// For consistency, not an efficiency problem.
spec.AddParametricSnippet([]string{
"/sys/devices/**/iio:device" /* ###PARAM### */, "/ r, # Add any condensed parametric rules",
}, deviceNum)
return nil
}
func (iface *iioInterface) UDevConnectedPlug(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
var path string
if err := slot.Attr("path", &path); err != nil {
return nil
}
spec.TagDevice(fmt.Sprintf(`KERNEL=="%s"`, strings.TrimPrefix(path, "/dev/")))
return nil
}
func (iface *iioInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool {
// Allow what is allowed in the declarations
return true
}
func init() {
registerIface(&iioInterface{})
}