Exemple #1
0
    def write(self):
        '''
        Write the contents file.
        '''

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        self.check_installdir()

        values = [' '.join(i) for i in list(self.__content.values())]

        if not self.__p:
            try:
                fd = os.open(self.appdb(), os.O_WRONLY | os.O_CREAT,
                             self.__perm(0o600))

                os.write(fd, ('\n'.join(values)).encode('utf-8'))

                os.close(fd)
            except Exception as e:
                OUT.warn('Failed to write content file ' + dbpath + '!\n' 
                         + 'Error was: ' + str(e))
        else:
            OUT.info('Would have written content file ' + dbpath + '!')
Exemple #2
0
    def listunused(self, db):
        '''
        Outputs a list of what has not been installed so far
        '''

        packages = self.list_locations()

        if not packages:
            OUT.die('No packages found!')

        keys = sorted(packages)

        OUT.debug('Check for unused web applications', 7)

        for i in keys:

            db.set_category(packages[i][0])
            db.set_package (packages[i][1])
            db.set_version (packages[i][2])

            if not db.has_installs():
                if packages[i][0]:
                    OUT.notice(packages[i][0] + '/' + packages[i][1] + '-' + packages[i][2])
                else:
                    OUT.notice(packages[i][1] + '-' + packages[i][2])
Exemple #3
0
    def listinstalls(self):
        '''
        Outputs a list of what has been installed so far.
        '''

        loc = self.read_db()

        if not loc and self.__v:
            OUT.die('No virtual installs found!')

        keys = sorted(loc)

        for j in keys:
            # The verbose output is meant to be readable for the user
            if self.__v:
                OUT.info('Installs for ' + '-'.join(j.split('/')), 4)

            for i in loc[j]:
                if self.__v:
                    # The verbose output is meant to be readable for
                    # the user
                    OUT.info('  ' + i[3].strip(), 1)
                else:
                    # This is a simplified form for the webapp.eclass
                    print(i[3].strip())
Exemple #4
0
    def write(self):
        '''
        Write the contents file.
        '''

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        self.check_installdir()

        values = [' '.join(i) for i in list(self.__content.values())]

        if not self.__p:
            try:
                fd = os.open(self.appdb(), os.O_WRONLY | os.O_CREAT,
                             self.__perm(0o600))

                os.write(fd, ('\n'.join(values)).encode('utf-8'))

                os.close(fd)
            except Exception as e:
                OUT.warn('Failed to write content file ' + dbpath + '!\n' +
                         'Error was: ' + str(e))
        else:
            OUT.info('Would have written content file ' + dbpath + '!')
Exemple #5
0
    def listunused(self, db):
        '''
        Outputs a list of what has not been installed so far
        '''

        packages = self.list_locations()

        if not packages:
            OUT.die('No packages found!')

        keys = sorted(packages)

        OUT.debug('Check for unused web applications', 7)

        for i in keys:

            db.set_category(packages[i][0])
            db.set_package(packages[i][1])
            db.set_version(packages[i][2])

            if not db.has_installs():
                if packages[i][0]:
                    OUT.notice(packages[i][0] + '/' + packages[i][1] + '-' +
                               packages[i][2])
                else:
                    OUT.notice(packages[i][1] + '-' + packages[i][2])
Exemple #6
0
    def listinstalls(self):
        '''
        Outputs a list of what has been installed so far.
        '''

        loc = self.read_db()

        if not loc and self.__v:
            OUT.die('No virtual installs found!')

        keys = sorted(loc)

        for j in keys:
            # The verbose output is meant to be readable for the user
            if self.__v:
                OUT.info('Installs for ' + '-'.join(j.split('/')), 4)

            for i in loc[j]:
                if self.__v:
                    # The verbose output is meant to be readable for
                    # the user
                    OUT.info('  ' + i[3].strip(), 1)
                else:
                    # This is a simplified form for the webapp.eclass
                    print(i[3].strip())
Exemple #7
0
def get_root(config):
    '''Returns the $ROOT variable'''
    if config.config.get('USER', 'package_manager') == "portage":
        try:
            import portage
        except ImportError as e:
            OUT.die("Portage libraries not found, quitting:\n%s" % e)

        return portage.settings['ROOT']

    elif config.config.get('USER', 'package_manager') == "paludis":
        cat = config.maybe_get('cat')
        pn  = config.maybe_get('pn')

        if cat and pn:
            cmd="cave print-id-environment-variable -b --format '%%v\n' --variable-name ROOT %s/%s" % (cat,pn)

            fi, fo, fe = os.popen3(cmd)
            fi.close()
            result_lines = fo.readlines()
            fo.close()
            fe.close()

            if result_lines[0].strip():
                return result_lines[0].strip()
            else:
                return '/'
        else:
            return '/'
    else:
        OUT.die("Unknown package manager: " + pm)
Exemple #8
0
    def dirisconfigprotected(self, installdir):
        '''
        Traverses the path of parent directories for the
        given install dir and checks if any matches the list
        of config protected files.

        >>> a = Protection('','horde','3.0.5','portage')

        Add a virtual config protected directory:

        >>> a.config_protect += ' /my/strange/htdocs/'
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x')
        True
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x/')
        True
        >>> a.config_protect += ' /my/strange/htdocs'
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x')
        True
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x/')
        True

        >>> a.config_protect += ' bad_user /my/strange/htdocs'
        >>> a.dirisconfigprotected('/my/bad_user/htdocs/where/i/installed/x')
        False
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x/')
        True

        >>> a.dirisconfigprotected('/')
        False
        '''

        my_master = []
        for i in self.config_protect.split(' '):
            if i[0] == '/':
                if i[-1] == '/':
                    my_master.append(i[:-1])
                else:
                    my_master.append(i)

        if installdir[0] != '/':
            OUT.die('BUG! Don\'t call this with a relative path.')

        if installdir[-1] == '/':
            my_dir = installdir[:-1]
        else:
            my_dir = installdir

        while my_dir:

            if my_dir == '.' or my_dir == '/':
                return False

            for x in my_master:
                if my_dir == x:
                    return True

            my_dir = os.path.dirname(my_dir)

        # nope, the directory isn't config-protected at this time
        return False
Exemple #9
0
    def __init__(self, directories, permissions, handler, flags, pm):

        if self.dep and not self.supported(pm):
            print(self.dep)
            OUT.die('Your configuration file sets the server type "' +
                    self.name +
                    '"\nbut the corresponding package does not seem to be '
                    'installed!\nPlease "emerge ' + self.dep + '" or correct '
                    'your settings.')

        try:
            self.set_server_user()
        except KeyError:
            OUT.die('The user for the server type "' + self.name +
                    '" does not exist!')

        self.__sourced = directories['source']
        self.__destd = directories['destination']
        self.__hostroot = directories['hostroot']
        self.__vhostroot = directories['vhostroot']

        # + server owned
        if permissions['file']['server-owned'][0] == 0:
            permissions['file']['server-owned'][0] = self.vhost_server_uid
            permissions['dir']['server-owned'][0] = self.vhost_server_uid
        if permissions['file']['server-owned'][1] == 0:
            permissions['file']['server-owned'][1] = self.vhost_server_gid
            permissions['dir']['server-owned'][1] = self.vhost_server_gid
            # and config owned directories have server gid
            permissions['dir']['config-owned'][1] = self.vhost_server_gid
            # allows server and config owned
            permissions['file']['config-server-owned'][
                1] = self.vhost_server_gid
            permissions['dir']['config-server-owned'][
                1] = self.vhost_server_gid

        self.__perm = permissions
        self.__handler = handler
        self.__flags = flags

        self.__ws = handler['source']
        self.__content = handler['content']
        self.__protect = handler['protect']
        self.__dotconfig = handler['dotconfig']
        self.__ebuild = handler['ebuild']
        self.__db = handler['db']

        self.__v = flags['verbose']
        self.__p = flags['pretend']

        wd = WebappRemove(self.__content, self.__v, self.__p)

        handler['removal'] = wd

        self.__del = wd

        # Set by the install function
        self.__add = None
Exemple #10
0
def want_category(config):
    '''Check if the package manager requires category info

    Portage: optional
    Paludis: mandatory
    '''

    if config.config.get('USER', 'package_manager') == "portage":
        return
    elif config.config.get('USER', 'package_manager') == "paludis":
        if not config.config.has_option('USER', 'cat'):
            OUT.die("Package name must be in the form CAT/PN")
    else:
        OUT.die("Unknown package manager: " + pm)
Exemple #11
0
 def create_module(self, package_version, vhost_root, server_files, server_dirs):
     temp_dir = tempfile.mkdtemp()
     OUT.info('Creating SELinux modules')
     cleaned_version = re.match(r'(?P<version>[0-9]*\.[0-9]*(?:\.[0-9]*)?)', package_version).group('version')
     for policy in self.policy_types:
         base_dir = os.path.join(temp_dir, policy)
         os.mkdir(base_dir)
         with open(os.path.join(base_dir, '{}.te'.format(self.policy_name)), 'w') as te_file:
             te_file.write('policy_module({},{})\n'.format(self.policy_name, cleaned_version))
             te_file.write('require {\n')
             te_file.write('  type httpd_sys_rw_content_t;\n')
             te_file.write('}')
         with open(os.path.join(base_dir, '{}.fc'.format(self.policy_name)), 'w') as fc_file:
             for files in server_files:
                 fc_file.write('{} gen_context(system_u:object_r:httpd_sys_rw_content_t,s0)\n'.format(SELinux.filename_re_escape(os.path.join(vhost_root, files.rstrip('\n')))))
             for dirs in server_dirs:
                 fc_file.write('{}(/.*)? gen_context(system_u:object_r:httpd_sys_rw_content_t,s0)\n'.format(SELinux.filename_re_escape(os.path.join(vhost_root, dirs.rstrip('\n')))))
         if subprocess.call(['make', '-s', '-C', base_dir, '-f', os.path.join('/usr/share/selinux', policy, 'include/Makefile'), '{}.pp'.format(self.policy_name)]):
             if not os.path.isfile(os.path.join('/usr/share/selinux', policy, 'include/Makefile')):
                 OUT.die('Policy {} is not supported, please fix your configuration'.format(policy))
             OUT.die('Unable to create {} SELinux module for {} @ {}'.format(policy, self.package_name, self.vhost_hostname))
     OUT.info('Installing SELinux modules')
     try:
         for policy in self.policy_types:
             if subprocess.call(['semodule', '-s', policy, '-i', os.path.join(temp_dir, policy, '{}.pp'.format(self.policy_name))]):
                 OUT.die('Unable to install {} SELinux module for {} @ {}'.format(policy, self.package_name, self.vhost_hostname))
     except IOError:
         OUT.die('"semodule" was not found, please check you SELinux installation')
     shutil.rmtree(temp_dir)
Exemple #12
0
    def __init__(self,
                 config_owned,
                 server_owned,
                 server_owned_r,
                 virtual_files = 'virtual',
                 default_dirs  = 'default-owned'):
        '''
        Populates the cache with the file types as provided by the
        ebuild.
        '''

        self.__cache = {}

        # Validity of entries are checked by the command line parser
        self.__virtual_files = virtual_files
        self.__default_dirs  = default_dirs

        # populate cache
        for i in config_owned:

            OUT.debug('Adding config-owned file', 8)

            self.__cache[self.__fix(i)] = 'config-owned'

        for i in server_owned:

            if self.__fix(i) in self.__cache.keys():

                OUT.debug('Adding config-server-owned file', 8)

                self.__cache[self.__fix(i)] = 'config-server-owned'

            else:

                OUT.debug('Adding server-owned file', 8)

                self.__cache[self.__fix(i)] = 'server-owned'

        for i in server_owned_r:

            if self.__fix(i) in self.__cache.keys():

                OUT.die('{} is a the same time recursively server-owned and {}: This case is not supported.'.format(self.__fix(i), self.__cache[self.__fix(i)]))

            else :

                OUT.debug('Adding recursively server-owned file', 8)

                self.__cache[self.__fix(i).strip()] = 'server-owned-dir'
Exemple #13
0
    def write(self,
              category,
              package,
              version,
              host,
              original_installdir,
              user_group):
        '''
        Output the .webapp file, that tells us in future what has been installed
        into this directory.
        '''
        self.__data['WEB_CATEGORY']      = category
        self.__data['WEB_PN']            = package
        self.__data['WEB_PVR']           = version
        self.__data['WEB_INSTALLEDBY']   = pwd.getpwuid(os.getuid())[0]
        self.__data['WEB_INSTALLEDDATE'] = strftime('%Y-%m-%d %H:%M:%S')
        self.__data['WEB_INSTALLEDFOR']  = user_group
        self.__data['WEB_HOSTNAME']      = host
        self.__data['WEB_INSTALLDIR']    = original_installdir


        info = ['# ' + self.__file,
                '#	config file for this copy of '
                + package + '-' + version,
                '#',
                '#	automatically created by Gentoo\'s webapp-config',
                '#	do NOT edit this file by hand',
                '',]
        for i in self.__tokens:
            info.append(i + '="' + self.__data[i] + '"')

        if not self.__p:
            try:

                fd = os.open(self.__dot_config(),
                             os.O_WRONLY | os.O_CREAT,
                             self.__perm(0o600))

                os.write(fd, ('\n'.join(info)).encode('utf-8'))
                os.close(fd)

            except Exception as e:

                OUT.die('Unable to write to ' + self.__dot_config()
                        + '\nError was: ' + str(e))
        else:
            OUT.info('Would have written the following information into '
                     + self.__dot_config() + ':\n' + '\n'.join(info))
Exemple #14
0
    def show_installed(self):
        ''' Show which application has been installed in the install 
        location.'''
        if not self.has_dotconfig():
            OUT.die('No ' + self.__file + ' file in ' + self.__instdir
                    + '; unable to continue')

        self.read()

        if 'WEB_CATEGORY' in self.__data:
            OUT.notice(self.__data['WEB_CATEGORY'] + ' ' +
                   self.__data['WEB_PN'] + ' ' +
                   self.__data['WEB_PVR'])
        else:
            OUT.notice(
                   self.__data['WEB_PN'] + ' ' +
                   self.__data['WEB_PVR'])
Exemple #15
0
    def dirtype(self, directory, parent_type = ''):
        '''
        Inputs:

          directory     - the directory that we need a decision about

          parent_type  - the type of the parent directory

        returns one of these:

          server-owned         - dir needs to be owned by the webserver user
          config-owned         - dir needs to be owned by the config user
          config-server-owned  - Both the previous cases at the same time
          server-owned-dir     - Directory that contains file/dirs to be owned
                                 by the webserver user
          default-owned        - we need a local copy, owned by root

        NOTE:
          Use get_filetype(filename) for files

        NOTE:
          the user can use --default-dirs on the command-line to change
          what type default directories are really reported as
        '''

        # remove any whitespace and trailing /
        directory = self.__fix(directory)

        # check the cache
        if directory in self.__cache.keys():
            # Check if parent type is recursive
            if parent_type == 'server-owned-dir':
                new_type = self.__cache[directory]
                if new_type == 'config-owned':
                    OUT.die('This version does not support config dirs')
                if new_type == server-owned:
                    OUT.warn('Configuration error: {} is marked server-owned two times'.format(filename))
                return 'server-owned-dir'
            return self.__cache[directory]

        # Check if parent type is recursive
        if parent_type == 'server-owned-dir':
            return 'server-owned-dir'
        # unspecified directories are default-owned
        return self.__default_dirs
Exemple #16
0
def package_installed(full_name, pm):
    '''
    This function identifies installed packages.
    The Portage part is stolen from gentoolkit.
    We are not using gentoolkit directly as it doesn't seem to support ${ROOT}
    '''

    if pm == "portage":
        try:
            import portage
        except ImportError as e:
            OUT.die("Portage libraries not found, quitting:\n%s" % e)

        try:
             t = portage.db[portage.root]["vartree"].dbapi.match(full_name)
        # catch the "ambiguous package" Exception
        except ValueError as e:
            if isinstance(e[0], list):
                t = []
                for cp in e[0]:
                    t += portage.db[portage.root]["vartree"].dbapi.match(cp)
            else:
                raise ValueError(e)
        return t

    elif pm == "paludis":

        cmd="cave print-best-version '%s'" % (full_name)

        fi, fo, fe = os.popen3(cmd)
        fi.close()
        result_lines = fo.readlines()
        error_lines  = fe.readlines()
        fo.close()
        fe.close()

        if error_lines:
            for i in error_lines:
                OUT.warn(i)

        return ' '.join(result_lines)

    else:
        OUT.die("Unknown package manager: " + pm)
Exemple #17
0
    def prune_database(self, action):
        '''
        Prunes the installs files to ensure no webapp
        is incorrectly listed as installed.
        '''

        loc = self.read_db()

        if not loc and self.__v:
            OUT.die('No virtual installs found!')

        files = self.list_locations()
        keys = sorted(loc)

        if action != 'clean':
            OUT.warn(
                'This is a list of all outdated entries that would be removed: '
            )
        for j in keys:
            for i in loc[j]:
                appdir = i[3].strip()
                # We check to see if the webapp is installed.
                if not os.path.exists(appdir + '/.webapp-' + j):
                    if self.__v:
                        OUT.warn('No .webapp file found in dir: ')
                        OUT.warn(appdir)
                        OUT.warn('Assuming webapp is no longer installed.')
                        OUT.warn('Pruning entry from database.')
                    if action == 'clean':
                        for installs in list(files.keys()):
                            contents = open(installs).readlines()
                            new_entries = ''
                            for entry in contents:
                                # Grab all the other entries but the one that
                                # isn't installed.
                                if not re.search('.* ' + appdir + '\\n',
                                                 entry):
                                    new_entries += entry
                            f = open(installs, 'w')
                            f.write(new_entries)
                            f.close()
                    else:
                        OUT.warn(appdir)
Exemple #18
0
 def __init__(self, package_name, vhost_hostname, policy_types = ()):
     self.package_name = package_name
     self.vhost_hostname = vhost_hostname
     self.policy_name = '{}_{}'.format(package_name, vhost_hostname)
     self.policy_types = policy_types
     if self.policy_types is ():
         for filename in MAKE_CONF_FILE:
             try:
                 with open(filename) as file:
                     for line in file.readlines():
                         if line.startswith('POLICY_TYPES='):
                             self.policy_types = line[len('POLICY_TYPES='):-1].strip(' "').split()
                             break
                     if self.policy_types is not None:
                         break
             except IOError:
                 pass
         if self.policy_types is ():
              OUT.die('No SELinux policy was found, abording')
Exemple #19
0
    def reportpackageavail(self):
        '''
        This is a simple wrapper around packageavail() that outputs
        user-friendly error messages if an error occurs

        Cannot test the rest, do not want to die.
        '''

        OUT.info('Do we have ' + self.package_name() + ' available?')

        available = self.packageavail()

        if available == 0:
            OUT.info('  Yes, we do')
        if available == 1:
            OUT.die('  Please emerge ' + self.package_name() + ' first.')
        if available == 3:
            OUT.die('  ' + self.package_name() + ' is not compatible with '
                    'webapp-config.\nIf it should be, report this at ' +
                    wrapper.bugs_link)
Exemple #20
0
    def reportpackageavail(self):
        '''
        This is a simple wrapper around packageavail() that outputs
        user-friendly error messages if an error occurs

        Cannot test the rest, do not want to die.
        '''

        OUT.info('Do we have ' + self.package_name() + ' available?')

        available = self.packageavail()

        if available == 0:
            OUT.info('  Yes, we do')
        if available == 1:
            OUT.die('  Please emerge ' + self.package_name() + ' first.')
        if available == 3:
            OUT.die('  ' + self.package_name() + ' is not compatible with '
                    'webapp-config.\nIf it should be, report this at '
                    + wrapper.bugs_link)
Exemple #21
0
    def __init__(self,
                 fs_root,
                 root,
                 category   = '',
                 package    = '',
                 version    = '',
                 dbfile     = 'installs'):

        self.__r        = fs_root
        self.root       = self.__r + root
        self.root       = re.compile('/+').sub('/', self.root)

        if not os.path.isdir(self.root):
            OUT.die('"' + self.root + '" specifies no directory! webapp'
                    '-config needs a valid directory to store/retrieve in'
                    'formation. Please correct your settings.')

        self.category   = category
        self.pn         = package
        self.pvr        = version
        self.dbfile     = dbfile
Exemple #22
0
    def __init__(self,
                 fs_root,
                 root,
                 category='',
                 package='',
                 version='',
                 dbfile='installs'):

        self.__r = fs_root
        self.root = self.__r + root
        self.root = re.compile('/+').sub('/', self.root)

        if not os.path.isdir(self.root):
            OUT.die('"' + self.root + '" specifies no directory! webapp'
                    '-config needs a valid directory to store/retrieve in'
                    'formation. Please correct your settings.')

        self.category = category
        self.pn = package
        self.pvr = version
        self.dbfile = dbfile
