root/trunk/bcfg2/src/lib/Client/Tools/POSIX.py

Revision 5582, 29.2 KB (checked in by solj, 5 days ago)

POSIX: Remove support for old-style posix entries

This commit forces the user to specify <Path> entries on the server
side while still maintaining compatibility with old clients via the
POSIXCompat plugin.

Signed-off-by: Sol Jerome <solj@…>

  • Property svn:keywords set to Revision Id
Line 
1'''All POSIX Type client support for Bcfg2'''
2__revision__ = '$Revision$'
3
4from datetime import datetime
5from stat import S_ISVTX, S_ISGID, S_ISUID, S_IXUSR, S_IWUSR, S_IRUSR, S_IXGRP
6from stat import S_IWGRP, S_IRGRP, S_IXOTH, S_IWOTH, S_IROTH, ST_MODE, S_ISDIR
7from stat import S_IFREG, ST_UID, ST_GID, S_ISREG, S_IFDIR, S_ISLNK, ST_MTIME
8import binascii
9import difflib
10import grp
11import logging
12import os
13import pwd
14import shutil
15import stat
16import string
17import time
18import Bcfg2.Client.Tools
19import Bcfg2.Options
20
21log = logging.getLogger('posix')
22
23# map between dev_type attribute and stat constants
24device_map = {'block': stat.S_IFBLK,
25              'char': stat.S_IFCHR,
26              'fifo': stat.S_IFIFO}
27
28
29def calcPerms(initial, perms):
30    '''This compares ondisk permissions with specified ones'''
31    pdisp = [{1:S_ISVTX, 2:S_ISGID, 4:S_ISUID},
32             {1:S_IXUSR, 2:S_IWUSR, 4:S_IRUSR},
33             {1:S_IXGRP, 2:S_IWGRP, 4:S_IRGRP},
34             {1:S_IXOTH, 2:S_IWOTH, 4:S_IROTH}]
35    tempperms = initial
36    if len(perms) == 3:
37        perms = '0%s' % (perms)
38    pdigits = [int(perms[digit]) for digit in range(4)]
39    for index in range(4):
40        for (num, perm) in list(pdisp[index].items()):
41            if pdigits[index] & num:
42                tempperms |= perm
43    return tempperms
44
45def normUid(entry):
46    '''
47       This takes a user name or uid and
48       returns the corresponding uid or False
49    '''
50    try:
51        try:
52            return int(entry.get('owner'))
53        except:
54            return int(pwd.getpwnam(entry.get('owner'))[2])
55    except (OSError, KeyError):
56        log.error('UID normalization failed for %s' % (entry.get('name')))
57        return False
58
59def normGid(entry):
60    '''
61       This takes a group name or gid and
62       returns the corresponding gid or False
63    '''
64    try:
65        try:
66            return int(entry.get('group'))
67        except:
68            return int(grp.getgrnam(entry.get('group'))[2])
69    except (OSError, KeyError):
70        log.error('GID normalization failed for %s' % (entry.get('name')))
71        return False
72
73text_chars = "".join([chr(y) for y in range(32, 127)] + list("\n\r\t\b"))
74notrans = string.maketrans("", "")
75
76def isString(strng):
77    '''Returns true if a string contains no binary chars'''
78    if "\0" in strng:
79        return False
80
81    if not strng:
82        return True
83
84    return len(strng.translate(notrans, text_chars)) == 0
85
86class POSIX(Bcfg2.Client.Tools.Tool):
87    '''POSIX File support code'''
88    name = 'POSIX'
89    __handles__ = [('ConfigFile', None),
90                   ('Directory', None),
91                   ('Path', 'device'),
92                   ('Path', 'directory'),
93                   ('Path', 'file'),
94                   ('Path', 'hardlink'),
95                   ('Path', 'nonexistent'),
96                   ('Path', 'permissions'),
97                   ('Path', 'symlink'),
98                   ('Permissions', None),
99                   ('SymLink', None)]
100    __req__ = {'ConfigFile': ['name', 'owner', 'group', 'perms'],
101               'Directory': ['name', 'owner', 'group', 'perms'],
102               'Path': ['name', 'type'],
103               'Permissions': ['name', 'owner', 'group', 'perms'],
104               'SymLink': ['name', 'to']}
105
106    # grab paranoid options from /etc/bcfg2.conf
107    opts = {'ppath': Bcfg2.Options.PARANOID_PATH,
108            'max_copies': Bcfg2.Options.PARANOID_MAX_COPIES}
109    setup = Bcfg2.Options.OptionParser(opts)
110    setup.parse([])
111    ppath = setup['ppath']
112    max_copies = setup['max_copies']
113
114    def canInstall(self, entry):
115        '''Check if entry is complete for installation'''
116        if Bcfg2.Client.Tools.Tool.canInstall(self, entry):
117            if (entry.tag, entry.text, entry.get('empty', 'false')) == \
118               ('ConfigFile', None, 'false'):
119                return False
120            return True
121        else:
122            return False
123
124    def VerifySymLink(self, entry, _):
125        '''Verify SymLink Entry'''
126        try:
127            sloc = os.readlink(entry.get('name'))
128            if sloc == entry.get('to'):
129                return True
130            self.logger.debug("Symlink %s points to %s, should be %s" % \
131                              (entry.get('name'), sloc, entry.get('to')))
132            entry.set('current_to', sloc)
133            entry.set('qtext', "Link %s to %s? [y/N] " % (entry.get('name'),
134                                                   entry.get('to')))
135            return False
136        except OSError:
137            entry.set('current_exists', 'false')
138            entry.set('qtext', "Link %s to %s? [y/N] " % (entry.get('name'),
139                                                   entry.get('to')))
140            return False
141
142    def InstallSymLink(self, entry):
143        '''Install SymLink Entry'''
144        self.logger.info("Installing Symlink %s" % (entry.get('name')))
145        if os.path.lexists(entry.get('name')):
146            try:
147                fmode = os.lstat(entry.get('name'))[ST_MODE]
148                if S_ISREG(fmode) or S_ISLNK(fmode):
149                    self.logger.debug("Non-directory entry already exists at "
150                                      "%s. Unlinking entry." % \
151                                      (entry.get('name')))
152                    os.unlink(entry.get('name'))
153                elif S_ISDIR(fmode):
154                    self.logger.debug("Directory entry already exists at %s" %\
155                                      (entry.get('name')))
156                    self.cmd.run("mv %s/ %s.bak" % \
157                                 (entry.get('name'),
158                                  entry.get('name')))
159                else:
160                    os.unlink(entry.get('name'))
161            except OSError:
162                self.logger.info("Symlink %s cleanup failed" % (entry.get('name')))
163        try:
164            os.symlink(entry.get('to'), entry.get('name'))
165            return True
166        except OSError:
167            return False
168
169    def VerifyDirectory(self, entry, modlist):
170        '''Verify Directory Entry'''
171        while len(entry.get('perms', '')) < 4:
172            entry.set('perms', '0' + entry.get('perms', ''))
173        try:
174            ondisk = os.stat(entry.get('name'))
175        except OSError:
176            entry.set('current_exists', 'false')
177            self.logger.debug("%s %s does not exist" %
178                              (entry.tag, entry.get('name')))
179            return False
180        try:
181            owner = str(ondisk[ST_UID])
182            group = str(ondisk[ST_GID])
183        except (OSError, KeyError):
184            self.logger.error('User/Group resolution failed for path %s' % \
185                              entry.get('name'))
186            owner = 'root'
187            group = '0'
188        finfo = os.stat(entry.get('name'))
189        perms = oct(finfo[ST_MODE])[-4:]
190        if entry.get('mtime', '-1') != '-1':
191            mtime = str(finfo[ST_MTIME])
192        else:
193            mtime = '-1'
194        pTrue = ((owner == str(normUid(entry))) and
195                 (group == str(normGid(entry))) and
196                 (perms == entry.get('perms')) and
197                 (mtime == entry.get('mtime', '-1')))
198
199        pruneTrue = True
200        ex_ents = []
201        if entry.get('prune', 'false') == 'true' \
202               and entry.tag == 'Directory':
203            try:
204                entries = ['/'.join([entry.get('name'), ent]) \
205                           for ent in os.listdir(entry.get('name'))]
206                ex_ents = [e for e in entries if e not in modlist]
207                if ex_ents:
208                    pruneTrue = False
209                    self.logger.debug("Directory %s contains extra entries:" % \
210                                      entry.get('name'))
211                    self.logger.debug(ex_ents)
212                    nqtext = entry.get('qtext', '') + '\n'
213                    nqtext += "Directory %s contains extra entries:" % entry.get('name')
214                    nqtext += ":".join(ex_ents)
215                    entry.set('qtest', nqtext)
216            except OSError:
217                ex_ents = []
218                pruneTrue = True
219
220        if not pTrue:
221            if owner != str(normUid(entry)):
222                entry.set('current_owner', owner)
223                self.logger.debug("%s %s ownership wrong" % \
224                                  (entry.tag, entry.get('name')))
225                nqtext = entry.get('qtext', '') + '\n'
226                nqtext += "%s owner wrong. is %s should be %s" % \
227                          (entry.get('name'), owner, entry.get('owner'))
228                entry.set('qtext', nqtext)
229            if group != str(normGid(entry)):
230                entry.set('current_group', group)
231                self.logger.debug("%s %s group wrong" % (entry.tag, entry.get('name')))
232                nqtext = entry.get('qtext', '') + '\n'
233                nqtext += "%s group is %s should be %s" % \
234                          (entry.get('name'), group, entry.get('group'))
235                entry.set('qtext', nqtext)
236            if perms != entry.get('perms'):
237                entry.set('current_perms', perms)
238                self.logger.debug("%s %s permissions are %s should be %s" %
239                               (entry.tag, entry.get('name'), perms, entry.get('perms')))
240                nqtext = entry.get('qtext', '') + '\n'
241                nqtext += "%s perms are %s should be %s" % \
242                          (entry.get('name'), perms, entry.get('perms'))
243                entry.set('qtext', nqtext)
244            if mtime != entry.get('mtime', '-1'):
245                entry.set('current_mtime', mtime)
246                self.logger.debug("%s %s mtime is %s should be %s" \
247                                  % (entry.tag, entry.get('name'), mtime,
248                                     entry.get('mtime')))
249                nqtext = entry.get('qtext', '') + '\n'
250                nqtext += "%s mtime is %s should be %s" % \
251                          (entry.get('name'), mtime, entry.get('mtime'))
252                entry.set('qtext', nqtext)
253            if entry.tag != 'ConfigFile':
254                nnqtext = entry.get('qtext')
255                nnqtext += '\nInstall %s %s: (y/N) ' % (entry.tag, entry.get('name'))
256                entry.set('qtext', nnqtext)
257        return pTrue and pruneTrue
258
259    def InstallDirectory(self, entry):
260        '''Install Directory Entry'''
261        self.logger.info("Installing Directory %s" % (entry.get('name')))
262        try:
263            fmode = os.lstat(entry.get('name'))
264            if not S_ISDIR(fmode[ST_MODE]):
265                self.logger.debug("Found a non-directory entry at %s" % \
266                                  (entry.get('name')))
267                try:
268                    os.unlink(entry.get('name'))
269                    exists = False
270                except OSError:
271                    self.logger.info("Failed to unlink %s" % (entry.get('name')))
272                    return False
273            else:
274                self.logger.debug("Found a pre-existing directory at %s" % \
275                                  (entry.get('name')))
276                exists = True
277        except OSError:
278            # stat failed
279            exists = False
280
281        if not exists:
282            parent = "/".join(entry.get('name').split('/')[:-1])
283            if parent:
284                try:
285                    os.stat(parent)
286                except:
287                    self.logger.debug('Creating parent path for directory %s' % (entry.get('name')))
288                    for idx in range(len(parent.split('/')[:-1])):
289                        current = '/'+'/'.join(parent.split('/')[1:2+idx])
290                        try:
291                            sloc = os.stat(current)
292                        except OSError:
293                            try:
294                                os.mkdir(current)
295                                continue
296                            except OSError:
297                                return False
298                        if not S_ISDIR(sloc[ST_MODE]):
299                            try:
300                                os.unlink(current)
301                                os.mkdir(current)
302                            except OSError:
303                                return False
304
305            try:
306                os.mkdir(entry.get('name'))
307            except OSError:
308                self.logger.error('Failed to create directory %s' % \
309                                  (entry.get('name')))
310                return False
311        if entry.get('prune', 'false') == 'true' and entry.get("qtest"):
312            for pname in entry.get("qtest").split(":"):
313                ulfailed = False
314                if os.path.isdir(pname):
315                    self.logger.info("Not removing extra directory %s, please check and remove manually" % pname)
316                    continue
317                try:
318                    self.logger.debug("Unlinking file %s" % pname)
319                    os.unlink(pname)
320                except OSError:
321                    self.logger.error("Failed to unlink path %s" % pname)
322                    ulfailed = True
323            if ulfailed:
324                return False
325        return self.InstallPermissions(entry)
326
327    def VerifyhardLink(self, entry, _):
328        '''Verify HardLink Entry'''
329        try:
330            if os.path.samefile(entry.get('name'), entry.get('to')):
331                return True
332            self.logger.debug("Hardlink %s is incorrect" % \
333                              entry.get('name'))
334            entry.set('qtext', "Link %s to %s? [y/N] " % \
335                      (entry.get('name'),
336                       entry.get('to')))
337            return False
338        except OSError:
339            entry.set('current_exists', 'false')
340            entry.set('qtext', "Link %s to %s? [y/N] " % \
341                      (entry.get('name'),
342                       entry.get('to')))
343            return False
344
345    def InstallhardLink(self, entry):
346        '''Install HardLink Entry'''
347        self.logger.info("Installing Hardlink %s" % (entry.get('name')))
348        if os.path.lexists(entry.get('name')):
349            try:
350                fmode = os.lstat(entry.get('name'))[ST_MODE]
351                if S_ISREG(fmode) or S_ISLNK(fmode):
352                    self.logger.debug("Non-directory entry already exists at "
353                                      "%s. Unlinking entry." % (entry.get('name')))
354                    os.unlink(entry.get('name'))
355                elif S_ISDIR(fmode):
356                    self.logger.debug("Directory entry already exists at %s" % \
357                                      (entry.get('name')))
358                    self.cmd.run("mv %s/ %s.bak" % \
359                                 (entry.get('name'),
360                                  entry.get('name')))
361                else:
362                    os.unlink(entry.get('name'))
363            except OSError:
364                self.logger.info("Hardlink %s cleanup failed" % (entry.get('name')))
365        try:
366            os.link(entry.get('to'), entry.get('name'))
367            return True
368        except OSError:
369            return False
370
371    def VerifyPermissions(self, entry, _):
372        '''Verify Permissions entry'''
373        return self.VerifyDirectory(entry, _)
374
375    def InstallPermissions(self, entry):
376        '''Install POSIX Permissions'''
377        try:
378            os.chown(entry.get('name'), normUid(entry), normGid(entry))
379            os.chmod(entry.get('name'), calcPerms(S_IFDIR, entry.get('perms')))
380            return True
381        except (OSError, KeyError):
382            self.logger.error('Permission fixup failed for %s' % \
383                              (entry.get('name')))
384            return False
385
386    def Verifydevice(self, entry, _):
387        '''Verify device entry'''
388        try:
389            # check for file existence
390            filestat = os.stat(entry.get('name'))
391        except OSError:
392            entry.set('current_exists', 'false')
393            self.logger.debug("%s %s does not exist" %
394                              (entry.tag, entry.get('name')))
395            return False
396
397        try:
398            # attempt to verify device properties as specified in config
399            dev_type = entry.get('dev_type')
400            mode = calcPerms(device_map[dev_type],
401                             entry.get('mode', '0600'))
402            owner = entry.get('owner')
403            group = entry.get('group')
404            if dev_type in ['block', 'char']:
405                major = int(entry.get('major'))
406                minor = int(entry.get('minor'))
407                if major == os.major(filestat.st_rdev) and \
408                   minor == os.minor(filestat.st_rdev) and \
409                   mode == filestat.st_mode and \
410                   owner == filestat.st_uid and \
411                   group == filestat.st_gid:
412                    return True
413                else:
414                    return False
415            elif dev_type == 'fifo' and \
416                 mode == filestat.st_mode and \
417                 owner == filestat.st_uid and \
418                 group == filestat.st_gid:
419                return True
420            else:
421                self.logger.info('Device properties for %s incorrect' % \
422                                 entry.get('name'))
423                return False
424        except OSError:
425            self.logger.debug("%s %s failed to verify" %
426                              (entry.tag, entry.get('name')))
427            return False
428
429    def Installdevice(self, entry):
430        '''Install device entries'''
431        try:
432            # check for existing paths and remove them
433            filestat = os.lstat(entry.get('name'))
434            try:
435                os.unlink(entry.get('name'))
436                exists = False
437            except OSError:
438                self.logger.info('Failed to unlink %s' % \
439                                 entry.get('name'))
440                return False
441        except OSError:
442            exists = False
443
444        if not exists:
445            try:
446                dev_type = entry.get('dev_type')
447                mode = calcPerms(device_map[dev_type],
448                                 entry.get('mode', '0600'))
449                if dev_type in ['block', 'char']:
450                    major = int(entry.get('major'))
451                    minor = int(entry.get('minor'))
452                    device = os.makedev(major, minor)
453                    os.mknod(entry.get('name'), mode, device)
454                else:
455                    os.mknod(entry.get('name'), mode)
456                os.chown(entry.get('name'), normUid(entry), normGid(entry))
457                return True
458            except OSError:
459                self.logger.error('Failed to install %s' % entry.get('name'))
460                return False
461
462    def Verifynonexistent(self, entry, _):
463        '''Verify nonexistent entry'''
464        # return true if path does _not_ exist
465        return not os.path.lexists(entry.get('name'))
466
467    def Installnonexistent(self, entry):
468        '''Remove nonexistent entries'''
469        try:
470            os.remove(entry.get('name'))
471            return True
472        except OSError:
473            self.logger.error('Failed to remove %s' % entry.get('name'))
474            return False
475
476    def gatherCurrentData(self, entry):
477        if entry.tag == 'ConfigFile':
478            try:
479                ondisk = os.stat(entry.get('name'))
480            except OSError:
481                entry.set('current_exists', 'false')
482                self.logger.debug("%s %s does not exist" %
483                                  (entry.tag, entry.get('name')))
484                return False
485            try:
486                entry.set('current_owner', str(ondisk[ST_UID]))
487                entry.set('current_group', str(ondisk[ST_GID]))
488            except (OSError, KeyError):
489                pass
490            entry.set('perms', str(oct(ondisk[ST_MODE])[-4:]))
491            try:
492                content = open(entry.get('name')).read()
493                entry.set('current_bfile', binascii.b2a_base64(content))
494            except IOError, error:
495                self.logger.error("Failed to read %s: %s" % (error.filename, error.strerror))
496
497    def VerifyConfigFile(self, entry, _):
498        '''Install ConfigFile Entry'''
499        # configfile verify is permissions check + content check
500        permissionStatus = self.VerifyDirectory(entry, _)
501        tbin = False
502        if entry.get('encoding', 'ascii') == 'base64':
503            tempdata = binascii.a2b_base64(entry.text)
504            tbin = True
505        elif entry.get('empty', 'false') == 'true':
506            tempdata = ''
507        else:
508            if entry.text == None:
509                self.logger.error("Cannot verify incomplete ConfigFile %s" % \
510                                  (entry.get('name')))
511                return False
512            tempdata = entry.text
513            if type(tempdata) == unicode:
514                try:
515                    tempdata = tempdata.encode(self.setup['encoding'])
516                except UnicodeEncodeError, e:
517                    self.logger.error("Error encoding file %s:\n %s" % \
518                                      (entry.get('name'), e))
519        try:
520            content = open(entry.get('name')).read()
521        except IOError, error:
522            if error.strerror == "No such file or directory":
523                # print diff for files that don't exist (yet)
524                content = ''
525            else:
526                self.logger.error("Failed to read %s: %s" % \
527                                  (error.filename, error.strerror))
528                return False
529        # comparison should be done with fingerprints or
530        # md5sum so it would be faster for big binary files
531        contentStatus = content == tempdata
532        if not contentStatus:
533            if tbin or not isString(content):
534                entry.set('current_bfile', binascii.b2a_base64(content))
535                nqtext = entry.get('qtext', '')
536                nqtext += '\nBinary file, no printable diff'
537            else:
538                do_diff = True
539                rawdiff = []
540                start = time.time()
541                longtime = False
542                for x in difflib.ndiff(content.split('\n'), tempdata.split('\n')):
543                    now = time.time()
544                    rawdiff.append(x)
545                    if now - start > 5 and not longtime:
546                        self.logger.info("Diff of %s taking a long time" % \
547                                         (entry.get('name')))
548                        longtime = True
549                    elif now - start > 30:
550                        self.logger.error("Diff of %s took too long; giving up" % \
551                                          (entry.get('name')))
552                        do_diff = False
553                        break
554                if do_diff:
555                    diff = '\n'.join(rawdiff)
556                    entry.set("current_bdiff", binascii.b2a_base64(diff))
557#                    entry.set("current_diff", diff)
558                    udiff = '\n'.join([x for x in \
559                                       difflib.unified_diff(content.split('\n'), \
560                                                            tempdata.split('\n'))])
561                    try:
562                        eudiff = udiff.encode('ascii')
563                    except:
564                        eudiff = "Binary file: no diff printed"
565
566                    nqtext = entry.get('qtext', '')
567
568                    if nqtext:
569                        nqtext += '\n'
570                    nqtext += eudiff
571                else:
572                    entry.set('current_bfile', binascii.b2a_base64(content))
573                    nqtext = entry.get('qtext', '')
574                    nqtext += '\nDiff took too long to compute, no printable diff'
575            entry.set('qtext', nqtext)
576        qtxt = entry.get('qtext', '')
577        qtxt += "\nInstall ConfigFile %s: (y/N): " % (entry.get('name'))
578        entry.set('qtext', qtxt)
579        return contentStatus and permissionStatus
580
581    def InstallConfigFile(self, entry):
582        '''Install ConfigFile Entry'''
583        self.logger.info("Installing ConfigFile %s" % (entry.get('name')))
584
585        parent = "/".join(entry.get('name').split('/')[:-1])
586        if parent:
587            try:
588                os.stat(parent)
589            except:
590                self.logger.debug('Creating parent path for config file %s' % \
591                                  (entry.get('name')))
592                current = '/'
593                for next in parent.split('/')[1:]:
594                    current += next + '/'
595                    try:
596                        sloc = os.stat(current)
597                        try:
598                            if not S_ISDIR(sloc[ST_MODE]):
599                                self.logger.debug('%s is not a directory; recreating' \
600                                                  % (current))
601                                os.unlink(current)
602                                os.mkdir(current)
603                        except OSError:
604                            return False
605                    except OSError:
606                        try:
607                            self.logger.debug("Creating non-existent path %s" % current)
608                            os.mkdir(current)
609                        except OSError:
610                            return False
611
612        # If we get here, then the parent directory should exist
613        if (entry.get("paranoid", False) == 'true') and \
614           self.setup.get("paranoid", False) and not \
615           (entry.get('current_exists', 'true') == 'false'):
616            bkupnam = entry.get('name').replace('/', '_')
617            # current list of backups for this ConfigFile
618            bkuplist = [f for f in os.listdir(self.ppath) if
619                              f.startswith(bkupnam)]
620            bkuplist.sort()
621            if len(bkuplist) == int(self.max_copies):
622                # remove the oldest backup available
623                oldest = bkuplist.pop(0)
624                self.logger.info("Removing %s" % oldest)
625                try:
626                    os.remove("%s/%s" % (self.ppath, oldest))
627                except:
628                    self.logger.error("Failed to remove %s/%s" % \
629                                      (self.ppath, oldest))
630                    return False
631            try:
632                # backup existing file
633                shutil.copy(entry.get('name'),
634                            "%s/%s_%s" % (self.ppath, bkupnam, datetime.now()))
635                self.logger.info("Backup of %s saved to %s" %
636                                 (entry.get('name'), self.ppath))
637            except IOError, e:
638                self.logger.error("Failed to create backup file for ConfigFile %s" % \
639                                  (entry.get('name')))
640                self.logger.error(e)
641                return False
642        try:
643            newfile = open("%s.new"%(entry.get('name')), 'w')
644            if entry.get('encoding', 'ascii') == 'base64':
645                filedata = binascii.a2b_base64(entry.text)
646            elif entry.get('empty', 'false') == 'true':
647                filedata = ''
648            else:
649                if type(entry.text) == unicode:
650                    filedata = entry.text.encode(self.setup['encoding'])
651                else:
652                    filedata = entry.text
653            newfile.write(filedata)
654            newfile.close()
655            try:
656                os.chown(newfile.name, normUid(entry), normGid(entry))
657            except KeyError:
658                self.logger.error("Failed to chown %s to %s:%s" % \
659                                  (entry.get('name'), entry.get('owner'),
660                                   entry.get('group')))
661                os.chown(newfile.name, 0, 0)
662            os.chmod(newfile.name, calcPerms(S_IFREG, entry.get('perms')))
663            os.rename(newfile.name, entry.get('name'))
664            if entry.get('mtime', '-1') != '-1':
665                try:
666                    os.utime(entry.get('name'), (int(entry.get('mtime')),
667                                                 int(entry.get('mtime'))))
668                except:
669                    self.logger.error("ConfigFile %s mtime fix failed" \
670                                      % (entry.get('name')))
671                    return False
672            return True
673        except (OSError, IOError), err:
674            if err.errno == 13:
675                self.logger.info("Failed to open %s for writing" % (entry.get('name')))
676            else:
677                print(err)
678            return False
679
680    def Verifydirectory(self, entry, _):
681        ret = getattr(self, 'VerifyDirectory')
682        return ret(entry, _)
683
684    def Installdirectory(self, entry):
685        ret = getattr(self, 'InstallDirectory')
686        return ret(entry)
687
688    def Verifyfile(self, entry, _):
689        ret = getattr(self, 'VerifyConfigFile')
690        return ret(entry, _)
691
692    def Installfile(self, entry):
693        ret = getattr(self, 'InstallConfigFile')
694        return ret(entry)
695
696    def Verifynonexistent(self, entry, _):
697        # FIXME: not implemented
698        return True
699
700    def Installnonexistent(self, entry):
701        # FIXME: not implemented
702        return True
703
704    def Verifypermissions(self, entry, _):
705        ret = getattr(self, 'VerifyPermissions')
706        return ret(entry, _)
707
708    def Installpermissions(self, entry):
709        ret = getattr(self, 'InstallPermissions')
710        return ret(entry)
711
712    def Verifysymlink(self, entry, _):
713        ret = getattr(self, 'VerifySymLink')
714        return ret(entry, _)
715
716    def Installsymlink(self, entry):
717        ret = getattr(self, 'InstallSymLink')
718        return ret(entry)
719
720    def InstallPath(self, entry):
721        ret = getattr(self, 'Install%s' % entry.get('type'))
722        return ret(entry)
723
724    def VerifyPath(self, entry, _):
725        ret = getattr(self, 'Verify%s' % entry.get('type'))
726        return ret(entry, _)
Note: See TracBrowser for help on using the browser.