github.com/rigado/snapd@v2.42.5-go-mod+incompatible/usersession/userd/helpers.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 "bufio" 24 "fmt" 25 "os" 26 "path/filepath" 27 "strings" 28 29 "github.com/godbus/dbus" 30 31 "github.com/snapcore/snapd/dirs" 32 ) 33 34 var snapFromSender = snapFromSenderImpl 35 36 func snapFromSenderImpl(conn *dbus.Conn, sender dbus.Sender) (string, error) { 37 pid, err := connectionPid(conn, sender) 38 if err != nil { 39 return "", fmt.Errorf("cannot get connection pid: %v", err) 40 } 41 snap, err := snapFromPid(pid) 42 if err != nil { 43 return "", fmt.Errorf("cannot find snap for connection: %v", err) 44 } 45 // Check that the sender is still connected to the bus: if it 46 // has disconnected between the GetConnectionUnixProcessID 47 // call and when we poked around in /proc, then it is possible 48 // that the process ID was reused. 49 if !nameHasOwner(conn, sender) { 50 return "", fmt.Errorf("sender is no longer connected to the bus") 51 } 52 return snap, nil 53 } 54 55 func connectionPid(conn *dbus.Conn, sender dbus.Sender) (pid int, err error) { 56 call := conn.BusObject().Call("org.freedesktop.DBus.GetConnectionUnixProcessID", 0, sender) 57 if call.Err != nil { 58 return 0, call.Err 59 } 60 call.Store(&pid) 61 return pid, nil 62 } 63 64 func nameHasOwner(conn *dbus.Conn, sender dbus.Sender) bool { 65 call := conn.BusObject().Call("org.freedesktop.DBus.NameHasOwner", 0, sender) 66 if call.Err != nil { 67 return false 68 } 69 var hasOwner bool 70 call.Store(&hasOwner) 71 return hasOwner 72 } 73 74 // FIXME: move to osutil? 75 func snapFromPid(pid int) (string, error) { 76 f, err := os.Open(fmt.Sprintf("%s/proc/%d/cgroup", dirs.GlobalRootDir, pid)) 77 if err != nil { 78 return "", err 79 } 80 defer f.Close() 81 82 scanner := bufio.NewScanner(f) 83 for scanner.Scan() { 84 // we need to find a string like: 85 // ... 86 // 7:freezer:/snap.hello-world 87 // ... 88 // See cgroup(7) for details about the /proc/[pid]/cgroup 89 // format. 90 l := strings.Split(scanner.Text(), ":") 91 if len(l) < 3 { 92 continue 93 } 94 controllerList := l[1] 95 cgroupPath := l[2] 96 if !strings.Contains(controllerList, "freezer") { 97 continue 98 } 99 if strings.HasPrefix(cgroupPath, "/snap.") { 100 snap := strings.SplitN(filepath.Base(cgroupPath), ".", 2)[1] 101 return snap, nil 102 } 103 } 104 if scanner.Err() != nil { 105 return "", scanner.Err() 106 } 107 108 return "", fmt.Errorf("cannot find a snap for pid %v", pid) 109 }