2 # -*- coding: utf-8 -*-
4 # (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 __title__ = 'Dependency/Version Check Utility'
26 __doc__ = """Check the existence and versions of HPLIP dependencies. (Run as 'python ./check.py' from the HPLIP tarball before installation.)"""
37 from base import utils, tui, models
38 from installer import dcheck
39 from installer.core_install import *
43 from base import device, pml
44 # This can fail due to hpmudext not being present
46 log.debug("Device library is not avail.")
51 USAGE = [(__doc__, "", "name", True),
52 ("Usage: %s [OPTIONS]" % __mod__, "", "summary", True),
54 ("Compile-time check:", "-c or --compile", "option", False),
55 ("Run-time check:", "-r or --run", "option", False),
56 ("Compile and run-time checks:", "-b or --both (default)", "option", False),
57 utils.USAGE_LOGGING1, utils.USAGE_LOGGING2, utils.USAGE_LOGGING3,
58 utils.USAGE_LOGGING_PLAIN,
61 ("1. For checking for the proper build environment for the HPLIP supplied tarball (.tar.gz or .run),", "", "note", False),
62 ("use the --compile or --both switches.", "", "note", False),
63 ("2. For checking for the proper runtime environment for a distro supplied package (.deb, .rpm, etc),", "", "note", False),
64 ("use the --runtime switch.", "", "note", False),
67 def usage(typ='text'):
69 utils.log_title(__title__, __version__)
71 utils.format_text(USAGE, typ, __title__, __mod__, __version__)
75 build_str = "HPLIP will not build, install, and/or function properly without this dependency."
77 pat_deviceuri = re.compile(r"""(.*):/(.*?)/(\S*?)\?(?:serial=(\S*)|device=(\S*)|ip=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[^&]*)|zc=(\S+))(?:&port=(\d))?""", re.I)
78 #pat_deviceuri = re.compile(r"""(.*):/(.*?)/(\S*?)\?(?:serial=(\S*)|device=(\S*)|ip=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[^&]*))(?:&port=(\d))?""", re.I)
80 pat_cups_error_log = re.compile("""^loglevel\s?(debug|debug2|warn|info|error|none)""", re.I)
83 def parseDeviceURI(device_uri):
84 m = pat_deviceuri.match(device_uri)
87 raise Error(ERROR_INVALID_DEVICE_URI)
89 back_end = m.group(1).lower() or ''
90 is_hp = (back_end in ('hp', 'hpfax', 'hpaio'))
91 bus = m.group(2).lower() or ''
93 if bus not in ('usb', 'net', 'bt', 'fw', 'par'):
94 raise Error(ERROR_INVALID_DEVICE_URI)
96 model = m.group(3) or ''
97 serial = m.group(4) or ''
98 dev_file = m.group(5) or ''
99 host = m.group(6) or ''
102 zc = host = m.group(7) or ''
103 port = m.group(8) or 1
108 except (ValueError, TypeError):
114 # log.debug("%s: back_end '%s' is_hp '%s' bus '%s' model '%s' serial '%s' dev_file '%s' host '%s' zc '%s' port '%s' " %
115 # (device_uri, back_end, is_hp, bus, model, serial, dev_file, host, zc, port))
117 return back_end, is_hp, bus, model, serial, dev_file, host, zc, port
121 overall_commands_to_run = []
122 time_flag = DEPENDENCY_RUN_AND_COMPILE_TIME
125 log.set_module(__mod__)
128 opts, args = getopt.getopt(sys.argv[1:], 'hl:gtcrb',
129 ['help', 'help-rest', 'help-man', 'help-desc', 'logging=',
130 'run', 'runtime', 'compile', 'both'])
132 except getopt.GetoptError, e:
137 if os.getenv("HPLIP_DEBUG"):
138 log.set_level('debug')
143 if o in ('-h', '--help'):
146 elif o == '--help-rest':
149 elif o == '--help-man':
152 elif o == '--help-desc':
156 elif o in ('-l', '--logging'):
157 log_level = a.lower().strip()
165 elif o in ('-c', '--compile'):
166 time_flag = DEPENDENCY_COMPILE_TIME
168 elif o in ('-r', '--runtime', '--run'):
169 time_flag = DEPENDENCY_RUN_TIME
171 elif o in ('-b', '--both'):
172 time_flag = DEPENDENCY_RUN_AND_COMPILE_TIME
174 if not log.set_level(log_level):
180 utils.log_title(__title__, __version__)
182 log.info(log.bold("Note: hp-check can be run in three modes:"))
184 for l in tui.format_paragraph("1. Compile-time check mode (-c or --compile): Use this mode before compiling the HPLIP supplied tarball (.tar.gz or .run) to determine if the proper dependencies are installed to successfully compile HPLIP."):
187 for l in tui.format_paragraph("2. Run-time check mode (-r or --run): Use this mode to determine if a distro supplied package (.deb, .rpm, etc) or an already built HPLIP supplied tarball has the proper dependencies installed to successfully run."):
190 for l in tui.format_paragraph("3. Both compile- and run-time check mode (-b or --both) (Default): This mode will check both of the above cases (both compile- and run-time dependencies)."):
195 log_file = os.path.normpath('./hp-check.log')
196 log.info(log.bold("Saving output in log file: %s" % log_file))
197 log.debug("Log file=%s" % log_file)
198 if os.path.exists(log_file):
201 log.set_logfile(log_file)
202 log.set_where(log.LOG_TO_CONSOLE_AND_FILE)
204 log.info("\nInitializing. Please wait...")
205 core = CoreInstall(MODE_CHECK)
207 core.set_plugin_version()
209 tui.header("SYSTEM INFO")
211 log.info(log.bold("Basic system information:"))
212 log.info(core.sys_uname_info)
215 log.info(log.bold("Distribution:"))
216 log.info("%s %s" % (core.distro_name, core.distro_version))
218 #log.info(log.bold("\nHPOJ running?"))
220 #if core.hpoj_present:
221 #log.error("Yes, HPOJ is running. HPLIP is not compatible with HPOJ. To run HPLIP, please remove HPOJ.")
224 #log.info("No, HPOJ is not running (OK).")
228 log.info(log.bold("Checking Python version..."))
229 ver = sys.version_info
230 log.debug("sys.version_info = %s" % repr(ver))
237 log.info("OK, version %d.%d.%d installed" % ver[:3])
239 log.error("Version %d.%d.%d installed. Please update to Python >= 2.1" % ver[:3])
242 ui_toolkit = sys_conf.get('ui_toolkit', 'qt4')
243 if ui_toolkit == 'qt3':
245 log.info(log.bold("Checking PyQt 3.x version..."))
252 log.error("NOT FOUND OR FAILED TO LOAD!")
254 # check version of Qt
255 qtMajor = int(qt.qVersion().split('.')[0])
257 if qtMajor < MINIMUM_QT_MAJOR_VER:
258 log.error("Incorrect version of Qt installed. Ver. 3.0.0 or greater required.")
260 #check version of PyQt
262 pyqtVersion = qt.PYQT_VERSION_STR
263 except AttributeError:
264 pyqtVersion = qt.PYQT_VERSION
266 while pyqtVersion.count('.') < 2:
269 (maj_ver, min_ver, pat_ver) = pyqtVersion.split('.')
271 if pyqtVersion.find('snapshot') >= 0:
272 log.error("A non-stable snapshot version of PyQt is installed (%s)." % pyqtVersion)
276 maj_ver = int(maj_ver)
277 min_ver = int(min_ver)
278 pat_ver = int(pat_ver)
280 maj_ver, min_ver, pat_ver = 0, 0, 0
282 if maj_ver < MINIMUM_PYQT_MAJOR_VER or \
283 (maj_ver == MINIMUM_PYQT_MAJOR_VER and min_ver < MINIMUM_PYQT_MINOR_VER):
285 log.error("HPLIP may not function properly with the version of PyQt that is installed (%d.%d.%d)." % (maj_ver, min_ver, pat_ver))
286 log.error("Ver. %d.%d or greater required." % (MINIMUM_PYQT_MAJOR_VER, MINIMUM_PYQT_MINOR_VER))
288 log.info("OK, version %d.%d installed." % (maj_ver, min_ver))
295 log.info(log.bold("Checking PyQt 4.x version..."))
302 log.error("NOT FOUND OR FAILED TO LOAD!")
304 from PyQt4 import QtCore
305 log.info("OK, version %s installed." % QtCore.PYQT_VERSION_STR)
309 # log.info(log.bold("Checking SIP version..."))
314 # except ImportError:
317 # sip_ver = pyqtconfig.Configuration().sip_version_str
319 # if sip_ver is not None:
320 # log.info("OK, Version %s installed" % sip_ver)
323 # log.error("SIP not installed or version not found.")
326 log.info(log.bold("Checking for CUPS..."))
329 status, output = utils.run('lpstat -r')
331 log.info("Status: %s" % output.strip())
333 log.error("Status: (Not available. CUPS may not be installed or not running.)")
338 status, output = utils.run('cups-config --version')
340 log.info("Version: %s" % output.strip())
342 log.warn("Version: (cups-config) Not available. Unable to determine installed version of CUPS.)")
345 cups_conf = '/etc/cups/cupsd.conf'
348 f = file(cups_conf, 'r')
349 except (IOError, OSError):
350 log.warn("%s file not found or not accessible." % cups_conf)
353 m = pat_cups_error_log.match(l)
355 level = m.group(1).lower()
356 log.info("error_log is set to level: %s" % level)
358 #if level not in ('debug', 'debug2'):
359 #log.note("For troubleshooting printing issues, it is best to have the CUPS 'LogLevel'")
360 #log.note("set to 'debug'. To set the LogLevel to debug, edit the file %s (as root)," % cups_conf)
361 #log.note("and change the line near the top of the file that begins with 'LogLevel' to read:")
362 #log.note("LogLevel debug")
363 #log.note("Save the file and then restart CUPS (see your OS/distro docs on how to restart CUPS).")
364 #log.note("Now, when you print, helpful debug information will be saved to the file:")
365 #log.note("/var/log/cups/error_log")
366 #log.note("You can monitor this file by running this command in a console/shell:")
367 #log.note("tail -f /var/log/cups/error_log")
374 log.info(log.bold("Checking for dbus/python-dbus..."))
376 if dcheck.check_ps(['dbus-daemon']):
377 log.info("dbus daemon is running.")
379 log.warn("dbus daemon is not running.")
384 log.info("python-dbus version: %s" % dbus.__version__)
385 except AttributeError:
387 log.info("python-dbus version: %s" % '.'.join([str(x) for x in dbus.version]))
388 except AttributeError:
389 log.warn("python-dbus imported OK, but unknown version.")
391 log.warn("python-dbus not installed.")
396 if time_flag == DEPENDENCY_RUN_AND_COMPILE_TIME:
397 tui.header("COMPILE AND RUNTIME DEPENDENCIES")
398 log.note("To check for compile-time only dependencies, re-run hp-check with the -c parameter (ie, hp-check -c).")
399 log.note("To check for run-time only dependencies, re-run hp-check with the -r parameter (ie, hp-check -r).")
401 elif time_flag == DEPENDENCY_COMPILE_TIME:
402 tui.header("COMPILE TIME DEPENDENCIES")
404 elif time_flag == DEPENDENCY_RUN_TIME:
405 tui.header("RUNTIME DEPENDENCIES")
409 dd = core.dependencies.keys()
411 status, output = utils.run('cups-config --version')
413 if status == 0 and (string.count(output, '.') == 1 or string.count(output, '.') == 2):
414 if string.count(output, '.') == 1:
415 major, minor = string.split(output, '.', 2)
416 if string.count(output, '.') == 2:
417 major, minor, release = string.split(output, '.', 3)
418 if len(minor) > 1 and minor[1] >= '0' and minor[1] <= '9':
419 minor = ((ord(minor[0]) - ord('0')) * 10) + (ord(minor[1]) - ord('0'))
421 minor = ord(minor[0]) - ord('0')
422 if major > '1' or (major == '1' and minor >= 4):
423 dd.remove('cups-ddk')
427 if (d == 'pyqt' and ui_toolkit != 'qt3') or \
428 (d == 'pyqt4' and ui_toolkit != 'qt4'):
433 if time_flag == DEPENDENCY_RUN_AND_COMPILE_TIME or time_flag == core.dependencies[d][4]:
435 log.info(log.bold("Checking for dependency: %s..." % core.dependencies[d][2]))
437 if core.have_dependencies[d]:
438 log.info("OK, found.")
442 if core.dependencies[d][4] == DEPENDENCY_RUN_AND_COMPILE_TIME:
444 elif core.dependencies[d][4] == DEPENDENCY_COMPILE_TIME:
445 s = '/COMPILE TIME ONLY'
447 elif core.dependencies[d][4] == DEPENDENCY_RUN_TIME:
450 if core.dependencies[d][0]:
451 log.error("NOT FOUND! This is a REQUIRED%s dependency. Please make sure that this dependency is installed before installing or running HPLIP." % s)
453 log.warn("NOT FOUND! This is an OPTIONAL%s dependency. Some HPLIP functionality may not function properly." %s)
455 if core.distro_supported():
456 packages_to_install, commands = core.get_dependency_data(d)
460 if packages_to_install:
461 package_mgr_cmd = core.get_distro_data('package_mgr_cmd')
464 packages_to_install = ' '.join(packages_to_install)
465 commands_to_run.append(utils.cat(package_mgr_cmd))
468 commands_to_run.extend(commands)
470 overall_commands_to_run.extend(commands_to_run)
472 if len(commands_to_run) == 1:
473 log.info("To install this dependency, execute this command:")
474 log.info(commands_to_run[0])
476 elif len(commands_to_run) > 1:
477 log.info("To install this dependency, execute these commands:")
478 for c in commands_to_run:
484 if time_flag in (DEPENDENCY_RUN_TIME, DEPENDENCY_RUN_AND_COMPILE_TIME):
485 tui.header("HPLIP INSTALLATION")
487 scanning_enabled = utils.to_bool(sys_conf.get('configure', 'scanner-build', '0'))
490 log.info(log.bold("Currently installed HPLIP version..."))
491 v = sys_conf.get('hplip', 'version')
492 home = sys_conf.get('dirs', 'home')
495 log.info("HPLIP %s currently installed in '%s'." % (v, home))
498 log.info(log.bold("Current contents of '/etc/hp/hplip.conf' file:"))
500 output = file('/etc/hp/hplip.conf', 'r').read()
501 except (IOError, OSError), e:
502 log.error("Could not access file: %s" % e.strerror)
507 log.info(log.bold("Current contents of '/var/lib/hp/hplip.state' file:"))
509 output = file(os.path.expanduser('/var/lib/hp/hplip.state'), 'r').read()
510 except (IOError, OSError), e:
511 log.info("Plugins are not installed. Could not access file: %s" % e.strerror)
516 log.info(log.bold("Current contents of '~/.hplip/hplip.conf' file:"))
518 output = file(os.path.expanduser('~/.hplip/hplip.conf'), 'r').read()
519 except (IOError, OSError), e:
520 log.error("Could not access file: %s" % e.strerror)
525 log.info("Not found.")
530 #tui.header("DISCOVERED PARALLEL DEVICES")
532 #devices = device.probeDevices(['par'])
536 #f.header = ("Device URI", "Model")
538 #for d, dd in devices.items():
544 #log.info("No devices found.")
546 #if not core.have_dependencies['ppdev']:
547 #log.error("'ppdev' kernel module not loaded.")
550 tui.header("DISCOVERED USB DEVICES")
552 devices = device.probeDevices(['usb'])
556 f.header = ("Device URI", "Model")
558 for d, dd in devices.items():
564 log.info("No devices found.")
567 tui.header("INSTALLED CUPS PRINTER QUEUES")
569 lpstat_pat = re.compile(r"""(\S*): (.*)""", re.IGNORECASE)
570 status, output = utils.run('lpstat -v')
574 for p in output.splitlines():
576 match = lpstat_pat.search(p)
577 printer_name = match.group(1)
578 device_uri = match.group(2)
579 cups_printers.append((printer_name, device_uri))
580 except AttributeError:
583 log.debug(cups_printers)
587 for p in cups_printers:
588 printer_name, device_uri = p
590 if device_uri.startswith("cups-pdf:/") or \
591 device_uri.startswith('ipp://'):
595 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
596 parseDeviceURI(device_uri)
598 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
599 '', False, '', '', '', '', '', '', 1
601 #print back_end, is_hp, bus, model, serial, dev_file, host, zc, port
603 log.info(log.bold(printer_name))
604 log.info(log.bold('-'*len(printer_name)))
607 if back_end == 'hpfax':
609 elif back_end == 'hp':
612 log.info("Type: %s" % x)
615 # x = 'Yes, using the %s: CUPS backend.' % back_end
617 # x = 'No, not using the hp: or hpfax: CUPS backend.'
620 #log.info("Installed in HPLIP?: %s" % x)
621 log.info("Device URI: %s" % device_uri)
623 ppd = os.path.join('/etc/cups/ppd', printer_name + '.ppd')
625 if os.path.exists(ppd):
626 log.info("PPD: %s" % ppd)
627 nickname_pat = re.compile(r'''\*NickName:\s*\"(.*)"''', re.MULTILINE)
629 f = file(ppd, 'r').read(4096)
632 desc = nickname_pat.search(f).group(1)
633 except AttributeError:
636 log.info("PPD Description: %s" % desc)
638 status, output = utils.run('lpstat -p%s' % printer_name)
639 log.info("Printer status: %s" % output.replace("\n", ""))
641 if back_end == 'hpfax' and not 'HP Fax' in desc:
643 log.error("Incorrect PPD file for fax queue '%s'. Fax queues must use 'HP-Fax-hplip.ppd'." % printer_name)
645 elif back_end == 'hp' and 'HP Fax' in desc:
647 log.error("Incorrect PPD file for a print queue '%s'. Print queues must not use 'HP-Fax-hplip.ppd'." % printer_name)
649 elif back_end not in ('hp', 'hpfax'):
650 log.warn("Printer is not HPLIP installed. Printers must use the hp: or hpfax: CUPS backend to function in HPLIP.")
653 if device_avail and is_hp:
657 d = device.Device(device_uri)
659 log.error("Device initialization failed.")
662 plugin = d.mq.get('plugin', PLUGIN_NONE)
663 if plugin in (PLUGIN_REQUIRED, PLUGIN_OPTIONAL):
664 plugin_sts = core.check_for_plugin()
665 if plugin_sts == PLUGIN_INSTALLED:
666 if plugin == PLUGIN_REQUIRED:
667 log.info("Required plug-in status: Installed")
669 log.info("Optional plug-in status: Installed")
670 elif plugin_sts == PLUGIN_VERSION_MISMATCH:
672 log.warn("Optional plug-in status: Version mismatch")
676 if plugin == PLUGIN_REQUIRED:
677 log.error("Required plug-in status: Not installed")
679 log.warn("Optional plug-in status: Not installed")
682 if bus in ('par', 'usb'):
689 deviceid = d.getDeviceID()
694 log.error("Communication status: Failed")
695 #error_code = pml.ERROR_COMMAND_EXECUTION
698 log.info("Communication status: Good")
702 error_code, deviceid = d.getPML(pml.OID_DEVICE_ID)
704 #log.error("Communication with device failed.")
705 #error_code = pml.ERROR_COMMAND_EXECUTION
710 log.error("Communication status: Failed")
713 log.info("Communication status: Good")
724 log.warn("No queues found.")
727 tui.header("SANE CONFIGURATION")
728 log.info(log.bold("'hpaio' in '/etc/sane.d/dll.conf'..."))
730 f = file('/etc/sane.d/dll.conf', 'r')
732 log.error("'/etc/sane.d/dll.conf' not found. Is SANE installed?")
737 lineNoSpace = re.sub(r'\s', '', line)
738 hpaiomatched=re.match('hpaio',lineNoSpace)
739 # if 'hpaio' in line:
744 log.info("OK, found. SANE backend 'hpaio' is properly set up.")
747 log.error("Not found. SANE backend 'hpaio' NOT properly setup (needs to be added to /etc/sane.d/dll.conf).")
750 log.info(log.bold("Checking output of 'scanimage -L'..."))
751 if utils.which('scanimage'):
752 status, output = utils.run("scanimage -L")
755 log.error("scanimage not found.")
757 tui.header("PYTHON EXTENSIONS")
759 log.info(log.bold("Checking 'cupsext' CUPS extension..."))
764 log.error("NOT FOUND OR FAILED TO LOAD! Please reinstall HPLIP and check for the proper installation of cupsext.")
766 log.info("OK, found.")
769 log.info(log.bold("Checking 'pcardext' Photocard extension..."))
774 log.error("NOT FOUND OR FAILED TO LOAD! Please reinstall HPLIP and check for the proper installation of pcardext.")
776 log.info("OK, found.")
779 log.info(log.bold("Checking 'hpmudext' I/O extension..."))
782 hpmudext_avail = True
784 hpmudext_avail = False
786 log.error("NOT FOUND OR FAILED TO LOAD! Please reinstall HPLIP and check for the proper installation of hpmudext.")
788 log.info("OK, found.")
792 log.info(log.bold("Checking 'scanext' SANE scanning extension..."))
797 log.error("NOT FOUND OR FAILED TO LOAD! Please reinstall HPLIP and check for the proper installation of scanext.")
799 log.info("OK, found.")
805 lsusb = utils.which('lsusb')
809 lsusb = os.path.join(lsusb, 'lsusb')
810 status, output = utils.run("%s -d03f0:" % lsusb)
813 tui.header("USB I/O SETUP")
814 log.info(log.bold("Checking for permissions of USB attached printers..."))
816 lsusb_pat = re.compile("""^Bus\s([0-9a-fA-F]{3,3})\sDevice\s([0-9a-fA-F]{3,3}):\sID\s([0-9a-fA-F]{4,4}):([0-9a-fA-F]{4,4})(.*)""", re.IGNORECASE)
819 for o in output.splitlines():
821 match = lsusb_pat.search(o)
823 if match is not None:
824 bus, dev, vid, pid, mfg = match.groups()
825 log.info("\nHP Device 0x%x at %s:%s: " % (int(pid, 16), bus, dev))
826 result_code, deviceuri = hpmudext.make_usb_uri(bus, dev)
828 if result_code == hpmudext.HPMUD_R_OK:
829 log.info(" Device URI: %s" % deviceuri)
832 d = device.Device(deviceuri)
838 log.warn(" Device URI: (Makeuri FAILED)")
841 devnode = os.path.join("/", "dev", "bus", "usb", bus, dev)
843 if not os.path.exists(devnode):
844 devnode = os.path.join("/", "proc", "bus", "usb", bus, dev)
846 if os.path.exists(devnode):
847 log.info(" Device node: %s" % devnode)
849 st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, \
850 st_size, st_atime, st_mtime, st_ctime = \
853 log.info(" Mode: 0%o" % (st_mode & 0777))
855 getfacl = utils.which('getfacl')
857 getfacl = os.path.join(getfacl, "getfacl")
859 status, output = utils.run("%s %s" % (getfacl, devnode))
863 tui.header("USER GROUPS")
865 groups = utils.which('groups')
867 groups = os.path.join(groups, 'groups')
868 status, output = utils.run(groups)
874 tui.header("SUMMARY")
878 log.error("1 error or warning.")
880 log.error("%d errors and/or warnings." % num_errors)
882 if overall_commands_to_run:
884 log.info(log.bold("Summary of needed commands to run to satisfy missing dependencies:"))
885 for c in overall_commands_to_run:
889 log.info("Please refer to the installation instructions at:")
890 log.info("http://hplip.sourceforge.net/install/index.html\n")
893 log.info(log.green("No errors or warnings."))
895 except KeyboardInterrupt:
896 log.error("User exit")