#!/usr/bin/python

# Copyright (C) 2010 Intel Corporation
# 
# 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
# of the License, 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.
#
# Get test environment information for performance test
#
# Authors:
#       Lex, Yu <yucai.yu@intel.com>
#

# Test env configuration file sample
"""
******** HW/SW Overview ********
memory: 1024
graphic_driver: n/a
networking: n/a
compiler: n/a
ht: Enabled
bios_version: n/a 
platform_stepping: n/a 
cpu_stepping: n/a
cpu_frequency: 1.6GHZ
disk_size: n/a

******** File System Info ********
...
******** Graphics Info ********
...
"""

import sys
import os
import string
import re
import subprocess
import time
import glob
import getopt
import getpass

# Utility functions
def is_prg_existence(prg_name):
    prg = None
    returncode, stdout_val = run_shell_cmd('PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin which %s' % prg_name)
    if returncode == 0:
        prg = stdout_val.strip()
    return prg
    
def extract_field_from_section(info, field_name, section_name):
    ret = None
    pos = info.find(field_name, info.find(section_name)+ len(section_name))
    if pos != -1:
        eol = info.find('\n', pos)
        ret = info[pos+len(field_name):eol].strip()
    return ret

def run_shell_cmd(cmd):
    proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, \
                           stderr=subprocess.PIPE)
    stdout_val = proc.communicate()[0]
    return proc.returncode, stdout_val

def get_xorg_log_file_name():
    username = None
    returncode, stdout_val = run_shell_cmd("who am i | awk '{print $1}'")
    if returncode == 0:
	username = stdout_val.strip()
    search_files = ('/var/log/Xorg.0.log', '/tmp/Xorg.0.%s.log' % username)
    xorg_fn = 'not_exist'
    for i in search_files:
        if os.path.isfile(i):
            xorg_fn = i
            break
    return xorg_fn

hal_invalid_words = ('empty', 'null', 'unknown', 'unknow', 'system manufacturer',
                'system version', 'system name', 'system product name',
                'to be filled by o.e.m.', 'not applicable', 'not specified',
                'not available', 'oem', '00', 'none', '1234567890', '.')

def read_hal_info(names, udi = None):
    ret = None

    for ele in names:
        if udi == None:
            returncode, stdout_val = run_shell_cmd('lshal 2>&1 | grep "%s"' % ele)
        else: 
            returncode, stdout_val = run_shell_cmd('lshal -u %s 2>&1 | grep "%s"' % (udi, ele))
        if returncode == 0:
            # Parse hal value
            re_str = '%s\s=\s\'(.*)\'' % ele
            m = re.compile(re_str).search(stdout_val)
            if m is not None:
                val = m.group(1)
                # Check if value is in array hal_invalid_words
                if not (val.lower() in hal_invalid_words):
                    ret = val
                    break;
    return ret

def read_system_hal_info(names):
    # Read system HAL
    hal_info = read_hal_info(names, '/org/freedesktop/Hal/devices/computer')
    if hal_info is None:
        hal_info = read_hal_info(names)
    return hal_info

def read_pci_info(names, enable_extra_info = False):
    ret = None

    cmd = Env_Util.prgs["lspci"]
    returncode, pci_info = run_shell_cmd('%s 2>&1' % cmd)
    if returncode == 0:
        for name in names:
            if len(name) == 0:
                continue
            # prepare search string
            if name[-1:] != ':':
                name += ':'
            r = re.compile(name + '(.*)')
            m = r.search(pci_info)
            if m is not None:
                ret = m.group(1).strip()
                if not enable_extra_info:
                    # remove extra information
                    pos1 = ret.find('(')
                    pos2 = ret.find('[')
                    if pos1 != -1:
                        ret = ret[:pos1]
                    if pos2 != -1:
                        ret = ret[:pos2]
                break
    return ret

def read_lsb_info(field):
    ret = None
    returncode, info = run_shell_cmd('lsb_release -a 2>&1 | grep "%s"' % field) 
    if returncode == 0:
         start_pos = info.find(':')
         if start_pos > 0:
            ret = info[start_pos+1:].strip()
    return ret

