Kerala Cyber Warriors
KCW Uploader V1.1

Path : /proc/thread-self/root/sbin/
File Upload :
Current File : //proc/thread-self/root/sbin/checkrestart

#!/usr/bin/python3

# Copyright (C) 2001 Matt Zimmerman <mdz@debian.org>
# Copyright (C) 2007,2010-2015 Javier Fernandez-Sanguino <jfs@debian.org>
# - included patch from Justin Pryzby <justinpryzby_AT_users.sourceforge.net>
#   to work with the latest Lsof - modify to reduce false positives by not
#   complaining about deleted inodes/files under /tmp/, /var/log/,
#   /var/run or named   /SYSV.
# - introduced a verbose option

# PENDING:
# - included code from 'psdel' contributed by Sam Morris <sam_AT_robots.org.uk> to
#   make the program work even if lsof is not installed
#   (available at https://robots.org.uk/src/psdel)
# - make it work with a whitelist of directories instead of a blacklist
#   (might make it less false positive prone)
#
#
# 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, 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
#
# On Debian systems, a copy of the GNU General Public License may be
# found in /usr/share/common-licenses/GPL.

import sys
import os, errno
import re
import pwd
import sys
import string
import subprocess
import getopt
from stat import *

def checkroot():
    if os.getuid() != 0:
        sys.stderr.write('ERROR: This program must be run as root in order to obtain information\n')
        sys.stderr.write('about all open file descriptors in the system.\n')
        sys.exit(1)

def find_cmd(cmd):
     dirs = [ '/', '/usr/', '/usr/local/', sys.prefix ]
     for d in dirs:
         for sd in ('bin', 'sbin'):
             location = os.path.join(d, sd, cmd)
             if os.path.exists(location):
                 return location
     return False

def checksystemd():
# Check if systemd is installed in the system
    if os.path.exists('/bin/systemd'):
        return 0
    return 1

def usage():
    sys.stderr.write('usage: checkrestart [-vhpam] [ -b blacklist_file ] [ -i package_name ] [ -e pid ]\n')

def main():
    global lc_all_c_env, file_query_check
    process = None
    toRestart = {}

    lc_all_c_env = os.environ
    lc_all_c_env['LC_ALL'] = 'C'
    file_query_check = {}
    is_systemd = False
    useLsof = True
    blacklistFiles = []
    blacklist = []
    ignorelist = [ 'screen', 'systemd', 'dbus' ]
    excludepidlist = []

# Process options
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hvpamb:i:ne:t", ["help", "verbose", "packages", "all", "machine", "blacklist", "ignore", "nolsof", "excludepid", "terse"])
    except getopt.GetoptError as err:
        # print help information and exit:
        print(err) # will print something like "option -x not recognized"
        usage()
        sys.exit(2)

    # Global variables set through the command line
    global verbose, onlyPackageFiles, allFiles
    verbose = False
    # Only look for deleted files that belong to packages
    onlyPackageFiles = False
    # Look for any deleted file
    allFiles = False
    # Generate terse output, disabled by default
    terseOutput = False
    # Generate machine parsable output, disabled by default
    machineOutput = False

    for o, a in opts:
        if o in ("-v", "--verbose"):
            verbose = True
        elif o in ("-h", "--help"):
            usage()
            sys.exit()
        elif o in ("-p", "--packages"):
            onlyPackageFiles = True
        elif o in ("-a", "--all"):
            allFiles = True
            onlyPackageFiles = False
        elif o in ("-e", "--excludepid"):
            excludepidlist.append(a)
        elif o in ("-m", "--machine"):
            machineOutput = True
        elif o in ("-b", "--blacklist"):
            blacklistFiles.append(a)
            onlyPackageFiles = False
        elif o in ("-i", "--ignore"):
            ignorelist.append(a)
        elif o in ("-n", "--nolsof"):
            useLsof = False
        elif o in ("-t", "--terse"):
            terseOutput = True
        else:
            assert False, "unhandled option"

    checkroot()

    for f in blacklistFiles:
        blacklistFile = open(f, 'r')
        for line in blacklistFile.readlines():
            if line.startswith("#"):
                continue
            blacklist.append(re.compile(line.strip()))
        blacklistFile.close()

