#! /usr/bin/perl # Copyright (C) 2005 Nick Urbanik # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use warnings; use strict; use DBI; sub logit { print STDERR @_, "\n" } sub dielog { die @_ } use constant CONFIG_FILE => "/etc/games.rc"; use constant DEBUG => 1; # The following three constants are used as keys to access parts of each # piece of data in %config. Use constants to help detect mistypings. use constant LIMIT => "limit"; use constant USERS => "users"; use constant PROCS => "procs"; our %config; our %playing_times; # The format of the configuration file is: # groupname1 user limit_seconds processname1 processname2 ... processnamen # groupname2 user limit_seconds processname1 processname2 ... processnamen # ... # Note that "group" in this program refers to something totally unrelated # to a POSIX process group. We just mean a set of programs that we place # one particular time limit on. sub read_config_orig() { open CFG, '<', CONFIG_FILE or dielog "Cannot open config file @{[CONFIG_FILE]}: $!"; while ( ) { chomp; # Comments allowed. Blank lines skipped. s/#.*$//; next if /^\s*$/; logit "read from @{[CONFIG_FILE]}: $_"; my ( $group, $user, $seconds, @procs ) = split; $seconds =~ /^\d+$/ or dielog "Bad time limit in @{[CONFIG_FILE]}: '$_'\n"; $config{$group} = { user => $user, procs => [ @procs ], seconds => $seconds }; logit "stored: group=$group, user=$user, procs=@procs, ", "seconds=$seconds" if DEBUG; } close CFG or dielog "Cannot close config file @{[CONFIG_FILE]}: $!"; } sub write_config_to_db_orig($) { my ( $dbh ) = @_; foreach my $group ( keys %config ) { my $statement = <prepare( $statement ); $sth->execute or die "Unable to execute $statement: $!"; $sth->finish; foreach my $procname ( @{$config{$group}{procs}} ) { $statement = " INSERT INTO processes ( process_name, groupname ) VALUES ( '$procname', '$group' ) "; $sth = $dbh->prepare( $statement ); $sth->execute or die "Unable to execute $statement: $!"; $sth->finish; } } } # procs groupname_1 processname_1 processname_2 ... processname_n # users groupname_1 username_1 username_2 ... username_m # limit groupname_1 seconds # procs groupname_2 processname_1 processname_2 ... processname_n # users groupname_2 username_1 username_2 ... username_m # limit groupname_2 seconds # ... sub read_config() { open CFG, '<', CONFIG_FILE or dielog "Cannot open config file @{[CONFIG_FILE]}: $!"; while ( ) { chomp; # Comments allowed. Blank lines skipped. s/#.*$//; next if /^\s*$/; logit "read from @{[CONFIG_FILE]}: $_"; my ( $line_type, $group, @data ) = split; if ( $line_type eq LIMIT ) { $config{$group}{$line_type} = shift @data; } else { $config{$group}{$line_type} = [ @data ]; } $playing_times{$group} = 0; } close CFG or dielog "Cannot close config file @{[CONFIG_FILE]}: $!"; } sub check_config() { foreach my $group ( sort keys %config ) { foreach my $line_type ( LIMIT, USERS, PROCS ) { dielog "No '$line_type' for group $group in configuration" unless exists $config{$group}{$line_type} and defined $config{$group}{$line_type}; } foreach my $line_type ( sort keys %{$config{$group}} ) { if ( $line_type eq LIMIT ) { $config{$group}{$line_type} =~ /^\d+$/ or dielog "Bad time limit '$config{$group}{$line_type}' ", "in configuration\n"; } elsif ( $line_type eq USERS ) { dielog "No users for group $group" unless @{$config{$group}{$line_type}}; foreach my $user ( @{$config{$group}{$line_type}} ) { # See ~/RPM/BUILD/shadow-4.0.3/libmisc/chkname.c, # https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=157577 dielog "Bad user name $user in group $group" unless $user =~ /^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,30}[a-zA-Z0-9_.$-]?$/; } } elsif ( $line_type eq PROCS ) { dielog "No process names for group $group" unless @{$config{$group}{$line_type}}; foreach my $proc ( @{$config{$group}{$line_type}} ) { dielog "Bad process name $proc in group $group" unless length $proc; } } } } } sub print_config() { foreach my $group ( sort keys %config ) { foreach my $line_type ( sort keys %{$config{$group}} ) { print "$line_type $group "; if ( $line_type eq "limit" ) { print "$config{$group}{$line_type}\n"; } else { print join( " ", @{$config{$group}{$line_type}} ), "\n"; } } } } sub write_config_to_db($) { my ( $dbh ) = @_; foreach my $group ( keys %config ) { my $statement = <prepare( $statement ); $sth->execute or die "Unable to execute $statement: $!"; foreach my $procname ( @{$config{$group}{PROCS()}} ) { $statement = " INSERT INTO processes ( process_name, groupname ) VALUES ( '$procname', '$group' ) "; $sth = $dbh->prepare( $statement ); $sth->execute or die "Unable to execute $statement: $!"; } foreach my $username ( @{$config{$group}{USERS()}} ) { $statement = " INSERT INTO users ( username, groupname ) VALUES ( '$username', '$group' ) "; $sth = $dbh->prepare( $statement ); $sth->execute or die "Unable to execute $statement: $!"; $sth->finish; } } $dbh->commit; } sub setup_times($\%) { my ( $dbh, $config ) = @_; foreach my $group ( keys %$config ) { my $statement = " INSERT INTO times ( groupname, group_playing_time, date ) VALUES ( '$group', 0, 'today' ) "; $dbh->do( $statement ) or die "Unable to execute $statement: $!"; } $dbh->commit; } BEGIN{ require "$ENV{HOME}/.gamesrc"; } use Sys::Hostname; our $dbhost = hostname eq DBHOST ? "localhost" : DBHOST; read_config; check_config; print_config; my $dbh = DBI->connect( "dbi:Pg:dbname=@{[DBNAME]};host=$dbhost", USER, PW, {AutoCommit => 0} ) or die "Unable to connect to $dbhost: $!"; write_config_to_db $dbh; setup_times $dbh, %config; $dbh->commit; $dbh->disconnect;