def is_process_running(process):
    ret = False
    cmd = 'ps -C %s 2>&1' % process.lower()
    returncode, stdout_val = run_shell_cmd(cmd)
    if returncode == 0:
        removal_strs = ('CMD', 'PID', 'TIME', 'TTY')
        for str in removal_strs:
            stdout_val = stdout_val.replace(str, '')
        stdout_val = stdout_val.strip()
        if len(stdout_val) > 0:
            ret = True
    return ret
        
    
# Used for interactive mode
def text_input(prompt):
    s = raw_input(prompt)
    while len(s) <= 0 :
        s = raw_input(prompt)
    else:
        return s

# Used for interactive mode
def raw_choice_input(prompt):
    s = text_input(prompt)
    while s[0]  not in ('y', 'Y', 'n', 'N'):
        s = text_input(prompt)
    else:
        if s[0] in ('y', 'Y'): 
            return True
    return False

class Env_Util:
    prgs = {"lspci":None, "glxinfo":None, "xdpyinfo":None, "dmidecode":None, "gcc":None}

    def init_prgs(self):
        missing = []
        for p, t in Env_Util.prgs.items():
            prg = is_prg_existence(p)
            if prg is not None:
                Env_Util.prgs[p] = prg
            else:
                missing.append(p)
        return missing

