github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/polkit/pid_start_time.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 // +build linux 3 4 /* 5 * Copyright (C) 2017 Canonical Ltd 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 3 as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 package polkit 22 23 import ( 24 "fmt" 25 "io/ioutil" 26 "strconv" 27 "strings" 28 ) 29 30 // getStartTimeForPid determines the start time for a given process ID 31 func getStartTimeForPid(pid int32) (uint64, error) { 32 filename := fmt.Sprintf("/proc/%d/stat", pid) 33 return getStartTimeForProcStatFile(filename) 34 } 35 36 // getStartTimeForProcStatFile determines the start time from a process stat file 37 // 38 // The implementation is intended to be compatible with polkit: 39 // https://cgit.freedesktop.org/polkit/tree/src/polkit/polkitunixprocess.c 40 func getStartTimeForProcStatFile(filename string) (uint64, error) { 41 data, err := ioutil.ReadFile(filename) 42 if err != nil { 43 return 0, err 44 } 45 contents := string(data) 46 47 // start time is the token at index 19 after the '(process 48 // name)' entry - since only this field can contain the ')' 49 // character, search backwards for this to avoid malicious 50 // processes trying to fool us 51 // 52 // See proc(5) man page for a description of the 53 // /proc/[pid]/stat file format and the meaning of the 54 // starttime field. 55 idx := strings.IndexByte(contents, ')') 56 if idx < 0 { 57 return 0, fmt.Errorf("cannot parse %s", filename) 58 } 59 idx += 2 // skip ") " 60 if idx > len(contents) { 61 return 0, fmt.Errorf("cannot parse %s", filename) 62 } 63 tokens := strings.Split(contents[idx:], " ") 64 if len(tokens) < 20 { 65 return 0, fmt.Errorf("cannot parse %s", filename) 66 } 67 return strconv.ParseUint(tokens[19], 10, 64) 68 }