Exemple #23
0
    def prune_database(self, action):
        '''
        Prunes the installs files to ensure no webapp
        is incorrectly listed as installed.
        '''

        loc = self.read_db()
        
        if not loc and self.__v:
            OUT.die('No virtual installs found!')

        files = self.list_locations()
        keys = sorted(loc)

        if action != 'clean':
            OUT.warn('This is a list of all outdated entries that would be removed: ')
        for j in keys:
            for i in loc[j]:
                appdir = i[3].strip()
                # We check to see if the webapp is installed.
                if not os.path.exists(appdir+'/.webapp-'+j):
                    if self.__v:
                       OUT.warn('No .webapp file found in dir: ')
                       OUT.warn(appdir)
                       OUT.warn('Assuming webapp is no longer installed.')
                       OUT.warn('Pruning entry from database.')
                    if action == 'clean':
                        for installs in files.keys():
                            contents = open(installs).readlines()
                            new_entries = ''
                            for entry in contents:
                                # Grab all the other entries but the one that
                                # isn't installed.
                                if not re.search('.* ' + appdir +'\\n', entry):
                                    new_entries += entry
                            f = open(installs, 'w')
                            f.write(new_entries)
                            f.close()
                    else:
                        OUT.warn(appdir)
Exemple #24
0
def config_protect(cat, pn, pvr, pm):
    '''Return CONFIG_PROTECT (used by protect.py)'''
    if pm == "portage":
        try:
            import portage
        except ImportError as e:
            OUT.die("Portage libraries not found, quitting:\n%s" % e)

        return portage.settings['CONFIG_PROTECT']

    elif pm == "paludis":
        cmd="cave print-id-environment-variable -b --format '%%v\n' --variable-name CONFIG_PROTECT %s/%s" % (cat,pn)

        fi, fo, fe = os.popen3(cmd)
        fi.close()
        result_lines = fo.readlines()
        fo.close()
        fe.close()

        return ' '.join(result_lines).strip()
    else:
        OUT.die("Unknown package manager: " + pm)
Exemple #25
0
    def write(self):
        '''
        Write the contents file.

        A short test:

        >>> import os.path
        >>> here = os.path.dirname(os.path.realpath(__file__))
        >>> a = Contents(here + '/tests/testfiles/contents/',
        ...              package = 'test', version = '1.0',
        ...              pretend = True)
        >>> a.read()
        >>> OUT.color_off()
        >>> a.write() #doctest: +ELLIPSIS
        * Would have written content file .../tests/testfiles/contents//.webapp-test-1.0!
        '''

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        self.check_installdir()

        values = [' '.join(i) for i in self.__content.values()]

        if not self.__p:
            try:
                fd = os.open(self.appdb(), os.O_WRONLY | os.O_CREAT,
                             self.__perm(0o600))

                os.write(fd, ('\n'.join(values)).encode('utf-8'))

                os.close(fd)
            except Exception as e:
                OUT.warn('Failed to write content file ' + dbpath + '!\n' 
                         + 'Error was: ' + str(e))
        else:
            OUT.info('Would have written content file ' + dbpath + '!')
Exemple #26
0
    def dirisconfigprotected(self, installdir):
        '''
        Traverses the path of parent directories for the
        given install dir and checks if any matches the list
        of config protected files.
        '''

        my_master = []
        for i in self.config_protect.split(' '):
            if i[0] == '/':
                if i[-1] == '/':
                    my_master.append(i[:-1])
                else:
                    my_master.append(i)

        if installdir[0] != '/':
            OUT.die('BUG! Don\'t call this with a relative path.')

        if installdir[-1] == '/':
            my_dir = installdir[:-1]
        else:
            my_dir = installdir

        while my_dir:

            if my_dir == '.' or my_dir == '/':
                return False

            for x in my_master:
                if my_dir == x:
                    return True

            my_dir = os.path.dirname(my_dir)

        # nope, the directory isn't config-protected at this time
        return False
Exemple #27
0
    def dirisconfigprotected(self, installdir):
        '''
        Traverses the path of parent directories for the
        given install dir and checks if any matches the list
        of config protected files.
        '''

        my_master = []
        for i in self.config_protect.split(' '):
            if i[0] == '/':
                if i[-1] == '/':
                    my_master.append(i[:-1])
                else:
                    my_master.append(i)

        if installdir[0] != '/':
            OUT.die('BUG! Don\'t call this with a relative path.')

        if installdir[-1] == '/':
            my_dir = installdir[:-1]
        else:
            my_dir = installdir

        while my_dir:

            if my_dir == '.' or my_dir == '/':
                return False

            for x in my_master:
                if my_dir == x:
                    return True

            my_dir = os.path.dirname(my_dir)

        # nope, the directory isn't config-protected at this time
        return False
Exemple #28
0
    def add(self, installdir, user, group):
        '''
        Add a record to the list of virtual installs.

        installdir - the installation directory
        '''

        if not installdir:
            OUT.die('The installation directory must be specified!')

        if not str(user):
            OUT.die('Please specify a valid user!')

        if not str(group):
            OUT.die('Please specify a valid group!')

        OUT.debug('Adding install record', 6)

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        if not self.__p and not os.path.isdir(os.path.dirname(dbpath)):
            os.makedirs(os.path.dirname(dbpath), self.__dir_perm(0o755))

        fd = None

        if not self.__p:
            fd = os.open(dbpath,
                         os.O_WRONLY | os.O_APPEND | os.O_CREAT,
                         self.__file_perm(0o600))

        entry = str(int(time.time())) + ' ' + str(user) + ' ' + str(group)\
            + ' ' + installdir + '\n'

        OUT.debug('New record', 7)

        if not self.__p:
            os.write(fd, (entry).encode('utf-8'))
            os.close(fd)
        else:
            OUT.info('Pretended to append installation ' + installdir)
            OUT.info('Entry:\n' + entry)
Exemple #29
0
    def add(self, installdir, user, group):
        '''
        Add a record to the list of virtual installs.

        installdir - the installation directory
        '''

        if not installdir:
            OUT.die('The installation directory must be specified!')

        if not str(user):
            OUT.die('Please specify a valid user!')

        if not str(group):
            OUT.die('Please specify a valid group!')

        OUT.debug('Adding install record', 6)

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        if not self.__p and not os.path.isdir(os.path.dirname(dbpath)):
            os.makedirs(os.path.dirname(dbpath), self.__dir_perm(0o755))

        fd = None

        if not self.__p:
            fd = os.open(dbpath, os.O_WRONLY | os.O_APPEND | os.O_CREAT,
                         self.__file_perm(0o600))

        entry = str(int(time.time())) + ' ' + str(user) + ' ' + str(group)\
            + ' ' + installdir + '\n'

        OUT.debug('New record', 7)

        if not self.__p:
            os.write(fd, (entry).encode('utf-8'))
            os.close(fd)
        else:
            OUT.info('Pretended to append installation ' + installdir)
            OUT.info('Entry:\n' + entry)
Exemple #30
0
 def check_installdir(self):
     if not os.path.isdir(self.__installdir) and not self.__p:
         OUT.die('"' + self.__installdir + '" specifies no directory! '
                 'webapp-config needs a valid directory to store/retri'
                 'eve information. Please correct your settings.')
