PFZheng / psutil

Automatically exported from code.google.com/p/psutil
Other
0 stars 0 forks source link

Get the Environment Settings of a running process as a dictionary. #247

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Proposal
Get the environment settings from the process if available.

On what platforms would this be available?
Linux/Solaris

Proposed API
It's a mess to accomplish this for both Linux and Solaris.  I am not going to 
propose api, but I will provide a 
basic starting point for anyone that is interested.  Linux is pretty easy to 
get this information, you just have 
to read the environ file from proc.  On Solaris it is similar, but you have to 
decode the structure of 
ps_info_t first.  I can not provide a complete implementation at this point in 
time, but I can share what I know.

Are there existent implementations we can use as an example?
Soon, email me for specifics justin<dot>venus<at>gmail<dot>com. Basic thoughts 
follow in code.

Linux skeleton:
    #this snippet works today and in my opinion should be the reference for any other implementation as far
    #as the data that is returned (dict).

    #where self.path is '/proc/%(SOMEPID)d'

    def readFile(self,f):
        return open('%s/%s' % (self.path,f)).read()

    def getEnv(self):
        """the environment settings from the processes perpective,
           @return C{dict}
        """
        env = {}
        try: envlist = self.readFile('environ').split('\000')
        except: return env
        for e in envlist:
            if '=' in e:
                k,v = e.split('=',1)
            else:
                k,v = e,''
            k,v = k.strip(),v.strip()
            if not k: continue
            env[k] = v
        return env

Solaris 10+ proc decoding.  Requires 'struct' module to read. 
self.mapProcFiles['psinfo'][6] contains the envp. 
We would still need to decode this structure further for it to be useful.

#the basic decoder that I have is really old and messy.
class SunDecoder(object):
    """This is an absolute mess and I apologize in advance."""
    def __init__(self):
        #format of time struct
        self._timeStruct = "@iL"
        #/usr/include/sys/procfs.h, defines these
        self._lwpsinfo_t = [
            "@iiIIcccchcciHH",
            self._timeStruct,
            self._timeStruct,
            "@iiii",
        ]
        self._pstatus_t = [
            "@iiiiiiiiiIiIi",
            self._timeStruct,
            self._timeStruct,
            self._timeStruct,
            self._timeStruct,
            "@iiiic",
            "@3c",              #padding skip
            "@iiii"
            "@15i",             #unused as of 20110214 - skip
#            self._lwpsinfo_t,  #i don't feel like implementing this
        ]
        self._psinfo_t = [
            "@iiiiiiiiiiIiiiIHH",
            self._timeStruct,
            self._timeStruct,
            self._timeStruct,
            "@16c",             #PRFNSZ = 16
            "@80c",             #PRARGSZ = 80
            "@iiIIc",
            "@3c",              #padding skip
            "@iiiiii",
#            "@2i",             #unused as of 20110214
#            self._lwpsinfo_t,  #i don't feel like implementing this
        ]

        #maps the structure of a procfile
        #status is readable by the owner
        #psinfo is world readable
        self.mapProcFiles = {
            'status': {
                 'T': self._pstatus_t,
                 0: None, #use psinfo ('flags','nlwp','pid','ppid','pgid','sid','aslwpid','agentid','sigpend', 'brkbase','brksize','stksize','stkbase'),
                 1: ('utime',),
                 2: ('stime',),
                 3: ('cutime',),
                 4: ('cstime',),
                 5: ('sigtrace','flttrace','sysentry','sysexit','dmodel'),
                 6: None,
                 7: None, #use psinfo ('taskid','projid','nzomb','zoneid'),
                 8: None,
            },
            'psinfo' : {
                 'T': self._psinfo_t,
                 0: ('flag','nlwp','pid','ppid','pgid','sid','uid','euid', \
                     'gid','egid','addr','size','rssize','pad1','ttydev', \
                     'pctcpu','pctmem'),
                 1: ('starttime',),
                 2: ('time',),
                 3: ('ctime',),
                 4: ('fname',),
                 5: ('cmdline',),
                 6: ('wstat','argc','argv','envp','dmodel'),
                 7: None,
                 8: ('taskid','projid','nzomb','poolid','zoneid','contract')
            }
        }

    def readFile(self,f):
        if f in self.mapProcFiles:
            return self.__decode_struct(f)
        return open('%s/%s' % (self.path,f)).read()

    def __decode_struct(self, filename):
        """I hate this method!!!, it is a disaster but it will brute force through the structured files
        """
        stat = {}
        T = None
        MagicDecoderRing = self.mapProcFiles[filename]
        try:
            statusFile = open(self.path+'/'+filename)
            for i in _range(0,len(MagicDecoderRing['T'])):
                size_t = struct.calcsize(MagicDecoderRing['T'][i])
                T = struct.unpack(MagicDecoderRing['T'][i],statusFile.read(size_t))
                #None represents padding and should be skipped 
                if MagicDecoderRing[i] is not None:
                    #items with one to one attributes
                    if len(T) == len(MagicDecoderRing[i]):
                        for x in _range(0,len(T)):
                            stat[MagicDecoderRing[i][x]] = T[x]
                    #timestruc_t items below here
                    elif type(T[0]) is int:
                        stat[MagicDecoderRing[i]] = self._nanosec2dec(T)
                    #must be a string ... err character array
                    elif type(T[0]) is str:
                        #worst list comprehension ever!!!!
                        stat[MagicDecoderRing[i]] = \
                                [b for b in ' '.join([a for a in \
                                ''.join(list(T)).split('\x00') \
                                if a != '']).split(' ') if b != '']
            statusFile.close()
        except: pass
        return stat

    def _nanosec2dec(self, timetup=(0,0)):
        return timetup[0]+timetup[1]*0.000000001

Please provide any additional information below.
I am willing to help answer questions, but I have limited time to devote to 
coding this up.

Original issue reported on code.google.com by justin.v...@gmail.com on 24 Jan 2012 at 8:42

GoogleCodeExporter commented 9 years ago
This is already tracked as issue 52.
Process environment variables are pretty hard to get though, and the only 
platform where this is actually simple to retrieve is Linux.
We have a rough idea on how to do this on FreeBSD and Windows but we haven't 
actually looked into it yet.
No idea about OSX.

Solaris is currently not supported, see:
http://code.google.com/p/psutil/issues/detail?id=18
https://groups.google.com/forum/#!searchin/psutil/solaris/psutil/3FhRqDrnjjE/JwF
cOfx1PAkJ
https://groups.google.com/forum/#!searchin/psutil/solaris/psutil/_Zsa3GmilNg/u9K
B7gSSKIEJ

I'm closing this out as duplicate of issue 52. Let's continue the discussion 
there.

Original comment by g.rodola on 24 Jan 2012 at 9:23