# Class of HW environment
class Env_HWInfo:
    def __init__(self):
        self.cpu_model = 'n/a' 
        self.core_num = 0 
        self.cpu_stepping = 'n/a' # the same as platform_stepping 
        self.cpu_freq = 'n/a'
        self.cpu_ht = 'n/a'
        self.mem_total = 'n/a'
        self.networking = 'n/a'
        self.disk_string = 'n/a'
        self.bios = 'n/a'
        # Obsolete: use device name in predefined config file instead
        self.device_name = 'n/a' 
        #self.platform_name = 'n/a'
        self.motherboard = 'n/a'        
        self.chipset = 'n/a'    
        self.gpu_info = 'n/a' 
        self.screen_resolution = 'n/a'
        self.audio = 'n/a'
        self.camera = 'n/a'

    def get_cpu_info(self):
        proc_cpuinfo = "/proc/cpuinfo"
        cpuinfo = []
        if os.path.isfile(proc_cpuinfo):                
            f = open(proc_cpuinfo, 'r')
            for line in f.read().replace('\t','').splitlines(False):
                a = line.split(':')
                if len(a) == 2:
                    a[1] = a[1].strip(' ')
                    cpuinfo.append(a)
            f.close()
        # Extract CPU info
        if len(cpuinfo) > 0 :
            physical_id = []
            model_name = []
            model_unique_num = 0
            stepping = []
            cpu_freq = []
            cpu_ht_enabled = []
            for ele in cpuinfo:
                if ele[0] == 'physical id':
                    physical_id.append(ele[1])
                elif ele[0] == 'model name':
                    if ele[1] not in model_name:
                        model_unique_num += 1    
                    model_name.append(ele[1])                    
                elif ele[0] == 'stepping':
                    stepping.append(ele[1])
                elif ele[0] == 'cpu MHz':
                    cpu_freq.append(ele[1])
                elif ele[0] == 'flags':
                    # Search for "ht" in flags
                    if re.compile('\sht\s').search(ele[1]) is not None:
                        cpu_ht_enabled.append('Enabled')
            # CPU module, check for cases of multi-cores
            self.core_num = len(physical_id)
            if (len(physical_id) == 1) or (len(physical_id) == 0):
                # Just one processor
                self.core_num = 1
                self.cpu_model = model_name[0]
            elif (len(physical_id) > 1) and (model_unique_num == 1):
                # Multiple processors, same model
                self.cpu_model = '%s (Total cores: %d)'% (model_name[0], self.core_num) 
            elif (len(physical_id) > 1) and (len(model_name) > 1):
                # Multiple processors, different models
                for model in model_name:
                    self.cpu_model += model + '; ' 
            self.cpu_model = string.join(self.cpu_model.split())
            # CPU Stepping : cpu0
            self.cpu_stepping = stepping[0]
            # CPU Freq 
            # each CPU freq for future usage, currently use Hz from model string
            # self.cpu_freq = cpu_freq[0] + 'MHZ' 
            r = re.compile('@\s*(\d*.\d*GH[zZ])') 
            m = r.search(self.cpu_model)
            if m is not None:
                self.cpu_freq = m.group(1)
            # HT enabled: cpu0
            self.cpu_ht = cpu_ht_enabled[0]
        return self.cpu_model, self.cpu_stepping, self.cpu_freq, self.cpu_ht 

    def get_mem_info(self):
        proc_meminfo = "/proc/meminfo"
        meminfo = {}
        if os.path.isfile(proc_meminfo):                
            f = open(proc_meminfo, 'r')
            for line in f.read().replace('\t','').splitlines(False):
                a = line.split(':')
                if len(a) == 2:
                    #a[1] = a[1].strip(' ')
                    r = re.compile('(\d*)\s*kB')
                    m = r.search(a[1])
                    if m is not None:
                        val = int(m.group(1))/1024
                        #meminfo[a[0]] = str(val) + ' MB'
                        meminfo[a[0]] = val
            f.close()
            #self.mem_total = meminfo['MemTotal']
            # Calculate nearby value, like 512, 1024, 2048...
            mem_total = meminfo['MemTotal']
            factor = mem_total / 512
            if (mem_total % 512) > 412: # in range of  100 M
                mem_total = 512 * (factor + 1)
            self.mem_total = str(mem_total) + ' MB'
        return self.mem_total

    def gpu_memory_size(self):
        video_ram = 64; # Assume 64MB of video RAM at least 
        try:
            e = int(os.environ['VIDEO_MEMORY'],10)
            if e > video_ram:
                video_ram = e
        except KeyError:
            xorg_fn = get_xorg_log_file_name()
            if os.path.isfile(xorg_fn):
                returncode, stdout_val = run_shell_cmd('cat %s | grep -i VideoRAM' % xorg_fn)
                if returncode != 0:
                    returncode, stdout_val = run_shell_cmd('cat %s | grep "Video RAM"' % xorg_fn)
                if returncode == 0:
                    info = stdout_val.lower()
                    r = re.compile('ram:\s*(\S*)\s*kb')
                    m = r.search(info)
                    if m is not None:
                        video_ram = int(m.group(1))/1024
        return video_ram

    # get gpu info, ex: ATI Radeon HD 4800 Series 512MB (625/993MHz)
    def get_gpu_info(self):
        gpu_mem_size = self.gpu_memory_size() 
        cmd = Env_Util.prgs["glxinfo"]
        xorg_fn = get_xorg_log_file_name()
        returncode, stdout_val = run_shell_cmd('%s 2>&1 | grep renderer' % cmd)
        info = ''
        if returncode == 0:
            pos = stdout_val.find('renderer string:')
            if pos >= 0:
                info = stdout_val[pos+len('renderer string:'):]
                info = (info.replace('\n', '')).strip()
        if (info.find('Mesa ') >= 0) or (info == 'Software Rasterizer'):
            returncode, stdout_val = run_shell_cmd('cat %s 2>&1 | grep "Chipset" | grep -v "Driver"' % xorg_fn)
            if returncode == 0:
                pos = stdout_val.find('Chipset:') + 9
                eol = stdout_val.find('\n', pos)
                extracted_str = stdout_val[pos:eol]
                array = ('ATI', 'NVIDIA', 'VIA', 'Intel')
                test_str = extracted_str
                for ele in array:
                    test_str = test_str.replace(ele, '')
                if  len(test_str) != len(extracted_str):
                    info = extracted_str
                else:
                    pci_info = read_pci_info(('VGA compatible controller', ''))
                    if pci_info is not None:
                        info = pci_info
                    pos = info.find(' DRI ')
                    if pos > 0:
                        info = info[pos+5:]
        if len(info) > 0:
            self.gpu_info = '%s %sMB' % (info, str(gpu_mem_size))    
        return self.gpu_info

    # need xrandr support, ignore now
    def get_screen_resolution(self):
        cmd = Env_Util.prgs["xdpyinfo"]
        returncode, stdout_val = run_shell_cmd('%s | grep "dimensions:"' % cmd)
        if returncode == 0:
            pos = stdout_val.find('dimensions:')
            if pos >= 0:
                eol = stdout_val.find('\n')
                self.screen_resolution = stdout_val[pos+len('dimensions:'):eol].strip()                
        return self.screen_resolution

    def get_networking_info(self):
        cmd = Env_Util.prgs["lspci"]
        proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, \
                               stderr=subprocess.PIPE)
        stdout_val = proc.communicate()[0]
        if proc.returncode == 0:
            r = re.compile(r'Ethernet controller: (.*) \(rev')
            r1 = re.compile(r'Network controller: (.*)')
            networking = ''
            for line in stdout_val.splitlines():
                m = r.search(line)
                m1 = r1.search(line)
                if m is not None:
                    networking += m.group(1) + '; '
                if m1 is not None:
                    networking += m1.group(1) + '; '
            if len(networking) > 0:
                self.networking = networking.rstrip('; ') 
        return self.networking

    def get_disk_info(self):
        # Search /sys/block/sd*
        path = '/sys/block/'
        for root, dirs, files in os.walk(path): 
            r = re.compile('sd[a-z]')
            disk_string = ''
            for dir in dirs:
                if r.match(dir) is not None:
                    # Check device/model, size
                    model_file = os.path.join(path, dir + '/device/model')
                    size_file = os.path.join(path, dir + '/size')
                    if os.path.isfile(model_file) and os.path.isfile(size_file):
                        size_str = open(size_file, 'r').readline().rstrip('\n')
                        size = int(size_str) * 512 / 1000000000
                        if len(disk_string) > 0:
                            disk_string += '; ' # add seperator
                        disk_string += open(model_file, 'r').readline().rstrip('\n') + \
                                ' ' + str(size) + 'GB'
            if len(disk_string) > 0:
                disk_string = string.join(disk_string.split())
                self.disk_string = disk_string 
        return self.disk_string        

    # Get device name and bios info
    def get_device_info(self):
        cmd = Env_Util.prgs["dmidecode"]
        returncode, stdout_val = run_shell_cmd(cmd)
        bios_vendor, bios_version, bios_date = None, None, None
        device_name = None
        if returncode == 0:
            bios_vendor = extract_field_from_section(stdout_val, 'Vendor:', 'BIOS Information')
            bios_version = extract_field_from_section(stdout_val, 'Version:', 'BIOS Information')
            # Reserved for future
            bios_date = extract_field_from_section(stdout_val, 'Release Date:', 'BIOS Information')
            # device name doesn't include detailed model
            device_name = extract_field_from_section(stdout_val, 'Product Name:','System Information')
        if (bios_vendor is not None) and (bios_version is not None):
            self.bios =  bios_vendor + ' ' + bios_version
        if device_name is not None:
            self.device_name = device_name
        return self.bios, self.device_name
 
    # Get motherboard info
    def get_motherboard_info_from_hal(self):
        info = 'n/a'
        # Read system HAL
        vendor = read_system_hal_info(('system.hardware.vendor', 'system.board.vendor'))
        product  = read_system_hal_info(('system.hardware.product', 'system.board.product'))
        version = read_system_hal_info(('system.hardware.version', 'smbios.system.version'))
        if vendor is not None:
            info = vendor
        if product is not None:
            info += ' ' + product
        if version is not None:
            info += ' ' + version
        #if info == 'n/a':
        #    info = read_system_hal_info(('system.firmware.version'))
        #if info == 'n/a':
        #    info = read_hal(('pci.subsys_vendor'))
        self.motherboard = info
        return self.motherboard

    # Get motherboard info
    def get_motherboard_info(self):
        if os.path.isfile('/sys/devices/virtual/dmi/id/board_vendor'):
            returncode, stdout_val = run_shell_cmd('cd /sys/devices/virtual/dmi/id && cat board_vendor board_name board_version board_serial 2>/dev/null | xargs')
	    if returncode == 0:
                self.motherboard = stdout_val.strip()
        if self.motherboard == 'n/a':
            self.get_motherboard_info_from_hal()
        
    def get_chipset_info(self):
        info = read_pci_info(('RAM memory', 'Host bridge'))
        bridge = None
        if (info is not None) and (len(info.split()) == 1):
            bridge =  read_pci_info(('Bridge', 'PCI bridge'))
            if bridge is not None:
                seperators = ('High', 'USB', 'Ethernet', 'PCI')
                for sep in seperators:
                    pos = bridge.find(sep)
                    if pos != -1:
                        bridge = bridge[:pos]
                        info = bridge
                        break
        if (bridge is None) or (len(bridge) == 0):
            south_bridge = read_pci_info(('ISA bridge', 'SATA controller'), False)
            extracted_str = ''
            if south_bridge is not None:
                start_pos = south_bridge.find('(')
                end_pos = south_bridge.find(')')
                if min(start_pos, end_pos) != -1:
                    extracted_str = south_bridge[start_pos+1:end_pos]
                else:
                    start_pos = south_bridge.find('SB')
                    if start_pos != -1:
                        extracted_str = (south_bridge[start_pos:].split())[0]
            if len(extracted_str) > 0:
                info += ' + %s' % extracted_str   
        self.chipset = info
        return self.chipset

    def get_audio_info(self):
        info = read_pci_info(('Audio device',''), True)
        if info is not None:
            self.audio = info
        return self.audio

    def get_uvccamera_info(self):
        returncode, lshal_info = run_shell_cmd('lshal 2>&1')
        pos = lshal_info.find('info.linux.driver = \'uvcvideo\'')
        r = re.compile('info.parent = (\S*)\s*\(string\)')
        m = r.search(lshal_info[pos:])
        if m is not None:
            # search parent uid for camera hw
	    pos = lshal_info.find('udi = ' + m.group(1))
	    if pos > 0:
		product, vendor = None, None
		# get product name
		r = re.compile('usb_device.product = \'(.*)\'\s*\(string\)')
		m = r.search(lshal_info[pos:])
		if m is not None:
		    product = m.group(1)
		# get vendor name
                r = re.compile('usb_device.vendor = \'(.*)\'\s*\(string\)')
                m = r.search(lshal_info[pos:])
                if m is not None:
                    vendor = m.group(1)
		if (product is not None) and (vendor is not None):
		    self.camera = '%s %s' % (vendor.strip(), product.strip())
	return self.camera
     
    def get_camera_info(self):
        if os.path.isfile('/proc/bus/usb/devices') == False:
            returncode, stdout_val = run_shell_cmd('mount -t usbfs usbfs /proc/bus/usb')
            if returncode != 0:
                return self.camera
        if os.path.isfile('/proc/bus/usb/devices'):
            returncode, stdout_val = run_shell_cmd('cat /proc/bus/usb/devices | grep -i "product.*cam"')
            if returncode == 0:
                # Parse hal value
                re_str = '.*roduct\s*=\s*(.*)' 
                m = re.compile(re_str).search(stdout_val)
                if m is not None:
                    self.camera = m.group(1)
        return self.camera

