#!/usr/bin/perl # Read and edit PostgreSQL config files # vim:sw=4:et: # # (C) 2014-2017 Christoph Berg # # 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. use strict; use warnings; use Getopt::Long; use PgCommon qw(quote_conf_value user_cluster_map read_cluster_conf_file read_conf_file set_conffile_value set_conf_value disable_conffile_value disable_conf_value cluster_exists error config_bool); ## option parsing sub help ($;$) { my ($exit, $error) = @_; print STDERR "Error: $error\n" if ($error); print "Usage: $0 [options] [ ] [] Options: -b --boolean Format output as boolean -s --short Print only value -v --verbose Verbose output --help This help Commands: show |all set remove edit "; exit $exit; } my $boolean = 0; my $short = 0; my $verbose = 0; Getopt::Long::Configure ("bundling"); help(1) unless GetOptions ( 'help' => sub { help(0); }, 'b|boolean' => \$boolean, 's|short' => \$short, 'v|verbose' => \$verbose, ); # find command in argument array my $cmdidx; for (my $i = 0; $i < @ARGV; $i++) { if ($ARGV[$i] =~ /^(show|get|set|remove|delete|disable|edit)$/) { $cmdidx = $i; last; } } help(1, 'No command given') unless (defined $cmdidx); my ($version, $cluster, $conffile); if ($cmdidx == 0) { # operate on postgresql.conf in default cluster ($version, $cluster) = user_cluster_map(); error "No default cluster found" unless ($cluster); $conffile = 'postgresql.conf'; } elsif ($cmdidx == 1) { # operate on given file; default cluster must exist if file is relative $conffile = $ARGV[0]; unless ($conffile =~ m!^/!) { ($version, $cluster) = user_cluster_map(); error "No default cluster found" unless ($cluster); } } elsif ($cmdidx == 2) { # version cluster, postgresql.conf ($version, $cluster, $conffile) = ($ARGV[0], $ARGV[1], 'postgresql.conf'); } elsif ($cmdidx == 3) { # version cluster conffile ($version, $cluster, $conffile) = ($ARGV[0], $ARGV[1], $ARGV[2]); } else { help(1, 'Too many arguments before command'); } if ($cluster) { # the cluster needs to exist unless an absolute conffile was given error "Cluster $version $cluster does not exist" unless (cluster_exists $version, $cluster); } splice @ARGV, 0, $cmdidx; # remove everything before the command $ARGV[0] = 'show' if ($ARGV[0] eq 'get'); # accept alternative variants of some commands $ARGV[0] = 'remove' if ($ARGV[0] =~ /delete|disable/); my ($cmd, $key, $value); if ($ARGV[0] =~ /^(edit)$/) { help(1, "$ARGV[0] takes no argument") unless (@ARGV == 1); ($cmd) = @ARGV; } elsif ($ARGV[0] =~ /^(show|remove)$/) { help(1, "$ARGV[0] needs exactly one argument") unless (@ARGV == 2); ($cmd, $key) = @ARGV; } else { help(1, "$ARGV[0] needs exactly two arguments") unless (@ARGV == 3); ($cmd, $key, $value) = @ARGV; } #print "$version $cluster $conffile $cmd $key $value\n"; ## main if ($cmd eq 'show') { my %conf; if ($conffile =~ m!^/!) { %conf = read_conf_file ($conffile); } else { %conf = read_cluster_conf_file ($version, $cluster, $conffile); } if ($key eq 'all') { foreach my $k (sort keys %conf) { printf "%s = %s\n", $k, quote_conf_value($conf{$k}); } } elsif (exists $conf{$key}) { $conf{$key} = config_bool($conf{$key}) ? 'on' : 'off' if ($boolean); # normalize boolean output on request if ($short) { printf "%s\n", $conf{$key}; } else { printf "%s = %s\n", $key, quote_conf_value($conf{$key}); } } else { print "# $key not found in $conffile\n" if ($verbose); exit 1; } } elsif ($cmd eq 'set') { if ($conffile =~ m!^/!) { set_conffile_value ($conffile, $key, $value); } else { set_conf_value ($version, $cluster, $conffile, $key, $value); } } elsif ($cmd eq 'remove') { if ($conffile =~ m!^/!) { disable_conffile_value ($conffile, $key); } else { disable_conf_value ($version, $cluster, $conffile, $key); } } elsif ($cmd eq 'edit') { my $editor = 'vi'; if ($ENV{EDITOR}) { ($editor) = $ENV{EDITOR} =~ /(.*)/; # untaint } if ($conffile =~ m!^/!) { system $editor, $conffile; } else { system $editor, "$PgCommon::confroot/$version/$cluster/$conffile"; } } __END__ =head1 NAME pg_conftool - read and edit PostgreSQL cluster configuration files =head1 SYNOPSIS B [I] [I I] [I] B =head1 DESCRIPTION B allows showing and setting parameters in PostgreSQL configuration files. If I I is omitted, it defaults to the default cluster (see user_clusters(5) and postgresqlrc(5)). If I is omitted, it defaults to B. I can also be a path, in which case I I is ignored. =head1 OPTIONS =over 4 =item B<-b>, B<--boolean> Format boolean value as B or B (not for "show all"). =item B<-s>, B<--short> Show only the value (instead of key = value pair). =item B<-v>, B<--verbose> Verbose output. =item B<--help> Print help. =back =head1 COMMANDS =over 4 =item B I|B Show a parameter, or all present in this config file. =item B I I Set or update a parameter. =item B I Remove (comment out) a parameter from a config file. =item B Open the config file in an editor. Unless B<$EDITOR> is set, B is used. =back =head1 SEE ALSO user_clusters(5), postgresqlrc(5) =head1 AUTHOR Christoph Berg Lmyon@debian.orgE>