# Start checking

    if checksystemd() == 0:
        is_systemd = True

#    if find_cmd('lsof') == 1:
#        sys.stderr.write('ERROR: This program needs lsof in order to run.\n')
#        sys.stderr.write('Please install the lsof package in your system.\n')
#        sys.exit(1)
# Check if we have lsof, if not, use an alternative mechanism
    if not find_cmd('lsof') or not useLsof:
        if verbose and not find_cmd('lsof'):
                print("[DEBUG] Lsof is not available in the system. Using alternative mechanism.")
        toRestart = procfilescheck(blacklist = blacklist, excludepidlist = excludepidlist)
    else:
        toRestart = lsoffilescheck(blacklist = blacklist)

    if terseOutput:
    # Terse output and exit
    # Use Nagios exit codes: 0 OK, 1 warning, 2 critical, 3 unknown
    # we only care for 0 or 1
        if len(toRestart):
            print("%d processes using old versions of upgraded files" % len(toRestart))
            sys.exit(1) 
        # Exit with no error if there is nothing to restart
        print("No processes found using old versions of upgraded files")
        sys.exit(0)

    if not machineOutput:
        print("Found %d processes using old versions of upgraded files" % len(toRestart))
    else:
        print("PROCESSES: %d" % len(toRestart))

    if len(toRestart) == 0:
        sys.exit(0)

    programs = {}
    for process in toRestart:
        programs.setdefault(process.program, [])
        programs[process.program].append(process)

    if not machineOutput:
        if len(programs) == 1:
            print("(%d distinct program)" % len(programs))
        else:
            print("(%d distinct programs)" % len(programs))
    else:
        print("PROGRAMS: %d" % len(programs))
        

