MOON
Server: Apache
System: Linux vps.thepromohut.com 2.6.18-398.el5 #1 SMP Tue Sep 16 20:51:48 EDT 2014 i686
User: caretrak (507)
PHP: 5.2.10
Disabled: NONE
Upload Files
File: //usr/lib/Acronis/BackupAndRecovery/sysinfo.py
# @copyright (c) 2002-2016 Acronis International GmbH. All rights reserved.

"""Acronis System Info Report Utility."""

import os, sys
import argparse
import subprocess
import shutil
import hashlib


class _SysInfoReportBase():
    # Base class for sys-info reports

    _PLATFORM_LINUX, _PLATFORM_WIN, _PLATFORM_MACOS = range(3)

    def __init__(self, platform, report_dir, cmd_name):
        # Arguments
        #   - platform: (optional) one of _PLATFORM_* constants
        #   - report_dir: path to report directory
        #   - cmd_name: name of report command (f.e. 'collect_configs')
        #     Used for diagnostic purposes only
        self.cmd_name = cmd_name
        self.report_dir = os.path.abspath(report_dir)
        self.platform = platform if platform is not None else self._detect_platform()

    @classmethod
    def _detect_platform(cls):
        if sys.platform.startswith('win32'):
            return cls._PLATFORM_WIN
        elif sys.platform.startswith('linux'):
            return cls._PLATFORM_LINUX
        elif sys.platform.startswith('darwin'):
            return cls._PLATFORM_MACOS
        assert False, "Unexpected sys.platform name: {}".format(sys.platform)

    def _get_install_paths(self):
        # get list of Acronis installation locations
        if self.platform == self._PLATFORM_LINUX:
            return ["/etc/Acronis", "/usr/lib/Acronis", "/var/lib/Acronis"]
        elif self.platform == self._PLATFORM_WIN:
            return self._get_install_paths_windows()
        else:
            return [
                "/Library/Application Support/Acronis",
                "/Library/Application Support/BackupClient"]

    def _get_install_paths_windows(self):
        # on windows product installation path should be taken from registry
        import acrobind
        import acrort

        install_paths = set([])

        brand_name = acrort.common.BRAND_NAME

        for path_id in ('COMMONPROGRAMFILES', 'COMMONPROGRAMFILES(x86)',
                        'PROGRAMDATA', 'ALLUSERSPROFILE'):
            # paths like "C:\Program Files\Common Files\Acronis"
            #
            # %PROGRAMDATA% and %ALLUSERSPROFILE% reference the
            # same dir: usually "C:\ProgramData". But one of these variables
            # may be not present depending on Windows version.
            if path_id in os.environ:
                install_paths.add(os.path.join(os.environ[path_id], brand_name))

        key_path = r"SOFTWARE\{}\Installer".format(brand_name)
        val_name = "TargetDir"
        product_install_path = acrobind.registry_read_string(key_path, val_name)

        if product_install_path:
            install_paths.add(product_install_path)
        else:
            print(
                "Warning: Processing '{0}' report command. "
                "Product installation dir not found in registry. "
                "key_path: {1}, val_name {2}".format(self.cmd_name, key_path, val_name))

        return sorted(install_paths)

    @staticmethod
    def _iter_files(top_dir, ignore_dir, file_extentions=[], ignore_file_extentions=[]):
        # recursively yield (dir_name, file_name) for files from specified directory
        #
        # Arguments:
        #   - top_dir: top-level directory to yield files from
        #   - ignore_dir: ignore files in this dir (usefull if report directory
        #       is inside top_dir).
        #   - file_extentions: (optional) only yield files matching the extentions
        #   - ignore_file_extentions: (optional) ignore files with these extentions
     
        ignore_dir = os.path.normpath(ignore_dir)

        for dir_name, _sub_dirs, file_names in os.walk(top_dir):
            if ignore_dir and os.path.commonpath([dir_name, ignore_dir]) == ignore_dir:
                continue
            for file_name in file_names:
                if file_extentions:
                    if not any(file_name.endswith(ext) for ext in file_extentions):
                        continue
                if ignore_file_extentions:
                    if any(file_name.endswith(ext) for ext in ignore_file_extentions):
                        continue
                yield (dir_name, file_name)


#########################
# collect conf files

