#!/usr/bin/python
###########################################################################
# displayconfig-hwprobe.py - description                                  #
# ------------------------------                                          #
# begin     : Sun Jan 22 2006                                             #
# copyright : (C) 2006 by Simon Edwards                                   #
# email     : simon@simonzone.com                                         #
#                                                                         #
###########################################################################
#                                                                         #
#   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 should be run during boot time. It quickly examines the
# graphics cards (read: PCI devices) in the computer and compares they to
# the list in the file $hardware_info_filename. If the two lists differ
# then the Debian package manager is automatically called to regenerate
# /etc/X11/xorg.conf. This hopefully should mean that people can swap gfx
# cards in and out and always have a system that will run Xorg. (even
# though the config will be most likely be suboptimal. Suboptimal is better
# than no X server).

import ScanPCI
import os
import syslog
import select

hardware_info_filename = "/var/lib/guidance/guidance-gfxhardware-snapshot"
data_file_dir = "/usr/share/apps/guidance/"

def main():
    # Scan the PCI bus.
    pci_bus = ScanPCI.PCIBus(data_file_dir)
    pci_bus.detect()

    # Stuff our device info in to a string.
    hardware_config = ""
    for pci_device in pci_bus.devices:
        if pci_device.isGfxCard():
            hardware_config += "PCI:%i:%i:%i Vendor:%x Device:%x Subvendor:%x Subdevice:%x\n" % \
                (pci_device.pci_bus, pci_device.pci_device, pci_device.pci_function,
                pci_device.vendor, pci_device.device,
                pci_device.subvendor, pci_device.subdevice)

    # Read in the old gfx hardware info in.
    previous_hardware = None
    try:
        fhandle = open(hardware_info_filename)
        previous_hardware = fhandle.read()
        fhandle.close()
    except IOError:
        previous_hardware = None

    if previous_hardware is not None and previous_hardware!=hardware_config:
        # Run dpkg and configure the new hardware.
        syslog.syslog(syslog.LOG_INFO, "Graphics card hardware has changed. Reconfiguring xorg.conf using 'dpkg-reconfigure xserver-xorg'.")
        cmd = ['dpkg-reconfigure','xserver-xorg']
        environ = os.environ.copy()
        environ['DEBIAN_FRONTEND'] = 'noninteractive'
        #os.spawnvpe(os.P_WAIT, 'dpkg-reconfigure', cmd, environ)
        result = ExecWithCapture('/usr/sbin/dpkg-reconfigure', cmd, 0, '/', 0,1, -1, environ)
        for line in result.split('\n'):
            syslog.syslog(syslog.LOG_INFO,"dpkg-reconfigure:"+line)

        # [21:18] <Riddell> you are brave indeed
        # [21:21] <Sime> I figured some kind of non-interactive "dpkg-reconfigure xorg" might be enough.
        # [21:22] <Riddell> yep

    if previous_hardware is None or previous_hardware!=hardware_config:
        syslog.syslog(syslog.LOG_INFO, "Writing graphics card hardware list to "+hardware_info_filename)
        # Write out the gfx hardware info
        tmp_filename = hardware_info_filename + ".tmp"
        fhandle = open(tmp_filename,'w')
        fhandle.write(hardware_config)
        fhandle.close()
        os.rename(tmp_filename, hardware_info_filename)


############################################################################
def ExecWithCapture(command, argv, searchPath = 0, root = '/', stdin = 0,
        catchfd = 1, closefd = -1, environ = None):

    if not os.access(root + command, os.X_OK) and not searchPath:
        raise RuntimeError, command + " can not be run"

    (read, write) = os.pipe()
    childpid = os.fork()
    if (not childpid):
        if (root and root != '/'): os.chroot(root)
        os.dup2(write, catchfd)
        os.close(write)
        os.close(read)

        if closefd != -1:
            os.close(closefd)
        if stdin:
            os.dup2(stdin, 0)
            os.close(stdin)

        # Replace the environment
        if environ is not None:
            os.environ.clear()
            os.environ.update(environ)

        if searchPath:
            os.execvp(command, argv)
        else:
            os.execv(command, argv)
        sys.exit(1)
    os.close(write)

    rc = ""
    s = "1"
    while s:
        select.select([read], [], [])
        s = os.read(read, 1000)
        rc = rc + s

    os.close(read)

    try:
        os.waitpid(childpid, 0)
    except OSError, (errno, msg):
        print __name__, "waitpid:", msg

    return rc

main()
