#! /usr/bin/env python3
# -*- coding: utf-8 -*-

"""Check and fix /home fstab entry

"""

import os
import sys
from pyeole.process import system_out

fstab = '/etc/fstab'
fb = open(fstab, 'r').readlines()
home_options = ['usrquota', 'grpquota']


def add_fstab_options(mountpoint, options=None):
    """Add options to fstab entry
    """
    if options is None:
        raise ValueError(u"Missing options to add to fstab entry.")

    if not isinstance(options, list):
        new_options = set([options])
    else:
        new_options = set(options)

    for i in range(len(fb)):
        ligne = fb[i]
        if testligne(ligne, mountpoint):
            old_string_options = ligne.split()[3]
            old_options = set(old_string_options.split(','))
            added_options = new_options - old_options

            if len(added_options) == 0:
                return True

            if 'defaults' in old_options:
                # Put default in front
                updated_options = ['defaults']
                old_options.remove('defaults')
            else:
                updated_options = []

            updated_options.extend(sorted(list(old_options | new_options)))
            updated_string_options = ",".join(updated_options)
            fb[i] = ligne.replace(old_string_options, updated_string_options)

            message_string = "Option{0} {1} ajoutée{0} à '{2}'"
            if len(added_options) > 1:
                plural = 's'
            else:
                plural = ''

            print(message_string.format(plural,
                                        ",".join(new_options - old_options),
                                        mountpoint))
            ecrire()
            remount(mountpoint)
            start_quota()
            return True
    return False


def remount(mountpoint):
    os.system('/bin/mount -o remount %s' % mountpoint)


def start_quota():
    """
    Start quota service
    """
    os.system('service quota start')


def quota_options_enabled(mountpoint):
    """
    Check if quota mount options are active on the given mountpoint.

    On recent ext4 systems, quotas may already be active after remount.
    Using findmnt avoids noisy quotaon/quotacheck output on tmpfs mounts.
    """
    cmd = ['findmnt', '-no', 'OPTIONS', '-T', mountpoint]
    eni = {"LC_ALL": "C", "LANG": "C", "PATH": "/usr/bin:/bin:/sbin:/usr/sbin"}
    code, out, err = system_out(cmd, env=eni)

    if code != 0:
        return False

    options = set(out.strip().split(','))
    return 'usrquota' in options and 'grpquota' in options


def enable_quota(mountpoint):
    """Enable quota on the selected mountpoint if needed"""
    # Avoid leaving quotaon.service in failed state.
    os.system('systemctl reset-failed quotaon.service 2>/dev/null')

    # Check only the selected mountpoint and hide known non-blocking warnings.
    os.system('quotacheck -ugfm %s 2>/dev/null' % mountpoint)

    # quotaon is noisy and returns an error if quotas are already active.
    # Only call it if the mount options are not active after remount.
    if not quota_options_enabled(mountpoint):
        os.system('quotaon -ug %s 2>/dev/null' % mountpoint)


def check_quota(mountpoint):
    """
    Check quota state during instance.

    We only need to ensure that the selected mountpoint is mounted with
    usrquota and grpquota. This avoids quotaon -a, which is noisy on recent
    systems and may inspect unrelated tmpfs mounts.
    """
    return quota_options_enabled(mountpoint)


def testligne(line, mountpoint):
    """
    recherche du point de montage "motif"
    """
    if line.startswith('#'):
        return False
    try:
        items = line.split()
        return items[1] == mountpoint
    except:
        return False


def ecrire():
    """
    Write fstab file
    """
    fh = open(fstab, 'w')
    for i in fb:
        fh.write(i)
    fh.close()

def main():
    """
    Main program, call fstab modification and quota enable.
    """
    #seulement à l'instance
    if sys.argv[-1] != 'instance':
        sys.exit(0)

    if add_fstab_options('/home', home_options):
        mountpoint = '/home'
    else:
        add_fstab_options('/', home_options)
        mountpoint = '/'

    if not check_quota(mountpoint):
        enable_quota(mountpoint)


if __name__ == "__main__":
    main()