class Env_SysInfo:
    def __init__(self):
        self.fs_info = 'n/a'
        self.glx_info = 'n/a'
        self.compile_opt_info = 'n/a'

    def get_fs_info(self):
        returncode, stdout_val = run_shell_cmd('mount -v')
        if returncode == 0:
            self.fs_info = stdout_val.rstrip('\n')
        return self.fs_info

    def get_glx_info(self):
        cmd = Env_Util.prgs["glxinfo"]
        search_str = 'vendor|OpenGL renderer string|direct rendering'
        returncode, stdout_val = run_shell_cmd('%s > /dev/null 2>&1 && %s | egrep "%s"' % (cmd, cmd, search_str))
        if returncode == 0:
             self.glx_info = stdout_val.rstrip('\n')
        return self.glx_info

    def get_compile_opt_info(self):
        cmd = Env_Util.prgs["gcc"]
        returncode, stdout_val = run_shell_cmd('echo "CFLAGS=$CFLAGS"; echo "CXXFLAGS=$CXXFLAGS";')
        if returncode == 0:
            self.compile_opt_info = stdout_val
        returncode, stdout_val = run_shell_cmd('%s -v 2>&1' % cmd)
        if returncode == 0:
            self.compile_opt_info += stdout_val.rstrip('\n').replace("'", "")
        return self.compile_opt_info