Exemple #31
0
    def add(self,
            dsttype,
            ctype,
            destination,
            path,
            real_path,
            relative = True):
        '''
        Add an entry to the contents file.

        Just like Portage, when we install an app, we create a contents
        file to say what we installed and when.  We use this contents
        file to help us safely remove & upgrade apps.

        CONTENTS file format:

        <what> <rel> <type> <filename> <timestamp> <sum> [<optional>]

        where

        <what>      is one of dir|sym|file|hardlink

        <rel>       is 1 for relative filenames, 0 for absolute
                        filenames

        <type>      is one of
                        server-owned|default-owned|config-owned|virtual

        <timestamp> is the timestamp when the file was installed

        <sum>       is the md5sum of the file
                        (this is 0 for directories and symlinks)

        <filename>      is the actual name of the file we have installed

        <optional>      is additional data that depends upon <what>

        NOTE:
            Filenames used to be on the end of the line.  This made
                the old bash version more complicated, and
                prone to failure. So I have moved the filename into the
                middle of the line. -- Stuart

        Portage uses absolute names for its files, dirs, and symlinks.
        We do not.
        In theory, you can move a directory containing a web-based app,
        and

        a) the app itself will not break, and
        b) webapp-config will still work on that directory
           for upgrades and cleans.

        Position-independence *is* a design constraint that all future
        changes to this script need to honour.

        Inputs:

          dsttype     - type to add (one of dir|sym|file|hardlink)
          ctype       - internal webapp-config type
                      - (server-owned | config-owned | virtual)
          destination - install dir (normally $G_INSTALLDIR)
          path        - filename inside 'destination'
          real_path   - for config-protected files realpath =! path
                        (and this is important for md5)
          relative    - 1 for storing a relative filename, 0 otherwise
        '''

        OUT.debug('Adding entry to content dictionary', 6)

        # Build the full path that we use as index in the contents list
        while path[0] == '/':
            path = path[1:]
        while destination[-1] == '/':
            destination = destination[:-1]

        entry = destination + '/' + path

        # special case - we don't add entries for '.'

        if os.path.basename(entry) == '.':
            return

        if (not self.__p
                and not os.path.islink(entry)
                and (not os.path.exists(entry)
                    or not os.access(entry, os.R_OK))):
            OUT.warn('Cannot access file ' + entry + ' to add it as'
                     ' installation content. This should not happen!')
            return

        allowed_types = {
            'file'    : [ 'file', self.file_md5,  self.file_null ],
            'hardlink': [ 'file', self.file_md5,  self.file_null ],
            'dir'     : [  'dir', self.file_zero, self.file_null ],
            'sym'     : [  'sym', self.file_zero, self.file_link ],
            }

        if not dsttype in list(allowed_types.keys()):
            OUT.die('Oops, webapp-config bug. "dsttype" is ' + dsttype)

        # Generate handler for file attributes
        a = allowed_types[dsttype]

        # For absolute entries the path must match the entry
        if not relative:
            path = entry

        OUT.debug('Adding entry', 7)

        # report if pretending
        if self.__p:

            OUT.info('    pretending to add: ' +
                     ' '.join([dsttype,
                               str(int(relative)),
                               ctype,
                               '"' + path + '"']))
        else:

            # Only the path is enclosed in quotes, NOT the link targets
            self.__content[entry] = [ a[0],
                                      str(int(relative)),
                                      ctype,
                                      '"' + path + '"',
                                      self.file_time(entry),
                                      a[1](real_path),
                                      a[2](entry)]

            if self.__v:
                msg = path
                if msg[0] == "/":
                    msg = self.__root + msg
                    msg = self.__re.sub('/', msg)
                OUT.notice('>>> ' + a[0] + ' ' * (4 - len(a[0])) + ' ('  \
                           + ctype + ') ' + msg)
