#!/opt/alt/python37/bin/python3 -bb
# -*- coding: utf-8 -*-

# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import os
import sys
import subprocess
import re
import getopt
import pwd
import csv
from future.moves import configparser as ConfigParser
import tempfile
from builtins import map
from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH

class CLQuota(object):
    '''
    Class which gets and sets users filesystem inodes quotas
    '''
    def __init__(self, fmt='txt', mp='/home', user=None, sync=False,
                 p_limits=False, package=None, soft=None, hard=None,
                 print_names=False, cache=False):
        '''
        Initialize CLQuota instance. User is UID, limits is
        a tuple of soft and hard ones. If no arguments prints quota
        statistics
        '''
        self._user       = ((user and str(user)) or '')
        self._sync       = sync
        self._plimits    = p_limits
        self._names      = print_names
        self._cache      = cache
        self._package    = package
        self._soft       = soft
        self._hard       = hard
        self._format     = fmt
        self._mountpoint = mp
        self._device     = None
        self._datafile   = '/etc/container/cl-quotas.dat'
        self._cachefile   = '/etc/container/cl-quotas.cache'
        self._quota = {}
        self._grace = {}
        self._config = {}
        self._action = {'type':'users','item':None}
        self._packages = {}
        self._packagesMembers = {}

    def doIt(self):
        '''
        Acts depending on class instance arguments
        '''
        self._getData()
         
        if self._plimits:
            self._action['type'] = 'packages'
            self._getConfigWrapper(self._getPackagesData)
            
        elif self._package and not (self._soft or self._hard):
            self._action['type'] = 'packages'
            self._action['item'] = self._package
            self._getConfigWrapper(self._getPackagesData)
            
        elif self._sync:
            self._getDataWrapper(self._synchronize)
            
        elif self._user and (self._soft or self._hard):
            self._action['item'] = self._user
            self._getDataWrapper(self._setUserLimit)
            
        elif self._package and (self._soft or self._hard):
            self._action['type'] = 'packages'
            self._action['item'] = self._package
            self._getDataWrapper(self._setPackageLimit)
            
        else:
            self._getQuotaFS()
            if self._cache:
                self._getQuotaWrapper(cache=True)
            else:
                self._getQuotaWrapper()
                self._printData()

    def _getConfigWrapper(self, routine):
        '''
        When we need to output package data there is no need in getting quotas.
        '''
        routine()

    def _getDataWrapper(self, routine):
        '''
        We need to get quotas to output user quotas
        '''
        self._getQuotaFS()
        self._getQuota()
        routine()

    def _getQuotaWrapper(self, cache=False):
        '''
        Wrapper around printing. If user is root then return current quota data.
        If not return cached data because ordinary user has no access to quota data.
        '''
        if os.geteuid() == 0:
            self._getQuota(cache)
        else:
            self._getCache()

    def _getQuotaFS(self):
        '''
        Gets mounted filesystems list and picks ones with quota on
        '''
        q = {}
        cmd = ['/bin/mount']
        patt = re.compile(r'''
            (.*)\son                # filesystem
            \s(\S+)                 # mountpoint
            [^(]*\(                 # find open paren
            .*?usrj?quota
            (?:
                =([\w\.]+)          # get quota file if any
                (?:
                    .*?=(vfs\w+)    # get quota type if any
                )?
            )?
        ''', re.VERBOSE)
        for line in self._runCommand(cmd).splitlines():
            m = patt.match(line)
            if not m:
                continue
            q[m.group(2)] = {
                'device':      m.group(1),
                'quota_file':  m.group(3),
                'quota_type':  m.group(4)
            }
        if self._mountpoint in q:
            self._device = q[self._mountpoint]['device']
        elif '/' in q:
            self._mountpoint = '/'
            self._device = q['/']['device']
        else:
            self._exitWithMessage('ERROR','Quota FS not found!')

    def _getQuota(self, cache=False):
        '''
        Gets current quota settings for further processing
        '''
        q = {}
        cmdname = '/usr/sbin/repquota'
        if not os.path.exists(cmdname):
            self._exitWithMessage(
                'ERROR', 'no such command (%s)' % (cmdname,))
        cmd = [cmdname, '-uvn', self._device]
        data = self._runCommand(cmd)
        for line in data.splitlines():
            if line.startswith('#'):
                parts = line.split()
                if parts[0] == '#0': # We do not want to limit root :)
                    continue
                q[parts[0][1:]] = { # UID without leading '#'
                    'usage_flags': parts[1],
                    'bytes_used':  parts[2],
                    'bytes_soft':  parts[3],
                    'bytes_hard':  parts[4],
                    'inodes_used': parts[5],
                    'inodes_soft': parts[6],
                    'inodes_hard': parts[7],
                }
            elif 'grace' in line:
                p = re.compile(
                    r'(block|inode)\sgrace\stime:?\s(\d[\w:]+)(?:;|$|\s)',
                    re.IGNORECASE)
                found = p.findall(line)
                if found:
                    self._grace.update(
                        dict(
                            list(map(
                                (lambda x:(x[0].lower(), x[1])),
                                found))))
        self._getDefault()
        self._quota.update(q)
        if cache:
            self._cacheData(q)

    def _getDefault(self):
        try:
            self._quota.update({'0':{
                'inodes_used': '-',
                'inodes_soft': self._config['users']['0'][0],
                'inodes_hard': self._config['users']['0'][1]}})
        except KeyError:
            self._quota.update({'0':{
                'inodes_used': '-',
                'inodes_soft': '0',
                'inodes_hard': '0'}})

    def _cacheData(self, q):
        path = os.path.dirname(self._cachefile)
        cache_order = ['bytes_used', 'bytes_soft', 'bytes_hard',
                       'inodes_used', 'inodes_soft', 'inodes_hard']
        cache_content = []
        for k in sorted(list(q.keys()), key=int):
            cache_content.append([k] + list(map((lambda x: q[k][x]),
                    cache_order)))
        try:
            fd, temp_path = tempfile.mkstemp(prefix='lvetmp_', dir=path)
            file = os.fdopen(fd, 'wb')
            csv_out = csv.writer(file, quoting=csv.QUOTE_MINIMAL)
            csv_out.writerows(cache_content)
            file.close()
        except (IOError, OSError):
            if os.path.exists(temp_path):
                os.unlink(temp_path)
            return
        try:
            mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
            os.rename(temp_path, self._cachefile)
            os.chmod(self._cachefile, mask)
        except OSError:
            pass

    def _getCache(self):
        try:
            fd = os.open(self._cachefile, os.O_RDONLY|os.O_NOFOLLOW)
            fo = os.fdopen(fd, 'rb')
            cvs_in = csv.reader(fo, delimiter=',')
        except OSError:
            return
        fields = ['bytes_used', 'bytes_soft', 'bytes_hard',
                       'inodes_used', 'inodes_soft', 'inodes_hard']
        for row in cvs_in:
            if self._user:
                if row[0] == self._user:
                    self._quota[row[0]] = dict(
                        list(map((lambda x: (fields[x], row[x+1])), range(len(fields)))))
                    break
            else:
                self._quota[row[0]] = dict(
                    list(map((lambda x: (fields[x], row[x+1])), range(len(fields)))))

    def _setUserLimit(self, username=None, save=True, sync=True):
        '''
        Sets limits for users
        '''
        user = username or self._user
        if user == '0':
            self._setDefault(save)
            return
        cmdname = '/usr/sbin/setquota'
        if not os.path.exists(cmdname):
            self._exitWithMessage(
                'ERROR', 'no such command (%s)' % (cmdname,))
        soft, hard = self._soft, self._hard
        temp_soft, temp_hard = None, None
        users = self._getPackages(True)
        if sync:
            try:
                temp_soft = (self._config['users']['0'][0] != '0'
                    and self._config['users']['0'][0])
                temp_hard = (self._config['users']['0'][1] != '0'
                    and self._config['users']['0'][1])
            except KeyError:
                pass
            for package in users[user]:
                try:
                    temp_soft = ((self._config['packages'][package][0] != '0'
                        and self._config['packages'][package][0]) or temp_soft)
                    temp_hard = ((self._config['packages'][package][1] != '0'
                        and self._config['packages'][package][1]) or temp_hard)
                except KeyError:
                    continue
            try:
                if soft is None:
                    temp_soft = ((self._config['users'][user][0] != '0'
                        and self._config['users'][user][0]) or temp_soft)
                if hard is None:
                    temp_hard = ((self._config['users'][user][1] != '0'
                        and self._config['users'][user][1]) or temp_hard)
            except KeyError:
                pass
        if not soft or (soft and soft == '0'):
            soft = temp_soft or self._quota[user]['inodes_soft']
        if not hard or (hard and hard == '0'):
            hard = temp_hard or self._quota[user]['inodes_hard']
        cmd = [
            cmdname,
            '-u', self._user,
            self._quota[user]['bytes_soft'],
            self._quota[user]['bytes_hard'],
            soft,
            hard,
            self._device
        ]
        self._runCommand(cmd)
        if save:
            if self._soft:
                soft2save = self._soft
            else:
                try:
                    soft2save = self._config['users'][user][0]
                except KeyError:
                    soft2save = '0'
            if self._hard:
                hard2save = self._hard
            else:
                try:
                    hard2save = self._config['users'][user][1]
                except KeyError:
                    hard2save = '0'
            self._saveData(soft2save, hard2save)

    def _setPackageLimit(self, packagename=None, save=True, sync=True):
        '''
        Sets limits for packages
        '''
        self._getPackages()
        std_in = []
        package = packagename or self._package
        if package not in self._packagesMembers:
            if sync:
                self._exitWithMessage(
                    'ERROR', 'no such package (%s)' % (package,))
            else:
                return
        cmdname = '/usr/sbin/setquota'
        if not os.path.exists(cmdname):
            self._exitWithMessage(
                'ERROR', 'no such command (%s)' % (cmdname,))
        cmd = [cmdname, '-bu', self._device]
        soft, hard = self._soft, self._hard
        user_soft, user_hard = None, None
        if sync:
            try:
                soft = soft or self._config['packages'][package][0]
                hard = hard or self._config['packages'][package][1]
            except KeyError:
                pass
        for uid in self._packagesMembers[package]:
            try:
                user_soft = (self._config['users']['0'][0] != '0'
                    and self._config['users']['0'][0])
                user_hard = (self._config['users']['0'][1] != '0'
                    and self._config['users']['0'][1])
            except KeyError:
                pass
            user_soft = ((soft != '0' and soft) or user_soft)
            user_hard = ((hard != '0' and hard) or user_hard)
            try:
                user_soft = ((self._config['users'][uid][0] != '0'
                    and self._config['users'][uid][0]) or user_soft)
                user_hard = ((self._config['users'][uid][1] != '0'
                    and self._config['users'][uid][1]) or user_hard)
            except KeyError:
                pass
            user_soft = (user_soft or self._quota[uid]['inodes_soft'])
            user_hard = (user_hard or self._quota[uid]['inodes_hard'])
            std_in.append(
                '%s %s %s %s %s' % (
                    uid,
                    self._quota[uid]['bytes_soft'],
                    self._quota[uid]['bytes_hard'],
                    user_soft,
                    user_hard))
            user_soft, user_hard = None, None
        std_in = ('\n'.join(std_in) + '\n')
        self._runCommand(cmd, std_in)
        if save:
            soft = soft or '0'
            hard = hard or '0'
            print(soft, hard)
            self._saveData(soft, hard)

    def _getPackages(self, collect_users=False):
        '''
        Gets map of packages and users
        '''
        users = {}
        cmdname = '/usr/bin/getcontrolpaneluserspackages'
        if not os.path.exists(cmdname):
            self._exitWithMessage(
                'ERROR', 'no such command (%s)' % (cmdname,))
        cmd = [cmdname, '--list-all']
        for line in self._runCommand(cmd).splitlines():
            uid, package = list(map((lambda x: x.strip()),line.split(' ', 1)))
            if not package in self._packagesMembers:
                self._packagesMembers[package] = []
            self._packagesMembers[package].append(uid)
            if collect_users:
                if not uid in users:
                    users[uid] = []
                users[uid].append(package)
        return users

    def _runCommand(self, cmd, std_in=None):
        '''
        Runs an external command and returns result
        '''
        if not type(cmd) is list:
            return None
        if not std_in:
            stdin_arg = open('/dev/null')
        else:
            stdin_arg = subprocess.PIPE
        output = subprocess.Popen(
            cmd,
            stdin=stdin_arg,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            close_fds=True)
        if not std_in:
            std_out, std_err = output.communicate()
        else:
            std_out, std_err = output.communicate(std_in)
        if output.returncode != 0:
            self._exitWithMessage(
                'ERROR', 'command failed:\n%s' % (
                    ((std_err and std_err) or std_out),),
                output.returncode)
        return std_out

    def _filterUser(self):
        '''
        filter out all but specified user
        '''
        if self._user is not None and self._user in self._quota:
            self._quota = {self._user:self._quota[self._user]}
    

    def _printData(self, data=None):
        '''
        Wrapper around printing subroutines, picking right
        handler and delegating printing task to it
        '''
        dispatcher = {
        #    'json':self.printJSON,
        #    'perl':self.printPerl,
            'csv' :self._printCSV,
            'text':self._printText
        }
        self._filterUser()
        dispatcher[self._format](data)

    def _printText(self, data=None):
        '''
        Prints data as pure text
        '''
        if data:
            print("%s:%s" % ( data['status'], data['message'] ))
        else:
            item_id = ((self._action['type'] == 'users' and 'id') or 'package')
            fields = [item_id, 'inodes_used', 'inodes_soft', 'inodes_hard']
            fmt_list = ['%32s']
            fmt_list.extend(['%16s'] * (len(fields)-1))
            fmt = ''.join(fmt_list)
            print(fmt % tuple(fields))
            print('-' * 80)
            sort_key = ((self._action['type'] == 'users' and int) or str)
            if self._names:
                self._convertToNames()
                sort_key=str
            for data_id in sorted(list(self._quota.keys()), key=sort_key):
                row = [data_id]
                row.extend(
                    list(map(
                        (lambda x:self._quota[data_id][x]),
                        fields[1:])))
                print(fmt % tuple(row))

    def _printCSV(self, data=None):
        '''
        Prints data as comma separated values
        '''
        if data:
            csv_out = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
            csv_out.writerow(
                ['status', data['status'], 'message', data['message']])
        else:
            item_id = ((self._action['type'] == 'users' and 'id') or 'package')
            csv_out = csv.writer(sys.stdout, quoting=csv.QUOTE_MINIMAL)
            fields = [item_id, 'inodes_used', 'inodes_soft', 'inodes_hard']
            fmt = ','.join(['%s'] * len(fields))
            sort_key = ((self._action['type'] == 'users' and int) or str)
            if self._names:
                self._convertToNames()
                sort_key=str
            print(fmt % tuple(fields))
            for data_id in sorted(list(self._quota.keys()), key=sort_key):
                row = [data_id]
                row.extend(
                    list(map(
                        (lambda x: self._quota[data_id][x]),
                        fields[1:])))
                csv_out.writerow(row)

    def _getPackagesData(self):
        '''
        Returns packages limits summary
        '''
        self._getPackages()
        if self._action['item']:
            p = self._action['item']
            s = self._action['type']
            if p in self._packagesMembers:
                self._quota[p] = {}
                try:
                    soft, hard = self._config[s][p]
                except KeyError:
                    soft, hard = 0, 0
                self._quota[p]['inodes_used'] = '-'
                self._quota[p]['inodes_soft'] = soft
                self._quota[p]['inodes_hard'] = hard
            elif (self._action['item'] not in self._packagesMembers and
                    self._action['item'] == 'default'):
                self._addEmptyDefault()
        else:
            for package in self._packagesMembers:
                self._quota[package] = {}
                self._quota[package]['inodes_used'] = '-'
                try:
                    soft, hard = self._config['packages'][package]
                except KeyError:
                    soft, hard = 0, 0
                self._quota[package]['inodes_soft'] = soft
                self._quota[package]['inodes_hard'] = hard
            if 'default' not in self._quota:
                self._addEmptyDefault()
        self._printData()

    def _addEmptyDefault(self, package='default'):
        '''
        We need to output default package even if no users in it
        That's why such a nonsense
        '''
        self._quota[package] = {}
        self._quota[package]['inodes_used'] = '-'
        self._quota[package]['inodes_soft'] = '0'
        self._quota[package]['inodes_hard'] = '0'
    
    def _setDefault(self, save=True):
        '''
        Sets limits for packages
        '''
        users = self._getPackages(True)
        std_in = []
        cmdname = '/usr/sbin/setquota'
        if not os.path.exists(cmdname):
            self._exitWithMessage(
                'ERROR', 'no such command (%s)' % (cmdname,))
        cmd = [cmdname, '-bu', self._device]
        soft, hard = self._soft, self._hard
        user_soft, user_hard = None, None
        for uid in users:
            for package in users[uid]:
                try:
                    user_soft = (self._config['packages'][package][0] != '0'
                        and self._config['packages'][package][0])
                    user_hard = (self._config['packages'][package][1] != '0'
                        and self._config['packages'][package][1])
                except KeyError:
                    continue
            try:
                user_soft = ((self._config['users'][uid][0] != '0'
                    and self._config['users'][uid][0]) or user_soft)
                user_hard = ((self._config['users'][uid][1] != '0'
                    and self._config['users'][uid][1]) or user_hard)
            except KeyError:
                pass
            user_soft = (user_soft or soft or self._quota[uid]['inodes_soft'])
            user_hard = (user_hard or hard or self._quota[uid]['inodes_hard'])
            std_in.append('%s %s %s %s %s' % (
                uid,
                self._quota[uid]['bytes_soft'],
                self._quota[uid]['bytes_hard'],
                user_soft,
                user_hard))
            user_soft, user_hard = None, None
        std_in = ('\n'.join(std_in) + '\n')
        self._runCommand(cmd, std_in)
        if save:
            soft = soft or '0'
            hard = hard or '0'
            self._saveData(soft, hard)

    def _synchronize(self):
        '''
        Read limits from file and applies them to packages and users
        '''
        dispatch_table = {
            'packages':self._setPackageLimit,
            'users':   self._setUserLimit
        }
        sync_order = ['packages', 'users']
        cp = ConfigParser.ConfigParser(interpolation=None, strict=False)
        if not cp.read(self._datafile):
            return
        # Applying defaults and synchronizing are the same. No need to synchronize
        # twice.
        try:
            self._soft, self._hard = cp.get(
                        'users', '0').split(':', 1)
            dispatch_table['users']('0', save=False, sync=False)
            return
        except (ConfigParser.NoSectionError,ConfigParser.NoOptionError):
            pass
        for sync_item in sync_order:
            self._action['type'] = sync_item
            if cp.has_section(sync_item):
                for opt_item in cp.options(sync_item):
                    self._action['item'] = opt_item
                    self._soft, self._hard = cp.get(
                        sync_item, opt_item).split(':', 1)
                    dispatch_table[sync_item](opt_item, save=False, sync=False)

    def _convertToNames(self):
        '''
        Converts UIDs to names for printing
        '''
        temp = {}
        if self._action['type'] == 'users':
            for uid in self._quota:
                if uid == '0':
                    temp['default'] = self._quota[uid]
                    continue
                try:
                    name = pwd.getpwuid(int(uid)).pw_name
                    temp[name] = self._quota[uid]
                except KeyError:
                    temp[uid] = self._quota[uid]
                
            self._quota = {}
            self._quota.update(temp)

    def _getData(self):
        '''
        Gets saved data
        '''
        cp = ConfigParser.ConfigParser(interpolation=None, strict=False)
        cp.optionxform = str
        cp.read(self._datafile)
        for section in cp.sections():
            if not section in self._config:
                self._config[section] = {}
            for option in cp.options(section):
                self._config[section][option] = tuple(
                    cp.get(section, option).split(':'))

    def _saveData(self, soft, hard):
        '''
        Saves users and packages data to a file
        '''
        cp = ConfigParser.ConfigParser(interpolation=None, strict=False)
        cp.optionxform = str
        cp.read(self._datafile)
        if soft == '0' and hard == '0':
            try:
                cp.remove_option(self._action['type'], self._action['item'])
            except ConfigParser.NoSectionError:
                pass
        else:
            if not cp.has_section(self._action['type']):
                cp.add_section(self._action['type'])
            cp.set(self._action['type'], self._action['item'], 
                   '%s:%s' % (soft, hard))
        try:
            cp.write(open(self._datafile,'wb'))
        except (OSError, IOError):
            self._exitWithMessage(
                'ERROR', 'Could not save data')

    def _exitWithMessage(self, status, message, code=None):
        '''
        Prints message and exits with provided exit code if any
        If no code exits with code 1
        '''
        if not code:
            code = 1
        self._printData({'status':status,'message':message})
        sys.exit(code)


