<commit_before>package QnMSG; 

use strict; 
use warnings; 

use IO::File; 
use IO::Pipe; 
use Exporter qw(import); 
use File::Basename; 
use List::Util qw(sum); 

# symbol 
our @system = qw( get_user get_host get_pestat get_partition ); 
our @task   = qw( get_disk_usage scan_zombie ); 
our @output = qw( print_status print_disk_usage send_mail ); 

# default import (all) 
our @EXPORT = ( @system, @output, @task ); 
# tag import 
our %EXPORT_TAGS = ( 
    system => \@system,
    output => \@output,
    task   => \@task,
); 

##########
# SYSTEM #
##########

# get hash of user 
# arg : 
#   - none 
# return: 
#   - hash of user (home => { user => homedir })
sub get_user { 
    my %passwd; 

    my $passwd = IO::File->new('/etc/passwd', 'r') 
        or die "Cannot open /etc/passwd\n"; 

    while ( <$passwd> ) { 
        chomp; 
        if ( /\/home2?\// ) { 
            my ($user, $homedir) = (split ':')[0,5]; 
            my $home = dirname($homedir); 
            $passwd{$home}{$user} = $homedir; 
        }
    }
    $passwd->close; 
    
    return %passwd; 
}

# get local host from /etc/mail/local-host-names 
# args: 
#   - none 
# return: 
#   - hostname 
sub get_host { 
    my @hosts; 

    my $hostname = IO::File->new('/etc/mail/local-host-names', 'r') 
        or die "Cannot open /etc/mail/local-host-names\n"; 

    while ( <$hostname> ) { 
        chomp; 
        # skip the comment
        next if /^\s*#/; 
        push @hosts, $_; 
    }
    $hostname->close; 
    
    # get the first host
    return $hosts[0]; 
}

# get node status of nodes 
# args: 
#   - none 
# return: 
#   - hash ( node => status )
sub get_pestat { 
    my %pestat; 

    # pipe to pestat 
    my $pestat = IO::Pipe->new; 
    $pestat->reader('pestat') or die "Cannot pipe to pestat\n"; 

    while ( <$pestat> ) { 
        chomp; 
        # skip the header 
        if ( /node\s+state/ ) { next }
        # %node: ( id => status )
        my ($node_id, $node_status) = (split)[0,1]; 
        $pestat{$node_id} = $node_status; 
    }
    $pestat->close; 

    return %pestat; 
}

# get partition
# arg: 
#   - none 
# return: 
#   - hash ( partition => size )
sub get_partition { 

    # pipe to df 
    my $df = IO::Pipe->new;  
    $df->reader('df -B G') or die "Cannot open pipe to df\n"; 

    my @output = <$df>; 
    $df->close; 
    
    # remove output header 
    shift @output; 
    my %df = map { (split)[-1,1] } @output; 

    # strip the suffix G 
    my @partitions = sort keys %df; 
    @df{@partitions} = map { $1 if $df{$_} =~ /(\d+)G/ } @partitions; 

    return %df;  
}

########
# TASK #
########

# get users' disk usage 
# arg: 
#   - hash ref passwd {user => homedir}<commit_msg>Remove die statements of IO::Pipe->reader<commit_after>package QnMSG; 

use strict; 
use warnings; 

use IO::File; 
use IO::Pipe; 
use Exporter qw(import); 
use File::Basename; 
use List::Util qw(sum); 

# symbol 
our @system = qw( get_user get_host get_pestat get_partition ); 
our @task   = qw( get_disk_usage scan_zombie ); 
our @output = qw( print_status print_disk_usage send_mail ); 

# default import (all) 
our @EXPORT = ( @system, @output, @task ); 
# tag import 
our %EXPORT_TAGS = ( 
    system => \@system,
    output => \@output,
    task   => \@task,
); 

##########
# SYSTEM #
##########

# get hash of user 
# arg : 
#   - none 
# return: 
#   - hash of user (home => { user => homedir })
sub get_user { 
    my %passwd; 

    my $passwd = IO::File->new('/etc/passwd', 'r') 
        or die "Cannot open /etc/passwd\n"; 

    while ( <$passwd> ) { 
        chomp; 
        if ( /\/home2?\// ) { 
            my ($user, $homedir) = (split ':')[0,5]; 
            my $home = dirname($homedir); 
            $passwd{$home}{$user} = $homedir; 
        }
    }
    $passwd->close; 
    
    return %passwd; 
}

# get local host from /etc/mail/local-host-names 
# args: 
#   - none 
# return: 
#   - hostname 
sub get_host { 
    my @hosts; 

    my $hostname = IO::File->new('/etc/mail/local-host-names', 'r') 
        or die "Cannot open /etc/mail/local-host-names\n"; 

    while ( <$hostname> ) { 
        chomp; 
        # skip the comment
        next if /^\s*#/; 
        push @hosts, $_; 
    }
    $hostname->close; 
    
    # get the first host
    return $hosts[0]; 
}

# get node status of nodes 
# args: 
#   - none 
# return: 
#   - hash ( node => status )
sub get_pestat { 
    my %pestat; 

    # pipe to pestat 
    my $pestat = IO::Pipe->new; 
    $pestat->reader('pestat');  

    while ( <$pestat> ) { 
        chomp; 
        # skip the header 
        if ( /node\s+state/ ) { next }
        # %node: ( id => status )
        my ($node_id, $node_status) = (split)[0,1]; 
        $pestat{$node_id} = $node_status; 
    }
    $pestat->close; 

    return %pestat; 
}

# get partition
# arg: 
#   - none 
# return: 
#   - hash ( partition => size )
sub get_partition { 

    # pipe to df 
    my $df = IO::Pipe->new;  
    $df->reader('df -B G'); 

    my @output = <$df>; 
    $df->close; 
    
    # remove output header 
    shift @output; 
    my %df = map { (split)[-1,1] } @output; 

    # strip the suffix G 
    my @partitions = sort keys %df; 
    @df{@partitions} = map { $1 if $df{$_} =~ /(\d+)G/ } @partitions; 

    return %df;  
}

########
# TASK #
########

# get users' disk usage 
# arg: 
#   - hash ref passwd {user => homedir}
{'fraction_non_alphanumeric': 0.17378388414407725, 'fraction_numerical': 0.0033419977720014855, 'mean_word_length': 2.0400677200902932, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 50, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2662252', 'n_tokens_mistral': 2157, 'n_tokens_neox': 2025, 'n_words': 512}