#services Verbose information
    if verbose:
        for process in toRestart:
            if not machineOutput:
                print("[DEBUG] Process %s (PID: %d) "  % (process.program, process.pid))
                process.listDeleted()
            else:
                process.listDeletedMachine()

    packages = {}
    diverted = None

    dpkgQuery = ["dpkg-query", "--search"] + list(programs.keys())
    if verbose:
        print("[DEBUG] Running: %s" % ' '.join(dpkgQuery))
    dpkgProc = subprocess.Popen(dpkgQuery, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                env = lc_all_c_env)
    while True:
            line = dpkgProc.stdout.readline().decode("utf-8")
            if not line:
                break
            if verbose:
                print("[DEBUG] Reading line from dpkg-query: %s" % line)
            if line.startswith('local diversion'):
                continue
            if not ':' in line:
                continue

            m = re.match('^diversion by (\S+) (from|to): (.*)$', line)
            if m:
                if m.group(2) == 'from':
                    diverted = m.group(3)
                    continue
                if not diverted:
                    raise Exception('Weird error while handling diversion')
                packagename, program = m.group(1), diverted
            else:
                 packagename, program = line[:-1].split(': ')
                 if program == diverted:
                     # dpkg prints a summary line after the diversion, name both
                     # packages of the diversion, so ignore this line
                     # mutt-patched, mutt: /usr/bin/mutt
                    continue
            packages.setdefault(packagename,Package(packagename))
            try:
                 packages[packagename].processes.extend(programs[program])
                 if verbose:
                    print("[DEBUG] Found package %s for program %s" % (packagename, program))
            except KeyError:
                  sys.stderr.write ('checkrestart (program not found): %s: %s\n' % (packagename, program))
            sys.stdout.flush()

    # Close the pipe
    dpkgProc.stdout.close()

    # Remove the ignored packages from the list of packages
    if ignorelist:
        for i in ignorelist:
            if i in packages:
                if verbose:
                   print("[DEBUG] Removing %s from the package list (ignored)" % (i))
                try:
                    del packages[i]
                except KeyError:
                    continue

    if not machineOutput:
        print("(%d distinct packages)" % len(packages))
    else:
        print("PACKAGES: %d" % len(packages))
        

    if len(packages) == 0:
        if not machineOutput:
            print("No packages seem to need to be restarted.")
            print("(please read checkrestart(1))")
        sys.exit(0)

    for package in list(packages.values()):
        dpkgQuery = ["dpkg-query", "--listfiles", package.name]
        if verbose:
            print("[DEBUG] Running: %s" % ' '.join(dpkgQuery))
        dpkgProc = subprocess.Popen(dpkgQuery, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
                                env = lc_all_c_env)
        while True:
            line = dpkgProc.stdout.readline().decode("utf-8")
            if not line:
                break
            path = line[:-1]
            if path.startswith('/etc/init.d/'):
                if path.endswith('.sh'):
                    continue
                package.initscripts.add(path[12:])
            # If running on a systemd system, extract the systemd's service files from the package
            if is_systemd and path.startswith('/lib/systemd/system/') and path.endswith('.service') and path.find('.wants') == -1:
            # Read the service file and make sure it is not of type 'oneshot'
                servicefile = open (path)
                is_oneshot = False
                for line in servicefile.readlines():
                     if line.find ('Type=oneshot') > 0:
                         is_oneshot = True
                         continue
                servicefile.close ()
                if not is_oneshot:
                    package.systemdservice.add(path[20:])
            sys.stdout.flush()
        dpkgProc.stdout.close()

        # Alternatively, find init.d scripts that match the process name
        if len(package.initscripts) == 0 and len(package.systemdservice) == 0:
            for process in package.processes:
                proc_name = os.path.basename(process.program)
                if os.path.exists('/etc/init.d/' + proc_name):
                    package.initscripts.add(proc_name)

    restartable = []
    nonrestartable = []
    restartInitCommands = []
    restartServiceCommands = []
    for package in list(packages.values()):
        if len(package.initscripts) > 0:
            restartable.append(package)
            restartInitCommands.extend(['service ' + s + ' restart' for s in package.initscripts])
        elif len(package.systemdservice) > 0:
            restartable.append(package)
            restartServiceCommands.extend(['systemctl restart ' + s for s in package.systemdservice])
        else:
            nonrestartable.append(package)

    if len(restartable) > 0:
        if not machineOutput:
            print()
            print("Of these, %d seem to contain systemd service definitions or init scripts which can be used to restart them." % len(restartable))
            # TODO - consider putting this in a --verbose option
            print("The following packages seem to have definitions that could be used\nto restart their services:")
            for package in restartable:
                print(package.name + ':')
                for process in package.processes:
                    print("\t%s\t%s" % (process.pid,process.program))

            if len(restartServiceCommands)>0:
                print()
                print("These are the systemd services:")
                print('\n'.join(restartServiceCommands))
                print()

            if len(restartInitCommands)>0:
                print("These are the initd scripts:")
                print('\n'.join(restartInitCommands))
                print()
        else:
            for package in restartable:
                for process in package.processes:
                    print('SERVICE:%s,%s,%s' % (package.name, process.pid,process.program))

    if len(nonrestartable) == 0:
        sys.exit(0)

    # TODO - consider putting this in a --verbose option
    if not machineOutput:
        print("These processes (%d) do not seem to have an associated init script to restart them:" %len(nonrestartable))
    for package in nonrestartable:
        if not machineOutput:
            print(package.name + ':')
            for process in package.processes:
                print("\t%s\t%s" % (process.pid,process.program))
        else:
            for process in package.processes:
                print('OTHER:%s,%s,%s' % (package.name,process.pid,process.program))