def checkUser(fmt, user=None, uid=None):
    '''
    checks uid or username whichever is given
    and returns uid (in case of username, converted to uid)
    '''
    p = re.compile(r'(\d+)')
    if uid:
        pm = p.search(uid)
        if not pm:
            CLQuota(fmt)._exitWithMessage('ERROR','illegal UID (%s)' % (uid,))
        uid = pm.group(1)
        if uid == '0': # this is default. No need to check further
            return uid
        try:
            pwd.getpwuid(int(uid))
        except KeyError:
            CLQuota(fmt)._exitWithMessage('ERROR', 'no such UID (%s)' % (uid,))
        return uid
    if user:
        if user.lower() == 'default':
            return '0'
        try:
            uid = pwd.getpwnam(user).pw_uid
        except KeyError:
            CLQuota(fmt)._exitWithMessage('ERROR', 'no such user (%s)' % (user,))
        return uid

def usage():
    print('')
    print('Usage: ' + sys.argv[0] + ' [OPTIONS]')
    print('If no options given prints guota statistics for all users')
    print('Options:')
    print('')
    print(' -u | --user           : specifies the user')
    print(' -U | --user-id        : specifies the user ID')
    print(' -N | --print-names    : print user names instead of UIDs')
    print (' -S | --soft-limit     : sets the soft limit for a user. '
          'Pass 0 to cancel soft limit')
    print (' -H | --hard-limit     : sets the hard limit for a user. '
           'Pass 0 to cancel hard limit')
    print(' -V | --csv            : returns data as comma separated values')
    print (' -M | --mount-point    : specifies mount point. By default \'/ho'
           'me\' is used. If single filesystem or no \'/home\' \'/\' is used')
    print(' -p | --package        : specifies a package to set or get limits')
    print(' -P | --package-limits : prints package limits')
    print (' -Y | --sync           : synchronizes packages and users limits with'
           ' the database')
    print (' -C | --cache-content  : cache quota data to a file'
           ' the database')
    print('')

