Skip to content

Instantly share code, notes, and snippets.

@starks
Created February 26, 2017 20:27
Show Gist options
  • Save starks/192a68831e59769d2d9d840bf8903d05 to your computer and use it in GitHub Desktop.
Save starks/192a68831e59769d2d9d840bf8903d05 to your computer and use it in GitHub Desktop.
switchlibglx
#!/usr/bin/python
#
# switchlibglx
#
# Copyright 2011 Canonical Ltd.
# Author: Alberto Milone <alberto.milone@canonical.com>
#
# Script to switch between AMD and Intel graphics driver libraries.
#
# Usage:
# switchlibglx amd|intel|query
# amd: switches to AMD's version of libglx.so
# intel: switches to the open-source version of libglx.so
# query: checks which version is currently active and writes
# "amd", "intel" or "unknown" to the standard output
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
import optparse
import os
import sys
import re
import subprocess
from subprocess import Popen, PIPE, CalledProcessError
class Alternatives:
def __init__(self, master_link):
self._open_drivers_alternative = 'mesa/ld.so.conf'
self._command = 'update-alternatives'
self._master_link = master_link
# Make sure that the PATH environment variable is set
if not os.environ.get('PATH'):
os.environ['PATH'] = '/sbin:/usr/sbin:/bin:/usr/bin'
def _find_process(self, process_name):
ps = subprocess.Popen("ps -eaf | grep " + process_name + " | grep -v grep",
shell=True, stdout=subprocess.PIPE)
output = ps.stdout.read()
ps.stdout.close()
ps.wait()
m = re.search('^(\w+)\s+(\d+)\s+.*', output, re.M)
if m:
try:
output = int(m.group(2))
except ValueError:
output = -1
else:
output = -1
return output
def _is_process_running(self, process_name):
process_id = self._find_process(process_name)
if process_id < 0:
return False
try:
os.kill(process_id, 0)
return True
except OSError:
return False
def list_alternatives(self):
'''Get the list of alternatives for the master link'''
dev_null = open('/dev/null', 'w')
alternatives = []
p1 = Popen([self._command, '--list', self._master_link], stdout=PIPE, stderr=dev_null)
p = p1.communicate()[0]
dev_null.close()
c = p.split('\n')
for line in c:
line.strip() and alternatives.append(line.strip())
return alternatives
def get_current_alternative(self):
'''Get the alternative in use'''
dev_null = open('/dev/null', 'w')
current_alternative = None
p1 = Popen([self._command, '--query', self._master_link], stdout=PIPE, stderr=dev_null)
p = p1.communicate()[0]
dev_null.close()
c = p.split('\n')
for line in c:
if line.strip().startswith('Value:'):
return line.replace('Value:', '').strip()
return None
def get_alternative_by_name(self, name):
'''Get the alternative link by providing the driver name'''
alternatives = self.list_alternatives()
for alternative in alternatives:
if alternative.__contains__(name):
return alternative
return None
def get_open_drivers_alternative(self):
'''Get the alternative link for open drivers'''
return self.get_alternative_by_name(self._open_drivers_alternative)
def update_gmenu(self):
'''Trigger gmenu so that the icons will show up in the menu'''
try:
subprocess.check_call(['dpkg-trigger', '--by-package=fakepackage', 'gmenucache'], stdout=open(os.devnull, 'w'))
# Let's not call dpkg if dpkg is already running
if not self._is_process_running('dpkg'):
subprocess.check_call(['dpkg', '--configure', '-a'], stdout=open(os.devnull, 'w'))
except (OSError, CalledProcessError):
pass
def set_alternative(self, path):
'''Tries to set an alternative and returns the boolean exit status'''
try:
subprocess.check_call([self._command, '--set', self._master_link, path], stdout=open(os.devnull, 'w'))
self.ldconfig()
except CalledProcessError:
return False
self.update_gmenu()
return True
def ldconfig(self):
'''Call ldconfig'''
try:
subprocess.check_call(['ldconfig'], stdout=open(os.devnull, 'w'))
except CalledProcessError:
return False
return True
class Switcher(object):
def __init__(self):
self._supported_architectures = {'i386': 'i386', 'amd64': 'x86_64'}
main_arch = self._get_architecture()
other_arch = self._supported_architectures.values()[
int(not self._supported_architectures
.values().index(main_arch))]
main_alternative_name = self._get_alternative_name_from_arch(main_arch)
other_alternative_name = self._get_alternative_name_from_arch(other_arch)
# We have 2 alternatives, one for each architecture
self._gl_switcher = Alternatives(main_alternative_name)
self._gl_switcher_other = Alternatives(other_alternative_name)
def _get_architecture(self):
dev_null = open('/dev/null', 'w')
p1 = Popen(['dpkg', '--print-architecture'], stdout=PIPE, stderr=dev_null)
p = p1.communicate()[0]
dev_null.close()
architecture = p.strip()
return self._supported_architectures.get(architecture)
def _get_alternative_name_from_arch(self, architecture):
alternative = '%s-linux-gnu_gl_conf' % architecture
return alternative
def _simplify_x_alternative_name(self, alternative):
return alternative.split('/')[-1]
def _simplify_gl_alternative_name(self, alternative):
return alternative.split('/')[-2]
def _get_gl_alternatives_list(self):
raw_alternatives = self._gl_switcher.list_alternatives()
return [ self._simplify_gl_alternative_name(x) for x in raw_alternatives ]
def _update_initramfs(self):
subprocess.call(['update-initramfs', '-u'])
# This may not be necessary
subprocess.call(['update-initramfs', '-u', '-k', os.uname()[2]])
def _get_current_alternative(self):
# This is a list as the 2nd item could be another alternative
# we might be looking for e.g. an xorg.conf alternative
alternatives = [None, None]
raw_gl_alternative = self._gl_switcher.get_current_alternative()
raw_gl_alternative_other = self._gl_switcher_other.get_current_alternative()
if (raw_gl_alternative != None):
alternatives[0] = self._simplify_gl_alternative_name(raw_gl_alternative)
if (raw_gl_alternative_other != None):
alternatives[1] = self._simplify_gl_alternative_name(raw_gl_alternative_other)
return alternatives
def enable_alternative(self, alternative):
# Make sure that the alternative exists
gl_alternative = self._gl_switcher.get_alternative_by_name(alternative)
gl_alternative_other = self._gl_switcher_other.get_alternative_by_name(alternative)
# See if they are null
# Abort if gl_alternative is null
if gl_alternative and gl_alternative_other:
success = (self._gl_switcher.set_alternative(gl_alternative) and
self._gl_switcher_other.set_alternative(gl_alternative_other))
return success
else:
sys.stderr.write("Error: no alternative can be found for %s\n" % alternative)
return False
def print_current_alternative(self):
alternatives = self._get_current_alternative()
try:
alternative = str(alternatives[0])
alternative_other = str(alternatives[1])
except IndexError:
# No alternative exists
return False
if alternative == alternative_other == 'fglrx':
print 'amd'
elif alternative == alternative_other == 'pxpress':
print 'intel'
else:
print 'unknown'
return True
def check_root():
if not os.geteuid() == 0:
sys.stderr.write("This operation requires root privileges\n")
exit(1)
def handle_alternatives_error(mode):
sys.stderr.write('Error: %s mode can\'t be enabled\n' % mode)
exit(1)
def handle_query_error():
sys.stderr.write("Error: no alternative can be found\n")
exit(1)
def usage():
sys.stderr.write("Usage: %s amd|intel|query\n" % (sys.argv[0]))
if __name__ == '__main__':
try:
arg = sys.argv[1]
except IndexError:
arg = None
check_root()
if len(sys.argv[1:]) != 1:
usage()
exit(1)
switcher = Switcher()
if arg == "amd":
if not switcher.enable_alternative('fglrx'):
handle_alternatives_error(arg)
elif arg == "intel":
if not switcher.enable_alternative('pxpress'):
handle_alternatives_error(arg)
elif arg == "query":
if not switcher.print_current_alternative():
handle_query_error()
else:
usage()
sys.exit(1)
exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment