#!/usr/bin/python3
## Printing troubleshooter
## Copyright (C) 2008, 2010, 2014 Red Hat, Inc.
## Authors:
## Tim Waugh <twaugh@redhat.com>
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from gi.repository import Gtk
import cups
import os
from tempfile import NamedTemporaryFile
import datetime
import time
from timedops import TimedOperation
from .base import *
try:
from systemd import journal
except:
journal = False
class ErrorLogFetch(Question):
def __init__ (self, troubleshooter):
Question.__init__ (self, troubleshooter, "Error log fetch")
page = self.initial_vbox (_("Retrieve Journal Entries"),
_("No system journal entries were found. "
"This may be because you are not an "
"administrator. To fetch journal entries "
"please run this command:"))
self.entry = Gtk.Entry ()
self.entry.set_editable (False)
page.pack_start (self.entry, False, False, 0)
troubleshooter.new_page (page, self)
self.persistent_answers = {}
def display (self):
answers = self.troubleshooter.answers
parent = self.troubleshooter.get_window ()
self.answers = {}
checkpoint = answers.get ('error_log_checkpoint')
cursor = answers.get ('error_log_cursor')
timestamp = answers.get ('error_log_timestamp')
if ('error_log' in self.persistent_answers or
'journal' in self.persistent_answers):
checkpoint = None
cursor = None
def fetch_log (c):
prompt = c._get_prompt_allowed ()
c._set_prompt_allowed (False)
c._connect ()
with NamedTemporaryFile (delete=False) as tmpf:
success = False
try:
c.getFile ('/admin/log/error_log', file = tmpf)
success = True
except cups.HTTPError:
try:
os.remove (tmpf.name)
except OSError:
pass
c._set_prompt_allowed (prompt)
if success:
return tmpf.file
return None
now = datetime.datetime.fromtimestamp (time.time ()).strftime ("%F %T")
self.authconn = self.troubleshooter.answers['_authenticated_connection']
if 'error_log_debug_logging_set' in answers:
try:
self.op = TimedOperation (self.authconn.adminGetServerSettings,
parent=parent)
settings = self.op.run ()
except cups.IPPError:
return False
settings[cups.CUPS_SERVER_DEBUG_LOGGING] = '0'
orig_settings = answers['cups_server_settings']
settings['MaxLogSize'] = orig_settings.get ('MaxLogSize', '2000000')
success = False
def set_settings (connection, settings):
connection.adminSetServerSettings (settings)
# Now reconnect.
attempt = 1
while attempt <= 5:
try:
time.sleep (1)
connection._connect ()
break
except RuntimeError:
# Connection failed
attempt += 1
try:
self.op = TimedOperation (set_settings,
(self.authconn, settings),
parent=parent)
self.op.run ()
self.persistent_answers['error_log_debug_logging_unset'] = True
except cups.IPPError:
pass
self.answers = {}
if journal and cursor is not None:
def journal_format (x):
try:
priority = "XACEWNIDd"[x['PRIORITY']]
except (IndexError, TypeError):
priority = " "
return (priority + " " +
x['__REALTIME_TIMESTAMP'].strftime("[%m/%b/%Y:%T]") +
" " + x['MESSAGE'])
r = journal.Reader ()
r.seek_cursor (cursor)
r.add_match (_SYSTEMD_UNIT="cups.service")
self.answers['journal'] = [journal_format (x) for x in r]
if checkpoint is not None:
self.op = TimedOperation (fetch_log,
(self.authconn,),
parent=parent)
tmpfname = self.op.run ()
if tmpfname is not None:
f = open (tmpfname)
f.seek (checkpoint)
lines = f.readlines ()
os.remove (tmpfname)
self.answers = { 'error_log': [x.strip () for x in lines] }
if (len (self.answers.get ('journal', [])) +
len (self.answers.get ('error_log', []))) == 0:
cmd = ("su -c 'journalctl -u cups.service "
"--since=\"%s\" --until=\"%s\"' > troubleshoot-logs.txt" %
(timestamp, now))
self.entry.set_text (cmd)
return True
return False
def collect_answer (self):
answers = self.persistent_answers.copy ()
answers.update (self.answers)
return answers
def cancel_operation (self):
self.op.cancel ()
# Abandon the CUPS connection and make another.
answers = self.troubleshooter.answers
factory = answers['_authenticated_connection_factory']
self.authconn = factory.get_connection ()
self.answers['_authenticated_connection'] = self.authconn