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 CedarBackup2.util import resolveCommand, executeCommand, changeOwnership 
 74   
 75   
 76   
 77   
 78   
 79   
 80  logger = logging.getLogger("CedarBackup2.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        try: 
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        finally: 
144           outputFile.close() 
145        if not os.path.exists(filename): 
146           raise IOError("File [%s] does not seem to exist after Debian package dump finished." % filename) 
147        changeOwnership(filename, backupUser, backupGroup) 
 148   
150     """ 
151     Dumps information about the partition table via C{fdisk}. 
152     @param targetDir: Directory to write output file into. 
153     @param backupUser: User which should own the resulting file. 
154     @param backupGroup: Group which should own the resulting file. 
155     @param compress: Indicates whether to compress the output file. 
156     @raise IOError: If the dump fails for some reason. 
157     """ 
158     if not os.path.exists(FDISK_PATH): 
159        logger.info("Not executing partition table dump since %s doesn't seem to exist.", FDISK_PATH) 
160     elif not os.access(FDISK_PATH, os.X_OK): 
161        logger.info("Not executing partition table dump since %s cannot be executed.", FDISK_PATH) 
162     else: 
163        (outputFile, filename) = _getOutputFile(targetDir, "fdisk-l", compress) 
164        try: 
165           command = resolveCommand(FDISK_COMMAND) 
166           result = executeCommand(command, [], returnOutput=False, ignoreStderr=True, outputFile=outputFile)[0] 
167           if result != 0: 
168              raise IOError("Error [%d] executing partition table dump." % result) 
169        finally: 
170           outputFile.close() 
171        if not os.path.exists(filename): 
172           raise IOError("File [%s] does not seem to exist after partition table dump finished." % filename) 
173        changeOwnership(filename, backupUser, backupGroup) 
 174   
175 -def _dumpFilesystemContents(targetDir, backupUser, backupGroup, compress=True): 
 176     """ 
177     Dumps complete listing of filesystem contents via C{ls -laR}. 
178     @param targetDir: Directory to write output file into. 
179     @param backupUser: User which should own the resulting file. 
180     @param backupGroup: Group which should own the resulting file. 
181     @param compress: Indicates whether to compress the output file. 
182     @raise IOError: If the dump fails for some reason. 
183     """ 
184     (outputFile, filename) = _getOutputFile(targetDir, "ls-laR", compress) 
185     try: 
186         
187        command = resolveCommand(LS_COMMAND) 
188        executeCommand(command, [], returnOutput=False, ignoreStderr=True, doNotLog=True, outputFile=outputFile) 
189     finally: 
190        outputFile.close() 
191     if not os.path.exists(filename): 
192        raise IOError("File [%s] does not seem to exist after filesystem contents dump finished." % filename) 
193     changeOwnership(filename, backupUser, backupGroup) 
 194   
196     """ 
197     Opens the output file used for saving a dump to the filesystem. 
198   
199     The filename will be C{name.txt} (or C{name.txt.bz2} if C{compress} is 
200     C{True}), written in the target directory. 
201   
202     @param targetDir: Target directory to write file in. 
203     @param name: Name of the file to create. 
204     @param compress: Indicates whether to write compressed output. 
205   
206     @return: Tuple of (Output file object, filename) 
207     """ 
208     filename = os.path.join(targetDir, "%s.txt" % name) 
209     if compress: 
210        filename = "%s.bz2" % filename 
211     logger.debug("Dump file will be [%s].", filename) 
212     if compress: 
213        outputFile = BZ2File(filename, "w") 
214     else: 
215        outputFile = open(filename, "w") 
216     return (outputFile, filename) 
 217