1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 """
39 Provides an extension to save off important system recovery information.
40
41 This is a simple Cedar Backup extension used to save off important system
42 recovery information. It saves off three types of information:
43
44 - Currently-installed Debian packages via C{dpkg --get-selections}
45 - Disk partition information via C{fdisk -l}
46 - System-wide mounted filesystem contents, via C{ls -laR}
47
48 The saved-off information is placed into the collect directory and is
49 compressed using C{bzip2} to save space.
50
51 This extension relies on the options and collect configurations in the standard
52 Cedar Backup configuration file, but requires no new configuration of its own.
53 No public functions other than the action are exposed since all of this is
54 pretty simple.
55
56 @note: If the C{dpkg} or C{fdisk} commands cannot be found in their normal
57 locations or executed by the current user, those steps will be skipped and a
58 note will be logged at the INFO level.
59
60 @author: Kenneth J. Pronovici <pronovic@ieee.org>
61 """
62
63
64
65
66
67
68 import os
69 import logging
70 from bz2 import BZ2File
71
72
73 from CedarBackup3.util import resolveCommand, executeCommand, changeOwnership
74
75
76
77
78
79
80 logger = logging.getLogger("CedarBackup3.log.extend.sysinfo")
81
82 DPKG_PATH = "/usr/bin/dpkg"
83 FDISK_PATH = "/sbin/fdisk"
84
85 DPKG_COMMAND = [ DPKG_PATH, "--get-selections", ]
86 FDISK_COMMAND = [ FDISK_PATH, "-l", ]
87 LS_COMMAND = [ "ls", "-laR", "/", ]
88
89
90
91
92
93
94
95
96
97
98
122
124 """
125 Dumps a list of currently installed Debian packages via C{dpkg}.
126 @param targetDir: Directory to write output file into.
127 @param backupUser: User which should own the resulting file.
128 @param backupGroup: Group which should own the resulting file.
129 @param compress: Indicates whether to compress the output file.
130 @raise IOError: If the dump fails for some reason.
131 """
132 if not os.path.exists(DPKG_PATH):
133 logger.info("Not executing Debian package dump since %s doesn't seem to exist.", DPKG_PATH)
134 elif not os.access(DPKG_PATH, os.X_OK):
135 logger.info("Not executing Debian package dump since %s cannot be executed.", DPKG_PATH)
136 else:
137 (outputFile, filename) = _getOutputFile(targetDir, "dpkg-selections", compress)
138 with outputFile:
139 command = resolveCommand(DPKG_COMMAND)
140 result = executeCommand(command, [], returnOutput=False, ignoreStderr=True, doNotLog=True, outputFile=outputFile)[0]
141 if result != 0:
142 raise IOError("Error [%d] executing Debian package dump." % result)
143 if not os.path.exists(filename):
144 raise IOError("File [%s] does not seem to exist after Debian package dump finished." % filename)
145 changeOwnership(filename, backupUser, backupGroup)
146
148 """
149 Dumps information about the partition table via C{fdisk}.
150 @param targetDir: Directory to write output file into.
151 @param backupUser: User which should own the resulting file.
152 @param backupGroup: Group which should own the resulting file.
153 @param compress: Indicates whether to compress the output file.
154 @raise IOError: If the dump fails for some reason.
155 """
156 if not os.path.exists(FDISK_PATH):
157 logger.info("Not executing partition table dump since %s doesn't seem to exist.", FDISK_PATH)
158 elif not os.access(FDISK_PATH, os.X_OK):
159 logger.info("Not executing partition table dump since %s cannot be executed.", FDISK_PATH)
160 else:
161 (outputFile, filename) = _getOutputFile(targetDir, "fdisk-l", compress)
162 with outputFile:
163 command = resolveCommand(FDISK_COMMAND)
164 result = executeCommand(command, [], returnOutput=False, ignoreStderr=True, outputFile=outputFile)[0]
165 if result != 0:
166 raise IOError("Error [%d] executing partition table dump." % result)
167 if not os.path.exists(filename):
168 raise IOError("File [%s] does not seem to exist after partition table dump finished." % filename)
169 changeOwnership(filename, backupUser, backupGroup)
170
171 -def _dumpFilesystemContents(targetDir, backupUser, backupGroup, compress=True):
172 """
173 Dumps complete listing of filesystem contents via C{ls -laR}.
174 @param targetDir: Directory to write output file into.
175 @param backupUser: User which should own the resulting file.
176 @param backupGroup: Group which should own the resulting file.
177 @param compress: Indicates whether to compress the output file.
178 @raise IOError: If the dump fails for some reason.
179 """
180 (outputFile, filename) = _getOutputFile(targetDir, "ls-laR", compress)
181 with outputFile:
182
183 command = resolveCommand(LS_COMMAND)
184 executeCommand(command, [], returnOutput=False, ignoreStderr=True, doNotLog=True, outputFile=outputFile)
185 if not os.path.exists(filename):
186 raise IOError("File [%s] does not seem to exist after filesystem contents dump finished." % filename)
187 changeOwnership(filename, backupUser, backupGroup)
188
190 """
191 Opens the output file used for saving a dump to the filesystem.
192
193 The filename will be C{name.txt} (or C{name.txt.bz2} if C{compress} is
194 C{True}), written in the target directory.
195
196 @param targetDir: Target directory to write file in.
197 @param name: Name of the file to create.
198 @param compress: Indicates whether to write compressed output.
199
200 @return: Tuple of (Output file object, filename), file opened in binary mode for use with executeCommand()
201 """
202 filename = os.path.join(targetDir, "%s.txt" % name)
203 if compress:
204 filename = "%s.bz2" % filename
205 logger.debug("Dump file will be [%s].", filename)
206 if compress:
207 outputFile = BZ2File(filename, "wb")
208 else:
209 outputFile = open(filename, "wb")
210 return (outputFile, filename)
211