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  }