#!/usr/bin/python # -*- coding: utf-8 -*- # vim: set et ts=4: # Filename: grml-x # Purpose: wrapper for startx on grml [providing new xconfiguration tool] # Authors: grml-team (grml.org), (c) Christian Hofstaedtler # Bug-Reports: see http://grml.org/bugs/ # License: This file is licensed under the GPL v2. ############################################################################### # Requires python 2.6 or, possibly, a newer version of python 2.X. import fileinput, os, subprocess, sys, tempfile, time, traceback from optparse import OptionParser class Section(object): def __init__(self, name, identifier, data): self.name = name self.identifer = identifier self.data = data self.subsect = "" def __str__(self): s = "Section \"%s\"\n\tIdentifier \"%s\"\n" % (self.name, self.identifer) for k in self.data: v = self.data[k] if isinstance(v, list): v = '" "'.join(v) elif not isinstance(v, basestring): # int, others v = str(v) elif '-' in v: # sync range pass else: v = '"%s"' % v s += "\t%s %s\n" % (k, v) s += self.subsect s += 'EndSection\n' return s def get_monitor_section(options, force): if not options.hsync and not options.vsync and not force: return None d = {} d['HorizSync'] = options.hsync or '28.0 - 96.0' d['VertRefresh'] = options.vsync or '50.0 - 60.0' return Section('Monitor', 'Monitor0', d) def get_device_section(options): if not options.module: return None d = {} d['Driver'] = options.module d['VendorName'] = 'All' d['BoardName'] = 'All' return Section('Device', 'Card0', d) def build_bootparams(): lines = [] def walk_bootparams_path(p): try: if not os.path.exists(p): return for root, dirs, files in os.walk(p): for name in files: f = open(os.path.join(root, name)) lines.extend(f.readlines()) f.close() except: print 'W: Error while getting bootparams from %s' % p f = open('/proc/cmdline') lines.append(f.readline()) f.close() walk_bootparams_path('/cdrom/bootparams') walk_bootparams_path('/live/image/bootparams') params = {} for p in ' '.join(lines).split(' '): if '=' in p: (k,v) = p.split('=', 1) params[k] = v else: params[p] = True return params def detect_qemu(): f = open('/proc/cpuinfo') x = ''.join(f.readlines()) f.close() if 'QEMU' in x: return True return False def get_program_output(args): p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True) return p.communicate()[0] def run_program(args): subprocess.Popen(args, close_fds=True).wait() def which(program): def is_exe(fpath): return os.path.exists(fpath) and os.access(fpath, os.X_OK) fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file return None XORG_CONF_HEADER = "# Automatically generated by grml-x." def check_old_xorg_conf(filename, overwrite): # True: no problem, we can create/overwrite the config file # False: pre-existing config file, and we are not to overwrite it if overwrite: return True if not os.path.exists(filename): return True try: f = file(filename, 'r') lines = f.readlines() f.close() return (not XORG_CONF_HEADER in lines) except IOError: return False parser = OptionParser(usage="usage: %prog [options] [window-manager]") parser.add_option("--nostart", action="store_false", dest="start_server", default=True, help="Don't start X server") parser.add_option("--display", action="store", type="string", dest="display", help="Start X server on display DISPLAY") parser.add_option("--hsync", action="store", type="string", dest="hsync", help="Force writing a HorizSync range") parser.add_option("--vsync", action="store", type="string", dest="vsync", help="Force writing a VertRefresh range") parser.add_option("--mode", action="store", type="string", dest="mode", help="Force a specific resolution") parser.add_option("--module", action="store", type="string", dest="module", help="Force driver MODULE instead of Xorg autodetection") parser.add_option("-o", action="store", type="string", dest="xorg_conf", default="/etc/X11/xorg.conf", help="Specify alternate xorg.conf file [default: %default]") parser.add_option("-f", "--force", action="store_true", dest="overwrite", default=False, help="Overwrite xorg.conf if it exists [default: %default]") parser.add_option("-t", "--tcp", action="store_true", dest="tcp", default=False, help="Enable TCP") def main(): (options, args) = parser.parse_args() bootparams = build_bootparams() if os.getuid() == 0 and options.start_server: print "W: running as root is unsupported and may not work." time.sleep(1) if not check_old_xorg_conf(options.xorg_conf, options.overwrite): print "E: Not overwriting existing %r without --force." % options.xorg_conf print "I: If you previously ran grml-x, use startx /usr/bin/x-window-manager" return 1 if 'xmode' in bootparams and not options.mode: options.mode = bootparams['xmode'] if 'xmodule' in bootparams and not options.module: options.module = bootparams['xmodule'] force_monitor = False # cirrus driver for QEMU doesn't do 1024x768 without HorizSync set if detect_qemu(): force_monitor = True monitor = get_monitor_section(options, force_monitor) device = get_device_section(options) # build Screen section ourselves d = {} if monitor: d['Monitor'] = monitor.identifer if device: d['Device'] = device.identifer screen = Section('Screen', 'Screen0', d) if options.mode: d['DefaultColorDepth'] = 16 for depth in [8, 15, 16, 24, 32]: screen.subsect += "SubSection \"Display\"\n\tDepth %d\n\tModes \"%s\"\t\nEndSubSection\n" % (depth, options.mode) xinitrc = '/home/brad/.xinitrc' if 'XINITRC' in os.environ: xinitrc = os.environ['XINITRC'] xinitrc = os.path.expanduser(xinitrc) window_manager = 'x-window-manager' if len(args) == 1: window_manager = args[0] window_manager_path = which(window_manager) if not window_manager_path: print "E: Cannot find window manager %r, aborting." % window_manager return 2 wm_exec = "exec %s\n" % window_manager_path if not os.path.exists(xinitrc): f = open(xinitrc, 'w') f.write("#!/bin/sh\n") f.write(wm_exec) f.close() else: f = open(xinitrc, 'r') lines = f.readlines() f.close() f = open(xinitrc, 'w') for line in lines: if line.strip().startswith('exec '): line = wm_exec f.write(line) os.fchmod(f.fileno(), 0750) f.close() # write new config if monitor or device or len(screen.data) > 0 or screen.subsect != '': try: f = tempfile.NamedTemporaryFile(delete=False) f.write(XORG_CONF_HEADER + "\n") f.write("# DO NOT MODIFY, YOUR CHANGES WILL BE LOST - OR REMOVE ALL HEADER LINES\n") f.write("# See man xorg.conf or /etc/X11/xorg.conf.example for more\n") if monitor: f.write(str(monitor)) if device: f.write(str(device)) f.write(str(screen)) f.flush() os.fchmod(f.fileno(), 0644) run_program(['mv', '-f', f.name, options.xorg_conf]) finally: f.close() if options.start_server: if options.tcp: startx = ['su', '-', 'brad', '-c', 'startx', xinitrc, '--'] else: startx = ['su', '-', 'brad', '-c', 'startx', xinitrc, '--', '-nolisten', 'tcp'] if options.display: startx.append(':' + options.display) print "Starting X: %r" % startx run_program(startx) return 0 if __name__ == '__main__': rc = 1 try: rc = main() except Exception: print "E: Exception: ", traceback.print_exc() sys.exit(1)