Exemple #32
0
    def add(self,
            dsttype,
            ctype,
            destination,
            path,
            real_path,
            relative = True):
        '''
        Add an entry to the contents file.

        Just like Portage, when we install an app, we create a contents
        file to say what we installed and when.  We use this contents
        file to help us safely remove & upgrade apps.

        CONTENTS file format:

        <what> <rel> <type> <filename> <timestamp> <sum> [<optional>]

        where

        <what>      is one of dir|sym|file|hardlink

        <rel>       is 1 for relative filenames, 0 for absolute
                        filenames

        <type>      is one of
                        server-owned|default-owned|config-owned|virtual

        <timestamp> is the timestamp when the file was installed

        <sum>       is the md5sum of the file
                        (this is 0 for directories and symlinks)

        <filename>      is the actual name of the file we have installed

        <optional>      is additional data that depends upon <what>

        NOTE:
            Filenames used to be on the end of the line.  This made
                the old bash version more complicated, and
                prone to failure. So I have moved the filename into the
                middle of the line. -- Stuart

        Portage uses absolute names for its files, dirs, and symlinks.
        We do not.
        In theory, you can move a directory containing a web-based app,
        and

        a) the app itself will not break, and
        b) webapp-config will still work on that directory
           for upgrades and cleans.

        Position-independence *is* a design constraint that all future
        changes to this script need to honour.

        Inputs:

          dsttype     - type to add (one of dir|sym|file|hardlink)
          ctype       - internal webapp-config type
                      - (server-owned | config-owned | virtual)
          destination - install dir (normally $G_INSTALLDIR)
          path        - filename inside 'destination'
          real_path   - for config-protected files realpath =! path
                        (and this is important for md5)
          relative    - 1 for storing a relative filename, 0 otherwise

        OUT.color_off()
        import os.path
        here = os.path.dirname(os.path.realpath(__file__))

        One for pretending:

        a = Contents(here + '/tests/testfiles/contents/app/',
        ...              package = 'test', version = '1.0',
        ...              pretend = True)

        And this one is for real:

        b = Contents(here + '/tests/testfiles/contents/app/',
        ...              package = 'test', version = '1.0')

        Pretend to add a file:

        a.add('file', 'config-owned',
        ...       destination = here + '/tests/testfiles/contents/app/',
        ...       path = '/test1', relative = True)
        *     pretending to add: file 1 config-owned "test1"

        Lets not pretend this time:

        b.add('file', 'config-owned',
        ...       destination = here + '/tests/testfiles/contents/app/',
        ...       path = '/test1', relative = True)
        b.entry(here + '/tests/testfiles/contents/app/test1') #doctest: +ELLIPSIS
        'file 1 config-owned "test1" ... d8e8fca2dc0f896fd7cb4cb0031ba249 '

        Lets produce an error with a file that does not exist:

        b.add('file', 'config-owned',
        ...       destination = here + '/tests/testfiles/contents/app/',
        ...       path = '/nothere', relative = True) #doctest: +ELLIPSIS
        * Cannot access file .../tests/testfiles/contents/app/nothere to add it as installation content. This should not happen!

        Other file types:

        b.add('hardlink', 'config-owned',
        ...       destination = here + '/tests/testfiles/contents/app/',
        ...       path = '/test2', relative = True)
        b.entry(here + '/tests/testfiles/contents/app/test2') #doctest: +ELLIPSIS
        'file 1 config-owned "test2" ... d8e8fca2dc0f896fd7cb4cb0031ba249 '
        b.add('dir', 'default-owned',
        ...       destination = here + '/tests/testfiles/contents/app/',
        ...       path = '/dir1', relative = True)
        b.entry(here + '/tests/testfiles/contents/app/dir1') #doctest: +ELLIPSIS
        'dir 1 default-owned "dir1" ... 0 '
        b.add('dir', 'default-owned', destination = here + '/tests/testfiles/contents/app',
        ...       path = '/dir1',
        ...       relative = False)
        b.entry(here + '/tests/testfiles/contents/app/dir1') #doctest: +ELLIPSIS
        'dir 0 default-owned ".../tests/testfiles/contents/app/dir1" ... 0 '

        Q: Is the full link to the target what we want?
        A: Yes, since the link will still be ok even if we move the directory.

        b.add('sym', 'virtual',
        ...       destination = here + '/tests/testfiles/contents/app/',
        ...       path = '/test3', relative = True)
        b.entry(here + '/tests/testfiles/contents/app/test3') #doctest: +ELLIPSIS
        'sym 1 virtual "test3" ... 0 .../tests/testfiles/contents/app/test1'

        b.db_print() #doctest: +ELLIPSIS
        file 1 config-owned "test1" ... d8e8fca2dc0f896fd7cb4cb0031ba249 
        file 1 config-owned "test2" ... d8e8fca2dc0f896fd7cb4cb0031ba249 
        sym 1 virtual "test3" ... 0 .../tests/testfiles/contents/app/test1
        dir 0 default-owned ".../tests/testfiles/contents/app/dir1" ... 0 

        '''

        OUT.debug('Adding entry to content dictionary', 6)

        # Build the full path that we use as index in the contents list
        while path[0] == '/':
            path = path[1:]
        while destination[-1] == '/':
            destination = destination[:-1]

        entry = destination + '/' + path

        # special case - we don't add entries for '.'

        if os.path.basename(entry) == '.':
            return

        if (not self.__p
                and not os.path.islink(entry)
                and (not os.path.exists(entry)
                    or not os.access(entry, os.R_OK))):
            OUT.warn('Cannot access file ' + entry + ' to add it as'
                     ' installation content. This should not happen!')
            return

        allowed_types = {
            'file'    : [ 'file', self.file_md5,  self.file_null ],
            'hardlink': [ 'file', self.file_md5,  self.file_null ],
            'dir'     : [  'dir', self.file_zero, self.file_null ],
            'sym'     : [  'sym', self.file_zero, self.file_link ],
            }

        if not dsttype in allowed_types.keys():
            OUT.die('Oops, webapp-config bug. "dsttype" is ' + dsttype)

        # Generate handler for file attributes
        a = allowed_types[dsttype]

        # For absolute entries the path must match the entry
        if not relative:
            path = entry

        OUT.debug('Adding entry', 7)

        # report if pretending
        if self.__p:

            OUT.info('    pretending to add: ' +
                     ' '.join([dsttype,
                               str(int(relative)),
                               ctype,
                               '"' + path + '"']))
        else:

            # Only the path is enclosed in quotes, NOT the link targets
            self.__content[entry] = [ a[0],
                                      str(int(relative)),
                                      ctype,
                                      '"' + path + '"',
                                      self.file_time(entry),
                                      a[1](real_path),
                                      a[2](entry)]

            if self.__v:
                msg = path
                if msg[0] == "/":
                    msg = self.__root + msg
                    msg = self.__re.sub('/', msg)
                OUT.notice('>>> ' + a[0] + ' ' * (4 - len(a[0])) + ' ('  \
                           + ctype + ') ' + msg)
Exemple #33
0
    def __init__(self,
                 directories,
                 permissions,
                 handler,
                 flags,
                 pm):

        if self.dep and not self.supported(pm):
            print(self.dep)
            OUT.die('Your configuration file sets the server type "' + self.name
                    + '"\nbut the corresponding package does not seem to be '
                    'installed!\nPlease "emerge ' + self.dep + '" or correct '
                    'your settings.')

        try:
            self.set_server_user()
        except KeyError:
            OUT.die('The user for the server type "' + self.name
                    + '" does not exist!')

        self.__sourced   = directories['source']
        self.__destd     = directories['destination']
        self.__hostroot  = directories['hostroot']
        self.__vhostroot = directories['vhostroot']

        # + server owned
        if permissions['file']['server-owned'][0] == 0:
            permissions['file']['server-owned'][0] = self.vhost_server_uid
            permissions['dir']['server-owned'][0]  = self.vhost_server_uid
        if permissions['file']['server-owned'][1] == 0:
            permissions['file']['server-owned'][1] = self.vhost_server_gid
            permissions['dir']['server-owned'][1]  = self.vhost_server_gid
            # and config owned directories have server gid
            permissions['dir']['config-owned'][1]  = self.vhost_server_gid
            # allows server and config owned
            permissions['file']['config-server-owned'][1] = self.vhost_server_gid
            permissions['dir']['config-server-owned'][1]  = self.vhost_server_gid

        self.__perm      = permissions
        self.__handler   = handler
        self.__flags     = flags

        self.__ws        = handler['source']
        self.__content   = handler['content']
        self.__protect   = handler['protect']
        self.__dotconfig = handler['dotconfig']
        self.__ebuild    = handler['ebuild']
        self.__db        = handler['db']

        self.__v         = flags['verbose']
        self.__p         = flags['pretend']

        wd = WebappRemove(self.__content,
                          self.__v,
                          self.__p)

        handler['removal'] = wd

        self.__del       = wd

        # Set by the install function
        self.__add       = None
