1# Copyright 2018 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import subprocess 6 7# Full path of the CUPS configuration file 8_CUPS_CONF_FILE = '/etc/cups/cupsd.conf' 9 10class CommandFailedException(Exception): 11 """ 12 An simple exception that is thrown when OS command fails. 13 14 """ 15 pass 16 17class Configurator(): 18 """ 19 An instance of this class is responsible for an initial configuration of 20 the system. This is performed by the method configure(). To restore the 21 system to the state before a configure() call, the method restore() must 22 be called. 23 24 """ 25 26 def __init__(self): 27 """ 28 Constructor. 29 30 """ 31 self._cupsd_conf_loglevel_line_no = None 32 self._cupsd_conf_loglevel_content = None 33 34 35 def _run_as_root(self, argv): 36 """ 37 Run given command as root. 38 39 @param argv: an array of command-line parameters 40 41 @returns standard output produced by the command 42 43 @raises Exception if the command returns code different than 0 44 45 """ 46 p1 = subprocess.Popen(["echo", "test0000"], stdout=subprocess.PIPE) 47 p2 = subprocess.Popen(["sudo", "--stdin", "--prompt="] + argv, 48 stdin=p1.stdout, stdout=subprocess.PIPE) 49 p1.stdout.close() 50 out,err = p2.communicate() 51 if p2.returncode != 0: 52 raise CommandFailedException("The command '%s' returns %d" % 53 (' '.join(argv),p2.returncode)); 54 return out 55 56 57 def _set_cups_logging_level(self): 58 """ 59 Modify the CUPS configuration file to set log level to 'debug'. 60 61 @raises Exception in case of any errors 62 63 """ 64 # parse content of the CUPS configuration file and find a number of 65 # a line with 'LogLevel' option 66 lines = self._run_as_root(["cat", _CUPS_CONF_FILE]).splitlines() 67 68 for index, line in enumerate(lines): 69 if line.startswith('LogLevel'): 70 line_no = index 71 break 72 if line_no is None: 73 raise Exception('Cannot find a line with LogLevel in cupsd.conf') 74 # save the original line and replace it with 'LogLevel debug' 75 self._cupsd_conf_loglevel_content = lines[line_no] 76 self._cupsd_conf_loglevel_line_no = line_no + 1 77 self._run_as_root(['sed', '-i', '%ds/.*/LogLevel debug/' % (line_no+1), 78 _CUPS_CONF_FILE]) 79 # if CUPS is started, we have to stop 80 try: 81 self._run_as_root(['stop', 'cupsd']) 82 except CommandFailedException: 83 pass 84 85 86 def _restore_cups_logging_level(self): 87 """ 88 Restore content of the CUPS configuration file to this one before 89 calling _set_cups_logging_level(). Do nothing if the method 90 _set_cups_logging_level() was not called earlier. 91 92 """ 93 if self._cupsd_conf_loglevel_content is None: 94 return 95 self._run_as_root(['sed', '-i', '%ds/.*/%s/' % 96 (self._cupsd_conf_loglevel_line_no, 97 self._cupsd_conf_loglevel_content), _CUPS_CONF_FILE]) 98 self._cupsd_conf_loglevel_content = None 99 self._cupsd_conf_loglevel_line_no = None 100 101 102 def _set_root_partition_as_read_write(self): 103 """ 104 Remount the root partition in read-write mode. 105 106 """ 107 self._run_as_root(['mount', '-o', 'rw,remount', '/']) 108 109 110 def configure(self, set_cups_logging_level): 111 """ 112 Apply the configuration required by the test. 113 114 @param set_cups_logging_level: True or False; if True then 115 the root partition is remounted in R/W mode and the CUPS 116 configuration file is updated to set "LogLevel" to "debug". 117 """ 118 # Update CUPS logging level 119 if set_cups_logging_level: 120 self._set_root_partition_as_read_write() 121 self._set_cups_logging_level() 122 123 124 def restore(self): 125 """ 126 Restore the system state before configure(). It is safe to run 127 this method, even if configure() failed or has not been called. 128 129 """ 130 # Restore CUPS logging level 131 if self._cupsd_conf_loglevel_content is not None: 132 self._restore_cups_logging_level() 133