OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """Parser for Systemd journal files.""" | 2 """Parser for Systemd journal files.""" |
3 | 3 |
4 from __future__ import unicode_literals | 4 from __future__ import unicode_literals |
5 | 5 |
6 import os | 6 import os |
7 | 7 |
8 import construct | 8 import construct |
| 9 import lz4 |
9 | 10 |
10 from dfdatetime import posix_time as dfdatetime_posix_time | 11 from dfdatetime import posix_time as dfdatetime_posix_time |
11 | 12 |
12 try: | 13 try: |
13 import lzma | 14 import lzma |
14 except ImportError: | 15 except ImportError: |
15 from backports import lzma | 16 from backports import lzma |
16 | 17 |
17 from plaso.containers import events | 18 from plaso.containers import events |
18 from plaso.containers import time_events | 19 from plaso.containers import time_events |
(...skipping 24 matching lines...) Expand all Loading... |
43 self.reporter = None | 44 self.reporter = None |
44 | 45 |
45 | 46 |
46 class SystemdJournalParser(interface.FileObjectParser): | 47 class SystemdJournalParser(interface.FileObjectParser): |
47 """Parses Systemd Journal files.""" | 48 """Parses Systemd Journal files.""" |
48 | 49 |
49 NAME = 'systemd_journal' | 50 NAME = 'systemd_journal' |
50 | 51 |
51 DESCRIPTION = 'Parser for Systemd Journal files.' | 52 DESCRIPTION = 'Parser for Systemd Journal files.' |
52 | 53 |
53 _OBJECT_COMPRESSED_FLAG = 0x00000001 | 54 _OBJECT_COMPRESSED_FLAG_XZ = 1 |
| 55 _OBJECT_COMPRESSED_FLAG_LZ4 = 1 << 1 |
54 | 56 |
55 # Unfortunately this doesn't help us knowing about the "dirtiness" or | 57 # Unfortunately this doesn't help us knowing about the "dirtiness" or |
56 # "corrupted" file state. | 58 # "corrupted" file state. |
57 # A file can be in any of these states and still be corrupted, for example, by | 59 # A file can be in any of these states and still be corrupted, for example, by |
58 # an unexpected shut down. Once journald detects one of these, it will | 60 # an unexpected shut down. Once journald detects one of these, it will |
59 # "rotate" the corrupted journal file, an store it away, and change the status | 61 # "rotate" the corrupted journal file, an store it away, and change the status |
60 # to STATE_OFFLINE. | 62 # to STATE_OFFLINE. |
61 # STATE_ONLINE means the file wasn't closed, but the journal can still be in a | 63 # STATE_ONLINE means the file wasn't closed, but the journal can still be in a |
62 # clean state. | 64 # clean state. |
63 _JOURNAL_STATE = construct.Enum( | 65 _JOURNAL_STATE = construct.Enum( |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 """ | 199 """ |
198 object_header, payload_size = self._ParseObjectHeader(file_object, offset) | 200 object_header, payload_size = self._ParseObjectHeader(file_object, offset) |
199 file_object.read(self._DATA_OBJECT_SIZE) | 201 file_object.read(self._DATA_OBJECT_SIZE) |
200 | 202 |
201 if object_header.type != 'DATA': | 203 if object_header.type != 'DATA': |
202 raise errors.ParseError( | 204 raise errors.ParseError( |
203 'Expected an object of type DATA, but got {0:s}'.format( | 205 'Expected an object of type DATA, but got {0:s}'.format( |
204 object_header.type)) | 206 object_header.type)) |
205 | 207 |
206 event_data = file_object.read(payload_size - self._DATA_OBJECT_SIZE) | 208 event_data = file_object.read(payload_size - self._DATA_OBJECT_SIZE) |
207 if object_header.flags & self._OBJECT_COMPRESSED_FLAG: | 209 if object_header.flags & self._OBJECT_COMPRESSED_FLAG_XZ: |
208 event_data = lzma.decompress(event_data) | 210 event_data = lzma.decompress(event_data) |
209 | 211 |
| 212 if object_header.flags & self._OBJECT_COMPRESSED_FLAG_LZ4: |
| 213 decompressed_size = construct.ULInt32('size').parse(event_data[0:7]) |
| 214 event_data = lz4.block.decompress( |
| 215 event_data[8:], uncompressed_size=decompressed_size) |
| 216 |
210 event_string = event_data.decode('utf-8') | 217 event_string = event_data.decode('utf-8') |
211 event_key, event_value = event_string.split('=', 1) | 218 event_key, event_value = event_string.split('=', 1) |
212 return (event_key, event_value) | 219 return (event_key, event_value) |
213 | 220 |
214 def _ParseJournalEntry(self, parser_mediator, file_object, offset): | 221 def _ParseJournalEntry(self, parser_mediator, file_object, offset): |
215 """Parses a Systemd journal ENTRY object. | 222 """Parses a Systemd journal ENTRY object. |
216 | 223 |
217 This method will generate an event per ENTRY object. | 224 This method will generate an event per ENTRY object. |
218 | 225 |
219 Args: | 226 Args: |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 'Unable to complete parsing journal file: {0:s} at offset ' | 338 'Unable to complete parsing journal file: {0:s} at offset ' |
332 '0x{1:08x}').format(exception, entry_offset)) | 339 '0x{1:08x}').format(exception, entry_offset)) |
333 return | 340 return |
334 except construct.ConstructError as exception: | 341 except construct.ConstructError as exception: |
335 raise errors.UnableToParseFile(( | 342 raise errors.UnableToParseFile(( |
336 'Unable to parse journal header at offset: 0x{0:08x} with ' | 343 'Unable to parse journal header at offset: 0x{0:08x} with ' |
337 'error: {1:s}').format(entry_offset, exception)) | 344 'error: {1:s}').format(entry_offset, exception)) |
338 | 345 |
339 | 346 |
340 manager.ParsersManager.RegisterParser(SystemdJournalParser) | 347 manager.ParsersManager.RegisterParser(SystemdJournalParser) |
OLD | NEW |