# Class of SW Environment                    
class Env_SWInfo:
    def __init__(self):
        self.compiler = 'n/a'
        self.graphic_driver = 'n/a'
        # Obsolete, to use built_time in predefined config file instead
        self.built_time = 'n/a'
        #self.milestone = 'n/a'
        #self.image_name = 'n/a'
        #self.distribution_name = 'moblin'
        #self.is_baseline = '0'
        self.os = 'unknown'
        self.kernel = 'n/a'
        self.filesystem =  'n/a'
        self.OpenGL_version = 'n/a'
        self.desktop_env = 'n/a'
        self.display_server = 'n/a'

    def get_compiler(self):
        compiler = ''
        # check CC version
        cmd = 'cc -dumpversion'
        returncode, stdout_val = run_shell_cmd(cmd)
        if returncode == 0:
            compiler = 'CC ' + stdout_val.rstrip('\n')
            # check GCC version
            cmd = 'gcc -dumpversion'
            returncode, stdout_val = run_shell_cmd(cmd)
            if returncode == 0:
                self.compiler = 'GCC ' + stdout_val.rstrip('\n')
            else:
                self.compiler = compiler
        return self.compiler
        
    # Get sw graphic driver info
    def get_graphic_driver(self):
        # check /proc/dri/0/name for driver name
        dri_file = '/proc/dri/0/name'
        xorg_log_file = get_xorg_log_file_name()
        if os.path.isfile(dri_file) and os.path.isfile(xorg_log_file):
            dri_string = open(dri_file, 'r').readline().rstrip('\n')
            dri_driver = dri_string.split(' ')[0]
            if dri_driver == 'i915':
                dri_driver = 'intel'
            dri_driver += '_drv'
            # Check /var/log/Xorg.0.log for dri version
            logs = open(xorg_log_file, 'r').read()
            pos = logs.find('module version =', logs.find(dri_driver)+ len(dri_driver))
            if pos != -1:
                r = re.compile('module version = (\S*)\n')
                m = r.match(logs[pos:])
                if m is not None:
                    self.graphic_driver = dri_driver + ' ' + m.group(1)
        else:
            pass # ignore mesa or nvidia driver
        return self.graphic_driver
    
    def get_built_time(self):
        cmd = 'uname -v'
        returncode, stdout_val = run_shell_cmd(cmd)
        if returncode == 0:
            r = re.compile('(\S*) (\S*) (\d\d:\d\d:\d\d) \S* (\S*)')
            m = r.search(stdout_val)
            if m is not None:
                month = m.group(1)
                day = m.group(2)
                time = m.group(3)
                year = m.group(4)
                array_month = ['Jan','Feb', 'Mar', 'Apr', 'May', \
                        'Jun', 'Jul', 'Aug',  'Sep', 'Oct', 'Nov',  'Dec']
                for i in range(0, 11):
                    if month == array_month[i]:
                        month = '%02d' % (i + 1)
                        break
                self.built_time = '%s-%s-%s %s' % (year, month, day, time)
        return self.built_time 
    
    # For netbook, package "moblin-lsb" is needed 
    def get_os_info(self):
        vendor = read_lsb_info('Distributor ID')
        version = read_lsb_info('Release')
        if (vendor is not None) and (version is not None):
            self.os = '%s %s' % (vendor, version)
        else:
            # If no lsb_release available, check /etc/issue
            if os.path.isfile('/etc/issue'):
                f = open('/etc/issue', 'r')
                val = f.readline()
                self.os = val[:val.find('(')].strip()
                f.close()
        return self.os

    def get_kernel_info(self):
        returncode, kernel = run_shell_cmd('uname -r 2>&1')
        returncode, kernel_arch = run_shell_cmd('uname -m 2>&1')
        self.kernel = '%s(%s)' % (kernel.strip('\n '), kernel_arch.strip('\n '))
        return self.kernel

    def get_filesystem_info(self):
        returncode, info = run_shell_cmd('stat / -L -f -c %T 2> /dev/null')
        if returncode == 0:
            info = info.strip()
            if os.path.isfile('/etc/fstab'):
                fstab = open('/etc/fstab').read()
                if info == 'ext2/ext3':
                    ext2_used = (fstab.find('ext2') != -1)
                    ext3_used = (fstab.find('ext3') != -1)
                    ext4_used = (fstab.find('ext4') != -1)
                    if (ext2_used) and (not ext3_used) and (not ext4_used):
                        info = 'ext2'
                    elif (not ext2_used) and (ext3_used) and (not ext4_used):     
                        info = 'ext3'
                    elif (not ext2_used) and (not ext3_used) and (ext4_used):     
                        info = 'ext4'
            if (info.find('UNKNOWN') != -1) and os.path.isfile('/proc/mounts'):
                mounts = open('/proc/mounts').read()
                fs = []
                if mounts.find('squashfs') != -1:
                    fs.append('SquashFS')
                if mounts.find('aufs') != -1:
                    fs.append('AuFS')
                if mounts.find('unionfs') != -1:
                    fs.append('UnionFS')
                info = ''
                for ele in fs:
                    info = '%s + %s' % (info, ele)
            self.filesystem = info
        return self.filesystem

    # This function must run in graphic mode, since glxinfo needs GUI environment
    # or there would be no value returned by 'glxinfo'
    def get_OpenGL_info(self):
        cmd = Env_Util.prgs["glxinfo"]
        returncode, info = run_shell_cmd('%s 2>&1 | grep version' % cmd)
        search_str = 'OpenGL version string:'
        pos = info.find(search_str)
        if pos >= 0:
            pos += len(search_str)
            eol = info.find('\n', pos)
            ver = info[pos:eol].strip()
            self.OpenGL_version = ver.replace(' Release', '')
        return self.OpenGL_version 

    # This function must run in graphic mode
    def get_desktop_environment(self):
        desktop_env = ""
        desktop_ver = ""
        if is_process_running('gnome-panel'):
            desktop_env = 'GNOME'
            returncode, stdout_val = run_shell_cmd('gnome-about --version 2>/dev/null')
            if returncode == 0:
                desktop_ver = stdout_val.split()[-1]
        elif  is_process_running('kded4') or is_process_running('kded'):
            desktop_env = 'KDE' # ignore KDE version here
        elif is_process_running('xfce4-session') or is_process_running('xfce-mcs-manager'):
            desktop_env = 'Xfce'
            returncode, stdout_val = run_shell_cmd('xfce4-session-settings --version 2>/dev/null')
            start_pos = stdout_val.find('(')
            end_pos = stdout_val.find(')', start_pos)
            if (start_pos >= 0) and (end_pos > 0):
                desktop_ver = stdout_val[start_pos+1:end_pos]
        if len(desktop_env) > 0:
            self.desktop_env = ('%s %s' % (desktop_env, desktop_ver)).strip()
        return  self.desktop_env
                
    def get_display_server(self):
        returncode, stdout_val = run_shell_cmd('X -version 2>&1')
        if returncode == 0:
            pos_end = stdout_val.find('Release Date')
            if pos_end == -1:
                pos_end = stdout_val.find('Build Date')
    
            pos_beg = stdout_val.find('X.Org X Server')
            if pos_end > 0 and pos_beg > 0:
                info = stdout_val[pos_beg:pos_end].replace('\n','')
                info = info.strip()
                self.display_server = info 
        return self.display_server

