#!/usr/bin/env perl # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; } use lib "$::XCATROOT/lib/perl"; use xCAT::Table; use xCAT::NodeRange; use Getopt::Long; use strict; #This or something like this must always be available and not depend on server #Otherwise, can't set things to let server run in the first place # sub usage { print "Usage:\n"; print " To add or update rows for tables: chtab keycolname=keyvalue[,keycolname=keyvalue...] tablename.colname=newvalue [tablename.colname=newvalue...]\n"; print " To delete rows from tables: chtab -d|--delete keycolname=keyvalue[,keycolname=keyvalue...] tablename [tablename...]\n"; print " To display usage and other information: chtab [-h|--help|-v|--Version]\n\n"; print " -d|--delete Delete the rows from a list of tables. -v|--version Display the version of this command. -h|--help Display this usage information. keycolname=keyvalue a column name-and-value pair that identifies the rows in a table to be changed. tablename.colname=newvalue the new value for the specified row and column of the table.\n"; } my %tables; # options can be bundled up like -vV Getopt::Long::Configure("bundling"); $Getopt::Long::ignorecase = 0; # parse the options if (!GetOptions( 'd|delete' => \$::DELETE, 'h|help' => \$::HELP, 'v|version' => \$::VERSION,)) { &usage; exit(1); } # display the usage if -h or --help is specified if ($::HELP) { &usage; exit(0); } # display the version statement if -v or --verison is specified if ($::VERSION) { my $version = xCAT::Utils->Version(); print "chtab $version\n"; exit(0); } my $target = shift @ARGV; unless ($target) { usage; exit(1); } my $current_userid = getpwuid($>); if ($current_userid ne "root") { print "WARNING: chtab bypasses xcatd and does not enforce xCAT policy tables. Consider using tabch instead.\n"; } my %keyhash = (); my @keypairs = split(/,/, $target); if ($keypairs[0] !~ /([^\.\=]+)\.([^\.\=]+)\=(.+)/) { foreach (@keypairs) { m/(.*)=(.*)/; my $key = $1; my $val = $2; if (!defined($key) || !defined($val)) { print "Incorrect argument \"$_\".\n"; usage; exit(1); } $keyhash{$key} = $val; } } else { unshift(@ARGV, $target); } if ($::DELETE) { #delete option is specified my @tables_to_del = @ARGV; if (@tables_to_del == 0) { print "Missing table name.\n"; usage; exit(1); } for (@tables_to_del) { $tables{$_} = xCAT::Table->new($_, -create => 1, -autocommit => 0); $tables{$_}->delEntries(\%keyhash); $tables{$_}->commit; } } else { #update or create option my %tableupdates; for (@ARGV) { my $temp; my $table; my $column; my $value; ($table, $temp) = split('\.', $_, 2); #try to create the entry if it doesn't exist unless ($tables{$table}) { my $tab = xCAT::Table->new($table, -create => 1, -autocommit => 0); if ($tab) { $tables{$table} = $tab; } else { print "Table $table does not exist.\n"; exit(1); } } #splice assignment if (grep /\+=/, $temp) { ($column, $value) = split('\+=', $temp, 2); #grab the current values to check against my ($attrHash) = $tables{$table}->getAttribs(\%keyhash, $column); my @existing = split(",", $attrHash->{$column}); #if it has values, merge the new and old ones together so no dupes if (@existing) { my @values = split(",", $value); my %seen = (); my @uniq = (); my $item; foreach $item (@existing, @values) { unless ($seen{$item}) { # if we get here, we have not seen it before $seen{$item} = 1; push(@uniq, $item); } } $value = join(",", @uniq); } } #normal non-splicing assignment else { ($column, $value) = split("=", $temp, 2); } $tableupdates{$table}{$column} = $value; } #commit all the changes foreach (keys %tables) { if (exists($tableupdates{$_})) { my $rc = $tables{$_}->setAttribs(\%keyhash, \%{ $tableupdates{$_} }); if ($rc) { $::exitcode = 1; } } $tables{$_}->commit; } } if ($::exitcode) { exit $::exitcode; }