class _CollectConfigFilesReport(_SysInfoReportBase):
    # inclde all the Acronis configuration files into the report

    def run_report(self):
        configs_report_subdir = os.path.join(self.report_dir, "configs")

        file_extentions = [".config", ".cfg", ".conf", ".xml", ".json", ".ini"]
        install_paths = self._get_install_paths()

        src_2_tgt_dirs = {}  # {conf_file_dir: dir_in_report}

        for top_dir in install_paths:
            for dir_name, file_name in self._iter_files(top_dir, self.report_dir, file_extentions):
                if dir_name not in src_2_tgt_dirs:
                    src_2_tgt_dirs[dir_name] = self._make_tgt_dir_for_configs_report(
                        dir_name, configs_report_subdir)
                tgt_dir = src_2_tgt_dirs[dir_name]
                shutil.copy(os.path.join(dir_name, file_name), os.path.join(tgt_dir, file_name))

    def _make_tgt_dir_for_configs_report(self, config_dir_name, configs_report_subdir):
        # returns abs path of dir in the report to copy the config file to.
        # Create the dir if not exist yet.
        if self.platform in (self._PLATFORM_LINUX, self._PLATFORM_MACOS):
            tgt_file_rel_path = os.path.relpath(config_dir_name, "/")
        else:  # self.platform == _PLATFORM_WIN
            drive = os.path.splitdrive(config_dir_name)[0]  # "C:"
            drive = os.path.join(drive, os.sep)             # "C:\\"
            tgt_file_rel_path = os.path.relpath(config_dir_name, drive)
        tgt_file_location = os.path.join(configs_report_subdir, tgt_file_rel_path)
        os.makedirs(tgt_file_location, exist_ok=True)
        return tgt_file_location


#########################
# report Acronis files hashes

class _CollectFileHashes(_SysInfoReportBase):
    # calculate hashes of all the Acronis files

    def run_report(self):

        no_hash_for_exts = [".log", ]

        with open(os.path.join(self.report_dir, "file_hashes.txt"), "w+") as out_file:
            for file_path in self._iter_installed_files():
                skip_hash = (
                    any(file_path.endswith(ext) for ext in no_hash_for_exts)
                    or not os.path.isfile(file_path))

                if skip_hash:
                    hexdigest = "n/a"
                else:
                    with open(file_path, "rb") as file_data:
                        hexdigest = hashlib.md5(file_data.read()).hexdigest()
                out_file.write("{0}\t{1}\n".format(file_path, hexdigest))

    def _iter_installed_files(self):
        # yields all the files in Acronis installation directories
        for top_loc in self._get_install_paths():
            for dir_name, file_name in self._iter_files(top_loc, self.report_dir,
                                                        ignore_file_extentions=[".pyc", ]):
                yield os.path.join(dir_name, file_name)


#########################
# report netstat

class _CollectNetstat(_SysInfoReportBase):
    # just report 'netstat -a' output

    def run_report(self):
        rep_file_path = os.path.join(self.report_dir, "netstat.txt")

        options = "-nap" if self.platform == self._PLATFORM_LINUX else "-nab"

        with open(rep_file_path, "w+") as outfile:
            subprocess.call(["netstat", options], stdout=outfile)


#########################
# common functionality

_REPORT_CLASSES = {
    'collect_configs': _CollectConfigFilesReport,
# Disable hash collection because perfomance degradation  ABR-121489: Collecting sysinfo loads 100% CPU and woks too long ~ 5 min
#    'collect_filehashes': _CollectFileHashes,
    'netstat': _CollectNetstat,
}


def _parse_arguments():
    parser = argparse.ArgumentParser(
        description=("Part of Acronis sysinfo utility. "
                     "!!! Not intended to be executed directly !!!"))

    parser.add_argument(
        "-o", "--output-dir",
        dest="output_dir",
        help=("(optional) Path to output report directory. "
              "Default is current directory."))

    platform_names = {
        'linux': _SysInfoReportBase._PLATFORM_LINUX,
        'macos': _SysInfoReportBase._PLATFORM_MACOS,
        'win': _SysInfoReportBase._PLATFORM_WIN}

    parser.add_argument(
        "-p", "--platform",
        dest="platform_name",
        choices=sorted(platform_names.keys()))

    parser.add_argument(
        "commands", nargs='*', metavar='command',
        choices=[[]] + sorted(_REPORT_CLASSES.keys()),
        help=("(optional) Data collection command. "
              "If not specified all commands will be executed."))

    args = parser.parse_args()

    platform = platform_names.get(args.platform_name)

    output_dir = args.output_dir if args.output_dir is not None else os.getcwd()

    commands_to_execute = args.commands if args.commands else sorted(_REPORT_CLASSES.keys())

    return platform, output_dir, commands_to_execute


if __name__ == '__main__':

    platform, output_dir, commands_to_execute = _parse_arguments()

    for cmd_name in commands_to_execute:
        try:
            cmd_report = _REPORT_CLASSES[cmd_name](platform, output_dir, cmd_name)
            cmd_report.run_report()
        except:
            print("Warning: error processing '{0}' report command.".format(cmd_name))
            import traceback
            traceback.print_exc(file=sys.stdout)