#!/usr/bin/env python

# Copyright (c) 2015 Tim Savannah GPLv2
# You should have recieved a copy of LICENSE with this distrubition. Details on the license can be found therein
#
# This is a program that scans the running processes of a system for mappings (running executable, shared library, something else) and prints the results

# vim: set ts=4 sw=4 expandtab

import os
import sys


import ProcessMappingScanner

__version__ = '2.0.1'


if __name__ == '__main__':

    if '--version' in sys.argv:
        sys.stdout.write('findProcessesUsing version %s by Tim Savannah\n' %(__version__,))
        sys.exit(0)

    if '-f' in sys.argv:
        isFileScan = True
        sys.argv.remove('-f')
    else:
        isFileScan = False

    if '-e' in sys.argv:
        isExact = True
        sys.argv.remove('-e')
    elif '--exact' in sys.argv:
        isExact = True
        sys.argv.remove('--exact')
    else:
        isExact = False

    if len(sys.argv) not in (2, 3) or '--help' in sys.argv:
        sys.stderr.write('''Usage: findProcessesUsing (options) [search portion]

Searches all running processes for those containing a given mapping, or an open file (with -f). 
Mappings include running executables (like python), or a shared library, or a device.

    Options:

       -v or --verbose        Also print mapping lines containing the given pattern, or matched filenames when given -f.
       -e or --exact          Require exact match. Default is to allow partial matches
       -f                     Scan for open files instead of mappings. This should not be a symbolic link.
       --version              Print the version


Examples: 
  findProcessesUsing libpython2.7             # Scan for any processes linking against anything containing "libpython2.7"
  findProcessesUsing -f /var/lib/data.db      # Scan for any processes with an open handle to "/var/lib/data.db"

 
It is recommended to run this process as root, otherwise you are only able to scan your own processes.
''')
        sys.exit(1)

    if os.getuid() != 0:
        sys.stderr.write('Warning: You are not root. Results will only contain processes for which you are the owner.\n\n')


    isVerbose = False

    for verboseOption in ('-v', '--verbose'):
        if verboseOption in sys.argv:
            isVerbose = True
            sys.argv.remove(verboseOption)
            break

    searchPortion = sys.argv[1]

    if isFileScan is False:
        scanResults = ProcessMappingScanner.scanAllProcessesForMapping(searchPortion, isExact)
    else:
        scanResults = ProcessMappingScanner.scanAllProcessesForOpenFile(searchPortion, isExact)

    pids = scanResults.keys()
    for pid in pids:
        result = scanResults[pid]
        if isFileScan is False:
            sys.stdout.write('Found %s in %d (%s) [ %s ]\n' %(searchPortion, result['pid'], result['owner'], result['cmdline']))
            if isVerbose is True:
                sys.stdout.write('\n'.join(["\t" + line for line in result['matchedMappings']]) + '\n\n')
        else:
            sys.stdout.write('Found %s {fd=%s} in %d (%s) [ %s ]\n' %(searchPortion, ','.join(result['fds']), result['pid'], result['owner'], result['cmdline']))
            if isVerbose is True:
                for i in range(len(result['filenames'])):
                    (fd, filename) = (result['fds'][i], result['filenames'][i])
                    sys.stdout.write('\n\t%4d = "%s"' %(int(fd), filename))
                sys.stdout.write('\n\n')