# Class of Predefined system information
def collect_test_env(hw_info, sw_info, sys_info):
    # Auto collect environment infomation
    hw_info.get_cpu_info()
    hw_info.get_mem_info()
    hw_info.get_disk_info()
    hw_info.get_camera_info()
    hw_info.get_motherboard_info()
    if Env_Util.prgs["lspci"] is not None:
        hw_info.get_networking_info()
        hw_info.get_chipset_info()
        hw_info.get_audio_info()
    if Env_Util.prgs["dmidecode"] is not None:
        hw_info.get_device_info()
    if Env_Util.prgs["glxinfo"] is not None:
        hw_info.get_gpu_info()
    if Env_Util.prgs["xdpyinfo"] is not None:
        hw_info.get_screen_resolution()

    sw_info.get_compiler()
    sw_info.get_graphic_driver()
    sw_info.get_built_time()
    sw_info.get_os_info()
    sw_info.get_kernel_info()
    sw_info.get_filesystem_info()
    if Env_Util.prgs['glxinfo'] is not None:
        sw_info.get_OpenGL_info()    
    sw_info.get_desktop_environment()
    sw_info.get_display_server()

    sys_info.get_fs_info()
    if Env_Util.prgs['glxinfo'] is not None:
        sys_info.get_glx_info()
    if Env_Util.prgs['gcc'] is not None:
        sys_info.get_compile_opt_info()

