#!/usr/bin/perl

# --------------------------------------------------------------
# Prontus CMS
# http://www.prontus.cl
# by Altavoz.net
#
# licensed under LGPL license.
# http://www.prontus.cl/license.html
# --------------------------------------------------------------

#-------------------------------COMENTARIO GLOBAL---------------
#---------------------------------------------------------------
# PROPOSITO.
#---------------------------------------------------------------

#---------------------------------------------------------------
# DIRECTIVAS DE COMPILACION.
#---------------------------
package lib_quota;

use strict;
use utf8;
use prontus_varglb;

#---------------------------------------------------------------#
# SUB-RUTINAS.
#---------------------------------------------------------------#
sub calcula_unix {
    my $bgbar         = '';
    my $usado         = '';
    my $quota_asig    = '';
    my $custom_msg    = '';
    my $total_array   = 0;
    my $count         = 1;
    my $custom_result = 0;

    $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'SCRIPT_QUOTA'} =~ s/\.\.//g;
    $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'SCRIPT_QUOTA'} =~ s/ +//g;
    # Si existe el script de cálculo
    if ($prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'SCRIPT_QUOTA'}) {
        my $rutascript = "$prontus_varglb::DIR_SERVER$prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'SCRIPT_QUOTA'}";
        if (-f $rutascript) {
            if ($rutascript =~ /\.php$/) {
                $rutascript = 'php ' . $rutascript;
            }
            # Si el script funciona, lo ejecuta enviando el nombre del prontus y el DIR_SERVER
            my $res = `$rutascript $prontus_varglb::PRONTUS_ID $prontus_varglb::DIR_SERVER`;

            if ($res && $res =~ /^(\d+)\|(\d+)/) {
                ($usado, $quota_asig) = ($1, $2);

            } elsif ($res && $res =~ /^(.*)|(.*)|(.*),?/) {
                my @discos = split(",", $res);
                if (scalar @discos) {
                    $total_array = scalar(@discos);
                    foreach my $disco (@discos) {
                        my @item = split(/\|/, $disco);

                        if (scalar @item == 3) {
                            if ($item[1] > $item[2]) {
                                $custom_msg .= "<strong>$item[0]:</strong> Cuota sobrepasada.";
                            } else {
                                $custom_msg .= "<strong>$item[0]\:</strong> " . lib_quota::format_bytes($item[1]) . " / " . lib_quota::format_bytes($item[2]);
                                if ($count < $total_array) {
                                    $custom_msg .= " | ";
                                }
                            }
                        } else {
                            print STDERR "Script Quota no valido: [$res]\n";
                        }
                        $count++;
                    }
                    $custom_result = 1;
                } else {
                    if ($2 > $3) {
                        $custom_msg .= "<strong>$1:</strong> Cuota sobrepasada.";
                    } else {
                        $custom_msg = "<strong>$1\:</strong> " . &lib_quota::format_bytes($2) . " / " . &lib_quota::format_bytes($3);
                    }

                    $custom_result = 1;
                }

            } else {
                print STDERR "Script Quota no valido: [$res]\n";
            }
        }
    }

    if (-f '/usr/bin/quota') {
        # Valida que los campos no sean vacios.
        unless (($usado) && ($quota_asig)) {
            ($usado, $quota_asig) = &procesa_command_quota('/usr/bin/quota -v 2>/dev/null');
        }

        # Valida que los campos no sean vacios.
        unless (($usado) && ($quota_asig)) {
            ($usado, $quota_asig) = &procesa_command_quota('/usr/bin/quota -g 2>/dev/null');
        }
    }

    unless (($usado) && ($quota_asig)) {
        ($usado, $quota_asig) = &procesa_quota_vps();
    }

    unless (($usado) && ($quota_asig)) {
        return '<strong>Espacio en disco:</strong> Informaci&oacute;n no disponible.';
    }

    # Caso de cuota sobrepasada.
    if ($usado > $quota_asig) {
        return '<strong>Espacio en disco:</strong> Cuota sobrepasada.';
    }

    # Calcula porcentaje del espacio usado.
    my $usado_porc = ($usado * 100) / $quota_asig;
    # Quita los decimales.
    $usado_porc = sprintf("%.1f", $usado_porc);
    # Calcula porcentaje del espacio disponible.
    my $nousado_porc = 100 - $usado_porc;
    $usado_porc   .= '%';
    $nousado_porc .= '%';

    if ($custom_result) {
        return ($custom_msg, $usado, $quota_asig, $usado_porc, $nousado_porc);
    } else {
        return ('', $usado, $quota_asig, $usado_porc, $nousado_porc);
    }
};    # calcula_unix