def lsoffilescheck(blacklist = None):
# Use LSOF to extract the list of deleted files
    from subprocess import check_output
    processes = {}

    for line in check_output(['lsof', '+XL', '-F', 'nf']).decode(errors="ignore").splitlines():
        field, data = line[0], line[1:]

        if field == 'p':
            process = processes.setdefault(data,Process(int(data)))
        elif field == 'k':
            process.links.append(data)
        elif field == 'n':
            # Remove the previous entry to check if this is something we should use
            if data.find('SYSV') >= 0:
                # If we find SYSV we discard the previous descriptor
                last = process.descriptors.pop()
            elif data.startswith('/') or data.startswith('(deleted)/') or data.startswith(' (deleted)/'):
                last = process.descriptors.pop()

                # If the data starts with (deleted) put it in the end of the
                # file name, this is used to workaround different behaviour in
                # OpenVZ systems, see
                # https://bugzilla.openvz.org/show_bug.cgi?id=2932
                if data.startswith('(deleted)'):
                    data = data[9:] + ' (deleted)'
                elif data.startswith(' (deleted)'):
                    data = data[10:] + ' (deleted)'

                # Add it to the list of deleted files if the previous descriptor
                # was DEL or lsof marks it as deleted
                if re.compile("DEL").search(last) or re.compile("\(deleted\)").search(data) or re.compile("\(path inode=[0-9]+\)$").search(data):
                    process.files.append(data)
            else:
                # We discard the previous descriptors and drop it
                last = process.descriptors.pop()
        elif field == 'f':
            # Save the descriptor for later comparison
            process.descriptors.append(data)

    toRestart = [process for process in list(processes.values()) if process.needsRestart(blacklist)]
    return toRestart

def procfilescheck(blacklist = None, excludepidlist = None):
# Use the underlying /proc file system to determine processes that
# are using deleted files
    from subprocess import check_output
    processes = {}
    # Get a list of running processes
    pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]

    for pid in pids:
        if pid in excludepidlist:
            continue

        # Get the list of open files for this process from /proc
        # We can ignore failures over this block as links will
        # disappear as we run them
        foundfiles = []
        try:
            for fd in os.listdir('/proc/' + pid + '/fd'):
                if os.path.islink('/proc/' + pid + '/fd/' + fd):
                    fname = os.readlink('/proc/' + pid + '/fd/' + fd)
                    if re.compile("\s\(deleted\)$").search(fname):
                        foundfiles.append(fname)
        except:
            continue

        # Get the list of memory mapped files using system pmap
        for output in check_output(['pmap', pid]).decode(errors="ignore").splitlines():
            data = re.split('\s+', output.strip('\n'), 3)
            if len(data) == 4:
                f = data[3]
                if re.compile("\s\(deleted\)$").search(f):
                    foundfiles.append(f)

        if len(foundfiles) > 1:
            process = processes.setdefault(pid,Process(int(pid)))
            # print pid + ': ' + ', '.join(foundfiles)
            process.files = foundfiles

    toRestart = [process for process in list(processes.values()) if process.needsRestart(blacklist)]
    return toRestart



