-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from FrostyX/develop
Version 0.1
- Loading branch information
Showing
11 changed files
with
270 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ dist | |
build | ||
eggs | ||
parts | ||
bin | ||
#bin | ||
var | ||
sdist | ||
develop-eggs | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,25 @@ | ||
tracer | ||
====== | ||
# tracer | ||
|
||
Tracer finds outdated running packages in your system | ||
|
||
How does he do it? He simply finds all packages you have modified since you boot up. Then he traces their files in the jungle of your memory, ... senses them, and finally, finds them. In the end you will get list of packages what have been running while you updated or removed them. | ||
|
||
## Requirements | ||
- Supported linux distribution - There are currently supported [Fedora](http://fedoraproject.org/) and [Gentoo](http://www.gentoo.org/) | ||
- Python interpreter | ||
- Python [psutil](https://code.google.com/p/psutil/) module. Available [here](https://admin.fedoraproject.org/pkgdb/acls/name/python-psutil?_csrf_token=09739007ef8cd539e0b5903b86bd3ef76d614a4b) and [here](https://packages.gentoo.org/package/dev-python/psutil). Please use testing version on gentoo. | ||
|
||
## Usage | ||
Clone tracer from GitHub | ||
|
||
git clone [email protected]:FrostyX/tracer.git | ||
|
||
And simply run it | ||
|
||
sudo ./tracer/bin/tracer.py | ||
|
||
_Yeah, you really have to run it as root._ | ||
|
||
|
||
## Feedback | ||
Please report any bugs or feature requests right [here](https://github.com/FrostyX/tracer/issues) on GitHub. Pull requests are also welcome. If you rather want a talk or something, you can find me on `#gentoo.cs` or `fedora-cs` `@freenode` or you can [mail me](mailto:[email protected]). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#!/usr/bin/python | ||
# -*- coding: utf-8 -*- | ||
# Tracer finds outdated running packages in your system | ||
# Copyright 2013 Jakub Kadlčík | ||
|
||
# Enable importing modules from parent directory (tracer's root directory) | ||
import os | ||
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
os.sys.path.insert(0, parentdir) | ||
|
||
# System modules | ||
import re | ||
import psutil | ||
import platform | ||
|
||
# Tracer modules | ||
from packageManagers.yum import Yum | ||
from packageManagers.portage import Portage | ||
import resources.memory as memory | ||
|
||
# Returns instance of package manager according to installed linux distribution | ||
def package_manager(): | ||
def e(): raise OSError("Unknown or unsupported linux distribution") | ||
|
||
distro = platform.linux_distribution(full_distribution_name=False)[0] | ||
return { | ||
'gentoo': Portage(), | ||
'fedora': Yum(), | ||
}.get(distro, e) | ||
|
||
PACKAGE_MANAGER = package_manager() | ||
|
||
# Returns list of packages what tracer should care about | ||
def modified_packages(): | ||
# Else branch is only for dev and testing purposes | ||
# Use: if True or if not True | ||
if True: | ||
packages = PACKAGE_MANAGER.packages_newer_than(psutil.BOOT_TIME) | ||
else: | ||
# Lets say these packages were updated | ||
packages = [ | ||
{'name': 'xterm'}, | ||
{'name': 'ark'}, | ||
{'name': 'kactivities'}, | ||
] | ||
return packages | ||
|
||
# Returns list of packages which have some files loaded in memory | ||
def trace_running(): | ||
""" | ||
Returns list of package names which owns outdated files loaded in memory | ||
@TODO This function should be hardly optimized | ||
""" | ||
|
||
files_in_memory = memory.files_in_memory() | ||
packages = modified_packages() | ||
|
||
modified = [] | ||
for package in packages: | ||
for file in PACKAGE_MANAGER.package_files(package['name']): | ||
# Doesnt matter what is after dot cause in package files there is version number after it | ||
regex = re.compile('^' + re.escape(file) + "(\.*|$)") | ||
if memory.is_in_memory(regex, files_in_memory): | ||
modified.append(package['name']) | ||
break | ||
return modified | ||
|
||
# More times a package is updated the more times it is contained in a package list. | ||
for package in set(trace_running()): | ||
print package |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#-*- coding: utf-8 -*- | ||
"""This class should be inherited by any other package manager | ||
Copyright 2013 Jakub Kadlčík""" | ||
|
||
class IPackageManager: | ||
def packages_newer_than(self, unix_time): | ||
"""Returns list of packages which were modified between unix_time and present""" | ||
raise NotImplementedError | ||
|
||
def package_files(self, pkg_name): | ||
"""Returns list of files provided by package""" | ||
raise NotImplementedError |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#-*- coding: utf-8 -*- | ||
"""Module to work with portage package manager class | ||
Copyright 2013 Jakub Kadlčík""" | ||
|
||
from ipackageManager import IPackageManager | ||
import commands | ||
import time | ||
|
||
class Portage(IPackageManager): | ||
|
||
def packages_newer_than(self, unix_time): | ||
""" | ||
Returns list of packages which were modified between unix_time and present | ||
Requires root permissions. | ||
""" | ||
newer = [] | ||
packages = commands.getoutput('sudo qlop -lC').split('\n') | ||
for package in packages: | ||
package = package.split(" >>> ") | ||
|
||
# There actually should be %e instead of %d | ||
modified = time.mktime(time.strptime(package[0], "%a %b %d %H:%M:%S %Y")) | ||
if modified >= unix_time: | ||
pkg_name = package[1] | ||
pkg_name = pkg_name[:pkg_name.index('.')] # Cut from first . to end | ||
pkg_name = pkg_name[:pkg_name.rindex('-')] # Cut from last - to end | ||
newer.append({"name":pkg_name}) | ||
return newer | ||
|
||
def package_files(self, pkg_name): | ||
"""Returns list of files provided by package""" | ||
return commands.getoutput('equery -q f ' + pkg_name).split('\n') | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#-*- coding: utf-8 -*- | ||
"""Module to work with yum package manager class | ||
Copyright 2013 Jakub Kadlčík""" | ||
|
||
from os import listdir | ||
from ipackageManager import IPackageManager | ||
import sqlite3 | ||
import commands | ||
|
||
class Yum(IPackageManager): | ||
|
||
def packages_newer_than(self, unix_time): | ||
""" | ||
Returns list of packages which were modified between unix_time and present | ||
Requires root permissions. | ||
""" | ||
|
||
sql = """ | ||
SELECT * | ||
FROM trans_data_pkgs JOIN pkgtups ON trans_data_pkgs.pkgtupid=pkgtups.pkgtupid | ||
WHERE trans_data_pkgs.tid = ? | ||
ORDER BY pkgtups.pkgtupid | ||
""" | ||
|
||
packages = [] | ||
sqlite = self._database_file() | ||
conn = sqlite3.connect(sqlite) | ||
conn.row_factory = sqlite3.Row | ||
c = conn.cursor() | ||
|
||
for t in self._transactions_newer_than(unix_time): | ||
c.execute(sql, [t['tid']]) | ||
packages.extend(c.fetchall()) | ||
return packages | ||
|
||
def package_files(self, pkg_name): | ||
"""Returns list of files provided by package""" | ||
# http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch04s02s03.html | ||
return commands.getoutput('rpm -ql ' + pkg_name).split('\n') | ||
|
||
def _transactions_newer_than(self, unix_time): | ||
""" | ||
Returns list of transactions which ran between unix_time and present. | ||
Requires root permissions. | ||
""" | ||
|
||
sql = """ | ||
SELECT trans_beg.tid, trans_beg.timestamp AS beg, trans_end.timestamp AS end | ||
FROM trans_beg JOIN trans_end ON trans_beg.tid=trans_end.tid | ||
WHERE beg > ? | ||
ORDER BY trans_beg.tid | ||
""" | ||
|
||
sqlite = self._database_file() | ||
conn = sqlite3.connect(sqlite) | ||
conn.row_factory = sqlite3.Row | ||
c = conn.cursor() | ||
c.execute(sql, [unix_time]) | ||
return c.fetchall() | ||
|
||
def _database_file(self): | ||
""" | ||
Returns path to yum history database file | ||
Requires root permissions. | ||
""" | ||
history_path = '/var/lib/yum/history/' | ||
return history_path + listdir(history_path)[-1] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#!/bin/bash | ||
|
||
# Pydoc has to be run from project root directory! | ||
pwd="$(pwd)" | ||
cd "$(dirname "$0")" # Change directory to script location | ||
cd ../ | ||
|
||
for file in $(pydoc -w ./ | awk '{print $2}'); | ||
do | ||
mv "$file" pydoc; | ||
done | ||
|
||
cd $pwd |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#-*- coding: utf-8 -*- | ||
"""Module to work with files in memory | ||
Copyright 2013 Jakub Kadlčík""" | ||
|
||
import psutil | ||
import re | ||
|
||
def process_files(pid): | ||
""" | ||
Returns list of files which are used by process with given pid | ||
""" | ||
# By default work only with applications | ||
paths = ['\/usr/bin', '\/usr/sbin'] | ||
|
||
# Work with libs too | ||
paths.append('\/usr/lib') | ||
|
||
# Make a regex that matches if any of our regexes match. | ||
combined = "(" + ")|(".join(paths) + ")" | ||
|
||
files = [] | ||
p = psutil.Process(pid) | ||
for mmap in p.get_memory_maps(): | ||
if re.match(combined, mmap.path): | ||
files.append(mmap.path) | ||
|
||
return files | ||
|
||
def is_in_memory(regex_file, memory): | ||
""" | ||
Predicates if file is loaded in memory | ||
@TODO This function should be hardly optimized | ||
""" | ||
for file in memory: | ||
if regex_file.match(file): | ||
return True | ||
return False | ||
|
||
def files_in_memory(): | ||
""" | ||
Returns list of all files loaded in memory | ||
""" | ||
files = [] | ||
for pid in psutil.get_pid_list(): | ||
try: | ||
files += process_files(pid) | ||
except psutil._error.NoSuchProcess: | ||
pass | ||
|
||
return set(files) |