예제 #1
0
파일: project.py 프로젝트: cjchung/main
class ProjectManager:
    def __init__(self):
        add_exports(    (
                ('getitem', self.getitem),
                ('getbool', self.getbool),
                ('setitem', self.setitem),
                ('setbool', self.setbool),
                ('get_projects', self.list_projects),
                ('get_profiles', self.list_profiles),
                ('get_installation_dir', self.get_ipath),
                ('set_installation_dir', self.set_ipath),
                ('testlarchify', self.testlarchify),
                ('set_project', self.set_projectname),
                ('get_project', self.get_projectname),
                ('delete_project', self.delete_project),
                ('delete_profile', self.delete_profile),
                ('list_free_projects', self.list_free_projects),
                ('list_free_profiles', self.list_free_profiles),
                ('get_new_profile', self.get_new_profile),
                ('rename_profile', self.rename_profile),
                ('can_rename_profile', self.can_rename_profile),
                ('save_profile', self.save_profile),
                ('get_profile', self.get_profile),
                ('set_profile', self.set_profile),
                ('get_example_profiles', self.get_example_profiles),
                ('set_profile_browse_dir', self.set_profile_browse_dir),
                ('get_mediumlabel', self.get_mediumlabel),
                ('set_mediumlabel', self.set_mediumlabel),
                ('getisosavedir', self.getisosavedir),
                ('getisofile', self.getisofile),
                ('getbootisofile', self.getbootisofile),
                ('get_bootisolabel', self.get_bootisolabel),
                ('set_bootisolabel', self.set_bootisolabel),
                ('newUserinfo', self.newUserinfo),
                ('allusers', self.allusers),
                ('getuserinfo', self.getuserinfo),
                ('newuser', self.newuser),
                ('userset', self.userset),
                ('deluser', self.deluser),
                ('listskels', self.listskels),
                ('saveusers', self.saveusers))
            )


    def init(self):
        self.projects_base = os.path.join(os.environ['HOME'], CONFIG_DIR)
        self.profiles_dir = os.path.join(self.projects_base, 'myprofiles')
        # Ensure the presence of the larch default project folder
        dpf = '%s/p_%s' % (self.projects_base, PROJECT0)
        if not os.path.isdir(dpf):
            os.makedirs(dpf)
        # Ensure the presence of the profiles folder and the 'default' profile
        if not os.path.isdir(self.profiles_dir):
            os.mkdir(self.profiles_dir)
        self.default_profile_dir = os.path.join(self.profiles_dir, PROFILE0)
        if not os.path.isdir(self.default_profile_dir):
            call(['cp', '-a', base_dir + '/profiles/'+ PROFILE0,
                    self.profiles_dir])

        # The application configs
        self.aconfig_file = os.path.join(self.projects_base, APP_CONF)
        self.aconfig = self.getconfig(self.aconfig_file)

        # The project-specific configs
        self.set_projectname(self.appget('project'))


    def get_projectname(self):
        return (True, self.project_name)

    def set_projectname(self, name):
        self.project_dir = os.path.join(self.projects_base, 'p_' + name)
        plist = self.list_projects()[1]
        if name not in plist:
            os.mkdir(self.project_dir)

        self.pconfig_file = os.path.join(self.project_dir, PROJECT_CONF)
        self.pconfig = self.getconfig(self.pconfig_file)
        self.profile_name = self.get('profile')

        self.profile_path = os.path.join(self.profiles_dir, self.profile_name)
        self.appset('project', name)
        self.project_name = name
        return (True, None)

    def delete_project(self, name):
        # This should probably be run as root, in case the build directory
        # is inside it ... cross that bridge when we come to it!
        r = call(['rm', '-r', '--interactive=never',
                os.path.join(self.projects_base, 'p_' + name)])
        return (True, r == 0)


    def delete_profile(self, name):
        r = call(['rm', '-r', '--interactive=never',
                os.path.join(self.profiles_dir, name)])
        return (True, r == 0)


    def get_profile(self):
        return (True, self.profile_name)

    def set_profile(self, name):
        self.set('profile', name)
        self.profile_name = name
        self.profile_path = os.path.join(self.profiles_dir, self.profile_name)
        return (True, None)


    def rename_profile(self, name):
        os.rename(self.profile_path, os.path.join(self.profiles_dir, name))
        self.set_profile(name)
        return (True, None)


    def get_new_profile(self, src, name):
        if not os.path.isfile(src + '/addedpacks'):
            return (True, False)
        dst = os.path.join(self.profiles_dir, name)
        call(['rm', '-rf', dst])
        shutil.copytree(src, dst, symlinks=True)
        self.set_profile(name)
        return (True, True)


    def get_example_profiles(self):
        pd = base_dir + '/profiles'
        return (True, (pd, os.listdir(pd)))

# location of working profiles
#        self.projects_base + '/myprofiles',


# What about not allowing changes to the default profile?
# That would mean also no renaming?
# One would have to copy a profile into the project before going
# any further ...
# Is it right to share profiles between projects? (Probably)

#+++++++++++++++++++++++++++++++++++++++++++++++
### A very simple configuration file handler
    def getconfig(self, filepath):
        cfg = {}
        if os.path.isfile(filepath):
            fh = open(filepath)
            for line in fh:
                ls = line.split('=', 1)
                if len(ls) > 1:
                    cfg[ls[0].strip()] = ls[1].strip()
        return cfg


    def saveconfig(self, filepath, config):
        fh = open(filepath, 'w')
        ci = config.items()
        ci.sort()
        for kv in ci:
            fh.write('%s = %s\n' % kv)
        fh.close()
###
#-----------------------------------------------

    def list_projects(self):
        projects = [p[2:] for p in os.listdir(self.projects_base)
                if p.startswith('p_')]
        projects.sort()
        return (True, projects)


    def list_free_projects(self):
        """This returns a list of projects which are free for (e.g.) deletion.
        """
        plist = self.list_projects()[1]
        plist.remove(PROJECT0)          # this one is not 'free'
        if self.project_name in plist:
            plist.remove(self.project_name)
        return (True, plist)


    def list_profiles(self):
        profiles = [d for d in os.listdir(self.profiles_dir) if
                os.path.isfile(os.path.join(self.profiles_dir, d, 'addedpacks'))]
        profiles.sort()
        return (True, profiles)


    def list_free_profiles(self):
        """This returns a list of profiles which are not in use by any project.
        """
        plist = self.list_profiles()[1]
        plist.remove(PROFILE0)          # this one is not 'free'
        for project in self.list_projects()[1]:
            cfg = self.getconfig(os.path.join(self.projects_base,
                    'p_' + project, PROJECT_CONF))
            p = cfg.get('profile')
            if p in plist:
                plist.remove(p)
        return (True, plist)


    def can_rename_profile(self):
        if self.profile_name == PROFILE0:
            return (True, False)
        for project in self.list_projects()[1]:
            if project != self.project_name:
                cfg = self.getconfig(os.path.join(self.projects_base,
                        'p_' + project, PROJECT_CONF))
                if self.profile_name == cfg.get('profile'):
                    return (True, False)
        return (True, True)


    def save_profile(self, path, force):
        if path[0] != '/':
            # cloning, only the profile name is passed
            path = os.path.join(self.profiles_dir, path)
        else:
            # copying, the destination will have the same name
            if os.path.basename(path) != self.profile_name:
                path = os.path.join(path, self.profile_name)
        if os.path.exists(path):
            if force:
                call(['rm', '-rf', path])
            elif os.path.isfile(os.path.join(path, 'addedpacks')):
                # This is an existing profile
                return (True, False)
            else:
                # This location is otherwise in use
                return (True, None)
        shutil.copytree(self.profile_path, path, symlinks=True)
        return (True, True)


    def set_profile_browse_dir(self, path):
        if os.path.isfile(os.path.join(path, 'addedpacks')):
            # Don't set the profile browse path to a profile directory,
            # but rather tp the containing directory
            path = os.path.dirname(path)
        self.set('profile_browse_dir', path)


    def appget(self, item):
        """Read an entry in the application configuration.
        """
        v = self.aconfig.get(item)
        if v:
            return v
        elif APP_DEFAULTS.has_key(item):
            return APP_DEFAULTS[item]
        debug("Unknown application configuration option: %s" % item)
        assert False

    def appset(self, item, value):
        """Set an entry in the application configuration.
        """
        self.aconfig[item] = value.strip()
        self.saveconfig(self.aconfig_file, self.aconfig)


    def getitem(self, item):
        return (True, self.get(item))

    def getbool(self, item):
        return (True, self.get(item) == 'Yes')

    def setitem(self, item, value):
        self.set(item, value)
        return (True, None)

    def setbool(self, item, on):
        self.set(item, 'Yes' if on else 'No')
        return (True, None)


    def get(self, item):
        """Read an entry in the project configuration.
        """
        v = self.pconfig.get(item)
        if v:
            return v
        elif DEFAULTS.has_key(item):
            return DEFAULTS[item]
        debug("Unknown configuration option: %s" % item)
        assert False

    def set(self, item, value):
        """Set an entry in the project configuration.
        """
        self.pconfig[item] = value.strip()
        self.saveconfig(self.pconfig_file, self.pconfig)
#        return True


    def get_ipath(self):
        ip = self.get('installation_dir')
        if not ip:
            ip = self.set_ipath('')[1]
        return (True, ip)

    def set_ipath(self, path):
        path = path.strip()
        if path:
            path = '/' + path.strip('/')
        else:
            path = os.environ['HOME'] + '/larch_build'
        self.set('installation_dir', path)
        return (True, path)


    def testlarchify(self):
        ipath = self.get_ipath()[1]
        path = ipath + CHROOT_DIR_MEDIUM
        bl = []
        nosave = False
        ok = (os.path.isfile(path + '/larch/system.sqf')
                and os.path.isfile(ipath + SYSLINUXDIR + '/isolinux.bin'))
        return (True, (path, ok))


    def newUserinfo(self):
        self.userInfo = Userinfo(self.profile_path)
        return (True, None)

    def allusers(self):
        return (True, self.userInfo.allusers())

    def getuserinfo(self, user, fields):
        return (True, self.userInfo.userinfo(user, fields))

    def newuser(self, user):
        return (True, self.userInfo.newuser(user))

    def saveusers(self):
        return (True, self.userInfo.saveusers())

    def userset(self, uname, field, text):
        self.userInfo.userset(uname, field, text)
        return (True, None)

    def deluser(self, user):
        return (True, self.userInfo.deluser(user))

    def listskels(self):
        return (True, glob(self.profile_path + '/skel_*'))


    def get_mediumlabel(self):
        l = self.get('medium_label')
        return (True, l if l else LABEL)

    def set_mediumlabel(self, l):
        if len(l) > 16:
            l = l[:16]
        self.set('medium_label', l)
        return self.get_mediumlabel()

    def set_bootisolabel(self, l):
        if len(l) > 32:
            l = l[:32]
        self.set('bootisolabel', l)
        return self.get_bootisolabel()


    def getisosavedir(self):
        d = self.get('isosavedir')
        return (True, d if d else os.environ['HOME'])

    def getisofile(self):
        f = self.get('isofile')
        return (True, f if f else ISOFILE)

    def getbootisofile(self):
        f = self.get('bootisofile')
        return (True, f if f else BOOTISO)

    def get_bootisolabel(self):
        l = self.get('bootisolabel')
        return (True, l if l else BOOTISOLABEL)
예제 #2
0
    def add_users(self, rootcmd):
        userinfo = Userinfo(self.profile_dir)
        userlist = []
        for user in userinfo.allusers():
            # Only include if the user does not yet exist
            if runcmd('bash -c "grep \"^%s\" %s/etc/passwd || echo -"'
                    % (user, self.installation_dir))[1][0] != '-':
                comment("(WARNING): User '%s' exists already" % user)
            else:
                userlist.append(user)

        # Only continue if there are new users in the list
        if rootcmd:
            clist = [('root', rootcmd + ' %s')]
        else:
            if userlist == []:
                return True
            clist = []

        # Save system files and replace them by the overlay versions
        savedir = self.larchify_dir + '/save_etc'
        runcmd('rm -rf %s' % savedir)
        runcmd('mkdir -p %s/default' % savedir)
        savelist = 'group,gshadow,passwd,shadow,login.defs,skel'
        runcmd('bash -c "cp -a %s/etc/{%s} %s"'
                % (self.installation0, savelist, savedir))
        runcmd('cp -a %s/etc/default/useradd %s/default'
                % (self.installation0, savedir))
        for f in ('group', 'gshadow', 'passwd', 'shadow', 'login.defs'):
            if os.path.isfile(self.overlay + '/etc/%s'):
                runcmd('cp %s/etc/%s %s/etc'
                        % (self.overlay, f, self.installation0))
        if os.path.isfile(self.overlay + '/etc/default/useradd'):
            runcmd('cp %s/etc/default/useradd %s/etc/default'
                    % (self.overlay, self.installation0))
        if os.path.isdir(self.overlay + '/etc/skel'):
            runcmd('cp -r %s/etc/skel %s/etc'
                    % (self.overlay, self.installation0))

        # Build the useradd command
        userdir0 = '/users'
        userdir = self.larchify_dir + userdir0
        userdirs = []
        runcmd('mkdir -p %s/home' % self.overlay)
        for u in userlist:
            cline = 'useradd -m'
            pgroup = userinfo.get(u, 'maingroup')
            if pgroup:
                cline += ' -g ' + pgroup
            uid = userinfo.get(u, 'uid')
            if uid:
                cline += ' -u ' + uid
            pw = userinfo.get(u, 'pw')
            if (pw == ''):
                # Passwordless login
                pwcrypt = ''
            else:
                # Normal MD5 password
                pwcrypt = encryptPW(pw)
            cline += " -p '%s'" % pwcrypt
            skeldir = userinfo.get(u, 'skel')
            if skeldir:
                # Custom home initialization directories in the profile
                # always start with 'skel_'
                skel = 'skel_' + skeldir
                if skel not in userdirs:
                    userdirs.append(skel)
                cline += ' -k %s/%s' % (CHROOT_DIR_LARCHIFY + userdir0,
                        skel)
            # Allow for expert tweaking
            cline += ' ' + userinfo.get(u, 'expert')
            # The user and the command to be run
            clist.append((u, cline + ' %s'))
            xgroups = userinfo.get(u, 'xgroups')
            if xgroups:
                xgl = []
                for g in xgroups.split(','):
                    clist.append((u, 'usermod -a -G %s %%s' % g))

        if userdirs:
            # Copy custom 'skel' directories to build space
            runcmd('rm -rf %s' % userdir)
            runcmd('mkdir -p %s' % userdir)
            for ud in userdirs:
                runcmd('cp -r %s/%s %s/%s' %
                        (self.profile_dir, ud, userdir, ud))

        nfail = 0
        ok = True
        for u, cmd in clist:
            if not chroot(self.installation0, cmd % u):
                nfail += 1
                # Errors adding users to groups are not fatal:
                if not cmd.startswith('usermod -a -G'):
                    ok = False
            if os.path.isdir('%s/home/%s' % (self.installation0, u)):
                runcmd('mv %s/home/%s %s/home'
                        % (self.installation0, u, self.overlay))

        if nfail > 0:
            errout(_("%d user account operation(s) failed") % nfail, 0)
        # Move changed /etc/{group,gshadow,passwd,shadow} to overlay
        runcmd('bash -c "mv %s/etc/{group,gshadow,passwd,shadow} %s/etc"'
                % (self.installation0, self.overlay))
        # Restore system files in base installation
        runcmd('rm -rf %s/etc/skel' % self.installation0)
        runcmd('bash -c "cp -a %s/* %s/etc"'
                % (savedir, self.installation0))
        return ok
예제 #3
0
파일: project.py 프로젝트: cjchung/main
class ProjectManager:
    def __init__(self):
        add_exports(
            (('getitem', self.getitem), ('getbool', self.getbool),
             ('setitem', self.setitem), ('setbool', self.setbool),
             ('get_projects', self.list_projects), ('get_profiles',
                                                    self.list_profiles),
             ('get_installation_dir',
              self.get_ipath), ('set_installation_dir',
                                self.set_ipath), ('testlarchify',
                                                  self.testlarchify),
             ('set_project', self.set_projectname), ('get_project',
                                                     self.get_projectname),
             ('delete_project', self.delete_project), ('delete_profile',
                                                       self.delete_profile),
             ('list_free_projects',
              self.list_free_projects), ('list_free_profiles',
                                         self.list_free_profiles),
             ('get_new_profile', self.get_new_profile), ('rename_profile',
                                                         self.rename_profile),
             ('can_rename_profile',
              self.can_rename_profile), ('save_profile', self.save_profile),
             ('get_profile', self.get_profile), ('set_profile',
                                                 self.set_profile),
             ('get_example_profiles',
              self.get_example_profiles), ('set_profile_browse_dir',
                                           self.set_profile_browse_dir),
             ('get_mediumlabel', self.get_mediumlabel), ('set_mediumlabel',
                                                         self.set_mediumlabel),
             ('getisosavedir', self.getisosavedir), ('getisofile',
                                                     self.getisofile),
             ('getbootisofile', self.getbootisofile), ('get_bootisolabel',
                                                       self.get_bootisolabel),
             ('set_bootisolabel',
              self.set_bootisolabel), ('newUserinfo',
                                       self.newUserinfo), ('allusers',
                                                           self.allusers),
             ('getuserinfo', self.getuserinfo), ('newuser',
                                                 self.newuser), ('userset',
                                                                 self.userset),
             ('deluser', self.deluser), ('listskels',
                                         self.listskels), ('saveusers',
                                                           self.saveusers)))

    def init(self):
        self.projects_base = os.path.join(os.environ['HOME'], CONFIG_DIR)
        self.profiles_dir = os.path.join(self.projects_base, 'myprofiles')
        # Ensure the presence of the larch default project folder
        dpf = '%s/p_%s' % (self.projects_base, PROJECT0)
        if not os.path.isdir(dpf):
            os.makedirs(dpf)
        # Ensure the presence of the profiles folder and the 'default' profile
        if not os.path.isdir(self.profiles_dir):
            os.mkdir(self.profiles_dir)
        self.default_profile_dir = os.path.join(self.profiles_dir, PROFILE0)
        if not os.path.isdir(self.default_profile_dir):
            call([
                'cp', '-a', base_dir + '/profiles/' + PROFILE0,
                self.profiles_dir
            ])

        # The application configs
        self.aconfig_file = os.path.join(self.projects_base, APP_CONF)
        self.aconfig = self.getconfig(self.aconfig_file)

        # The project-specific configs
        self.set_projectname(self.appget('project'))

    def get_projectname(self):
        return (True, self.project_name)

    def set_projectname(self, name):
        self.project_dir = os.path.join(self.projects_base, 'p_' + name)
        plist = self.list_projects()[1]
        if name not in plist:
            os.mkdir(self.project_dir)

        self.pconfig_file = os.path.join(self.project_dir, PROJECT_CONF)
        self.pconfig = self.getconfig(self.pconfig_file)
        self.profile_name = self.get('profile')

        self.profile_path = os.path.join(self.profiles_dir, self.profile_name)
        self.appset('project', name)
        self.project_name = name
        return (True, None)

    def delete_project(self, name):
        # This should probably be run as root, in case the build directory
        # is inside it ... cross that bridge when we come to it!
        r = call([
            'rm', '-r', '--interactive=never',
            os.path.join(self.projects_base, 'p_' + name)
        ])
        return (True, r == 0)

    def delete_profile(self, name):
        r = call([
            'rm', '-r', '--interactive=never',
            os.path.join(self.profiles_dir, name)
        ])
        return (True, r == 0)

    def get_profile(self):
        return (True, self.profile_name)

    def set_profile(self, name):
        self.set('profile', name)
        self.profile_name = name
        self.profile_path = os.path.join(self.profiles_dir, self.profile_name)
        return (True, None)

    def rename_profile(self, name):
        os.rename(self.profile_path, os.path.join(self.profiles_dir, name))
        self.set_profile(name)
        return (True, None)

    def get_new_profile(self, src, name):
        if not os.path.isfile(src + '/addedpacks'):
            return (True, False)
        dst = os.path.join(self.profiles_dir, name)
        call(['rm', '-rf', dst])
        shutil.copytree(src, dst, symlinks=True)
        self.set_profile(name)
        return (True, True)

    def get_example_profiles(self):
        pd = base_dir + '/profiles'
        return (True, (pd, os.listdir(pd)))

# location of working profiles
#        self.projects_base + '/myprofiles',

# What about not allowing changes to the default profile?
# That would mean also no renaming?
# One would have to copy a profile into the project before going
# any further ...
# Is it right to share profiles between projects? (Probably)

#+++++++++++++++++++++++++++++++++++++++++++++++
### A very simple configuration file handler

    def getconfig(self, filepath):
        cfg = {}
        if os.path.isfile(filepath):
            fh = open(filepath)
            for line in fh:
                ls = line.split('=', 1)
                if len(ls) > 1:
                    cfg[ls[0].strip()] = ls[1].strip()
        return cfg

    def saveconfig(self, filepath, config):
        fh = open(filepath, 'w')
        ci = config.items()
        ci.sort()
        for kv in ci:
            fh.write('%s = %s\n' % kv)
        fh.close()
###
#-----------------------------------------------

    def list_projects(self):
        projects = [
            p[2:] for p in os.listdir(self.projects_base) if p.startswith('p_')
        ]
        projects.sort()
        return (True, projects)

    def list_free_projects(self):
        """This returns a list of projects which are free for (e.g.) deletion.
        """
        plist = self.list_projects()[1]
        plist.remove(PROJECT0)  # this one is not 'free'
        if self.project_name in plist:
            plist.remove(self.project_name)
        return (True, plist)

    def list_profiles(self):
        profiles = [
            d for d in os.listdir(self.profiles_dir)
            if os.path.isfile(os.path.join(self.profiles_dir, d, 'addedpacks'))
        ]
        profiles.sort()
        return (True, profiles)

    def list_free_profiles(self):
        """This returns a list of profiles which are not in use by any project.
        """
        plist = self.list_profiles()[1]
        plist.remove(PROFILE0)  # this one is not 'free'
        for project in self.list_projects()[1]:
            cfg = self.getconfig(
                os.path.join(self.projects_base, 'p_' + project, PROJECT_CONF))
            p = cfg.get('profile')
            if p in plist:
                plist.remove(p)
        return (True, plist)

    def can_rename_profile(self):
        if self.profile_name == PROFILE0:
            return (True, False)
        for project in self.list_projects()[1]:
            if project != self.project_name:
                cfg = self.getconfig(
                    os.path.join(self.projects_base, 'p_' + project,
                                 PROJECT_CONF))
                if self.profile_name == cfg.get('profile'):
                    return (True, False)
        return (True, True)

    def save_profile(self, path, force):
        if path[0] != '/':
            # cloning, only the profile name is passed
            path = os.path.join(self.profiles_dir, path)
        else:
            # copying, the destination will have the same name
            if os.path.basename(path) != self.profile_name:
                path = os.path.join(path, self.profile_name)
        if os.path.exists(path):
            if force:
                call(['rm', '-rf', path])
            elif os.path.isfile(os.path.join(path, 'addedpacks')):
                # This is an existing profile
                return (True, False)
            else:
                # This location is otherwise in use
                return (True, None)
        shutil.copytree(self.profile_path, path, symlinks=True)
        return (True, True)

    def set_profile_browse_dir(self, path):
        if os.path.isfile(os.path.join(path, 'addedpacks')):
            # Don't set the profile browse path to a profile directory,
            # but rather tp the containing directory
            path = os.path.dirname(path)
        self.set('profile_browse_dir', path)

    def appget(self, item):
        """Read an entry in the application configuration.
        """
        v = self.aconfig.get(item)
        if v:
            return v
        elif APP_DEFAULTS.has_key(item):
            return APP_DEFAULTS[item]
        debug("Unknown application configuration option: %s" % item)
        assert False

    def appset(self, item, value):
        """Set an entry in the application configuration.
        """
        self.aconfig[item] = value.strip()
        self.saveconfig(self.aconfig_file, self.aconfig)

    def getitem(self, item):
        return (True, self.get(item))

    def getbool(self, item):
        return (True, self.get(item) == 'Yes')

    def setitem(self, item, value):
        self.set(item, value)
        return (True, None)

    def setbool(self, item, on):
        self.set(item, 'Yes' if on else 'No')
        return (True, None)

    def get(self, item):
        """Read an entry in the project configuration.
        """
        v = self.pconfig.get(item)
        if v:
            return v
        elif DEFAULTS.has_key(item):
            return DEFAULTS[item]
        debug("Unknown configuration option: %s" % item)
        assert False

    def set(self, item, value):
        """Set an entry in the project configuration.
        """
        self.pconfig[item] = value.strip()
        self.saveconfig(self.pconfig_file, self.pconfig)


