File: processinfo.py

package info (click to toggle)
update-manager 0.200.5-2.1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 5,900 kB
  • sloc: python: 4,557; xml: 1,571; makefile: 103; sh: 71
file content (110 lines) | stat: -rw-r--r-- 3,353 bytes parent folder | download | duplicates (2)
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
# UpdateManager/Util/processinfo.py
#
#  Copyright (c) 2009 Canonical
#                2009 Stephan Peijnik
#
#  Author: Stephan Peijnik <debian@sp.or.at>
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation; either version 2 of the
#  License, or (at your option) any later version.
#
#  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, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
#  USA.

import logging
import os

LOG = logging.getLogger('UpdateManager.Util.procesinfo')

class ProcessInfo(object):
    """ Process info representation """
    def __init__(self, pid):
        assert(type(pid) == int)
        self._pid = pid
        self._owner_uid = None
        self._parent_pid = None
        self._name = None
        self._parent = None
        self._ready = False
        self.__read_info()

    def __read_info(self):
        """ Reads the process info from /proc/<pid>/status """
        path = os.path.join('/proc/', str(self._pid), 'status')
        assert(os.path.exists(path))
        try:
            fp = open(path, 'r')
            for line in fp.readlines():
                data = line.strip().split('\t')
                name = data[0]
                if name == 'PPid:':
                    self._parent_pid = int(data[1])
                elif name == 'Uid:':
                    self._owner_uid = int(data[1])
                    # TODO: What can we use data[2:] for? What does it mean?
                elif name == 'Name:':
                    self._name = data[1]
                    
            fp.close()
        except IOError, e:
            LOG.error('IO Error occured: %s', e)

    @property
    def parent(self):
        """ Parent ProcessInfo object """
        if self._parent is not None:
            return self._parent

        if self._parent_pid != 0:
            self._parent = ProcessInfo(self._parent_pid)
        return self._parent

    @property
    def pid(self):
        """ Process ID """
        return self._pid

    @property
    def owner_uid(self):
        """ Process owner UID """
        return self._owner_uid

    @property
    def name(self):
        """ Process name """
        return self._name

    def __repr__(self):
        return '<ProcessInfo(pid=%d, name=%s, owner_uid=%s, parent_pid=%s)' %\
               (self._pid, self._name, self._owner_uid, self._parent_pid)

def find_nonroot_parent():
    """
    Finds the first parent process that is not owned by root, starting
    at the current process.

    :returns: :class:`ProcessInfo` object or None
    """
    my_pid = os.getpid()
    my_proc = ProcessInfo(my_pid)
    if my_proc.owner_uid != 0:
        return my_proc

    parent_proc = my_proc.parent
    while parent_proc:
        LOG.debug('Proc: %r', parent_proc)
        if parent_proc.owner_uid != 0:
            break

        parent_proc = parent_proc.parent

    return parent_proc