1
# detectors: lib to detect what hardware tags apply to the current system
3
# Copyright (C) 2012 Canonical
6
# Michael Vogt <mvo@ubuntu.com>
8
# This program is free software; you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation; either version 2 of the License, or
11
# (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with this program; if not, write to the Free Software
20
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
import multiprocessing
27
LOG=logging.getLogger(__name__)
30
from gi.repository import GUdev
35
from enums import HardwareSupported
37
class Detector(object):
38
""" Base detector class """
40
# helper functions for tags have this prefix, so the code can find them
41
# via introspecton, e.g.
42
# hardware::video:opengl -> _run_check_hardware__video_opengl
43
CHECK_FUNCTION_PREFIX = "_run_check_"
45
def is_supported(self, tag):
46
""" check if the given tag is supported, returns a
47
HardwareSupported class
49
f = self._get_func_for_tag(tag)
52
return HardwareSupported.UNKNOWN
54
def generate_tag_expressions(self):
55
""" Generate debtags expressions for the given HW """
56
for tag in self.get_supported_tags():
57
res = self.is_supported(tag)
58
if res == HardwareSupported.UNKNOWN:
62
def get_supported_tags(self):
63
""" return list of supported tags by this detector """
65
for name in dir(self):
66
tag = self._get_tag_for_func(name)
72
def _has_func_for_tag(self, tag):
73
return hasattr(self, "%s%s" % (
74
self.CHECK_FUNCTION_PREFIX, tag.replace(":", "_")))
76
def _get_func_for_tag(self, tag):
77
return getattr(self, "%s%s" % (
78
self.CHECK_FUNCTION_PREFIX, tag.replace(":", "_")), None)
80
def _get_tag_for_func(self, func_name):
81
if not func_name.startswith("%shardware" % self.CHECK_FUNCTION_PREFIX):
83
tag = func_name[len(self.CHECK_FUNCTION_PREFIX):].replace("_",":")
87
class DetectorUdev(Detector):
88
""" detect hardware based on udev """
90
DEBTAG_TO_UDEV_PROPERTY = {
92
"hardware::storage:cd" : "ID_CDROM",
93
"hardware::storage:cd-writer" : "ID_CDROM_CD_R",
94
"hardware::storage:dvd" : "ID_CDROM_DVD",
95
"hardware::storage:dvd-writer" : "ID_CDROM_DVD_R",
97
"hardware::input:touchscreen" : "ID_INPUT_TOUCH",
98
"hardware::input:mouse" : "ID_INPUT_MOUSE",
99
"hardware::input:keyboard" : "ID_INPUT_KEYBOARD",
100
"hardware::input:joystick" : "ID_INPUT_JOYSTICK",
105
self._uc = GUdev.Client()
109
def is_supported(self, tag):
110
LOG.debug("DetectorUdev.is_supported: '%s'" % tag)
112
return HardwareSupported.UNKNOWN
113
for device in self._uc.query_by_subsystem(None):
114
#print device.get_property_keys(), device.get_property("DEVPATH")
115
# supported a (theoretical at this point) udev property that
116
# sets the debtag tag directly
117
if device.has_property("HW_DEBTAGS"):
118
return tag in device.get_property("HW_DEBTAGS")
119
# use our own device detection magic
120
prop = self.DEBTAG_TO_UDEV_PROPERTY.get(tag)
121
if prop and device.has_property(prop):
122
#print device.get_property(prop)
123
if bool(device.get_property(prop)):
124
return HardwareSupported.YES
126
return HardwareSupported.NO
127
return HardwareSupported.UNKNOWN
129
def get_supported_tags(self):
130
return self.DEBTAG_TO_UDEV_PROPERTY.keys()
132
class DetectorCmdline(Detector):
133
""" detect hardware using cmdline helpers """
135
LAPTOP_DETECT = "/usr/sbin/laptop-detect"
136
SCANIMAGE = ["scanimage", "-L"]
139
def _run_check_hardware__laptop(self):
140
if os.path.exists(self.LAPTOP_DETECT):
141
if subprocess.call([self.LAPTOP_DETECT]) == 0:
142
return HardwareSupported.YES
144
return HardwareSupported.NO
147
"No laptop-detect '%s' helper found" % self.LAPTOP_DETECT)
148
return HardwareSupported.UNKOWN
151
def _run_check_hardware__scanner(self):
152
# note that this is slow to run (1-2s)
155
#sane = cdll.LoadLibrary("libsane.so.1")
156
#res = sane.sane_init(byref(ver), None)
158
#if not res == SANE_STATUS_GOOD:
161
#sane.sane_get_devices(byref(devices), False)
162
# device is SANE_device** device_list how to get data?
164
# Note: you can use multiprocessing.Pool.map to run all checks in
167
output = subprocess.check_output(self.SCANIMAGE)
168
if output.startswith("device"):
169
return HardwareSupported.YES
171
return HardwareSupported.NO
173
LOG.warn("error running '%s'" % self.SCANIMAGE)
174
return HardwareSupported.UNKNOWN
176
class DetectorCtypes(Detector):
177
""" detect hardware using ctypes c calls """
180
def _run_check_hardware__video_opengl(self):
181
# Launch in a seperate subprocess, since the ctypes opengl stuff might
182
# be fragile (segfault happy)
183
# multiprocessing is python 2.6+
185
pool = multiprocessing.Pool(1)
186
res = pool.apply(opengl.run_check)
190
return HardwareSupported.YES
192
return HardwareSupported.NO
195
class DetectorPython(Detector):
196
""" detect hadware using python imports """
199
def _run_check_hardware__printer(self):
201
# alternative use lpstat -p
203
c = cups.Connection()
204
if len(c.getPrinters()) > 0:
205
return HardwareSupported.YES
207
return HardwareSupported.NO
209
LOG.warn("No python-cups installed")
211
LOG.exception("_run_cups_check")
212
return HardwareSupported.UNKNOWN
216
""" hepler that returns a list of all lowlevel detector classes """
217
# introspect the detectors modules to load all availalbe detectors
219
for name, klass in globals().iteritems():
220
if name.startswith("Detector"):
221
detectors.append(klass())