#        return True

    def get_ipath(self):
        ip = self.get('installation_dir')
        if not ip:
            ip = self.set_ipath('')[1]
        return (True, ip)

    def set_ipath(self, path):
        path = path.strip()
        if path:
            path = '/' + path.strip('/')
        else:
            path = os.environ['HOME'] + '/larch_build'
        self.set('installation_dir', path)
        return (True, path)

    def testlarchify(self):
        ipath = self.get_ipath()[1]
        path = ipath + CHROOT_DIR_MEDIUM
        bl = []
        nosave = False
        ok = (os.path.isfile(path + '/larch/system.sqf')
              and os.path.isfile(ipath + SYSLINUXDIR + '/isolinux.bin'))
        return (True, (path, ok))

    def newUserinfo(self):
        self.userInfo = Userinfo(self.profile_path)
        return (True, None)

    def allusers(self):
        return (True, self.userInfo.allusers())

    def getuserinfo(self, user, fields):
        return (True, self.userInfo.userinfo(user, fields))

    def newuser(self, user):
        return (True, self.userInfo.newuser(user))

    def saveusers(self):
        return (True, self.userInfo.saveusers())

    def userset(self, uname, field, text):
        self.userInfo.userset(uname, field, text)
        return (True, None)

    def deluser(self, user):
        return (True, self.userInfo.deluser(user))

    def listskels(self):
        return (True, glob(self.profile_path + '/skel_*'))

    def get_mediumlabel(self):
        l = self.get('medium_label')
        return (True, l if l else LABEL)

    def set_mediumlabel(self, l):
        if len(l) > 16:
            l = l[:16]
        self.set('medium_label', l)
        return self.get_mediumlabel()

    def set_bootisolabel(self, l):
        if len(l) > 32:
            l = l[:32]
        self.set('bootisolabel', l)
        return self.get_bootisolabel()

    def getisosavedir(self):
        d = self.get('isosavedir')
        return (True, d if d else os.environ['HOME'])

    def getisofile(self):
        f = self.get('isofile')
        return (True, f if f else ISOFILE)

    def getbootisofile(self):
        f = self.get('bootisofile')
        return (True, f if f else BOOTISO)

    def get_bootisolabel(self):
        l = self.get('bootisolabel')
        return (True, l if l else BOOTISOLABEL)