# Tells if a given file is part of a package
# Returns:
#  - False - file does not exist in the system or cannot be found when querying the package database
#  - True  - file is found in an operating system package
def ispackagedFile (f):
    file_in_package = False
    file_regexp = False
    if verbose:
        print("[DEBUG] Checking if file %s belongs to any package" % f)
    # First check if the file exists
    if not os.path.exists(f):
        if ( f.startswith('/lib/') or f.startswith('/usr/lib/') ) and re.compile("\.so[\d.]+$"):
        # For libraries that do not exist then try to use a regular expression with the
        # soname
        # In libraries, indent characters that could belong to a regular expression first
            f = re.compile("\+").sub("\+", f)
            f = re.compile(".so[\d.]+$").sub(".so.*", f)
            f = re.compile("\.").sub("\.", f)
            file_regexp = True
        else:
        # Do not call dpkg-query if the file simply does not exist in the file system
        # just assume it does not belong to any package
            return False

    # If it exists, run dpkg-query
    dpkgQuery = ["dpkg-query", "--search", f ]
    if verbose:
        print("[DEBUG] Running: %s" % ' '.join(dpkgQuery))
    dpkgProc = subprocess.Popen(dpkgQuery, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
                env = lc_all_c_env, close_fds=True, universal_newlines=True)
    dpkgProc.wait()
    if verbose:
        print("[DEBUG] Running: %s" % ' '.join(dpkgQuery))
    for line in dpkgProc.stdout.readlines():
        line = line.strip()
        if line.find('no path found matching pattern ' + f) > 0:
            file_in_package = False
            break
        if line.endswith(f) or ( file_regexp and re.search(f, line)):
            package  = re.compile(":.*$").sub("",line)
            file_in_package = True
            break

    if file_in_package and verbose:
        print("[DEBUG] YES: File belongs to package %s" % package)
    if not file_in_package and verbose:
        print("[DEBUG] NO: File does not belongs to any package")
    return file_in_package

# Tells if a file has to be considered a deleted file
# Returns:
#  - 0 (NO) for known locations of files which might be deleted
#  - 1 (YES) for valid deleted files we are interested in
def isdeletedFile (f, blacklist = None):

    global lc_all_c_env, file_query_check

    if allFiles:
        return 1
    if blacklist:
        for p in blacklist:
            if p.search(f):
                return 0
    # We don't care about log files
    if f.startswith('/var/log/') or f.startswith('/var/local/log/'):
        return 0
    # Or about files under temporary locations
    if f.startswith('/var/run/') or f.startswith('/var/local/run/'):
        return 0
    # Or about files under /tmp
    if f.startswith('/tmp/'):
        return 0
    # Or about files under /dev
    if f.startswith('/dev/'):
        return 0
    # Or about files under /run
    if f.startswith('/run/'):
        return 0
    # Or about files under /drm
    if f.startswith('/drm'):
        return 0
    # Or about files under /i915
    if f.startswith('/i915'):
        return 0
    # Or about files under /var/tmp and /var/local/tmp
    if f.startswith('/var/tmp/') or f.startswith('/var/local/tmp/'):
        return 0
    # Or /usr/lib/locale
    if f.startswith('/usr/lib/locale/'):
        return 0
    # Skip files from the user's home directories
    # many processes hold temporary files there
    if f.startswith('/home/'):
        return 0
    # Skip automatically generated files
    if f.endswith('icon-theme.cache'):
        return 0
    # Skip font files
    if f.startswith('/var/cache/fontconfig/'):
        return 0
    # Skip Nagios Spool
    if f.startswith('/var/lib/nagios3/spool/'):
        return 0
    # Skip nagios spool files
    if f.startswith('/var/lib/nagios3/spool/checkresults/'):
        return 0
    # Skip PostgreSQL files
    if f.startswith('/var/lib/postgresql/'):
        return 0
    # Skip VDR lib files
    if f.startswith('/var/lib/vdr/'):
        return 0
    # Skip Aio files found in MySQL servers
    if f.startswith('/[aio]'):
        return 0
    # Skip memfd files
    if f.startswith('/memfd:'):
        return 0
    # Skip, if asked to, files that do not belong to any package
    if onlyPackageFiles:
        # Remove some lsof information from the file to ensure that it is
        # a proper filename
        file_name = re.sub(r'\(.*\)','', f)
        file_name = re.sub(r'\s+$','', file_name)
        # First check: have we checked this file before? If we have not then make the check
        if not file_name in file_query_check:
                file_query_check[file_name] = ispackagedFile(file_name)
        # Once we have the result then check if the file belongs to a package
        if not file_query_check[file_name]:
                return 0

    # TODO: it should only care about library files (i.e. /lib, /usr/lib and the like)
    # build that check with a regexp to exclude others
    if f.endswith(' (deleted)'):
        return 1
    if re.compile("\(path inode=[0-9]+\)$").search(f):
        return 1
    # Default: it is a deleted file we are interested in
    return 1

def psdelcheck():
# TODO - Needs to be fixed to work here
# Useful for seeing which processes need to be restarted after you upgrade
# programs or shared libraries. Written to replace checkrestart(1) from the
# debian-goodies, which often misses out processes due to bugs in lsof; see
# <https://bugs.debian.org/264985> for more information.

    numeric = re.compile(r'\d+')
    toRestart = list(map (delmaps, list(map (string.atoi, list(filter (numeric.match, os.listdir('/proc')))))))
    return toRestart

def delmaps (pid):
    processes = {}
    process = processes.setdefault(pid,Process(int(pid)))
    deleted = re.compile(r'(.*) \(deleted\)$')
    boring = re.compile(r'/(dev/zero|SYSV([\da-f]{8}))|/usr/lib/locale')

    mapline = re.compile(r'^[\da-f]{8}-[\da-f]{8} [r-][w-][x-][sp-] '
            r'[\da-f]{8} [\da-f]{2}:[\da-f]{2} (\d+) *(.+)( \(deleted\))?\n$')
    maps = open('/proc/%d/maps' % (pid))
    for line in maps.readlines ():
        m = mapline.match (line)
        if (m):
            inode = string.atoi (m.group (1))
            file = m.group (2)
            if inode == 0:
                continue
            # remove ' (deleted)' suffix
            if deleted.match (file):
                file = file [0:-10]
            if boring.match (file):
                continue
            # list file names whose inode numbers do not match their on-disk
            # values; or files that do not exist at all
            try:
                if os.stat (file)[stat.ST_INO] != inode:
                    process = processes.setdefault(pid,Process(int(pid)))
            except OSError as e_tuple:
                (e, strerror) = e_tuple.args
                if e == errno.ENOENT:
                    process = processes.setdefault(pid,Process(int(pid)))
                else:
                    sys.stderr.write ('checkrestart (psdel): %s %s: %s\n' % (SysProcess.get(pid).info (), file, os.strerror (e)))
        else:
            print('checkrestart (psdel): Error parsing "%s"' % (line [0:-1]))
    maps.close ()

    return process


class SysProcess:
	re_name = re.compile('Name:\t(.*)$')
	re_uids = re.compile('Uid:\t(\d+)\t(\d+)\t(\d+)\t(\d+)$')
	processes = {}
	def get (pid):
		try:
			return Process.processes [pid]
		except KeyError:
			Process.processes [pid] = Process (pid)
			return Process.get (pid)

	# private
	def __init__ (self, pid):
		self.pid = pid

		status = open ('/proc/%d/status' % (self.pid))
		for line in status.readlines ():
			m = self.re_name.match (line)
			if m:
				self.name = m.group (1)
				continue
			m = self.re_uids.match (line)
			if m:
				self.user = pwd.getpwuid (string.atoi (m.group (1)))[0]
				continue
		status.close ()
	
	def info (self):
		return '%d %s %s' % (self.pid, self.name, self.user)

