blob: 9387a227bf5f938a79acda46db3a6df80ade9f9d [file] [log] [blame]
# Copyright 2018 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import subprocess
# Full path of the CUPS configuration file
_CUPS_CONF_FILE = '/etc/cups/cupsd.conf'
class CommandFailedException(Exception):
"""
An simple exception that is thrown when OS command fails.
"""
pass
class Configurator():
"""
An instance of this class is responsible for an initial configuration of
the system. This is performed by the method configure(). To restore the
system to the state before a configure() call, the method restore() must
be called.
"""
def __init__(self):
"""
Constructor.
"""
self._cupsd_conf_loglevel_line_no = None
self._cupsd_conf_loglevel_content = None
def _run_as_root(self, argv):
"""
Run given command as root.
@param argv: an array of command-line parameters
@returns standard output produced by the command
@raises Exception if the command returns code different than 0
"""
p1 = subprocess.Popen(["echo", "test0000"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["sudo", "--stdin", "--prompt="] + argv,
stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
out,err = p2.communicate()
if p2.returncode != 0:
raise CommandFailedException("The command '%s' returns %d" %
(' '.join(argv),p2.returncode));
return out
def _set_cups_logging_level(self):
"""
Modify the CUPS configuration file to set log level to 'debug'.
@raises Exception in case of any errors
"""
# parse content of the CUPS configuration file and find a number of
# a line with 'LogLevel' option
lines = self._run_as_root(["cat", _CUPS_CONF_FILE]).splitlines()
for index, line in enumerate(lines):
if line.startswith('LogLevel'):
line_no = index
break
if line_no is None:
raise Exception('Cannot find a line with LogLevel in cupsd.conf')
# save the original line and replace it with 'LogLevel debug'
self._cupsd_conf_loglevel_content = lines[line_no]
self._cupsd_conf_loglevel_line_no = line_no + 1
self._run_as_root(['sed', '-i', '%ds/.*/LogLevel debug/' % (line_no+1),
_CUPS_CONF_FILE])
# if CUPS is started, we have to stop
try:
self._run_as_root(['stop', 'cupsd'])
except CommandFailedException:
pass
def _restore_cups_logging_level(self):
"""
Restore content of the CUPS configuration file to this one before
calling _set_cups_logging_level(). Do nothing if the method
_set_cups_logging_level() was not called earlier.
"""
if self._cupsd_conf_loglevel_content is None:
return
self._run_as_root(['sed', '-i', '%ds/.*/%s/' %
(self._cupsd_conf_loglevel_line_no,
self._cupsd_conf_loglevel_content), _CUPS_CONF_FILE])
self._cupsd_conf_loglevel_content = None
self._cupsd_conf_loglevel_line_no = None
def _set_root_partition_as_read_write(self):
"""
Remount the root partition in read-write mode.
"""
self._run_as_root(['mount', '-o', 'rw,remount', '/'])
def configure(self, set_cups_logging_level):
"""
Apply the configuration required by the test.
@param set_cups_logging_level: True or False; if True then
the root partition is remounted in R/W mode and the CUPS
configuration file is updated to set "LogLevel" to "debug".
"""
# Update CUPS logging level
if set_cups_logging_level:
self._set_root_partition_as_read_write()
self._set_cups_logging_level()
def restore(self):
"""
Restore the system state before configure(). It is safe to run
this method, even if configure() failed or has not been called.
"""
# Restore CUPS logging level
if self._cupsd_conf_loglevel_content is not None:
self._restore_cups_logging_level()