def print_env_info(hw_info, sw_info, sys_info):
    # basic info
    print('**********  HW/SW Overview  **********')
    print('memory: %s' % hw_info.mem_total)
    print('graphic_driver: %s' % sw_info.graphic_driver)
    print('networking: %s' % hw_info.networking)
    print('compiler: %s' % sw_info.compiler)
    print('ht: %s' % hw_info.cpu_ht)
    print('bios_version: %s' % hw_info.bios)
    print('platform_stepping: %s' % hw_info.cpu_stepping)
    print('cpu_stepping: %s' % hw_info.cpu_stepping)
    print('cpu_frequency: %s' % hw_info.cpu_freq)
    print('disk_size: %s' % hw_info.disk_string)
    # extra fields
    print('cpu_model: %s' % hw_info.cpu_model)
    print('motherboard: %s' % hw_info.motherboard)
    print('chipset: %s' % hw_info.chipset)
    print('graphics: %s' % hw_info.gpu_info)
    print('audio: %s' % hw_info.audio)
    print('camera: %s' % hw_info.camera)
    print('OS: %s' % sw_info.os)
    print('kernel: %s' % sw_info.kernel)
    print('filesystem: %s' % sw_info.filesystem)
    print('OpenGL: %s' % sw_info.OpenGL_version)
    print('Desktop: %s' % sw_info.desktop_env)
    print('Display_server: %s' % sw_info.display_server)
    print('screen_resolution: %s\n' % hw_info.screen_resolution)
    # sub system info
    print('**********  File System Info  **********')
    print('%s\n' % sys_info.fs_info)
    print('**********  Graphics Info  **********')
    print('%s\n' % sys_info.glx_info)
    print('**********  Compile Option Info *********')
    print('%s' % sys_info.compile_opt_info)