# ------------------------------------------------------------------------------------- #
sub procesa_command_quota {

    my $command = shift;
    my $largo;    # 1.1
    my ($usado, $quota_asig);

    my @quota_out = `$command`;

    # Disk quotas for user lan000 (uid 2800):  Para Altavoz
    #      Filesystem   usage   quota   limit   grace   files   quota   limit   grace
    #          /sites13834022 2560000025600000          765811       0       0
    # Disk quotas for group group2550 (gid 2550):  Para T1
    #      Filesystem  blocks   quota   limit   grace   files   quota   limit   grace
    #          /dev/sda4  441356  512000  512000            3534       0       0
    if ($#quota_out >= 2) {
        # 1.4 - Para manejar el T1 que usa sda4
        if ($quota_out[2] =~ /(\d{2,})\s+(\d{2,})/) {    # 1.1 Toma solo los dos primeros numeros.
            $usado      = $1;
            $quota_asig = $2;
            # 1.1 Si la cuota asignada es muy grande (o sea, los numeros se pegaron), la parte en dos y toma el primer numero.
            $largo = length($quota_asig);
            if ($largo > 10) {
                $quota_asig = substr($quota_asig, 0, int($largo / 2));
            }
        } elsif ($quota_out[3] =~ /(\d{2,})\s+(\d{2,})/) {
            $usado      = $1;
            $quota_asig = $2;
            # 1.1 Si la cuota asignada es muy grande (o sea, los numeros se pegaron), la parte en dos y toma el primer numero.
            $largo = length($quota_asig);
            if ($largo > 10) {
                $quota_asig = substr($quota_asig, 0, int($largo / 2));
            }
        }
    }
    # return (441856, 512000);
    return ($usado, $quota_asig);
}

# ------------------------------------------------------------------------------------- #
sub procesa_quota_vps {
    my ($usado, $quota_asig, $disponible);
    my ($usado_raiz, $disponible_raiz);

    my $df = `df -T | grep -v tmpfs`;
    if (!$df) {
        if ($prontus_varglb::DIR_SERVER =~ /^\/sites\//) {
            $df = `df -t notmpfs | grep '/sites'`;
            if ($df =~ /(\d+)\s+(\d+)\s+(\d+)\s+\d+%\s+/) {
                my $usado      = $2;
                my $disp       = $3;
                my $quota_asig = $usado + $disp;
                return ($usado, $quota_asig);
            }
        }
        return ('', '');
    }

    my @lineas_df = split(/\n/, $df);
    shift @lineas_df;    # quitar cabecera.
    return ('', '') if (scalar @lineas_df == 0);

    my @parts = split(/\//, $prontus_varglb::DIR_SERVER);

    for (my $i = scalar @parts; $i > 0; $i--) {
        my $document_root = join('/', @parts);
        # Tratar de buscar el punto de montaje en base al document root.
        # por ejemplo comienza con:
        # /var/www/sitios/xxxx
        # /var/www/sitios
        # /var/www
        # /var
        # /
        # hasta dar con alguno
        foreach my $linea (@lineas_df) {
            if ($linea =~ /(\d+)\s+(\d+)\s+(\d+)%\s+(\/.*)/) {
                $usado      = $1;
                $disponible = $2;
                my $montaje = $4;

                # Los guardamos, en caso de que no haya match!, usar por defecto la particion raiz.
                if ($montaje eq '/') {
                    $usado_raiz      = $usado;
                    $disponible_raiz = $disponible;
                }

                # busca el punto de montaje que contiene lo mas posible del document root
                # print STDERR "montaje[$montaje] document_root[$document_root]\n";
                if ($montaje eq $document_root) {
                    # print STDERR "match! document_root[$document_root] = montaje[$montaje]\n";
                    $quota_asig = $usado + $disponible;
                    last;
                }
            }
        }

        last if ($quota_asig);
        pop @parts;
    }

    if (!$quota_asig) {
        # print STDERR "[lib_quota] Usando valores de la particion raiz\n";
        $usado      = $usado_raiz;
        $quota_asig = $usado_raiz + $disponible_raiz;
    }

    return ($usado, $quota_asig);
}


# ------------------------------------------------------------------------------------- #
sub format_bytes {
    my $espacio = shift;
    # Conversion a Megas.
    my $espacio_final = $espacio / 1024;
    my $unidad        = ' MiB';
    if ($espacio_final >= 1024) {
        $espacio_final = $espacio_final / 1024;
        $unidad        = ' GiB';
        if ($espacio_final >= 1024) {
            $espacio_final = $espacio_final / 1024;
            $unidad        = ' TiB';
        }
    }
    $espacio_final = lib_prontus::format_number($espacio_final);
    if ($espacio_final) {
        return $espacio_final . $unidad;
    } else {
        return '0 B';
    }
}

# Revisa si hay cuota suficiente para publicar, siempre que esta se pueda calcular
sub check_quota_suficiente {

    my ($msg, $usado_bytes, $quota_asig_bytes, $usado_porc, $nousado_porc) = &lib_quota::calcula_unix();
    # my ($msg, $usado_mb, $quota_asig_mb, $usado_porc, $nousado_porc) = ('', 111, 222, '98%', '60%');# debug
    # cuota se pudo calcular; el espacio libre, debe ser mayor a 500MiB
    my $libre_bytes = $quota_asig_bytes - $usado_bytes;

    if ($msg eq '' && $libre_bytes < 512000) {
        return "No es posible completar la operación porque no hay espacio suficiente en el disco: $usado_porc en uso.<br />Espacio utilizado: ". &format_bytes($usado_bytes) ." / Espacio libre: ". &format_bytes($libre_bytes);
    }
    return '';
}

1;