Exemple #34
0
    def add(self, dsttype, ctype, destination, path, real_path, relative=True):
        '''
        Add an entry to the contents file.

        Just like Portage, when we install an app, we create a contents
        file to say what we installed and when.  We use this contents
        file to help us safely remove & upgrade apps.

        CONTENTS file format:

        <what> <rel> <type> <filename> <timestamp> <sum> [<optional>]

        where

        <what>      is one of dir|sym|file|hardlink

        <rel>       is 1 for relative filenames, 0 for absolute
                        filenames

        <type>      is one of
                        server-owned|default-owned|config-owned|virtual

        <timestamp> is the timestamp when the file was installed

        <sum>       is the md5sum of the file
                        (this is 0 for directories and symlinks)

        <filename>      is the actual name of the file we have installed

        <optional>      is additional data that depends upon <what>

        NOTE:
            Filenames used to be on the end of the line.  This made
                the old bash version more complicated, and
                prone to failure. So I have moved the filename into the
                middle of the line. -- Stuart

        Portage uses absolute names for its files, dirs, and symlinks.
        We do not.
        In theory, you can move a directory containing a web-based app,
        and

        a) the app itself will not break, and
        b) webapp-config will still work on that directory
           for upgrades and cleans.

        Position-independence *is* a design constraint that all future
        changes to this script need to honour.

        Inputs:

          dsttype     - type to add (one of dir|sym|file|hardlink)
          ctype       - internal webapp-config type
                      - (server-owned | config-owned | virtual)
          destination - install dir (normally $G_INSTALLDIR)
          path        - filename inside 'destination'
          real_path   - for config-protected files realpath =! path
                        (and this is important for md5)
          relative    - 1 for storing a relative filename, 0 otherwise
        '''

        OUT.debug('Adding entry to content dictionary', 6)

        # Build the full path that we use as index in the contents list
        while path[0] == '/':
            path = path[1:]
        while destination[-1] == '/':
            destination = destination[:-1]

        entry = destination + '/' + path

        # special case - we don't add entries for '.'

        if os.path.basename(entry) == '.':
            return

        if (not self.__p and not os.path.islink(entry) and
            (not os.path.exists(entry) or not os.access(entry, os.R_OK))):
            OUT.warn('Cannot access file ' + entry + ' to add it as'
                     ' installation content. This should not happen!')
            return

        allowed_types = {
            'file': ['file', self.file_md5, self.file_null],
            'hardlink': ['file', self.file_md5, self.file_null],
            'dir': ['dir', self.file_zero, self.file_null],
            'sym': ['sym', self.file_zero, self.file_link],
        }

        if not dsttype in list(allowed_types.keys()):
            OUT.die('Oops, webapp-config bug. "dsttype" is ' + dsttype)

        # Generate handler for file attributes
        a = allowed_types[dsttype]

        # For absolute entries the path must match the entry
        if not relative:
            path = entry

        OUT.debug('Adding entry', 7)

        # report if pretending
        if self.__p:

            OUT.info('    pretending to add: ' + ' '.join(
                [dsttype, str(int(relative)), ctype, '"' + path + '"']))
        else:

            # Only the path is enclosed in quotes, NOT the link targets
            self.__content[entry] = [
                a[0],
                str(int(relative)), ctype, '"' + path + '"',
                self.file_time(entry), a[1](real_path), a[2](entry)
            ]

            if self.__v:
                msg = path
                if msg[0] == "/":
                    msg = self.__root + msg
                    msg = self.__re.sub('/', msg)
                OUT.notice('>>> ' + a[0] + ' ' * (4 - len(a[0])) + ' ('  \
                           + ctype + ') ' + msg)
Exemple #35
0
    def remove(self, installdir):
        '''
        Remove a record from the list of virtual installs.

        installdir - the installation directory
        '''
        if not installdir:
            OUT.die('The installation directory must be specified!')

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        if not os.access(dbpath, os.R_OK):
            OUT.warn('Unable to read the install database ' + dbpath)
            return

        # Read db file
        fdb = open(dbpath)
        entries = fdb.readlines()
        fdb.close()

        newentries = []
        found = False

        for i in entries:

            j = i.strip().split(' ')

            if j:

                if len(j) != 4:

                    # Remove invalid entry
                    OUT.warn('Invalid line "' + i.strip() + '" remo'
                             'ved from the database file!')
                elif j[3] != installdir:

                    OUT.debug('Keeping entry', 7)

                    # Keep valid entry
                    newentries.append(i.strip())

                elif j[3] == installdir:

                    # Remove entry, indicate found
                    found = True

        if not found:
            OUT.warn('Installation at "' + installdir + '" could not be '
                     'found in the database file. Check the entries in "' +
                     dbpath + '"!')

        if not self.__p:
            installs = open(dbpath, 'w')
            installs.write('\n'.join(newentries) + '\n')
            installs.close()
            if not self.has_installs():
                os.unlink(dbpath)
        else:
            OUT.info('Pretended to remove installation ' + installdir)
            OUT.info('Final DB content:\n' + '\n'.join(newentries) + '\n')
Exemple #36
0
    def read(self):
        '''
        Reads the contents database.
        '''

        dbpath = self.appdb()

        if not dbpath or not os.access(dbpath, os.R_OK):
            OUT.die('Content file ' + dbpath + ' is missing or not accessibl'
                    'e!')

        content = open(dbpath).readlines()

        for i in content:

            i = i.strip()

            rfn = re.compile('"(.*)"')
            rfs = rfn.search(i)
            if not rfs:
                ok = False
            else:
                fn = rfs.group(1)
                i = rfn.sub('', i)
                line_split = i.split(' ')
                line_split[3] = fn

                OUT.debug('Adding content line', 10)

                ok = True

                if len(line_split) < 6:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nNot enough entries.')

                if ok and not line_split[0] in ['file', 'sym', 'dir']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid file type: ' +
                             line_split[0])

                if ok and not line_split[1] in ['0', '1']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid relative flag: ' +
                             line_split[1])

                if ok and not line_split[2] in [
                        'virtual',
                        'server-owned',
                        'config-owned',
                        'default-owned',
                        'config-server-owned',
                        # Still need that in case an
                        # application was installed
                        # with w-c-1.11
                        'root-owned'
                ]:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid owner: ' + line_split[2])

                if ok and line_split[0] == 'sym' and len(line_split) == 6:
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nMissing link target! ')

                if len(line_split) == 6:
                    line_split.append('')

                # I think this could happen if the link target contains
                # spaces
                # -- wrobel
                if len(line_split) > 7:
                    line_split = line_split[0:6]                         \
                                 + [' '.join(line_split[6:])]

            if ok:
                if line_split[1] == '0':
                    self.__content[line_split[3]] = line_split
                else:
                    self.__content[self.__installdir + '/' +
                                   line_split[3]] = line_split

            else:
                OUT.warn('Invalid line in content file (' + i + '). Ignor'
                         'ing!')
Exemple #37
0
 def check_installdir(self):
     if not os.path.isdir(self.__installdir) and not self.__p:
         OUT.die('"' + self.__installdir + '" specifies no directory! '
                 'webapp-config needs a valid directory to store/retri'
                 'eve information. Please correct your settings.')
Exemple #38
0
def config_libdir(pm):
    OUT.die("I shouldn't get called at all")
