~xnox/ubuntu/focal/apport/apport-on-powerpc-crashes-subiquity-during-crash-reporting

1369.1.310 by Martin Pitt
Update all copyright and description headers and consistently format them.
1
'''Convenience functions for use in package hooks.'''
2
1369.34.543 by Martin Pitt
* hookutils.py: Add attach_default_grub() convenience function from the grub2 package hook so it can be used by other packages. Thanks Brian Murray.
3
# Copyright (C) 2008 - 2012 Canonical Ltd.
1369.34.404 by Martin Pitt
remove trailing whitespace
4
# Authors:
1369.1.408 by Martin Pitt
hookutils.py: Add new method attach_drm_info() to read and format /sys/class/drm/*.
5
#   Matt Zimmerman <mdz@canonical.com>
6
#   Brian Murray <brian@ubuntu.com>
7
#   Martin Pitt <martin.pitt@ubuntu.com>
1369.34.404 by Martin Pitt
remove trailing whitespace
8
#
1369.1.310 by Martin Pitt
Update all copyright and description headers and consistently format them.
9
# This program is free software; you can redistribute it and/or modify it
10
# under the terms of the GNU General Public License as published by the
11
# Free Software Foundation; either version 2 of the License, or (at your
12
# option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
13
# the full text of the license.
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
14
15
import subprocess
16
import os
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
17
import sys
18
import time
1369.34.236 by Martin Pitt
hookutils.py: Add attach_conffiles().
19
import datetime
1174 by Matt Zimmerman
apport/hookutils.py: add attach_gconf() function to add non-default gconf
20
import glob
1257.1.1 by Andy Whitcroft
apport/hookutils.py: define and include a machine type from the hardware
21
import re
1369.1.67 by Martin Pitt
hookutils: replace hal stuff with udev
22
import stat
1369.1.408 by Martin Pitt
hookutils.py: Add new method attach_drm_info() to read and format /sys/class/drm/*.
23
import base64
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
24
import tempfile
25
import shutil
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
26
import locale
1174 by Matt Zimmerman
apport/hookutils.py: add attach_gconf() function to add non-default gconf
27
1369.34.265 by Martin Pitt
Fix some import statements to also work for the system-installed test suite.
28
from apport.packaging_impl import impl as packaging
1282 by Martin Pitt
apport/hookutils.py: Add attach_printing(). Thanks to Brian Murray
29
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
30
import apport
1369.34.802 by Martin Pitt
* Move shared_libraries() and links_with_shared_library() from hookutils into fileutils, so that we can use it from apport-valgrind. Thanks to Kyle Nitzsche for the initial patch.
31
import apport.fileutils
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
32
1369.34.1287 by Martin Pitt
* hookutils.py: Fix generation of valid report key names from arbitrary paths in attach_file() and related functions. This will now replace all invalid characters with dots, not just a few known invalid ones. (LP: #1566975)
33
_invalid_key_chars_re = re.compile(r'[^0-9a-zA-Z_.-]')
1369.34.253 by Martin Pitt
apport/hookutils.py: Port to Python 3
34
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
35
1149 by Matt Zimmerman
Add recent_syslog to hookutils
36
def path_to_key(path):
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
37
    '''Generate a valid report key name from a file path.
1369.34.404 by Martin Pitt
remove trailing whitespace
38
1369.61.2 by Bryce Harrington
Describe translation behavior more clearly
39
    This will replace invalid punctuation symbols with valid ones.
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
40
    '''
1369.34.253 by Martin Pitt
apport/hookutils.py: Port to Python 3
41
    if sys.version[0] >= '3':
1369.34.1203 by Martin Pitt
Fix PEP-8 errors
42
        if isinstance(path, bytes):
1369.34.253 by Martin Pitt
apport/hookutils.py: Port to Python 3
43
            path = path.decode('UTF-8')
44
    else:
1369.34.1203 by Martin Pitt
Fix PEP-8 errors
45
        if not isinstance(path, bytes):
1369.34.253 by Martin Pitt
apport/hookutils.py: Port to Python 3
46
            path = path.encode('UTF-8')
1369.34.1287 by Martin Pitt
* hookutils.py: Fix generation of valid report key names from arbitrary paths in attach_file() and related functions. This will now replace all invalid characters with dots, not just a few known invalid ones. (LP: #1566975)
47
    return _invalid_key_chars_re.sub('.', path.replace(' ', '_'))
1149 by Matt Zimmerman
Add recent_syslog to hookutils
48
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
49
1369.34.576 by Martin Pitt
* hookutils.py, read_file, attach_file(), attach_file_if_exists(): Convert file contents to unicode if the contents is UTF-8, or the newly added force_unicode argument is True.
50
def attach_file_if_exists(report, path, key=None, overwrite=True, force_unicode=False):
1369.34.117 by Martin Pitt
hookutils.py, attach_file() and attach_file_if_exists(): Add a new "overwrite" flag option. If not given, now default to overwriting an existing key, as this is usually what you need when attaching files (instead of attaching it several times with '_' appended to the keys). You can get the old behaviour by setting overwrite=False.
51
    '''Attach file contents if file exists.
52
53
    If key is not specified, the key name will be derived from the file
54
    name with path_to_key().
55
56
    If overwrite is True, an existing key will be updated. If it is False, a
57
    new key with '_' appended will be added instead.
1369.34.576 by Martin Pitt
* hookutils.py, read_file, attach_file(), attach_file_if_exists(): Convert file contents to unicode if the contents is UTF-8, or the newly added force_unicode argument is True.
58
59
    If the contents is valid UTF-8, or force_unicode is True, then the value
2457 by Brian Murray
data/iwlwifi_error_dump: fix add_package call. (LP: #1496268)
60
    will be a string, otherwise it will be bytes.
1369.34.117 by Martin Pitt
hookutils.py, attach_file() and attach_file_if_exists(): Add a new "overwrite" flag option. If not given, now default to overwriting an existing key, as this is usually what you need when attaching files (instead of attaching it several times with '_' appended to the keys). You can get the old behaviour by setting overwrite=False.
61
    '''
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
62
    if not key:
63
        key = path_to_key(path)
64
65
    if os.path.exists(path):
1369.34.576 by Martin Pitt
* hookutils.py, read_file, attach_file(), attach_file_if_exists(): Convert file contents to unicode if the contents is UTF-8, or the newly added force_unicode argument is True.
66
        attach_file(report, path, key, overwrite, force_unicode)
67
68
69
def read_file(path, force_unicode=False):
1369.34.404 by Martin Pitt
remove trailing whitespace
70
    '''Return the contents of the specified path.
71
1369.34.576 by Martin Pitt
* hookutils.py, read_file, attach_file(), attach_file_if_exists(): Convert file contents to unicode if the contents is UTF-8, or the newly added force_unicode argument is True.
72
    If the contents is valid UTF-8, or force_unicode is True, then the value
73
    will a string, otherwise it will be bytes.
74
1369.61.1 by Bryce Harrington
Fix a couple typos
75
    Upon error, this will deliver a text representation of the error,
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
76
    instead of failing.
77
    '''
78
    try:
1369.34.253 by Martin Pitt
apport/hookutils.py: Port to Python 3
79
        with open(path, 'rb') as f:
1369.34.576 by Martin Pitt
* hookutils.py, read_file, attach_file(), attach_file_if_exists(): Convert file contents to unicode if the contents is UTF-8, or the newly added force_unicode argument is True.
80
            contents = f.read().strip()
81
        if force_unicode:
82
            return contents.decode('UTF-8', errors='replace')
83
        try:
84
            return contents.decode('UTF-8')
85
        except UnicodeDecodeError:
86
            return contents
1369.34.40 by Martin Pitt
Python 3 compatible exception handling
87
    except Exception as e:
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
88
        return 'Error: ' + str(e)
1175.1.1 by Matt Zimmerman
Add attach_hardware to hookutils and change source_linux.py to use it
89
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
90
1369.34.576 by Martin Pitt
* hookutils.py, read_file, attach_file(), attach_file_if_exists(): Convert file contents to unicode if the contents is UTF-8, or the newly added force_unicode argument is True.
91
def attach_file(report, path, key=None, overwrite=True, force_unicode=False):
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
92
    '''Attach a file to the report.
93
94
    If key is not specified, the key name will be derived from the file
95
    name with path_to_key().
1369.34.117 by Martin Pitt
hookutils.py, attach_file() and attach_file_if_exists(): Add a new "overwrite" flag option. If not given, now default to overwriting an existing key, as this is usually what you need when attaching files (instead of attaching it several times with '_' appended to the keys). You can get the old behaviour by setting overwrite=False.
96
97
    If overwrite is True, an existing key will be updated. If it is False, a
98
    new key with '_' appended will be added instead.
1369.34.576 by Martin Pitt
* hookutils.py, read_file, attach_file(), attach_file_if_exists(): Convert file contents to unicode if the contents is UTF-8, or the newly added force_unicode argument is True.
99
100
    If the contents is valid UTF-8, or force_unicode is True, then the value
101
    will a string, otherwise it will be bytes.
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
102
    '''
103
    if not key:
104
        key = path_to_key(path)
105
1369.34.7 by Kees Cook
avoid clobbering existing keys when adding files
106
    # Do not clobber existing keys
1369.34.117 by Martin Pitt
hookutils.py, attach_file() and attach_file_if_exists(): Add a new "overwrite" flag option. If not given, now default to overwriting an existing key, as this is usually what you need when attaching files (instead of attaching it several times with '_' appended to the keys). You can get the old behaviour by setting overwrite=False.
107
    if not overwrite:
1369.34.245 by Martin Pitt
has_key() -> in, for Python 3 friendliness
108
        while key in report:
1369.34.117 by Martin Pitt
hookutils.py, attach_file() and attach_file_if_exists(): Add a new "overwrite" flag option. If not given, now default to overwriting an existing key, as this is usually what you need when attaching files (instead of attaching it several times with '_' appended to the keys). You can get the old behaviour by setting overwrite=False.
109
            key += '_'
1369.34.576 by Martin Pitt
* hookutils.py, read_file, attach_file(), attach_file_if_exists(): Convert file contents to unicode if the contents is UTF-8, or the newly added force_unicode argument is True.
110
    report[key] = read_file(path, force_unicode=force_unicode)
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
111
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
112
1800.2.2 by Brian Murray
modifications based off reviewer feedback
113
def attach_conffiles(report, package, conffiles=None, ui=None):
1369.34.236 by Martin Pitt
hookutils.py: Add attach_conffiles().
114
    '''Attach information about any modified or deleted conffiles.
1369.34.404 by Martin Pitt
remove trailing whitespace
115
1369.34.236 by Martin Pitt
hookutils.py: Add attach_conffiles().
116
    If conffiles is given, only this subset will be attached. If ui is given,
117
    ask whether the contents of the file may be added to the report; if this is
118
    denied, or there is no UI, just mark it as "modified" in the report.
119
    '''
120
    modified = packaging.get_modified_conffiles(package)
121
122
    for path, contents in modified.items():
1803.1.4 by Brian Murray
resolve error with conffiles test in hookutils.py
123
        if conffiles and path not in conffiles:
124
            continue
125
1581 by Martin Pitt
merge to upstream 1.9.6
126
        key = 'modified.conffile.' + path_to_key(path)
1369.34.869 by Martin Pitt
* hookutils.py, attach_conffiles(): Fix check for inaccessible or modified conffiles. (LP: #1192899)
127
        if type(contents) == str and (contents == '[deleted]' or contents.startswith('[inaccessible')):
1369.34.236 by Martin Pitt
hookutils.py: Add attach_conffiles().
128
            report[key] = contents
129
            continue
130
131
        if ui:
132
            response = ui.yesno('It seems you have modified the contents of "%s".  Would you like to add the contents of it to your bug report?' % path)
133
            if response:
134
                report[key] = contents
135
            else:
136
                report[key] = '[modified]'
1581 by Martin Pitt
merge to upstream 1.9.6
137
        else:
1369.34.236 by Martin Pitt
hookutils.py: Add attach_conffiles().
138
            report[key] = '[modified]'
1581 by Martin Pitt
merge to upstream 1.9.6
139
1369.34.236 by Martin Pitt
hookutils.py: Add attach_conffiles().
140
        mtime = datetime.datetime.fromtimestamp(os.stat(path).st_mtime)
141
        report['mtime.conffile.' + path_to_key(path)] = mtime.isoformat()
1803.1.1 by Brian Murray
* data/package-hooks/source_ubiquity.py:
142
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
143
1803.1.1 by Brian Murray
* data/package-hooks/source_ubiquity.py:
144
def attach_upstart_overrides(report, package):
145
    '''Attach information about any Upstart override files'''
146
147
    try:
1369.34.239 by Martin Pitt
hookutils.py: Add attach_upstart_overrides().
148
        files = apport.packaging.get_files(package)
149
    except ValueError:
1803.1.1 by Brian Murray
* data/package-hooks/source_ubiquity.py:
150
        return
151
1369.34.239 by Martin Pitt
hookutils.py: Add attach_upstart_overrides().
152
    for file in files:
153
        if os.path.exists(file) and file.startswith('/etc/init/'):
154
            override = file.replace('.conf', '.override')
155
            key = 'upstart.' + override.replace('/etc/init/', '')
156
            attach_file_if_exists(report, override, key)
1803.1.1 by Brian Murray
* data/package-hooks/source_ubiquity.py:
157
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
158
1369.34.844 by Martin Pitt
* hookutils.py: Add attach_upstart_logs(), thanks Steve Langasek.
159
def attach_upstart_logs(report, package):
160
    '''Attach information about a package's session upstart logs'''
161
162
    try:
163
        files = apport.packaging.get_files(package)
164
    except ValueError:
165
        return
166
167
    for f in files:
1369.34.875 by Martin Pitt
* hookutils.py, attach_upstart_logs(): Also attach ~/.cache/upstart/application-<desktopname>.log for any *.desktop file shipped by a package.
168
        if not os.path.exists(f):
169
            continue
170
        if f.startswith('/usr/share/upstart/sessions/'):
1369.34.844 by Martin Pitt
* hookutils.py: Add attach_upstart_logs(), thanks Steve Langasek.
171
            log = os.path.basename(f).replace('.conf', '.log')
172
            key = 'upstart.' + log
173
            try:
174
                log = os.path.join(os.environ['XDG_CACHE_HOME'], 'upstart', log)
175
            except KeyError:
176
                try:
177
                    log = os.path.join(os.environ['HOME'], '.cache', 'upstart', log)
178
                except KeyError:
179
                    continue
180
181
            attach_file_if_exists(report, log, key)
182
1369.34.875 by Martin Pitt
* hookutils.py, attach_upstart_logs(): Also attach ~/.cache/upstart/application-<desktopname>.log for any *.desktop file shipped by a package.
183
        if f.startswith('/usr/share/applications/') and f.endswith('.desktop'):
184
            desktopname = os.path.splitext(os.path.basename(f))[0]
185
            key = 'upstart.application.' + desktopname
186
            log = 'application-%s.log' % desktopname
187
            try:
188
                log = os.path.join(os.environ['XDG_CACHE_HOME'], 'upstart', log)
189
            except KeyError:
190
                try:
191
                    log = os.path.join(os.environ['HOME'], '.cache', 'upstart', log)
192
                except KeyError:
193
                    continue
194
195
            attach_file_if_exists(report, log, key)
196
1369.34.844 by Martin Pitt
* hookutils.py: Add attach_upstart_logs(), thanks Steve Langasek.
197
1175.1.1 by Matt Zimmerman
Add attach_hardware to hookutils and change source_linux.py to use it
198
def attach_dmesg(report):
1369.34.37 by Martin Pitt
hookutils.py, attach_dmesg(): Do not overwrite already existing dmesg.
199
    '''Attach information from the kernel ring buffer (dmesg).
1175.1.2 by Matt Zimmerman
Add docstrings
200
1369.61.1 by Bryce Harrington
Fix a couple typos
201
    This will not overwrite already existing information.
1369.34.37 by Martin Pitt
hookutils.py, attach_dmesg(): Do not overwrite already existing dmesg.
202
    '''
203
    if not report.get('CurrentDmesg', '').strip():
1369.34.1137 by Martin Pitt
* hookutils, attach_dmesg(): Only attach dmesg as CurrentDmesg, drop BootDmesg as /var/log/dmesg is upstart specific and thus not reliably correct any more.
204
        report['CurrentDmesg'] = command_output(['dmesg'])
1175.1.1 by Matt Zimmerman
Add attach_hardware to hookutils and change source_linux.py to use it
205
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
206
1369.1.387 by Martin Pitt
hookutils.py: Factor out the DMI collection code from attach_hardware() into attach_dmi(), and call that in attach_alsa() as well. Thanks to Brad Figg for the patch! (LP: #552091)
207
def attach_dmi(report):
208
    dmi_dir = '/sys/class/dmi/id'
209
    if os.path.isdir(dmi_dir):
210
        for f in os.listdir(dmi_dir):
211
            p = '%s/%s' % (dmi_dir, f)
212
            st = os.stat(p)
213
            # ignore the root-only ones, since they have serial numbers
214
            if not stat.S_ISREG(st.st_mode) or (st.st_mode & 4 == 0):
215
                continue
216
            if f in ('subsystem', 'uevent'):
217
                continue
218
219
            try:
2626 by Brian Murray
apport/hookutils.py: When gathering dmi information use read_file() which
220
                value = read_file(p)
1369.1.387 by Martin Pitt
hookutils.py: Factor out the DMI collection code from attach_hardware() into attach_dmi(), and call that in attach_alsa() as well. Thanks to Brad Figg for the patch! (LP: #552091)
221
            except (OSError, IOError):
222
                continue
223
            if value:
224
                report['dmi.' + f.replace('_', '.')] = value
225
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
226
1175.1.1 by Matt Zimmerman
Add attach_hardware to hookutils and change source_linux.py to use it
227
def attach_hardware(report):
1399 by Martin Pitt
apport/hookutils.py: Add docstring for attach_hardware, thanks Matt
228
    '''Attach a standard set of hardware-related data to the report, including:
229
230
    - kernel dmesg (boot and current)
231
    - /proc/interrupts
232
    - /proc/cpuinfo
233
    - /proc/cmdline
234
    - /proc/modules
235
    - lspci -vvnn
2762 by Brian Murray
apport/hookutils.py: Add in "lspci -vt" output for the HWE team.
236
    - lscpi -vt
1399 by Martin Pitt
apport/hookutils.py: Add docstring for attach_hardware, thanks Matt
237
    - lsusb
2728 by Brian Murray
* bin/oem-getlogs: add in script for getting hardware enablement related
238
    - lsusb -v
239
    - lsusb -t
1369.1.67 by Martin Pitt
hookutils: replace hal stuff with udev
240
    - devices from udev
241
    - DMI information from /sys
1485 by Colin Watson
apport/hookutils.py: Add command_available method, and use it to add
242
    - prtconf (sparc)
243
    - pccardctl status/ident
1399 by Martin Pitt
apport/hookutils.py: Add docstring for attach_hardware, thanks Matt
244
    '''
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
245
    attach_dmesg(report)
246
247
    attach_file(report, '/proc/interrupts', 'ProcInterrupts')
248
    attach_file(report, '/proc/cpuinfo', 'ProcCpuinfo')
1369.34.6 by Kees Cook
apport/hookutils.py: rename ProcCmdLine to ProcKernelCmdLine to not wipe wipe out /proc/$pid/cmdline information. (LP: #657091)
249
    attach_file(report, '/proc/cmdline', 'ProcKernelCmdLine')
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
250
1369.34.85 by Martin Pitt
hookutils.py, attach_hardware(): Avoid error message if machine does not have a PCI bus. Thanks Marcin Juszkiewicz! (LP: #608449)
251
    if os.path.exists('/sys/bus/pci'):
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
252
        report['Lspci'] = command_output(['lspci', '-vvnn'])
2762 by Brian Murray
apport/hookutils.py: Add in "lspci -vt" output for the HWE team.
253
        report['Lspci-vt'] = command_output(['lspci', '-vt'])
1193 by Martin Pitt
hookutils.py: Fix Lspci and Lsusb key names
254
    report['Lsusb'] = command_output(['lsusb'])
2728 by Brian Murray
* bin/oem-getlogs: add in script for getting hardware enablement related
255
    report['Lsusb-v'] = command_output(['lsusb', '-v'])
256
    report['Lsusb-t'] = command_output(['lsusb', '-t'])
1369.34.346 by Martin Pitt
hookutils.py, attach_hardware(): Sort ProcModules, thanks Brian Murray.
257
    report['ProcModules'] = command_output(['sort', '/proc/modules'])
1369.1.67 by Martin Pitt
hookutils: replace hal stuff with udev
258
    report['UdevDb'] = command_output(['udevadm', 'info', '--export-db'])
259
1369.1.261 by Martin Pitt
hookutils.py, attach_hardware(): Anonymize disk labels. (LP: #394411)
260
    # anonymize partition labels
1369.34.1325 by Martin Pitt
Fix PEP-8 errors with latest pycodestyle
261
    labels = report['UdevDb']
262
    labels = re.sub('ID_FS_LABEL=(.*)', 'ID_FS_LABEL=<hidden>', labels)
263
    labels = re.sub('ID_FS_LABEL_ENC=(.*)', 'ID_FS_LABEL_ENC=<hidden>', labels)
264
    labels = re.sub('by-label/(.*)', 'by-label/<hidden>', labels)
265
    labels = re.sub('ID_FS_LABEL=(.*)', 'ID_FS_LABEL=<hidden>', labels)
266
    labels = re.sub('ID_FS_LABEL_ENC=(.*)', 'ID_FS_LABEL_ENC=<hidden>', labels)
267
    labels = re.sub('by-label/(.*)', 'by-label/<hidden>', labels)
268
    report['UdevDb'] = labels
1369.24.1 by Marco Rodrigues
Hide disk label in Udev output
269
1369.1.387 by Martin Pitt
hookutils.py: Factor out the DMI collection code from attach_hardware() into attach_dmi(), and call that in attach_alsa() as well. Thanks to Brad Figg for the patch! (LP: #552091)
270
    attach_dmi(report)
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
271
1257.1.1 by Andy Whitcroft
apport/hookutils.py: define and include a machine type from the hardware
272
    # Use the hardware information to create a machine type.
1369.1.67 by Martin Pitt
hookutils: replace hal stuff with udev
273
    if 'dmi.sys.vendor' in report and 'dmi.product.name' in report:
274
        report['MachineType'] = '%s %s' % (report['dmi.sys.vendor'],
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
275
                                           report['dmi.product.name'])
1257.1.1 by Andy Whitcroft
apport/hookutils.py: define and include a machine type from the hardware
276
1485 by Colin Watson
apport/hookutils.py: Add command_available method, and use it to add
277
    if command_available('prtconf'):
278
        report['Prtconf'] = command_output(['prtconf'])
279
280
    if command_available('pccardctl'):
1369.1.220 by Martin Pitt
hookutils.py, attach_hardware(): Do not attach empty Pccardctl*.
281
        out = command_output(['pccardctl', 'status']).strip()
282
        if out:
283
            report['PccardctlStatus'] = out
284
        out = command_output(['pccardctl', 'ident']).strip()
285
        if out:
286
            report['PccardctlIdent'] = out
1485 by Colin Watson
apport/hookutils.py: Add command_available method, and use it to add
287
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
288
1369.87.1 by David Henningsson
hookutils: attach_alsa now uses alsa-info script if available
289
def attach_alsa_old(report):
290
    ''' (loosely based on http://www.alsa-project.org/alsa-info.sh)
291
    for systems where alsa-info is not installed (i e, *buntu 12.04 and earlier)
1399 by Martin Pitt
apport/hookutils.py: Add docstring for attach_hardware, thanks Matt
292
    '''
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
293
    attach_file_if_exists(report, os.path.expanduser('~/.asoundrc'),
1175.1.3 by Matt Zimmerman
Add attach_alsa function to hookutils
294
                          'UserAsoundrc')
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
295
    attach_file_if_exists(report, os.path.expanduser('~/.asoundrc.asoundconf'),
1175.1.3 by Matt Zimmerman
Add attach_alsa function to hookutils
296
                          'UserAsoundrcAsoundconf')
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
297
    attach_file_if_exists(report, '/etc/asound.conf')
1369.1.266 by Martin Pitt
hookutils.py, attach_alsa(): Attach /proc/asound/version. (LP: #467233)
298
    attach_file_if_exists(report, '/proc/asound/version', 'AlsaVersion')
1576.1.1 by Daniel T Chen
Need /proc/cpuinfo for ALSA and PulseAudio, too
299
    attach_file(report, '/proc/cpuinfo', 'ProcCpuinfo')
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
300
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
301
    report['AlsaDevices'] = command_output(['ls', '-l', '/dev/snd/'])
302
    report['AplayDevices'] = command_output(['aplay', '-l'])
303
    report['ArecordDevices'] = command_output(['arecord', '-l'])
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
304
305
    report['PciMultimedia'] = pci_devices(PCI_MULTIMEDIA)
306
307
    cards = []
1369.34.23 by Martin Pitt
hookutils.py, attach_alsa(): Fix crash if /proc/asound/cards does not exist. (LP: #626215)
308
    if os.path.exists('/proc/asound/cards'):
1369.34.253 by Martin Pitt
apport/hookutils.py: Port to Python 3
309
        with open('/proc/asound/cards') as fd:
310
            for line in fd:
311
                if ']:' in line:
312
                    fields = line.lstrip().split()
313
                    cards.append(int(fields[0]))
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
314
315
    for card in cards:
1369.1.15 by Martin Pitt
apport/hookutils.py, attach_alsa(): Add codec information
316
        key = 'Card%d.Amixer.info' % card
317
        report[key] = command_output(['amixer', '-c', str(card), 'info'])
318
        key = 'Card%d.Amixer.values' % card
319
        report[key] = command_output(['amixer', '-c', str(card)])
320
321
        for codecpath in glob.glob('/proc/asound/card%d/codec*' % card):
322
            if os.path.isfile(codecpath):
323
                codec = os.path.basename(codecpath)
324
                key = 'Card%d.Codecs.%s' % (card, path_to_key(codec))
325
                attach_file(report, codecpath, key=key)
326
            elif os.path.isdir(codecpath):
327
                codec = os.path.basename(codecpath)
328
                for name in os.listdir(codecpath):
329
                    path = os.path.join(codecpath, name)
330
                    key = 'Card%d.Codecs.%s.%s' % (card, path_to_key(codec), path_to_key(name))
331
                    attach_file(report, path, key)
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
332
1369.87.1 by David Henningsson
hookutils: attach_alsa now uses alsa-info script if available
333
334
def attach_alsa(report):
335
    '''Attach ALSA subsystem information to the report.
336
    '''
337
    if os.path.exists('/usr/share/alsa-base/alsa-info.sh'):
338
        report['AlsaInfo'] = command_output(['/usr/share/alsa-base/alsa-info.sh', '--stdout', '--no-upload'])
339
    else:
340
        attach_alsa_old(report)
341
1369.1.13 by Martin Pitt
apport/hookutils.py, attach_alsa(): Add fuser info and dmesg
342
    report['AudioDevicesInUse'] = command_output(
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
343
        ['fuser', '-v'] + glob.glob('/dev/dsp*') + glob.glob('/dev/snd/*') + glob.glob('/dev/seq*'))
1369.1.13 by Martin Pitt
apport/hookutils.py, attach_alsa(): Add fuser info and dmesg
344
1369.62.1 by Luke Yelavich
Get a list of outputs/inputs that PulseAudio knows about, which also shows
345
    if os.path.exists('/usr/bin/pacmd'):
1369.34.445 by Martin Pitt
hookutils.py, attach_alsa(): Add the full "pacmd list" output instead of just sinks and sources. Thanks David Henningsson.
346
        report['PulseList'] = command_output(['pacmd', 'list'])
1369.62.1 by Luke Yelavich
Get a list of outputs/inputs that PulseAudio knows about, which also shows
347
1369.1.387 by Martin Pitt
hookutils.py: Factor out the DMI collection code from attach_hardware() into attach_dmi(), and call that in attach_alsa() as well. Thanks to Brad Figg for the patch! (LP: #552091)
348
    attach_dmi(report)
1369.1.13 by Martin Pitt
apport/hookutils.py, attach_alsa(): Add fuser info and dmesg
349
    attach_dmesg(report)
350
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
351
1485 by Colin Watson
apport/hookutils.py: Add command_available method, and use it to add
352
def command_available(command):
353
    '''Is given command on the executable search path?'''
354
    if 'PATH' not in os.environ:
355
        return False
356
    path = os.environ['PATH']
357
    for element in path.split(os.pathsep):
358
        if not element:
359
            continue
360
        filename = os.path.join(element, command)
361
        if os.path.isfile(filename) and os.access(filename, os.X_OK):
362
            return True
363
    return False
364
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
365
1369.34.577 by Martin Pitt
* hooktuils, command_output(): Convert output to unicode by default, and add a "decode_utf8" parameter to disable this.
366
def command_output(command, input=None, stderr=subprocess.STDOUT,
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
367
                   keep_locale=False, decode_utf8=True):
2457 by Brian Murray
data/iwlwifi_error_dump: fix add_package call. (LP: #1496268)
368
    '''Try to execute given command (list) and return its stdout.
1369.34.404 by Martin Pitt
remove trailing whitespace
369
1369.1.99 by Martin Pitt
hookutils.py, command_output(): Force LC_MESSAGES=C, to avoid translated output in bug reports. (LP: #383230)
370
    In case of failure, a textual error gets returned. This function forces
371
    LC_MESSAGES to C, to avoid translated output in bug reports.
1369.34.577 by Martin Pitt
* hooktuils, command_output(): Convert output to unicode by default, and add a "decode_utf8" parameter to disable this.
372
373
    If decode_utf8 is True (default), the output will be converted to a string,
374
    otherwise left as bytes.
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
375
    '''
1369.1.397 by Martin Pitt
hookutils.py, command_output(): Do not set $LC_MESSAGES for the calling process/hook, just for the command to be called.
376
    env = os.environ.copy()
1369.34.458 by Martin Pitt
hookutils.py, command_output(): Add option to keep the locale instead of disabling it. - hookutils.py, command_output(): Actually make the "input" parameter work, instead of causing an eternal hang. Add tests for all possible modes of operation.
377
    if not keep_locale:
378
        env['LC_MESSAGES'] = 'C'
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
379
    try:
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
380
        sp = subprocess.Popen(command, stdout=subprocess.PIPE,
381
                              stderr=stderr,
382
                              stdin=(input and subprocess.PIPE or None),
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
383
                              env=env)
1369.34.40 by Martin Pitt
Python 3 compatible exception handling
384
    except OSError as e:
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
385
        return 'Error: ' + str(e)
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
386
387
    out = sp.communicate(input)[0]
388
    if sp.returncode == 0:
1369.34.577 by Martin Pitt
* hooktuils, command_output(): Convert output to unicode by default, and add a "decode_utf8" parameter to disable this.
389
        res = out.strip()
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
390
    else:
2652 by Brian Murray
Fix PEP8 605 warnings and ignore 503,504 ones.
391
        res = (b'Error: command ' + str(command).encode() + b' failed with exit code '
392
               + str(sp.returncode).encode() + b': ' + out)
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
393
1369.34.577 by Martin Pitt
* hooktuils, command_output(): Convert output to unicode by default, and add a "decode_utf8" parameter to disable this.
394
    if decode_utf8:
395
        res = res.decode('UTF-8', errors='replace')
396
    return res
397
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
398
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
399
def _root_command_prefix():
1369.1.82 by Martin Pitt
add apport.hookutils.root_command_output()
400
    if os.getuid() == 0:
1369.34.676 by Martin Pitt
* hookutils.py, attach_root_command_outputs() and root_command_output(): Drop usage of sudo, kdesudo, and gksu, and replace with pkexec. For attach_root_command_outputs(), use a wrapper and proper .policy file which explains the action and works under every environment; thus attach_root_command_outputs() is preferred over root_command_output() now, as it provides a better user experience.
401
        return []
2683 by Brian Murray
debian/control, apport/hookutils.py: pkexec does not work in non-graphical
402
    elif os.path.exists('/usr/bin/pkexec'):
1369.34.676 by Martin Pitt
* hookutils.py, attach_root_command_outputs() and root_command_output(): Drop usage of sudo, kdesudo, and gksu, and replace with pkexec. For attach_root_command_outputs(), use a wrapper and proper .policy file which explains the action and works under every environment; thus attach_root_command_outputs() is preferred over root_command_output() now, as it provides a better user experience.
403
        return ['pkexec']
2683 by Brian Murray
debian/control, apport/hookutils.py: pkexec does not work in non-graphical
404
    # the package hook won't have everything it wanted but that's okay
405
    else:
406
        return []
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
407
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
408
1369.34.577 by Martin Pitt
* hooktuils, command_output(): Convert output to unicode by default, and add a "decode_utf8" parameter to disable this.
409
def root_command_output(command, input=None, stderr=subprocess.STDOUT, decode_utf8=True):
2457 by Brian Murray
data/iwlwifi_error_dump: fix add_package call. (LP: #1496268)
410
    '''Try to execute given command (list) as root and return its stdout.
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
411
1369.34.676 by Martin Pitt
* hookutils.py, attach_root_command_outputs() and root_command_output(): Drop usage of sudo, kdesudo, and gksu, and replace with pkexec. For attach_root_command_outputs(), use a wrapper and proper .policy file which explains the action and works under every environment; thus attach_root_command_outputs() is preferred over root_command_output() now, as it provides a better user experience.
412
    This passes the command through pkexec, unless the caller is already root.
1369.34.404 by Martin Pitt
remove trailing whitespace
413
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
414
    In case of failure, a textual error gets returned.
1369.34.577 by Martin Pitt
* hooktuils, command_output(): Convert output to unicode by default, and add a "decode_utf8" parameter to disable this.
415
416
    If decode_utf8 is True (default), the output will be converted to a string,
417
    otherwise left as bytes.
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
418
    '''
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
419
    assert isinstance(command, list), 'command must be a list'
1369.34.459 by Martin Pitt
hooktuils.py: Change root_command_output() and attach_root_command_outputs() to disable translated messages (LC_MESSAGES=C) only as part of the command to be run, not already for the root prefix command. This will keep the latter (gksu, kdesudo, etc.) translated. (LP: #961659)
420
    return command_output(_root_command_prefix() + command, input, stderr,
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
421
                          keep_locale=True, decode_utf8=decode_utf8)
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
422
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
423
1369.61.4 by Bryce Harrington
Review by pitti: Just always strip and always skip empties.
424
def attach_root_command_outputs(report, command_map):
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
425
    '''Execute multiple commands as root and put their outputs into report.
426
427
    command_map is a keyname -> 'shell command' dictionary with the commands to
428
    run. They are all run through /bin/sh, so you need to take care of shell
429
    escaping yourself. To include stderr output of a command, end it with
430
    "2>&1".
431
1369.34.676 by Martin Pitt
* hookutils.py, attach_root_command_outputs() and root_command_output(): Drop usage of sudo, kdesudo, and gksu, and replace with pkexec. For attach_root_command_outputs(), use a wrapper and proper .policy file which explains the action and works under every environment; thus attach_root_command_outputs() is preferred over root_command_output() now, as it provides a better user experience.
432
    Just like root_command_output, this passes the command through pkexec,
433
    unless the caller is already root.
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
434
435
    This is preferrable to using root_command_output() multiple times, as that
436
    will ask for the password every time.
437
    '''
1369.34.676 by Martin Pitt
* hookutils.py, attach_root_command_outputs() and root_command_output(): Drop usage of sudo, kdesudo, and gksu, and replace with pkexec. For attach_root_command_outputs(), use a wrapper and proper .policy file which explains the action and works under every environment; thus attach_root_command_outputs() is preferred over root_command_output() now, as it provides a better user experience.
438
    wrapper_path = os.path.join(os.path.abspath(
439
        os.environ.get('APPORT_DATA_DIR', '/usr/share/apport')), 'root_info_wrapper')
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
440
    workdir = tempfile.mkdtemp()
441
    try:
442
        # create a shell script with all the commands
443
        script_path = os.path.join(workdir, ':script:')
444
        script = open(script_path, 'w')
445
        for keyname, command in command_map.items():
446
            assert hasattr(command, 'strip'), 'command must be a string (shell command)'
447
            # use "| cat" here, so that we can end commands with 2>&1
448
            # (otherwise it would have the wrong redirection order)
449
            script.write('%s | cat > %s\n' % (command, os.path.join(workdir, keyname)))
450
        script.close()
451
452
        # run script
1369.34.676 by Martin Pitt
* hookutils.py, attach_root_command_outputs() and root_command_output(): Drop usage of sudo, kdesudo, and gksu, and replace with pkexec. For attach_root_command_outputs(), use a wrapper and proper .policy file which explains the action and works under every environment; thus attach_root_command_outputs() is preferred over root_command_output() now, as it provides a better user experience.
453
        sp = subprocess.Popen(_root_command_prefix() + [wrapper_path, script_path])
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
454
        sp.wait()
455
456
        # now read back the individual outputs
457
        for keyname in command_map:
1369.34.706 by Martin Pitt
* hookutils.py, attach_root_command_outputs(): Ignore IOError crash about nonexisting files, which can happen if the user dismisses authorization. (LP: #1051222)
458
            try:
1369.34.1105 by Martin Pitt
* hookutils, attach_root_command_outputs(): Fix UnicodeDecodeError crash for non-textual values. (LP: #1370259)
459
                with open(os.path.join(workdir, keyname), 'rb') as f:
1369.34.706 by Martin Pitt
* hookutils.py, attach_root_command_outputs(): Ignore IOError crash about nonexisting files, which can happen if the user dismisses authorization. (LP: #1051222)
460
                    buf = f.read().strip()
461
            except IOError:
462
                # this can happen if the user dismisses authorization in
463
                # _root_command_prefix
464
                continue
1369.34.1296 by Martin Pitt
* hookutils, attach_root_command_outputs(): Return str again, like before 2.15.2. (LP: #1370259)
465
            # opportunistically convert to strings, like command_output()
466
            try:
467
                buf = buf.decode('UTF-8')
468
            except UnicodeDecodeError:
469
                pass
1369.61.4 by Bryce Harrington
Review by pitti: Just always strip and always skip empties.
470
            if buf:
471
                report[keyname] = buf
1369.34.57 by Martin Pitt
hookutils.py: Add attach_root_command_outputs() to run several commands at once. This avoids asking for the password several times. (LP: #716595)
472
            f.close()
473
    finally:
474
        shutil.rmtree(workdir)
1369.1.82 by Martin Pitt
add apport.hookutils.root_command_output()
475
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
476
1369.34.1139 by Martin Pitt
* hookutils, attach_mac_events(): Read kernel violation messages from dmesg instead of /var/log/kern.log, as that's specific to rsyslog and its configuration.
477
def __filter_re_process(pattern, process):
478
    lines = ''
479
    while process.poll() is None:
480
        for line in process.stdout:
481
            line = line.decode('UTF-8', errors='replace')
482
            if pattern.search(line):
483
                lines += line
484
    process.stdout.close()
485
    process.wait()
486
    if process.returncode == 0:
487
        return lines
488
    return ''
489
490
1369.34.1138 by Martin Pitt
* hookutils, recent_syslog(): Read system logs from the journal when running under systemd, and fall back to /var/log/syslog if not.
491
def recent_syslog(pattern, path=None):
492
    '''Extract recent system messages which match a regex.
493
494
    pattern should be a "re" object. By default, messages are read from
495
    the systemd journal, or /var/log/syslog; but when giving "path", messages
496
    are read from there instead.
497
    '''
498
    if path:
499
        p = subprocess.Popen(['tail', '-n', '10000', path],
500
                             stdout=subprocess.PIPE)
501
    elif os.path.exists('/run/systemd/system'):
502
        p = subprocess.Popen(['journalctl', '--system', '--quiet', '-b', '-a'],
503
                             stdout=subprocess.PIPE)
504
    elif os.access('/var/log/syslog', os.R_OK):
1369.34.1141 by Martin Pitt
hookutils.py: Fix arguments to tail subprocess call
505
        p = subprocess.Popen(['tail', '-n', '10000', '/var/log/syslog'],
1369.34.1138 by Martin Pitt
* hookutils, recent_syslog(): Read system logs from the journal when running under systemd, and fall back to /var/log/syslog if not.
506
                             stdout=subprocess.PIPE)
1369.34.1139 by Martin Pitt
* hookutils, attach_mac_events(): Read kernel violation messages from dmesg instead of /var/log/kern.log, as that's specific to rsyslog and its configuration.
507
    return __filter_re_process(pattern, p)
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
508
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
509
1369.34.394 by Martin Pitt
hookutils.py, xsession_errors(): Add a reasonable default pattern which matches glib-style warnings, errors, criticals etc. and X window errors. In data/general-hooks/generic.py, call it with that default instead of the rather incomplete custom pattern. (LP: #932660)
510
def xsession_errors(pattern=None):
511
    '''Extract messages from ~/.xsession-errors.
1369.34.404 by Martin Pitt
remove trailing whitespace
512
1369.34.394 by Martin Pitt
hookutils.py, xsession_errors(): Add a reasonable default pattern which matches glib-style warnings, errors, criticals etc. and X window errors. In data/general-hooks/generic.py, call it with that default instead of the rather incomplete custom pattern. (LP: #932660)
513
    By default this parses out glib-style warnings, errors, criticals etc. and
514
    X window errors.  You can specify a "re" object as pattern to customize the
515
    filtering.
516
517
    Please note that you should avoid attaching the whole file to reports, as
518
    it can, and often does, contain sensitive and private data.
1369.1.284 by Matt Zimmerman
- New hookutils functions:
519
    '''
520
    path = os.path.expanduser('~/.xsession-errors')
1369.165.19 by Brian Murray
Don't crash if .xsession-errors is not readable by the user.
521
    if not os.path.exists(path) or \
522
            not os.access(path, os.R_OK):
1369.34.394 by Martin Pitt
hookutils.py, xsession_errors(): Add a reasonable default pattern which matches glib-style warnings, errors, criticals etc. and X window errors. In data/general-hooks/generic.py, call it with that default instead of the rather incomplete custom pattern. (LP: #932660)
523
        return ''
524
525
    if not pattern:
2566 by Brian Murray
Cherry picked from upstream's unreleased 2.20.6 - Convert regular
526
        pattern = re.compile(r'^(\(.*:\d+\): \w+-(WARNING|CRITICAL|ERROR))|(Error: .*No Symbols named)|([^ ]+\[\d+\]: ([A-Z]+):)|([^ ]-[A-Z]+ \*\*:)|(received an X Window System error)|(^The error was \')|(^  \(Details: serial \d+ error_code)')
1369.1.284 by Matt Zimmerman
- New hookutils functions:
527
528
    lines = ''
1369.34.587 by Martin Pitt
* hookutils.py, xsession_errors(): Fix crash when running under a non-UTF8 locale.
529
    with open(path, 'rb') as f:
1369.34.505 by Martin Pitt
apport/hookutils.py: Fix for Python 3
530
        for line in f:
1369.34.587 by Martin Pitt
* hookutils.py, xsession_errors(): Fix crash when running under a non-UTF8 locale.
531
            line = line.decode('UTF-8', errors='replace')
1369.34.505 by Martin Pitt
apport/hookutils.py: Fix for Python 3
532
            if pattern.search(line):
533
                lines += line
1369.1.284 by Matt Zimmerman
- New hookutils functions:
534
    return lines
535
1369.34.1325 by Martin Pitt
Fix PEP-8 errors with latest pycodestyle
536
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
537
PCI_MASS_STORAGE = 0x01
538
PCI_NETWORK = 0x02
539
PCI_DISPLAY = 0x03
540
PCI_MULTIMEDIA = 0x04
541
PCI_MEMORY = 0x05
542
PCI_BRIDGE = 0x06
543
PCI_SIMPLE_COMMUNICATIONS = 0x07
544
PCI_BASE_SYSTEM_PERIPHERALS = 0x08
545
PCI_INPUT_DEVICES = 0x09
546
PCI_DOCKING_STATIONS = 0x0a
547
PCI_PROCESSORS = 0x0b
548
PCI_SERIAL_BUS = 0x0c
549
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
550
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
551
def pci_devices(*pci_classes):
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
552
    '''Return a text dump of PCI devices attached to the system.'''
553
554
    if not pci_classes:
555
        return command_output(['lspci', '-vvnn'])
556
1369.1.134 by Martin Pitt
apport/hookutils.py, pci_devices(): Deliver all matching devices, not just the last one. (LP: #398906)
557
    result = ''
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
558
    output = command_output(['lspci', '-vvmmnn'])
1369.34.577 by Martin Pitt
* hooktuils, command_output(): Convert output to unicode by default, and add a "decode_utf8" parameter to disable this.
559
    for paragraph in output.split('\n\n'):
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
560
        pci_class = None
561
        slot = None
562
1369.34.577 by Martin Pitt
* hooktuils, command_output(): Convert output to unicode by default, and add a "decode_utf8" parameter to disable this.
563
        for line in paragraph.split('\n'):
1369.34.419 by Martin Pitt
apport/hookutils.py, pci_devices(): Fix crash on unexpected lines from lspci. (LP: #904489)
564
            try:
1369.34.577 by Martin Pitt
* hooktuils, command_output(): Convert output to unicode by default, and add a "decode_utf8" parameter to disable this.
565
                key, value = line.split(':', 1)
1369.34.419 by Martin Pitt
apport/hookutils.py, pci_devices(): Fix crash on unexpected lines from lspci. (LP: #904489)
566
            except ValueError:
567
                continue
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
568
            value = value.strip()
569
            key = key.strip()
570
            if key == 'Class':
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
571
                n = int(value[-5:-1], 16)
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
572
                pci_class = (n & 0xff00) >> 8
573
            elif key == 'Slot':
574
                slot = value
575
576
        if pci_class and slot and pci_class in pci_classes:
1369.1.134 by Martin Pitt
apport/hookutils.py, pci_devices(): Deliver all matching devices, not just the last one. (LP: #398906)
577
            if result:
578
                result += '\n\n'
579
            result += command_output(['lspci', '-vvnns', slot]).strip()
580
581
    return result
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
582
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
583
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
584
def usb_devices():
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
585
    '''Return a text dump of USB devices attached to the system.'''
1175.1.2 by Matt Zimmerman
Add docstrings
586
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
587
    # TODO: would be nice to be able to filter by interface class
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
588
    return command_output(['lsusb', '-v'])
589
1148 by Matt Zimmerman
Add apport/hookutils.py with some convenience functions for writing hook
590
1174 by Matt Zimmerman
apport/hookutils.py: add attach_gconf() function to add non-default gconf
591
def files_in_package(package, globpat=None):
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
592
    '''Retrieve a list of files owned by package, optionally matching globpat'''
1175.1.2 by Matt Zimmerman
Add docstrings
593
1363 by Martin Pitt
apport/hookutils.py, files_in_package(): Replace dpkg-query call with
594
    files = packaging.get_files(package)
595
    if globpat:
596
        result = [f for f in files if glob.fnmatch.fnmatch(f, globpat)]
597
    else:
598
        result = files
599
    return result
1174 by Matt Zimmerman
apport/hookutils.py: add attach_gconf() function to add non-default gconf
600
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
601
1174 by Matt Zimmerman
apport/hookutils.py: add attach_gconf() function to add non-default gconf
602
def attach_gconf(report, package):
1369.34.197 by Martin Pitt
hookutils.py: Replace attach_gconf() with a no-op stub. It used static python modules like "gconf" which broke the PyGI GTK user interface, and gconf is rather obsolete these days.
603
    '''Obsolete'''
604
605
    # keeping a no-op function for some time to not break hooks
606
    pass
1174 by Matt Zimmerman
apport/hookutils.py: add attach_gconf() function to add non-default gconf
607
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
608
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
609
def attach_gsettings_schema(report, schema):
1369.160.1 by Sebastien Bacher
small typo fix
610
    '''Attach user-modified gsettings keys of a schema.'''
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
611
612
    cur_value = report.get('GsettingsChanges', '')
613
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
614
    defaults = {}  # schema -> key ->  value
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
615
    env = os.environ.copy()
616
    env['XDG_CONFIG_HOME'] = '/nonexisting'
617
    gsettings = subprocess.Popen(['gsettings', 'list-recursively', schema],
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
618
                                 env=env, stdout=subprocess.PIPE)
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
619
    for l in gsettings.stdout:
620
        try:
1369.159.1 by Sebastien Bacher
don't replace the schema variable in attach_gsettings_schema,
621
            (schema_name, key, value) = l.split(None, 2)
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
622
            value = value.rstrip()
623
        except ValueError:
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
624
            continue  # invalid line
1369.159.1 by Sebastien Bacher
don't replace the schema variable in attach_gsettings_schema,
625
        defaults.setdefault(schema_name, {})[key] = value
1369.34.404 by Martin Pitt
remove trailing whitespace
626
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
627
    gsettings = subprocess.Popen(['gsettings', 'list-recursively', schema],
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
628
                                 stdout=subprocess.PIPE)
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
629
    for l in gsettings.stdout:
630
        try:
1369.159.1 by Sebastien Bacher
don't replace the schema variable in attach_gsettings_schema,
631
            (schema_name, key, value) = l.split(None, 2)
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
632
            value = value.rstrip()
633
        except ValueError:
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
634
            continue  # invalid line
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
635
1369.159.1 by Sebastien Bacher
don't replace the schema variable in attach_gsettings_schema,
636
        if value != defaults.get(schema_name, {}).get(key, ''):
2624 by Brian Murray
apport/hookutils.py: When gathering gsettings schema changes redact
637
            if schema_name == b'org.gnome.shell' and \
638
                    key in [b'command-history', b'favorite-apps']:
639
                value = 'redacted by apport'
1369.159.1 by Sebastien Bacher
don't replace the schema variable in attach_gsettings_schema,
640
            cur_value += '%s %s %s\n' % (schema_name, key, value)
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
641
642
    report['GsettingsChanges'] = cur_value
643
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
644
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
645
def attach_gsettings_package(report, package):
646
    '''Attach user-modified gsettings keys of all schemas in a package.'''
647
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
648
    for schema_file in files_in_package(package, '/usr/share/glib-2.0/schemas/*.gschema.xml'):
1369.34.198 by Martin Pitt
hookutils.py: Add two new functions attach_gsettings_package() and attach_gsettings_schema() for adding user-modified gsettings keys to a report. (LP: #836489)
649
        schema = os.path.basename(schema_file)[:-12]
650
        attach_gsettings_schema(report, schema)
651
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
652
1175.1.4 by Matt Zimmerman
Add attach_network function to hookutils
653
def attach_network(report):
1369.1.154 by Martin Pitt
hookutils.py: Add attach_wifi()
654
    '''Attach generic network-related information to report.'''
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
655
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
656
    report['IpRoute'] = command_output(['ip', 'route'])
657
    report['IpAddr'] = command_output(['ip', 'addr'])
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
658
    report['PciNetwork'] = pci_devices(PCI_NETWORK)
1369.1.154 by Martin Pitt
hookutils.py: Add attach_wifi()
659
    attach_file_if_exists(report, '/etc/network/interfaces', key='IfupdownConfig')
1188 by Martin Pitt
* apport/hookutils.py: Add attach_network(), attach_alsa(), and
660
661
    for var in ('http_proxy', 'ftp_proxy', 'no_proxy'):
662
        if var in os.environ:
663
            report[var] = os.environ[var]
1175.1.4 by Matt Zimmerman
Add attach_network function to hookutils
664
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
665
1369.1.154 by Martin Pitt
hookutils.py: Add attach_wifi()
666
def attach_wifi(report):
667
    '''Attach wireless (WiFi) network information to report.'''
668
1369.58.1 by Mathieu Trudel-Lapierre
Add wpa_supplicant to the sources of syslog messages to retrieve in
669
    report['WifiSyslog'] = recent_syslog(re.compile(r'(NetworkManager|modem-manager|dhclient|kernel|wpa_supplicant)(\[\d+\])?:'))
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
670
    report['IwConfig'] = re.sub(
671
        'ESSID:(.*)', 'ESSID:<hidden>',
1369.34.404 by Martin Pitt
remove trailing whitespace
672
        re.sub('Encryption key:(.*)', 'Encryption key: <hidden>',
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
673
               re.sub('Access Point: (.*)', 'Access Point: <hidden>',
674
                      command_output(['iwconfig']))))
1369.1.154 by Martin Pitt
hookutils.py: Add attach_wifi()
675
    report['RfKill'] = command_output(['rfkill', 'list'])
1369.156.1 by Brian Murray
shorten value of CRDA if iw isn't available on the system
676
    if os.path.exists('/sbin/iw'):
677
        iw_output = command_output(['iw', 'reg', 'get'])
678
    else:
1369.34.1197 by Martin Pitt
* hookutils.attach_wifi(): Shorten value of CRDA if iw isn't available on the system. Thanks Brian Murray.
679
        iw_output = 'N/A'
1369.156.1 by Brian Murray
shorten value of CRDA if iw isn't available on the system
680
    report['CRDA'] = iw_output
1369.1.154 by Martin Pitt
hookutils.py: Add attach_wifi()
681
682
    attach_file_if_exists(report, '/var/log/wpa_supplicant.log', key='WpaSupplicantLog')
683
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
684
1282 by Martin Pitt
apport/hookutils.py: Add attach_printing(). Thanks to Brian Murray
685
def attach_printing(report):
686
    '''Attach printing information to the report.
687
688
    Based on http://wiki.ubuntu.com/PrintingBugInfoScript.
689
    '''
690
    attach_file_if_exists(report, '/etc/papersize', 'Papersize')
1296 by Martin Pitt
* apport/hookutils.py: Fix attach_printing():
691
    attach_file_if_exists(report, '/var/log/cups/error_log', 'CupsErrorLog')
1282 by Martin Pitt
apport/hookutils.py: Add attach_printing(). Thanks to Brian Murray
692
    report['Locale'] = command_output(['locale'])
693
    report['Lpstat'] = command_output(['lpstat', '-v'])
694
1296 by Martin Pitt
* apport/hookutils.py: Fix attach_printing():
695
    ppds = glob.glob('/etc/cups/ppd/*.ppd')
696
    if ppds:
697
        nicknames = command_output(['fgrep', '-H', '*NickName'] + ppds)
2566 by Brian Murray
Cherry picked from upstream's unreleased 2.20.6 - Convert regular
698
        report['PpdFiles'] = re.sub(r'/etc/cups/ppd/(.*).ppd:\*NickName: *"(.*)"', r'\g<1>: \g<2>', nicknames)
1282 by Martin Pitt
apport/hookutils.py: Add attach_printing(). Thanks to Brian Murray
699
1369.1.8 by Martin Pitt
apport/hookutils.py:
700
    report['PrintingPackages'] = package_versions(
701
        'foo2zjs', 'foomatic-db', 'foomatic-db-engine',
1282 by Martin Pitt
apport/hookutils.py: Add attach_printing(). Thanks to Brian Murray
702
        'foomatic-db-gutenprint', 'foomatic-db-hpijs', 'foomatic-filters',
703
        'foomatic-gui', 'hpijs', 'hplip', 'm2300w', 'min12xxw', 'c2050',
704
        'hpoj', 'pxljr', 'pnm2ppa', 'splix', 'hp-ppd', 'hpijs-ppds',
705
        'linuxprinting.org-ppds', 'openprinting-ppds',
706
        'openprinting-ppds-extra', 'ghostscript', 'cups',
707
        'cups-driver-gutenprint', 'foomatic-db-gutenprint', 'ijsgutenprint',
708
        'cupsys-driver-gutenprint', 'gimp-gutenprint', 'gutenprint-doc',
1369.1.8 by Martin Pitt
apport/hookutils.py:
709
        'gutenprint-locales', 'system-config-printer-common', 'kdeprint')
710
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
711
1369.91.1 by Marc Deslauriers
Allow specifying a list of profile names when using
712
def attach_mac_events(report, profiles=None):
1369.59.1 by Marc Deslauriers
- add MAC (AppArmor) hooks to apport
713
    '''Attach MAC information and events to the report.'''
1369.34.130 by Martin Pitt
hookutils.py: Add attach_mac_events() for reporting logs of MAC systems. Looks for AppArmor messages for now. Thanks Marc Deslauriers!
714
1369.91.1 by Marc Deslauriers
Allow specifying a list of profile names when using
715
    # Allow specifying a string, or a list of strings
716
    if isinstance(profiles, str):
717
        profiles = [profiles]
718
2566 by Brian Murray
Cherry picked from upstream's unreleased 2.20.6 - Convert regular
719
    mac_regex = r'audit\(|apparmor|selinux|security'
1369.59.1 by Marc Deslauriers
- add MAC (AppArmor) hooks to apport
720
    mac_re = re.compile(mac_regex, re.IGNORECASE)
1369.91.3 by Marc Deslauriers
hookutils.py: Add regexp support to attach_mac_events(), and properly
721
    aa_regex = 'apparmor="DENIED".+?profile=([^ ]+?)[ ]'
1369.91.1 by Marc Deslauriers
Allow specifying a list of profile names when using
722
    aa_re = re.compile(aa_regex, re.IGNORECASE)
723
724
    if 'KernLog' not in report:
1369.34.1139 by Martin Pitt
* hookutils, attach_mac_events(): Read kernel violation messages from dmesg instead of /var/log/kern.log, as that's specific to rsyslog and its configuration.
725
        report['KernLog'] = __filter_re_process(
726
            mac_re, subprocess.Popen(['dmesg'], stdout=subprocess.PIPE))
1369.91.1 by Marc Deslauriers
Allow specifying a list of profile names when using
727
728
    if 'AuditLog' not in report and os.path.exists('/var/run/auditd.pid'):
1369.60.1 by Marc Deslauriers
apport/hookutils.py: properly detect as non-root when auditd is being
729
        attach_root_command_outputs(report, {'AuditLog': 'egrep "' + mac_regex + '" /var/log/audit/audit.log'})
1369.59.1 by Marc Deslauriers
- add MAC (AppArmor) hooks to apport
730
2457 by Brian Murray
data/iwlwifi_error_dump: fix add_package call. (LP: #1496268)
731
    attach_file_if_exists(report, '/proc/version_signature', 'ProcVersionSignature')
1369.59.1 by Marc Deslauriers
- add MAC (AppArmor) hooks to apport
732
    attach_file(report, '/proc/cmdline', 'ProcCmdline')
733
1369.34.672 by Martin Pitt
* hookutils.py: Allow specifying a list of profile names when using attach_mac_events(). Thanks Marc Deslauriers.
734
    for match in re.findall(aa_re, report.get('KernLog', '') + report.get('AuditLog', '')):
1369.91.3 by Marc Deslauriers
hookutils.py: Add regexp support to attach_mac_events(), and properly
735
        if not profiles:
736
            _add_tag(report, 'apparmor')
1369.91.1 by Marc Deslauriers
Allow specifying a list of profile names when using
737
            break
2064 by Marc Deslauriers
hookutils.py: Allow specifying a list of profile names when using
738
1369.91.3 by Marc Deslauriers
hookutils.py: Add regexp support to attach_mac_events(), and properly
739
        try:
740
            if match[0] == '"':
741
                profile = match[1:-1]
742
            elif sys.version[0] >= '3':
743
                profile = bytes.fromhex(match).decode('UTF-8', errors='replace')
744
            else:
745
                profile = match.decode('hex', errors='replace')
2571 by Brian Murray
Fix new pep8 failures in artful - E722 do not use bare except.
746
        except Exception:
1369.91.3 by Marc Deslauriers
hookutils.py: Add regexp support to attach_mac_events(), and properly
747
            continue
748
749
        for search_profile in profiles:
750
            if re.match('^' + search_profile + '$', profile):
751
                _add_tag(report, 'apparmor')
752
                break
753
1369.91.5 by Marc Deslauriers
fix PEP-8 violations
754
1369.91.3 by Marc Deslauriers
hookutils.py: Add regexp support to attach_mac_events(), and properly
755
def _add_tag(report, tag):
756
    '''Adds or appends a tag to the report'''
757
    current_tags = report.get('Tags', '')
758
    if current_tags:
759
        current_tags += ' '
760
    report['Tags'] = current_tags + tag
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
761
1369.91.5 by Marc Deslauriers
fix PEP-8 violations
762
1369.1.8 by Martin Pitt
apport/hookutils.py:
763
def attach_related_packages(report, packages):
764
    '''Attach version information for related packages
765
1369.1.143 by Martin Pitt
PEP-8 compatible docstrings
766
    In the future, this might also run their hooks.
767
    '''
1369.1.8 by Martin Pitt
apport/hookutils.py:
768
    report['RelatedPackageVersions'] = package_versions(*packages)
769
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
770
1369.1.8 by Martin Pitt
apport/hookutils.py:
771
def package_versions(*packages):
1369.1.12 by Martin Pitt
apport/hookutils.py: Extend package_versions to accept globs.
772
    '''Return a text listing of package names and versions.
1369.34.404 by Martin Pitt
remove trailing whitespace
773
1369.1.12 by Martin Pitt
apport/hookutils.py: Extend package_versions to accept globs.
774
    Arguments may be package names or globs, e. g. "foo*"
775
    '''
1369.165.53 by Brian Murray
apport/hookutils.py: don't crash if packages is empty
776
    if not packages:
777
        return ''
1369.34.29 by Matt Zimmerman
Make hookutils.package_versions a bit more readable
778
    versions = []
1369.1.12 by Martin Pitt
apport/hookutils.py: Extend package_versions to accept globs.
779
    for package_pattern in packages:
1369.1.342 by Martin Pitt
hookutils, package_versions(): Ignore "None" packages, for more robust package hooks. (LP: #518295)
780
        if not package_pattern:
781
            continue
1369.34.28 by Matt Zimmerman
Always include all requested package names in hookutils.package_versions(),
782
1369.34.68 by Matt Zimmerman
In apport.hookutils.package_versions, when matching a glob, sort the
783
        matching_packages = packaging.package_name_glob(package_pattern)
1369.34.29 by Matt Zimmerman
Make hookutils.package_versions a bit more readable
784
1369.34.68 by Matt Zimmerman
In apport.hookutils.package_versions, when matching a glob, sort the
785
        if not matching_packages:
1369.34.29 by Matt Zimmerman
Make hookutils.package_versions a bit more readable
786
            versions.append((package_pattern, 'N/A'))
1369.34.28 by Matt Zimmerman
Always include all requested package names in hookutils.package_versions(),
787
1369.34.68 by Matt Zimmerman
In apport.hookutils.package_versions, when matching a glob, sort the
788
        for package in sorted(matching_packages):
1369.1.12 by Martin Pitt
apport/hookutils.py: Extend package_versions to accept globs.
789
            try:
790
                version = packaging.get_version(package)
791
            except ValueError:
792
                version = 'N/A'
793
            if version is None:
794
                version = 'N/A'
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
795
            versions.append((package, version))
1369.1.8 by Martin Pitt
apport/hookutils.py:
796
1369.34.67 by Matt Zimmerman
In hookutils.package_versions, return the list as a nicely formatted table
797
    package_width, version_width = \
798
        map(max, [map(len, t) for t in zip(*versions)])
799
800
    fmt = '%%-%ds %%s' % package_width
801
    return '\n'.join([fmt % v for v in versions])
1282 by Martin Pitt
apport/hookutils.py: Add attach_printing(). Thanks to Brian Murray
802
1369.34.802 by Martin Pitt
* Move shared_libraries() and links_with_shared_library() from hookutils into fileutils, so that we can use it from apport-valgrind. Thanks to Kyle Nitzsche for the initial patch.
803
1369.1.19 by Martin Pitt
move determination of nonfree kernel modules from core code to generic hook
804
def _get_module_license(module):
805
    '''Return the license for a given kernel module.'''
806
807
    try:
808
        modinfo = subprocess.Popen(['/sbin/modinfo', module],
1369.34.622 by Martin Pitt
* Fix PEP-8 violations picked up by latest pep8 checker.
809
                                   stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1369.34.253 by Martin Pitt
apport/hookutils.py: Port to Python 3
810
        out = modinfo.communicate()[0].decode('UTF-8')
1369.1.19 by Martin Pitt
move determination of nonfree kernel modules from core code to generic hook
811
        if modinfo.returncode != 0:
1369.1.130 by Martin Pitt
hookutils.py, _get_module_license(): Return "invalid" if modinfo fails, so that they do not count as "free". (LP: #341720)
812
            return 'invalid'
1369.1.19 by Martin Pitt
move determination of nonfree kernel modules from core code to generic hook
813
    except OSError:
814
        return None
815
    for l in out.splitlines():
816
        fields = l.split(':', 1)
817
        if len(fields) < 2:
818
            continue
819
        if fields[0] == 'license':
820
            return fields[1].strip()
821
822
    return None
823
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
824
825
def nonfree_kernel_modules(module_list='/proc/modules'):
1369.1.19 by Martin Pitt
move determination of nonfree kernel modules from core code to generic hook
826
    '''Check loaded modules and return a list of those which are not free.'''
1369.1.143 by Martin Pitt
PEP-8 compatible docstrings
827
1369.1.19 by Martin Pitt
move determination of nonfree kernel modules from core code to generic hook
828
    try:
1369.34.253 by Martin Pitt
apport/hookutils.py: Port to Python 3
829
        with open(module_list) as f:
830
            mods = [l.split()[0] for l in f]
1369.1.19 by Martin Pitt
move determination of nonfree kernel modules from core code to generic hook
831
    except IOError:
832
        return []
833
834
    nonfree = []
835
    for m in mods:
1369.34.1325 by Martin Pitt
Fix PEP-8 errors with latest pycodestyle
836
        s = _get_module_license(m)
837
        if s and not ('GPL' in s or 'BSD' in s or 'MPL' in s or 'MIT' in s):
1369.1.19 by Martin Pitt
move determination of nonfree kernel modules from core code to generic hook
838
            nonfree.append(m)
839
840
    return nonfree
841
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
842
1369.1.408 by Martin Pitt
hookutils.py: Add new method attach_drm_info() to read and format /sys/class/drm/*.
843
def __drm_con_info(con):
844
    info = ''
845
    for f in os.listdir(con):
846
        path = os.path.join(con, f)
847
        if f == 'uevent' or not os.path.isfile(path):
848
            continue
1369.34.1133 by Martin Pitt
* hookutils, attach_drm_info(): Avoid UnicodeDecodeErrors in Python 3 when reading binary files. Thanks Chad Miller. (LP: #1425254)
849
        val = open(path, 'rb').read().strip()
1369.1.408 by Martin Pitt
hookutils.py: Add new method attach_drm_info() to read and format /sys/class/drm/*.
850
        # format some well-known attributes specially
851
        if f == 'modes':
1369.143.1 by Chad MILLER
Avoid a str-not-support-buffer-interface TypeError by opening DRM files as byte
852
            val = val.replace(b'\n', b' ')
1369.1.408 by Martin Pitt
hookutils.py: Add new method attach_drm_info() to read and format /sys/class/drm/*.
853
        if f == 'edid':
854
            val = base64.b64encode(val)
855
            f += '-base64'
1369.34.1133 by Martin Pitt
* hookutils, attach_drm_info(): Avoid UnicodeDecodeErrors in Python 3 when reading binary files. Thanks Chad Miller. (LP: #1425254)
856
        info += '%s: %s\n' % (f, val.decode('UTF-8', errors='replace'))
1369.1.408 by Martin Pitt
hookutils.py: Add new method attach_drm_info() to read and format /sys/class/drm/*.
857
    return info
858
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
859
1369.1.408 by Martin Pitt
hookutils.py: Add new method attach_drm_info() to read and format /sys/class/drm/*.
860
def attach_drm_info(report):
861
    '''Add information about DRM hardware.
862
863
    Collect information from /sys/class/drm/.
864
    '''
865
    drm_dir = '/sys/class/drm'
866
    if not os.path.isdir(drm_dir):
867
        return
868
    for f in os.listdir(drm_dir):
869
        con = os.path.join(drm_dir, f)
870
        if os.path.exists(os.path.join(con, 'enabled')):
1369.32.1 by Christopher James Halse Rogers
Sanitise DRM connector name before using it as a report key
871
            # DRM can set an arbitrary string for its connector paths.
1369.1.411 by Martin Pitt
hookutils.py, attach_drm_info(): Sanitize connector names. Thanks Chris Halse Rogers! (LP: #597558)
872
            report['DRM.' + path_to_key(f)] = __drm_con_info(con)
1369.1.408 by Martin Pitt
hookutils.py: Add new method attach_drm_info() to read and format /sys/class/drm/*.
873
1369.34.492 by Martin Pitt
* Fix the whole code to be PEP-8 compatible, and enforce this in test/run by running the "pep8" tool.
874
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
875
def in_session_of_problem(report):
876
    '''Check if the problem happened in the currently running XDG session.
877
878
    This can be used to determine if e. g. ~/.xsession-errors is relevant and
879
    should be attached.
880
1369.34.845 by Martin Pitt
* hookutils.py, in_session_of_problem(): Port from ConsoleKit to logind.
881
    Return None if this cannot be determined.
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
882
    '''
1369.34.1125 by Martin Pitt
* hookutils.in_session_of_problem(): Check $XDG_SESSION_ID and /run/systemd/sessions instead of the cgroup, as the latter does not work under cgmanager.
883
    session_id = os.environ.get('XDG_SESSION_ID')
884
    if not session_id:
1369.34.1204 by Martin Pitt
* When determinining the logind session and $XDG_SESSION_ID is not set, fall back to reading it from /proc/pid/cgroup.
885
        # fall back to reading cgroup
886
        with open('/proc/self/cgroup') as f:
1369.34.1325 by Martin Pitt
Fix PEP-8 errors with latest pycodestyle
887
            for line in f:
888
                line = line.strip()
889
                if 'name=systemd:' in line and line.endswith('.scope') and '/session-' in line:
890
                    session_id = line.split('/session-', 1)[1][:-6]
1369.34.1204 by Martin Pitt
* When determinining the logind session and $XDG_SESSION_ID is not set, fall back to reading it from /proc/pid/cgroup.
891
                    break
892
            else:
893
                return None
1369.34.1125 by Martin Pitt
* hookutils.in_session_of_problem(): Check $XDG_SESSION_ID and /run/systemd/sessions instead of the cgroup, as the latter does not work under cgmanager.
894
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
895
    # report time is in local TZ
896
    orig_ctime = locale.getlocale(locale.LC_TIME)
897
    try:
1369.34.832 by Martin Pitt
* hookutils.in_session_of_problem(): Fix crash when the current locale is invalid. (LP: #1154896)
898
        try:
899
            locale.setlocale(locale.LC_TIME, 'C')
900
            report_time = time.mktime(time.strptime(report['Date']))
901
        except KeyError:
902
            return None
903
        finally:
904
            locale.setlocale(locale.LC_TIME, orig_ctime)
905
    except locale.Error:
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
906
        return None
907
1369.34.1125 by Martin Pitt
* hookutils.in_session_of_problem(): Check $XDG_SESSION_ID and /run/systemd/sessions instead of the cgroup, as the latter does not work under cgmanager.
908
    # determine session creation time
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
909
    try:
1369.34.1125 by Martin Pitt
* hookutils.in_session_of_problem(): Check $XDG_SESSION_ID and /run/systemd/sessions instead of the cgroup, as the latter does not work under cgmanager.
910
        session_start_time = os.stat('/run/systemd/sessions/' + session_id).st_mtime
911
    except (IOError, OSError):
1369.34.845 by Martin Pitt
* hookutils.py, in_session_of_problem(): Port from ConsoleKit to logind.
912
        return None
913
1369.34.200 by Martin Pitt
hookutils.py: Add new function in_session_of_problem() which returns whether the given report happened in the currently running XDG session. This can be used to determine if e. g. ~/.xsession-errors is relevant and should be attached.
914
    return session_start_time <= report_time
1369.84.1 by Brian Murray
hookutils.py: add in attach_default_grub convenience function from the grub2 package hook so it can be used by other packages
915
916
917
def attach_default_grub(report, key=None):
918
    '''attach /etc/default/grub after filtering out password lines'''
1369.34.543 by Martin Pitt
* hookutils.py: Add attach_default_grub() convenience function from the grub2 package hook so it can be used by other packages. Thanks Brian Murray.
919
1369.84.1 by Brian Murray
hookutils.py: add in attach_default_grub convenience function from the grub2 package hook so it can be used by other packages
920
    path = '/etc/default/grub'
921
    if not key:
922
        key = path_to_key(path)
923
924
    if os.path.exists(path):
925
        with open(path, 'r') as f:
926
            filtered = [l if not l.startswith('password')
927
                        else '### PASSWORD LINE REMOVED ###'
928
                        for l in f.readlines()]
929
            report[key] = ''.join(filtered)
1369.34.802 by Martin Pitt
* Move shared_libraries() and links_with_shared_library() from hookutils into fileutils, so that we can use it from apport-valgrind. Thanks to Kyle Nitzsche for the initial patch.
930
931
932
# backwards compatible API
933
shared_libraries = apport.fileutils.shared_libraries
934
links_with_shared_library = apport.fileutils.links_with_shared_library