github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/usersession/userd/userd.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 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 userd 21 22 import ( 23 "fmt" 24 25 "github.com/godbus/dbus" 26 "github.com/godbus/dbus/introspect" 27 "gopkg.in/tomb.v2" 28 29 "github.com/snapcore/snapd/dbusutil" 30 "github.com/snapcore/snapd/logger" 31 ) 32 33 type dbusInterface interface { 34 Interface() string 35 ObjectPath() dbus.ObjectPath 36 IntrospectionData() string 37 } 38 39 type Userd struct { 40 tomb tomb.Tomb 41 conn *dbus.Conn 42 dbusIfaces []dbusInterface 43 } 44 45 // userdBusNames contains the list of bus names userd will acquire on 46 // the session bus. It is unnecessary (and undesirable) to add more 47 // names here when adding new interfaces to the daemon. 48 var userdBusNames = []string{ 49 "io.snapcraft.Launcher", 50 "io.snapcraft.Settings", 51 } 52 53 func (ud *Userd) Init() error { 54 var err error 55 56 ud.conn, err = dbusutil.SessionBusPrivate() 57 if err != nil { 58 return err 59 } 60 61 ud.dbusIfaces = []dbusInterface{ 62 &Launcher{ud.conn}, 63 &PrivilegedDesktopLauncher{ud.conn}, 64 &Settings{ud.conn}, 65 } 66 for _, iface := range ud.dbusIfaces { 67 // export the interfaces at the godbus API level first to avoid 68 // the race between being able to handle a call to an interface 69 // at the object level and the actual well-known object name 70 // becoming available on the bus 71 xml := "<node>" + iface.IntrospectionData() + introspect.IntrospectDataString + "</node>" 72 ud.conn.Export(iface, iface.ObjectPath(), iface.Interface()) 73 ud.conn.Export(introspect.Introspectable(xml), iface.ObjectPath(), "org.freedesktop.DBus.Introspectable") 74 75 } 76 77 for _, name := range userdBusNames { 78 // beyond this point the name is available and all handlers must 79 // have been set up 80 reply, err := ud.conn.RequestName(name, dbus.NameFlagDoNotQueue) 81 if err != nil { 82 return err 83 } 84 85 if reply != dbus.RequestNameReplyPrimaryOwner { 86 return fmt.Errorf("cannot obtain bus name '%s'", name) 87 } 88 } 89 return nil 90 } 91 92 func (ud *Userd) Start() { 93 logger.Noticef("Starting snap userd") 94 95 ud.tomb.Go(func() error { 96 // Listen to keep our thread up and running. All DBus bits 97 // are running in the background 98 <-ud.tomb.Dying() 99 ud.conn.Close() 100 101 err := ud.tomb.Err() 102 if err != nil && err != tomb.ErrStillAlive { 103 return err 104 } 105 return nil 106 }) 107 } 108 109 func (ud *Userd) Stop() error { 110 ud.tomb.Kill(nil) 111 return ud.tomb.Wait() 112 } 113 114 func (ud *Userd) Dying() <-chan struct{} { 115 return ud.tomb.Dying() 116 }