Exemple #39
0
    def read(self):
        '''
        Reads the contents database.

        Some content files have been provided for test purposes:

        >>> import os.path
        >>> here = os.path.dirname(os.path.realpath(__file__))

        This one should succeed:

        >>> a = Contents(here + '/tests/testfiles/contents/',
        ...              package = 'test', version = '1.0')
        >>> a.read()
        >>> a.db_print()
        file 1 virtual util/icon_browser.php 1124612216 9ffb2ca9ccd2db656b97cd26a1b06010 
        file 1 config-owned inc/prefs.php 1124612215 ffae752dba7092cd2d1553d04a0f0045 
        file 1 virtual lib/prefs.php 1124612215 ffae752dba7092cd2d1553d04a0f0045 
        file 1 virtual signup.php 1124612220 dc838bc375b3d02dafc414f8e71a2aec 
        file 1 server-owned data.php 1117009618 0 
        sym 1 virtual test 1124612220 dc838bc375b3d02dafc414f8e71a2aec /I link / to a very / strange location
        dir 1 default-owned util 1117009618 0 
        dir 1 config-owned inc 1117009618 0 
        dir 1 default-owned lib 1117009618 0 
        dir 0 default-owned /var/www/localhost/cgi-bin 1124577741 0 
        dir 0 default-owned /var/www/localhost/error 1124577740 0 
        dir 0 default-owned /var/www/localhost/icons 1124577741 0 
        
        >>> a.get_directories() #doctest: +ELLIPSIS
        ['.../contents//util', '.../contents//inc', '.../contents//lib', '/var/www/localhost/cgi-bin', '/var/www/localhost/error', '/var/www/localhost/icons']

        This is a corrupted file that checks all fail safes:

        >>> OUT.color_off()
        >>> a = Contents(here + '/tests/testfiles/contents/',
        ...              package = 'test', version = '1.1')
        >>> a.read() #doctest: +ELLIPSIS
        * Invalid line in content file (dir 1 default-owned). Ignoring!
        * Content file .../tests/testfiles/contents//.webapp-test-1.1 has an invalid line:
        * dir 1 nobody-owned  1117009618 0
        * Invalid owner: nobody-owned
        * Invalid line in content file (dir 1 nobody-owned  1117009618 0). Ignoring!
        * Content file .../tests/testfiles/contents//.webapp-test-1.1 has an invalid line:
        * garbage 1 virtual  1124612215 ffae752dba7092cd2d1553d04a0f0045
        * Invalid file type: garbage
        * Invalid line in content file (garbage 1 virtual  1124612215 ffae752dba7092cd2d1553d04a0f0045). Ignoring!
        * Invalid line in content file (file 1 virtual). Ignoring!
        * Content file .../tests/testfiles/contents//.webapp-test-1.1 has an invalid line:
        * file 1 virtual 
        * Not enough entries.
        * Invalid line in content file (file 1 virtual ). Ignoring!
        * Content file .../tests/testfiles/contents//.webapp-test-1.1 has an invalid line:
        * file 31 config-owned  1124612215 ffae752dba7092cd2d1553d04a0f0045
        * Invalid relative flag: 31
        * Invalid line in content file (file 31 config-owned  1124612215 ffae752dba7092cd2d1553d04a0f0045). Ignoring!
        '''

        dbpath = self.appdb()

        if not dbpath or not os.access(dbpath, os.R_OK):
            OUT.die('Content file ' + dbpath + ' is missing or not accessibl'
                    'e!')

        content = open(dbpath).readlines()

        for i in content:

            i = i.strip()

            rfn = re.compile('"(.*)"')
            rfs = rfn.search(i)
            if not rfs:
                ok = False
            else:
                fn  = rfs.group(1)
                i   = rfn.sub('', i)
                line_split = i.split(' ')
                line_split[3] = fn

                OUT.debug('Adding content line', 10)

                ok = True

                if len(line_split) < 6:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nNot enough entries.')

                if ok and not line_split[0] in ['file', 'sym', 'dir']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid file type: '
                             + line_split[0])

                if ok and not line_split[1] in ['0', '1']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid relative flag: '
                             + line_split[1])

                if ok and not line_split[2] in ['virtual',
                                                'server-owned',
                                                'server-owned-dir',
                                                'config-owned',
                                                'default-owned',
                                                'config-server-owned',
                                                # Still need that in case an 
                                                # application was installed
                                                # with w-c-1.11
                                                'root-owned']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid owner: '
                             + line_split[2])

                if ok and line_split[0] == 'sym' and len(line_split) == 6:
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nMissing link target! ')

                if len(line_split) == 6:
                    line_split.append('')

                # I think this could happen if the link target contains
                # spaces
                # -- wrobel
                if len(line_split) > 7:
                    line_split = line_split[0:6]                         \
                                 + [' '.join(line_split[6:])]

            if ok:
                if line_split[1] == '0':
                    self.__content[line_split[3]] = line_split
                else:
                    self.__content[self.__installdir + '/'
                                   + line_split[3]] = line_split

            else:
                OUT.warn('Invalid line in content file (' + i + '). Ignor'
                         'ing!')
Exemple #40
0
    def remove(self, installdir):
        '''
        Remove a record from the list of virtual installs.

        installdir - the installation directory
        '''
        if not installdir:
            OUT.die('The installation directory must be specified!')

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        if not os.access(dbpath, os.R_OK):
            OUT.warn('Unable to read the install database ' + dbpath)
            return

        # Read db file
        fdb = open(dbpath)
        entries = fdb.readlines()
        fdb.close()

        newentries = []
        found = False

        for i in entries:

            j = i.strip().split(' ')

            if j:

                if len(j) != 4:

                    # Remove invalid entry
                    OUT.warn('Invalid line "' + i.strip() + '" remo'
                             'ved from the database file!')
                elif j[3] != installdir:

                    OUT.debug('Keeping entry', 7)

                    # Keep valid entry
                    newentries.append(i.strip())

                elif j[3] == installdir:

                    # Remove entry, indicate found
                    found = True

        if not found:
            OUT.warn('Installation at "' +  installdir + '" could not be '
                     'found in the database file. Check the entries in "'
                     + dbpath + '"!')

        if not self.__p:
            installs = open(dbpath, 'w')
            installs.write('\n'.join(newentries) + '\n')
            installs.close()
            if not self.has_installs():
                os.unlink(dbpath)
        else:
            OUT.info('Pretended to remove installation ' + installdir)
            OUT.info('Final DB content:\n' + '\n'.join(newentries) + '\n')
Exemple #41
0
    def read(self):
        '''
        Reads the contents database.
        '''

        dbpath = self.appdb()

        if not dbpath or not os.access(dbpath, os.R_OK):
            OUT.die('Content file ' + dbpath + ' is missing or not accessibl'
                    'e!')

        content = open(dbpath).readlines()

        for i in content:

            i = i.strip()

            rfn = re.compile('"(.*)"')
            rfs = rfn.search(i)
            if not rfs:
                ok = False
            else:
                fn  = rfs.group(1)
                i   = rfn.sub('', i)
                line_split = i.split(' ')
                line_split[3] = fn

                OUT.debug('Adding content line', 10)

                ok = True

                if len(line_split) < 6:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nNot enough entries.')

                if ok and not line_split[0] in ['file', 'sym', 'dir']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid file type: '
                             + line_split[0])

                if ok and not line_split[1] in ['0', '1']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid relative flag: '
                             + line_split[1])

                if ok and not line_split[2] in ['virtual',
                                                'server-owned',
                                                'config-owned',
                                                'default-owned',
                                                'config-server-owned',
                                                # Still need that in case an 
                                                # application was installed
                                                # with w-c-1.11
                                                'root-owned']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid owner: '
                             + line_split[2])

                if ok and line_split[0] == 'sym' and len(line_split) == 6:
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nMissing link target! ')

                if len(line_split) == 6:
                    line_split.append('')

                # I think this could happen if the link target contains
                # spaces
                # -- wrobel
                if len(line_split) > 7:
                    line_split = line_split[0:6]                         \
                                 + [' '.join(line_split[6:])]

            if ok:
                if line_split[1] == '0':
                    self.__content[line_split[3]] = line_split
                else:
                    self.__content[self.__installdir + '/'
                                   + line_split[3]] = line_split

            else:
                OUT.warn('Invalid line in content file (' + i + '). Ignor'
                         'ing!')