4 ## maintains a manifest of files of which to keep track
5 ## provides file meta-data (and optionally full data) to func-inventory
7 ## (C) Vito Laurenza <vitolaurenza@gmail.com>
8 ## + Michael DeHaan <mdehaan@redhat.com>
10 ## This software may be freely redistributed under the terms of the GNU
11 ## general public license.
13 ## You should have received a copy of the GNU General Public License
14 ## along with this program; if not, write to the Free Software
15 ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 CONFIG_FILE
='/etc/func/modules/filetracker.conf'
30 class FileTracker(func_module
.FuncModule
):
34 description
= "Maintains a manifest of files to keep track of."
38 Parse file and return data structure.
42 if os
.path
.exists(CONFIG_FILE
):
43 config
= open(CONFIG_FILE
, "r")
45 lines
= data
.split("\n")
47 tokens
= line
.split(None)
51 path
= " ".join(tokens
[1:])
52 if str(scan_mode
).lower() == "0":
56 filehash
[path
] = scan_mode
59 #==========================================================
61 def __save(self
, filehash
):
63 Write data structure to file.
66 config
= open(CONFIG_FILE
, "w+")
67 for (path
, scan_mode
) in filehash
.iteritems():
68 config
.write("%s %s\n" % (scan_mode
, path
))
71 #==========================================================
73 def track(self
, file_name
, full_scan
=0):
75 Adds files to keep track of.
76 full_scan implies tracking the full contents of the file, defaults to off
79 filehash
= self
.__load
()
80 filehash
[file_name
] = full_scan
84 #==========================================================
86 def untrack(self
, file_name
):
88 Stop keeping track of a file.
89 This routine is tolerant of most errors since we're forgetting about the file anyway.
92 filehash
= self
.__load
()
93 if file_name
in filehash
.keys():
94 del filehash
[file_name
]
98 #==========================================================
100 def inventory(self
, flatten
=1, checksum_enabled
=1):
102 Returns information on all tracked files
103 By default, 'flatten' is passed in as True, which makes printouts very clean in diffs
104 for use by func-inventory. If you are writting another software application, using flatten=False will
105 prevent the need to parse the returns.
108 # XMLRPC feeds us strings from the CLI when it shouldn't
109 flatten
= int(flatten
)
110 checksum_enabled
= int(checksum_enabled
)
112 filehash
= self
.__load
()
114 # we'll either return a very flat string (for clean diffs)
115 # or a data structure
121 for (file_name
, scan_type
) in filehash
.iteritems():
123 if not os
.path
.exists(file_name
):
125 results
= results
+ "%s: does not exist\n" % file_name
127 results
.append("%s: does not exist\n" % file_name
)
132 # ----- always process metadata
133 filestat
= os
.stat(file_name
)
134 mode
= filestat
[ST_MODE
]
135 mtime
= filestat
[ST_MTIME
]
136 uid
= filestat
[ST_UID
]
137 gid
= filestat
[ST_GID
]
138 if not os
.path
.isdir(file_name
) and checksum_enabled
:
139 sum_handle
= open(file_name
)
140 hash = self
.__sumfile
(sum_handle
)
145 # ------ what we return depends on flatten
147 this_result
= "%s: mode=%s mtime=%s uid=%s gid=%s md5sum=%s\n" % (file_name
,mode
,mtime
,uid
,gid
,hash)
149 this_result
= [file_name
,mode
,mtime
,uid
,gid
,hash]
151 # ------ add on file data only if requested
152 if scan_type
!= 0 and os
.path
.isfile(file_name
):
153 tracked_file
= open(file_name
)
154 data
= tracked_file
.read()
156 this_result
= this_result
+ "*** DATA ***\n" + data
+ "\n*** END DATA ***\n\n"
158 this_result
.append(data
)
161 if os
.path
.isdir(file_name
):
162 if not file_name
.endswith("/"):
163 file_name
= file_name
+ "/"
164 files
= glob
.glob(file_name
+ "*")
166 this_result
= this_result
+ "*** FILES ***\n" + "\n".join(files
) + "\n*** END FILES ***\n\n"
168 this_result
.append({"files" : files
})
171 results
= results
+ "\n" + this_result
173 results
.append(this_result
)
178 #==========================================================
180 def __sumfile(self
, fobj
):
182 Returns an md5 hash for an object with read() method.
183 credit: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266486