class Process:
    def __init__(self, pid):
        self.pid = pid
        self.files = []
        self.descriptors = []
        self.links = []
        self.program = ''

        try:
            self.program = os.readlink('/proc/%d/exe' % self.pid)
            # if the executable command is an interpreter such as perl/python/ruby/tclsh,
            # we want to find the real program
            m = re.match("^/usr/bin/(perl|python|ruby|tclsh)", self.program)
            if m:
                with open('/proc/%d/cmdline' % self.pid, 'r') as cmdline:
                    # only match program in /usr (ex.: /usr/sbin/smokeping)
                    # ignore child, etc.
                    #m = re.search(r'^(([/]\w*){1,5})\s.*$', cmdline.read())
                    # Split by null-bytes, see proc(5)
                    data = cmdline.read().split('\x00')
                    # Last character should be null-byte, too, see proc(5)
                    if not data[-1]: data.pop()
                    # Spamd sets $0 wrongly, see
                    # https://bugzilla.redhat.com/show_bug.cgi?id=755644
                    # i.e. the blank after spamd is relevant in case
                    # this will be fixed in the future.
                    m = re.match("^/usr/sbin/spamd |^spamd ", data[0])
                    if m:
                        self.program = "/usr/sbin/spamd"
                    else:
                        # Strip first value, the interpreter
                        data.pop(0)
                        # Check if something's left after the interpreter, see #715000
                        if data:
                            # Strip all options following the interpreter, e.g. python's -O
                            m = re.match("^-", data[0])
                            while (m):
                                data.pop(0)
                                if not data: break
                                m = re.match("^-", data[0])
                            if data and data[0]:
                                data = self.which(data[0])
                                m = re.search(r'^(/usr/\S+)$', data)
                                if m:
                                    # store the real full path of script as the program
                                    self.program = m.group(1)
        except OSError as e:
            if e.errno != errno.ENOENT:
                if self.pid == 1:
                    sys.stderr.write("Found unreadable pid 1. Assuming we're under vserver and continuing.\n")
                else:
                    sys.stderr.write('ERROR: Failed to read %d' % self.pid)
                    raise
        self.program = self.cleanFile(self.program)

    def which(self, program):
        if os.path.isabs(program):
            return program
        path = os.environ.get("PATH", os.defpath).split(os.pathsep)
        seen = set()
        for dir in path:
            dir = os.path.normcase(os.path.abspath(dir))
            if not dir in seen:
                seen.add(dir)
                name = os.path.join(dir, program)
                if os.path.exists(name) and os.access(name, os.F_OK|os.X_OK) and not os.path.isdir(name):
                    return name
        return program

    def cleanFile(self, f):
        # /proc/pid/exe has all kinds of junk in it sometimes
        null = f.find('\0')
        if null != -1:
            f = f[:null]
        # Support symlinked /usr
        if f.startswith('/usr'):
            statinfo = os.lstat('/usr')[ST_MODE]
            # If /usr is a symlink then find where it points to
            if S_ISLNK(statinfo):
                newusr = os.readlink('/usr')
                if not newusr.startswith('/'):
                    # If the symlink is relative, make it absolute
                    newusr = os.path.join(os.path.dirname('/usr'), newusr)
                f = re.sub('^/usr',newusr, f)
                # print "Changing usr to " + newusr + " result:" +f; # Debugging
        return re.sub('( \(deleted\)|.dpkg-new).*$','',f)

    def listDeletedHelper(self):
        listfiles = []
        listdescriptors = []
        for f in self.files:
            if isdeletedFile(f):
                listfiles.append(f)
        return listfiles
    def listDeleted(self):
        listfiles = self.listDeletedHelper()
        if listfiles != []:
             print("List of deleted files in use:")
             for file in listfiles:
                 print("\t" + file)
    def listDeletedMachine(self):
        listfiles = self.listDeletedHelper()
        for file in listfiles:
            print('file\t%s\t%s\t%s' % (self.pid, self.program, file))


    # Check if a process needs to be restarted, previously we would
    # just check if it used libraries named '.dpkg-new' since that's
    # what dpkg would do. Now we need to be more contrieved.
    # Returns:
    #  - 0 if there is no need to restart the process
    #  - 1 if the process needs to be restarted
    def needsRestart(self, blacklist = None):
        for f in self.files:
            if isdeletedFile(f, blacklist):
                return 1
        for f in self.links:
            if f == 0:
                return 1
        return 0

class Package:
    def __init__(self, name):
        self.name = name
        # use a set, we don't need duplicates
        self.initscripts = set()
        self.systemdservice = set()
        self.processes = []

if __name__ == '__main__':
    main()


-=[ KCW uplo4d3r c0ded by cJ_n4p573r ]=-
Ⓒ2017 ҠЄГѦLѦ СүѣЄГ ЩѦГГіѺГՏ