def main():
    config = {}
    config['user']          = None
    config['uid']           = None
    config['package']       = None
    config['soft']          = None
    config['hard']          = None
    config['sync']          = False
    config['packagelimits'] = False
    config['printnames']    = False
    config['cache']         = False
    config['format']        = 'text'
    config['mountpoint']    = '/home'
    
    try:
        opts, args = getopt.getopt(
            sys.argv[1:],
            'CNYVPu:U:H:S:M:p:',
            ['cache-content', 'print-names', 'sync', 'csv', 'package-limits',
                'user=', 'user-id=', 'soft-limit=', 'hard-limit=',
                'mount-point=', 'package=']
        )
    except getopt.GetoptError:
        usage()
        sys.exit(1)

    for o, a in opts:
        if o in ['-u', '--user']:
            config['user'] = a
        elif o in ['-U', '--user-id']:
            config['uid'] = a
        elif o in ['-S', '--soft-limit']:
            config['soft'] = a
        elif o in ['-H', '--hard-limit']:
            config['hard'] = a
        elif o in [ '-V',  '--csv' ]:
            config['format'] = 'csv'
        elif o in [ '-M',  '--mount-point' ]:
            config['mountpoint'] = a
        elif o in [ '-p',  '--package' ]:
            config['package'] = a
        elif o in [ '-P',  '--package-limits' ]:
            config['packagelimits'] = True
        elif o in [ '-N',  '--print-names' ]:
            config['printnames'] = True
        elif o in [ '-Y',  '--sync' ]:
            config['sync'] = True
        elif o in [ '-C',  '--cache-content' ]:
            config['cache'] = True
    
    uid_for_test = list([config[x] for x in ['format', 'user', 'uid']])
    uid = checkUser(*uid_for_test)
    q = CLQuota(config['format'], config['mountpoint'], uid, config['sync'],
                config['packagelimits'], config['package'], config['soft'],
                config['hard'], config['printnames'], config['cache'])
    q.doIt()

if __name__ == '__main__':
    main()