def generate_env_report():
    # Auto collect environment infomation
    hw_info = Env_HWInfo()
    sw_info = Env_SWInfo()
    sys_info = Env_SysInfo()
    collect_test_env(hw_info, sw_info, sys_info)
    
    return print_env_info(hw_info, sw_info, sys_info)
    
def usage(cmd):
    print 'Usage:\n' \
          '  %s [options...]: collect system environment information. \n\n' \
          'Options:\n' \
          '  -q, --Quiet               Quiet mode.\n' \
          '  -h, --help                Display this help.\n\n' \
	  'Examples:\n' \
          '    %s\n' \
	  '    Or %s -q \n' % (cmd, cmd, cmd)

def pre_check(enable_quiet_mode=False):
    prg_name = sys.argv[0]
    # run as root
    returncode, stdout_val = run_shell_cmd('whoami')
    username = stdout_val.strip()
    if username != 'root':
        print "Please run %s as 'root', you could either use sudo or su first." % prg_name
        if enable_quiet_mode == False:
            sys.exit(3)

    # under X 
    returncode, stdout_val = run_shell_cmd("xterm ls 2>&1 | grep -iq 't open display'")
    if returncode == 0:
        print "Can not open display, please run %s in X client." % prg_name
        if enable_quiet_mode == False:
	        sys.exit(3)

    # program existence
    missing = None
    eu_prgs = Env_Util()
    missing = eu_prgs.init_prgs()
    if len(missing) != 0:
        missing_txt = " ".join(missing)
        print "Warning!! Some needed programs are not found: %s" % missing_txt
        print "          You had better install them manually then rerun system_info, "
        print "          or some information will not be collected." 
        if enable_quiet_mode == False:
            prompt = 'Do you still want to continue (y/n)?'
            s = text_input(prompt)
            while s[0]  not in ('y', 'Y', 'n', 'N'):
                s = text_input(prompt)
            else:
                if s[0] in ('n', 'N'):
                    sys.exit()
    
if __name__ == '__main__':
    # Parse cmdline parameters
    try:
	opts, args = getopt.getopt(sys.argv[1:], 'qh', 
                        ['quiet', 'help'])
    except getopt.GetoptError:
        # print help information and exit:
        usage(os.path.basename(sys.argv[0]))
        sys.exit(2)

    enable_quiet_mode = False
    for o, a in opts:
        if o in ("-q", "--quite"):
            enable_quiet_mode = True
        if o in ('-h', '--help'):
            usage(os.path.basename(sys.argv[0]))
            sys.exit()
   
    pre_check(enable_quiet_mode)
    print ""
    generate_env_report()

