forked from snapcore/snapd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
userd.go
132 lines (112 loc) · 3.24 KB
/
userd.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
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 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 userd
import (
"fmt"
"github.com/godbus/dbus"
"github.com/godbus/dbus/introspect"
"gopkg.in/tomb.v2"
"github.com/snapcore/snapd/logger"
)
type dbusInterface interface {
Interface() string
ObjectPath() dbus.ObjectPath
IntrospectionData() string
}
type Userd struct {
tomb tomb.Tomb
conn *dbus.Conn
dbusIfaces []dbusInterface
}
// userdBusNames contains the list of bus names userd will acquire on
// the session bus. It is unnecessary (and undesirable) to add more
// names here when adding new interfaces to the daemon.
var userdBusNames = []string{
"io.snapcraft.Launcher",
"io.snapcraft.Settings",
}
func dbusSessionBus() (*dbus.Conn, error) {
// use a private connection to the session bus, this way we can manage
// its lifetime without worrying of breaking other code
conn, err := dbus.SessionBusPrivate()
if err != nil {
return nil, err
}
if err := conn.Auth(nil); err != nil {
conn.Close()
return nil, err
}
if err := conn.Hello(); err != nil {
conn.Close()
return nil, err
}
return conn, nil
}
func (ud *Userd) Init() error {
var err error
ud.conn, err = dbusSessionBus()
if err != nil {
return err
}
ud.dbusIfaces = []dbusInterface{
&Launcher{ud.conn},
&Settings{ud.conn},
}
for _, iface := range ud.dbusIfaces {
// export the interfaces at the godbus API level first to avoid
// the race between being able to handle a call to an interface
// at the object level and the actual well-known object name
// becoming available on the bus
xml := "<node>" + iface.IntrospectionData() + introspect.IntrospectDataString + "</node>"
ud.conn.Export(iface, iface.ObjectPath(), iface.Interface())
ud.conn.Export(introspect.Introspectable(xml), iface.ObjectPath(), "org.freedesktop.DBus.Introspectable")
}
for _, name := range userdBusNames {
// beyond this point the name is available and all handlers must
// have been set up
reply, err := ud.conn.RequestName(name, dbus.NameFlagDoNotQueue)
if err != nil {
return err
}
if reply != dbus.RequestNameReplyPrimaryOwner {
return fmt.Errorf("cannot obtain bus name '%s'", name)
}
}
return nil
}
func (ud *Userd) Start() {
logger.Noticef("Starting snap userd")
ud.tomb.Go(func() error {
// Listen to keep our thread up and running. All DBus bits
// are running in the background
<-ud.tomb.Dying()
ud.conn.Close()
err := ud.tomb.Err()
if err != nil && err != tomb.ErrStillAlive {
return err
}
return nil
})
}
func (ud *Userd) Stop() error {
ud.tomb.Kill(nil)
return ud.tomb.Wait()
}
func (ud *Userd) Dying() <-chan struct{} {
return ud.tomb.Dying()
}