andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
Blob Blame History Raw
From 7cb52179b891061803869b21c1000aa35a51e27c Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Mon, 14 Oct 2013 13:13:24 -0400
Subject: [PATCH 181/225] Ticket 47538 - RFE: repl-monitor.pl plain text
 output, cmdline config options

RFE Description:  Request option to print report in plain text(instead of HTML), and
                  be able to add the configfuration file directives as command line
                  options.

Fix Description:  Add a new option "-s" for displaying plain text report.

                  Added new options for the config file directives:

                      -c "connection value"
                      -a "alias value"
                      -k "color value"

                  Added a new option (-W, --prompt) to prompt for passwords.

                  Added "long names" to the commandline options.
                  Updated to use:  GetOpts::Long, strict, warnings

                  Cleaned up some HTML code/colors, and indentation.

                  Update man page.

https://fedorahosted.org/389/ticket/47538

Reviewed by: nhosoi, nkinder, and rmeggins(Thanks!!!)
(cherry picked from commit 76abd736d3bf763cc0e7bc1987fe76c27159db6f)
(cherry picked from commit dae03f042334ede551a6c1972e2163a2f923f352)
---
 ldap/admin/src/scripts/repl-monitor.pl.in | 576 ++++++++++++++++++++----------
 man/man1/repl-monitor.1                   |  35 +-
 2 files changed, 415 insertions(+), 196 deletions(-)

diff --git a/ldap/admin/src/scripts/repl-monitor.pl.in b/ldap/admin/src/scripts/repl-monitor.pl.in
index 8839ed2..45d58a1 100755
--- a/ldap/admin/src/scripts/repl-monitor.pl.in
+++ b/ldap/admin/src/scripts/repl-monitor.pl.in
@@ -41,8 +41,9 @@
 # FILE: repl-monitor.pl
 #
 # SYNOPSIS:
-#    repl-monitor.pl -f configuration-file [-h host] [-p port] [-r]
-#                    [-u refresh-url] [-t refresh-interval]
+#    repl-monitor.pl [-f configuration-file] [-h host] [-p port] [-r]
+#                    [-c connection] [-a alias] [-k color] [-u refresh-url] 
+#                    [-t refresh-interval] [-s] [-W]
 #
 #    repl-monitor.pl -v
 #
@@ -111,6 +112,22 @@
 #   If the color section or color entry is missing, the default color
 #   set is: green for [0-5) minutes lag, yellow [5-60), and red 60 and more.
 #
+#   The following three options (-c, -a, -k) are used if not providing a 
+#   configuration file:
+#
+#    -c connection
+#       The connection value is the same as the configuration file value(see above):
+#           -c "host:port:binddn:bindpwd:bindcert"
+#
+#    -a alias
+#       The alias value is the same as the configuration file value(see above):
+#           -a "alias=host:port"
+#
+#    -k color
+#       The color value is written as "lowmark:color".  Where the lowmark is in minutes.
+#       This option is ignored if printing a plain text report.
+#           -k "5=#ccffcc"
+#       
 #    -h host
 #       Initial replication supplier's host. Default to the current host.
 #
@@ -132,6 +149,10 @@
 #       the output HTML file would automatically refresh itself. This
 #       is useful for continuing monitoring. See also option -t.
 #
+#    -s Print output in plain text, instead of HTML.
+#
+#    -W Prompt for connection passwords.
+#
 #    -v Print out the version of this script
 # 
 # DIAGNOSTICS:
@@ -156,11 +177,17 @@
 # If using this script standalone, be sure to set the shared lib path and
 # the path to the perldap modules.
 
+use strict;
+use warnings;
 use lib qw(@perlpath@);
 
-$usage = "\nusage: $0 -f configuration-file [-h host] [-p port] [-r] [-u refresh-url] [-t refresh-interval]\n\nor   : $0 -v\n"; 
+my $usage = "\nusage: $0 [-f configuration-file | --configfile configuration-file] " .
+         "[-c connection, --conn connection] [-a alias, --alias alias] [-k color, --color color] " . 
+         "[-h host, --host host] [-p port, --port port] [-r, --skip-header] [-s, --text] " .
+         "[-u refresh-url, --url refresh-url] [-t refresh-interval, --interval refresh-interval ] " .
+         "[-W, --prompt]\n\nor   : $0 -v | --version\n"; 
 
-use Getopt::Std;		# parse command line arguments
+use Getopt::Long;		# parse command line arguments
 use Mozilla::LDAP::Conn;	# LDAP module for Perl
 use Mozilla::LDAP::Utils qw(normalizeDN);	# LULU, utilities.
 use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
@@ -169,29 +196,43 @@ use Time::Local; # to convert GMT Z strings to localtime
 #
 # Global variables
 #
-$product = "Directory Server Replication Monitor";
-$version = "Version 1.0";
+my $product = "Directory Server Replication Monitor";
+my $version = "Version 1.1";
 #
 # ldap servers given or discovered from the replication agreements:
-# @servers		= (host:port=shadowport:binddn:password:cert_db)
+my @servers; # = (host:port=shadowport:binddn:password:cert_db)
+my $serveridx;
 #
 # entries read from the connection section of the configuration file:
-# @allconnections	= (host:port=shadowport:binddn:password:cert_db)
+my @allconnections; # = (host:port=shadowport:binddn:password:cert_db)
 #
 # aliases of ldap servers read from the configuration file:
-# %allaliases{$host:$port}= (alias)
+my %allaliases; # = {$host:$port} = (alias)
+# colors
+my %allcolors;
+my @colorkeys;
+
 #
 # replicas discovered on all ldap servers
-# @allreplicas		= (server#:replicaroot:replicatype:serverid:replicadn)
+my @allreplicas; # = (server#:replicaroot:replicatype:serverid:replicadn)
 #
 # ruvs retrieved from all replicas
-# @allruvs{replica#:masterid} = (rawcsn:decimalcsn;mon/day/year hh:mi:ss)
+my %allruvs; # = {replica#:masterid} = (rawcsn:decimalcsn;mon/day/year hh:mi:ss)
 #
 # agreements discovered on all ldap supplier servers:
-# @allagreements	= (supplier_replica#:consumer#:conntype:schedule:status)
+my @allagreements; # = (supplier_replica#:consumer#:conntype:schedule:status)
 # the array may take another format after the consumer replicas are located:
-# @allagreements	= (supplier_replica#:consumer_replica#:conntype:schedule:status)
+# @allagreements; # = (supplier_replica#:consumer_replica#:conntype:schedule:status)
+#
+my %ld; # ldap connection hash
 #
+my ($opt_f, $opt_h, $opt_p, $opt_u, $opt_t, $opt_r, $opt_s);
+my (@conns, @alias, @color);
+my ($section, $interval, $nowraw, $now, $mm, $dd, $tt, $yy, $wday);
+my ($fn, $rc, $prompt, $last_sidx);
+my %passwords = ();
+my $passwd = "";
+$prompt = "";
 
 #main
 {
@@ -199,15 +240,23 @@ $version = "Version 1.0";
 	$| = 1;
 
 	# Check for legal options
-	if (!getopts('h:p:f:ru:t:v')) {
-		print $usage;
-		exit -1;
-  	}
-
-	if ($opt_v) {
-		print "$product - $version\n";
-		exit;
-	}
+  	GetOptions(
+		'h|host=s' => \$opt_h,
+		'p|port=s' => \$opt_p,
+		'f|configfile=s' => \$opt_f,
+		'c|conn=s' => \@conns,
+		'a|alias=s' => \@alias,
+		'k|color=s' => \@color,
+		'u|url=s' => \$opt_u,
+		't|interval=s' => \$opt_t,
+		'W|prompt' => sub { $prompt = "yes"; },
+		'r|skip-header' => sub { $opt_r = "1"; },
+		's|text' => sub {$opt_s = "1"; },
+		'v|version' => sub { print "$product - $version\n"; exit ;}
+	) or die "Usage error: $usage\n";
+
+	exit -1 if &validateArgs < 0;
+	exit if &read_cfg_file ($opt_f) < 0;
 
 	$interval = $opt_t;
 	$interval = 300 if ( !$interval || $interval <= 0 );
@@ -221,22 +270,23 @@ $version = "Version 1.0";
 	if (!$opt_r) {
 		# print the HTML header
 		&print_html_header;
-	} else {
-		# print separator for new replication set
-		print "<hr width=90% size=3><br>\n";
+	} else  {
+		if($opt_s){
+			print"\n";
+		} else {
+			# print separator for new replication set
+			print "<hr width=90% size=3><br>\n";
+		}
 	}
 
-	exit -1 if &validateArgs < 0;
-	exit if &read_cfg_file ($opt_f) < 0;
-
 	# Start with the given host and port
 	# The index names in %ld are defined in Mozilla::LDAP::Utils::ldapArgs()
 	&add_server ("$ld{host}:$ld{port}:$ld{bind}:$ld{pswd}:$ld{cert}");
 
 	$serveridx = 0;
-	while ($serveridx <= $#servers) {
+	while ($serveridx <= $#servers) { 
 		if (&get_replicas ($serveridx) != 0 && $serveridx == 0) {
-			my ($host, $port, $binddn) = split (/:/, $servers[0]);
+			my ($host, $port, $binddn) = split (/:/, $servers[$serveridx]);
 			print("Login to $host:$port as \"$binddn\" failed\n");
 			exit;
 		}
@@ -253,14 +303,19 @@ $version = "Version 1.0";
 
 sub validateArgs
 {
-	my ($rc) = 0;
+	$rc = 0;
 
 	%ld = Mozilla::LDAP::Utils::ldapArgs();
-
-	if (!$opt_v && !$opt_f) {
-		print "<p>Error: Missing configuration file.\n";
-		print "<p>If you need help on the configuration file, Please go back and click the Help button.\n";
-		#print $usage;	# Don't show usage in CGI
+	if (!$opt_f && $#conns < 0) {
+		if($opt_s){
+			print "Error: Missing configuration file or connection parameter.\n";
+			print $usage;  
+		} else {
+			print "<p>Error: Missing configuration file or connection paramater.\n";
+			print "<p>If you need help on the configuration file, or script usage, " .
+			"Please go back and click the Help button.\n";
+			#print $usage; # Don't show usage in CGI
+		}
 		$rc = -1;
 	}
 	elsif (!$opt_h) {
@@ -272,63 +327,90 @@ sub validateArgs
 
 sub read_cfg_file
 {
-	my ($fn) = @_;
-	unless (open(CFGFILEHANDLE, $fn)) {
-		print "<p>Error: Can't open \"$fn\": $!.\n";
-		print "<p>If you need help on the configuration file, Please go back and click the Help button.\n";
-		return -1;
+	($fn) = @_;
+	my $tmp;
+	
+	# process the command line config params
+	@allconnections = @conns;
+	if($#alias >= 0){
+		foreach $tmp (@alias){
+			$tmp =~ m/^\s*(\S.*)\s*=\s*(\S+)/;
+			$allaliases{$2} = $1;
+		}
 	}
-	$section = 0;
-	while (<CFGFILEHANDLE>) {
-		next if (/^\s*\#/ || /^\s*$/);
-		chop ($_);
-		if (m/^\[(.*)\]/) {
-			$section = $1;
+	if($#color >= 0){
+		foreach $tmp (@color){
+			$tmp =~ m/^\s*(-?\d+)\s*=\s*(\S+)/;
+			$allcolors{$1} = $2;
 		}
-		else {
-			if ( $section =~ /conn/i ) {
-				push (@allconnections, $_);
-			}
-			elsif ( $section =~ /alias/i ) {
-				m/^\s*(\S.*)\s*=\s*(\S+)/;
-				$allaliases {$2} = $1;
-			}
-			elsif ( $section =~ /color/i ) {
-				m/^\s*(-?\d+)\s*=\s*(\S+)/;
-				$allcolors {$1} = $2;
+	}
+	
+	if($opt_f){
+		unless (open(CFGFILEHANDLE, $fn)) {
+			if($opt_s){
+				print "Error: Can't open configuration file\"$fn\": $!.\n";
+			} else {
+				print "<p>Error: Can't open configuration file\"$fn\": $!.\n";
+				print "<p>If you need help on the configuration file, Please go back and click the Help button.\n";
 			}
-		}
+    			return -1;
+    		}
+    		$section = 0;
+    		while (<CFGFILEHANDLE>) {
+    			next if (/^\s*\#/ || /^\s*$/);
+			chop ($_);
+    		if (m/^\[(.*)\]/) {
+    			$section = $1;
+    		}
+    		else {
+    			if ( $section =~ /conn/i ) {
+    				push (@allconnections, $_);
+    			}
+    			elsif ( $section =~ /alias/i ) {
+    				m/^\s*(\S.*)\s*=\s*(\S+)/;
+    				$allaliases {$2} = $1;
+    			}
+    			elsif ( $section =~ /color/i ) {
+    				m/^\s*(-?\d+)\s*=\s*(\S+)/;
+    				$allcolors {$1} = $2;
+    			}
+    		}
+    	}
+    	close (CFGFILEHANDLE);
 	}
 	if ( ! keys (%allcolors) ) {
-		$allcolors {0} = "#ccffcc";	#apple green
-		$allcolors {5} = "#ffffcc";	#cream yellow
-		$allcolors {60} = "#ffcccc";	#pale pink
+		$allcolors {0} = "#ccffcc"; #apple green
+		$allcolors {5} = "#ffffcc"; #cream yellow
+		$allcolors {60} = "#ffcccc"; #pale pink
 	}
 	@colorkeys = sort (keys (%allcolors));
-	close (CFGFILEHANDLE);
+    
 	return 0;
 }
 
 sub get_replicas
 {
-	my ($serveridx) = @_;
+	$serveridx = $_[0];
 	my ($conn, $host, $port, $shadowport, $binddn, $bindpwd, $bindcert);
 	my ($others);
 	my ($replica, $replicadn);
 	my ($ruv, $replicaroot, $replicatype, $serverid, $masterid, $maxcsn);
 	my ($type, $flag, $i);
 	my ($myridx, $ridx, $cidx);
+	my ($lastmodifiedat, $agreement);
 
 	#
 	# Bind to the server
 	#
-	($host, $port, $binddn, $bindpwd, $bindcert) = split (/:/, "$servers[$serveridx]", 5);
+	if($#servers < 0 || $serveridx > $#servers + 1){
+		return -1;
+	}
 
+	($host, $port, $binddn, $bindpwd, $bindcert) = split (/:/, "$servers[$serveridx]", 5);
 	($port, $shadowport) = split (/=/, $port);
 	$shadowport = $port if !$shadowport;
 
 	$conn = new Mozilla::LDAP::Conn ($host, $shadowport, "$binddn", $bindpwd, $bindcert);
-
 	return -1 if (!$conn);
 
 	#
@@ -508,24 +590,21 @@ sub find_consumer_replicas
 
 sub process_suppliers
 {
-	my ($ridx, $mid, $maxcsn);
-
-	$mid = "";
+	my ($ridx, $mid, $maxcsn, $ismaster);
 	$ismaster = 0;
+	$mid = "";
 
 	$last_sidx = -1;	# global variable for print html page
 
 	for ($ridx = 0; $ridx <= $#allreplicas; $ridx++) {
-
 		# Handle masters and hubs
 		if ($allreplicas[$ridx] =~ /:master:(\d+):/i) {
 			$mid = $1;
 
 			# Skip replicas without agreements defined yet
 			next if (! grep {$_->{ridx} == $ridx} @allagreements);
-
 			$maxcsn = &print_master_header ($ridx, $mid);
-			if ( "$maxcsn" != "none" ) {
+			if ( "$maxcsn" ne "none" ) {
 				&print_consumer_header ();
 				&print_consumers ($ridx, $mid);
 			}
@@ -536,7 +615,7 @@ sub process_suppliers
 			# Skip replicas without agreements defined yet
 			next if (! grep {$_->{ridx} == $ridx} @allagreements);
 
-		    foreach $key (keys %allruvs) {
+		    foreach my $key (keys %allruvs) {
 				if ( $key =~ /$ridx:/) {
 					my ($myridx, $mymid) = split ( /:/, "$key" );
 					$maxcsn = &print_hub_header($myridx, $mymid);
@@ -549,7 +628,11 @@ sub process_suppliers
 	}
 
 	if ($mid eq "") {
-		print "<p>The server is not a master or a hub or it has no replication agreement\n";
+		if($opt_s){
+			print "The server is not a master or a hub or it has no replication agreement\n";
+		} else {
+			print "<p>The server is not a master or a hub or it has no replication agreement\n";
+		}
 	}
 }
 
@@ -560,34 +643,40 @@ sub print_master_header
 	my ($maxcsnval) = split ( /;/, "$myruv" );
 	my ($maxcsn) = &to_string_csn ($maxcsnval);
 	my ($sidx, $replicaroot, $replicatype, $serverid) = split (/:/, $allreplicas[$ridx]);
-
-	if ( $maxcsn == "" ) {
+    
+	if ( $maxcsn eq "" ) {
 		return $maxcsn;
 	}
 
 	# Print the master name
-	if ( $last_sidx != $sidx ) {
+	if ( $last_sidx ne $sidx ) {
 		my ($ldapurl) = &get_ldap_url ($sidx, $sidx);
 		&print_legend if ( $last_sidx < 0);
-		print "<p><p><hr><p>\n";
-		print "\n<p><center class=page-subtitle><font color=#0099cc>\n";
-		print "Master:&nbsp $ldapurl</center>\n";
+		if($opt_s){
+			print "Master: $ldapurl\n"
+		} else {
+			print "<p><p><hr><p>\n";
+			print "\n<p><center class=page-subtitle><font color=#0099cc>\n";
+			print "Master:&nbsp $ldapurl</center>\n";
+		}
 		$last_sidx = $sidx;
 	}
 
 	# Print the current replica info onthe master
-	print "\n<p><table border=0 cellspacing=1 cellpadding=6 cols=10 width=100% class=bgColor9>\n";
-
-	print "\n<tr><td colspan=10><center>\n";
-	print "<font class=areatitle>Replica ID:&nbsp;</font>";
-	print "<font class=text28>$serverid</font>\n";
-
-	print "<font class=areatitle>Replica Root:&nbsp;</font>";
-	print "<font class=text28>$replicaroot</font>\n";
-
-	print "<font class=areatitle>Max CSN:&nbsp;</font>";
-	print "<font class=text28>$maxcsn</font>\n";
-
+	if($opt_s){
+		print "Replica ID: $serverid\n";
+		print "Replica Root: $replicaroot\n";
+		print "Max CSN: $maxcsn\n";
+	} else {
+		print "\n<p><table border=0 cellspacing=1 cellpadding=6 cols=10 width=100% class=bgColor9>\n";
+		print "\n<tr><td colspan=10><center>\n";
+		print "<font class=areatitle>Replica ID:&nbsp;</font>";
+		print "<font class=text28>$serverid</font>\n";
+		print "<font class=areatitle>Replica Root:&nbsp;</font>";
+		print "<font class=text28>$replicaroot</font>\n";
+		print "<font class=areatitle>Max CSN:&nbsp;</font>";
+		print "<font class=text28>$maxcsn</font>\n";
+	}
 	return $maxcsn;
 }
 
@@ -597,36 +686,44 @@ sub print_hub_header
 	my ($myruv) = $allruvs {"$ridx:$mid"};
 	my ($maxcsnval) = split ( /;/, "$myruv" );
 	my ($maxcsn) = &to_string_csn ($maxcsnval);
-	my ($sidx, $replicaroot, $replicatype, $serverid) = split (/:/, $allreplicas[$ridx]);
+	my ($sidx, $last_sidx, $replicaroot, $replicatype, $serverid) = split (/:/, $allreplicas[$ridx]);
 
 	# Print the master name
 	if ( $last_sidx != $sidx ) {
 		my ($ldapurl) = &get_ldap_url ($sidx, $sidx);
 		&print_legend if ( $last_sidx < 0);
-		print "<p><p><hr><p>\n";
-		print "\n<p><center class=page-subtitle><font color=#0099cc>\n";
-		print "Hub:&nbsp $ldapurl</center>\n";
+		if($opt_s){
+			print "Hub: $ldapurl\n";
+		} else {
+			print "<p><p><hr><p>\n";
+			print "\n<p><center class=page-subtitle><font color=#0099cc>\n";
+			print "Hub:&nbsp $ldapurl</center>\n";
+		}
 		$last_sidx = $sidx;
 	}
 
 	# Print the current replica info onthe master
-	print "\n<p><table border=0 cellspacing=1 cellpadding=6 cols=10 width=100% class=bgColor9>\n";
-
-	print "\n<tr><td colspan=10><center>\n";
-	print "<font class=areatitle>Replica ID:&nbsp;</font>";
-	print "<font class=text28>$serverid</font>\n";
-
-	print "<font class=areatitle>Replica Root:&nbsp;</font>";
-	print "<font class=text28>$replicaroot</font>\n";
-
-	print "<font class=areatitle>Max CSN:&nbsp;</font>";
-	print "<font class=text28>$maxcsn</font>\n";
-
+	if($opt_s){
+		print "Replica ID: $serverid\n";
+		print "Replica Root: $replicaroot\n";
+		print "Max CSN: $maxcsn\n";
+	} else {
+		print "\n<p><table border=0 cellspacing=1 cellpadding=6 cols=10 width=100% class=bgColor9>\n";
+		print "\n<tr><td colspan=10><center>\n";
+		print "<font class=areatitle>Replica ID:&nbsp;</font>";
+		print "<font class=text28>$serverid</font>\n";
+		print "<font class=areatitle>Replica Root:&nbsp;</font>";
+		print "<font class=text28>$replicaroot</font>\n";
+		print "<font class=areatitle>Max CSN:&nbsp;</font>";
+		print "<font class=text28>$maxcsn</font>\n";
+	}
 	return $maxcsn;
 }
 
 sub print_consumer_header
 {
+	if($opt_s) { return; } # we'll do the text printing in "print_consumers"
+	
 	#Print the header of consumer
 	print "\n<tr class=bgColor16>\n";
 	print "<th nowrap>Receiver</th>\n";
@@ -648,15 +745,16 @@ sub print_consumers
 	my ($m_ridx, $mid) = @_;
 	my ($ignore, $m_replicaroot) = split (/:/, $allreplicas[$m_ridx]);
 	my (@consumers, @ouragreements, @myagreements);
-	my ($s_ridx, $c_ridx, $conntype, $schedule, $status);
-	my ($c_maxcsn_str, $lag, $markcolor);
+	my ($s_ridx, $c_ridx, $s_sidx, $conntype, $schedule, $status);
+	my ($c_maxcsn, $c_maxcsn_str, $c_lastmodified, $c_sidx, $lag, $markcolor);
 	my ($c_replicaroot, $c_replicatype);
-	my ($first_entry);
+	my ($first_entry, $s_ldapurl, $c_ldapurl);
 	my ($nrows);
 	my ($found);
 
 	undef @ouragreements;
-
+	$c_lastmodified = "";
+    
 	# Collect all the consumer replicas for the current master replica
 	push (@consumers, $m_ridx);
 	foreach (@consumers) {
@@ -688,7 +786,7 @@ sub print_consumers
 			$myruv = $allruvs {"$c_ridx:$mid"};
 			($c_maxcsn, $c_lastmodified) = split ( /;/, "$myruv" );
 			($c_maxcsn_str, $lag, $markcolor) = &cacl_time_lag ($m_maxcsn, $c_maxcsn);
-			$c_maxcsn_str =~ s/ /\<br\>/;
+			if(!$opt_s){ $c_maxcsn_str =~ s/ /\<br\>/; }
 			($c_sidx, $c_replicaroot, $c_replicatype) = split (/:/, $allreplicas[$c_ridx]);
 			$c_replicaroot = "same as master" if $m_replicaroot eq $c_replicaroot;
 		}
@@ -697,7 +795,7 @@ sub print_consumers
 			$c_sidx = -$c_ridx;
 			$c_maxcsn_str = "_";
 			$lag = "n/a";
-			$markcolor = red;
+			$markcolor = "red";
 			$c_replicaroot = "_";
 			$c_replicatype = "_";
 		}
@@ -719,16 +817,27 @@ sub print_consumers
 			$s_ldapurl = &get_ldap_url ($s_sidx, "n/a");
 
 			# Print out the consumer's replica and ruvs
-			print "\n<tr class=bgColor13>\n";
+			if(!$opt_s){ print "\n<tr class=bgColor13>\n"; }
 			if ($first_entry) {
 				$first_entry = 0;
 				$c_ldapurl = &get_ldap_url ($c_sidx, $conntype);
-				print "<td rowspan=$nrows width=5% class=bgColor5>$c_ldapurl<BR>Type: $c_replicatype</td>\n";
-				print "<td rowspan=$nrows width=5% nowrap bgcolor=$markcolor><center>$lag</center></td>\n";
-				print "<td rowspan=$nrows width=15% nowrap>$c_maxcsn_str</td>\n";
-				print "<td rowspan=$nrows width=15% nowrap>$c_lastmodified</td>\n";
+				if($opt_s){
+					print "Receiver: $c_ldapurl\nType: $c_replicatype\n";
+					print "Time Lag: $lag\n";
+					print "Max CSN: $c_maxcsn_str\n";
+					print "Last Modify Time: $c_lastmodified\n";
+				} else {
+					print "<td rowspan=$nrows width=5% class=bgColor5>$c_ldapurl<BR>Type: $c_replicatype</td>\n";
+					print "<td rowspan=$nrows width=5% nowrap bgcolor=$markcolor><center>$lag</center></td>\n";
+					print "<td rowspan=$nrows width=15% nowrap>$c_maxcsn_str</td>\n";
+					print "<td rowspan=$nrows width=15% nowrap>$c_lastmodified</td>\n";
+				}
+			}
+			if($opt_s){ 
+				print "Supplier: $s_ldapurl\n";
+			} else {
+				print "<td width=5% nowrap><center>$s_ldapurl</center></td>\n";
 			}
-			print "<td width=5% nowrap><center>$s_ldapurl</center></td>\n";
 			my $changecount = $_->{nsds5replicaChangesSentSinceStartup};
 			if ( $changecount =~ /^$mid:(\d+)\/(\d+) / || $changecount =~ / $mid:(\d+)\/(\d+) / ) {
 				$changecount = "$1 / $2";
@@ -739,7 +848,11 @@ sub print_consumers
 			else {
 				$changecount = "0 / 0";
 			}
-			print "<td width=3% nowrap>$changecount</td>\n";       
+			if($opt_s){
+				print "Sent/Skipped: $changecount\n";
+			} else {
+				print "<td width=3% nowrap>$changecount</td>\n";
+			}   
 			my $redfontstart = "";
 			my $redfontend = "";
 			if ($status =~ /error/i) {
@@ -753,22 +866,44 @@ sub print_consumers
 					$redfontend = "</font>";
 				}
 			}
-			print "<td width=20% nowrap>$redfontstart$status$redfontend</td>\n";
-			print "<td nowrap>", &format_z_time($_->{nsds5replicaLastUpdateStart}), "</td>\n";
-			print "<td nowrap>", &format_z_time($_->{nsds5replicaLastUpdateEnd}), "</td>\n";
+			if($opt_s){
+				print "Update Status: $status\n";
+				print "Update Started: ", &format_z_time($_->{nsds5replicaLastUpdateStart}), "\n";
+				print "Update Ended: ", &format_z_time($_->{nsds5replicaLastUpdateEnd}), "\n";			
+			} else {
+				print "<td width=20% nowrap>$redfontstart$status$redfontend</td>\n";
+				print "<td nowrap>", &format_z_time($_->{nsds5replicaLastUpdateStart}), "</td>\n";
+				print "<td nowrap>", &format_z_time($_->{nsds5replicaLastUpdateEnd}), "</td>\n";
+			}
 			if ( $schedule =~ /always/i ) {
-				print "<td colspan=2 width=10% nowrap>$schedule</td>\n";
+				if($opt_s){
+					print "Schedule: $schedule\n";
+				} else {
+					print "<td colspan=2 width=10% nowrap>$schedule</td>\n";
+				}
 			}
 			else {
 				my ($ndays, @days);
 				$schedule =~ /(\d\d)(\d\d)-(\d\d)(\d\d) (\d+)/;
-				print "<td width=10% nowrap>$1:$2-$3:$4</td>\n";
+				if($opt_s){
+				    print "Schedule: $1:$2-$3:$4 ";
+				} else {
+				    print "<td width=10% nowrap>$1:$2-$3:$4</td>\n";
+				}
 				$ndays = $5;
 				$ndays =~ s/(\d)/$1,/g;
-				@days = (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[eval $ndays];
-				print "<td width=10% nowrap>@days</td>\n";
+				@days = ("Sun","Mon","Tue","Wed","Thu","Fri","Sat")[eval $ndays];
+				if($opt_s){
+				    print "@days\n";
+				} else {
+				    print "<td width=10% nowrap>@days</td>\n";
+				}
+			}
+			if($opt_s){
+				print "SSL: $conntype\n";
+			} else {
+				print "<td width=3% nowrap class=bgColor5>$conntype</td>\n";
 			}
-			print "<td width=3% nowrap class=bgColor5>$conntype</td>\n";
 		}
 	}
 }
@@ -778,7 +913,7 @@ sub cacl_time_lag
 	my ($s_maxcsn, $c_maxcsn) = @_;
 	my ($markcolor);
 	my ($csn_str);
-	my ($s_tm, $c_tm, $lag_tm, $lag_str, $hours, $minute);
+	my ($s_tm, $c_tm, $lag_tm, $lag_str, $hours, $minutes);
 
 	$csn_str = &to_string_csn ($c_maxcsn);
 
@@ -831,7 +966,7 @@ sub cacl_time_lag
 #
 sub add_server
 {
-	my ($host, $port, $binddn, $bindpwd, $bindcert) = split (/:/, "@_");
+	my ($host, $port, $binddn, $bindpwd, $bindcert) = split (/:/, "$_[0]");
 	my ($shadowport) = $port;
 	my ($domainpattern) = '\.[^:]+';
 	my ($i);
@@ -846,7 +981,7 @@ sub add_server
 	$hostnode = $1 if $host =~ /^(.+?)\./;
 
 	# new host:port
-	if ($binddn eq "" || $bindpwd eq "" && $bindcert eq "") {
+	if (!$binddn || $binddn eq "" || !$bindpwd || $bindpwd eq "" || !$bindcert || $bindcert eq "") {
 		#
 		# Look up connection parameter in the order of
 		#	host:port
@@ -855,17 +990,25 @@ sub add_server
 		#	*:*
 		#
 		my (@myconfig, $h, $p, $d, $w, $c);
-		(@myconfig = grep (/^$hostnode($domainpattern)*:$port\D/i, @allconnections)) ||
+		$h = ""; $p = ""; $d = ""; $w = ""; $c = "";
+		(@myconfig = grep (/^$hostnode($domainpattern)*:[0-9]+\D/i, @allconnections)) ||
 		(@myconfig = grep (/^$hostnode($domainpattern)*:\*:/i, @allconnections)) ||
 		(@myconfig = grep (/^\*:$port\D/, @allconnections)) ||
 		(@myconfig = grep (/^\*:\*\D/, @allconnections));
 		if ($#myconfig >= 0) {
 			($h, $p, $d, $w, $c) = split (/:/, $myconfig[0]);
 			($p, $shadowport) = split (/=/, $p);
-			$p = "" if $p eq "*";
-			$c = "" if $c eq "*";
+			if(!$p || $p eq "*"){
+				$p = "";
+			}
+			if(!$c || $c eq "*"){
+				$c = "";
+			}
+			if(!$w || $w eq "*"){
+                $w = "";
+            }
 		}
-		if ($binddn eq "" || $binddn eq "*") {
+		if (!$binddn || $binddn eq "" || $binddn eq "*") {
 			if ($d eq "" || $d eq "*") {
 				$binddn = "cn=Directory Manager";
 			}
@@ -873,8 +1016,14 @@ sub add_server
 				$binddn = $d;
 			}
 		}
-		$bindpwd = $w if ($bindpwd eq "" || $bindpwd eq "*");
-		$bindcert = $c if ($bindcert eq "" || $bindcert eq "*");
+		if($prompt eq "yes" && ($w eq "" || (!$bindpwd || $bindpwd eq ""))){
+            $bindpwd = passwdPrompt($h, $p);
+		} elsif ($passwd ne ""){
+            $bindpwd = $passwd;
+		} else {
+            $bindpwd = $w if (!$bindpwd || $bindpwd eq "" || $bindpwd eq "*");
+        }
+		$bindcert = $c if (!$bindcert || $bindcert eq "" || $bindcert eq "*");
 	}
 
 	if ($shadowport) {
@@ -885,6 +1034,43 @@ sub add_server
 	return $i;
 }
 
+sub
+passwdPrompt
+{
+    my ($h, $p) = @_;
+    my $key = "$h:$p";
+    my $pw = "";
+    
+    if ($passwords{$key}){
+        # we already have a password for this replica     
+        return $passwords{$key};
+    }
+    # Disable console echo
+    system("@sttyexec@ -echo") if -t STDIN;
+
+    while ($pw eq ""){
+        if($passwd ne ""){
+            print "Enter password for ($h:$p) <hit Enter to use previous password>: ";
+            chomp($pw = <>);
+            if ($pw eq ""){
+                $pw = $passwd;
+            } else {
+                $passwords{$key} = $pw;
+                $passwd = $pw;         
+            }
+        } else {
+            print "Enter password for ($h:$p): ";
+            chomp($pw = <>);
+            $passwords{$key} = $pw;
+            $passwd = $pw;
+        }
+    }
+    # Enable console echo
+    system("@sttyexec@ echo") if -t STDIN;
+
+    return $pw;
+}
+
 sub get_ldap_url
 {
 	my ($sidx, $conntype) = @_;
@@ -893,19 +1079,22 @@ sub get_ldap_url
 	($port, $shadowport) = split (/=/, $port);
 	my ($protocol, $ldapurl);
 
-	if ($port eq 636 && $conntype eq "0" || $conntype =~ /SSL/i) {
-		$protocol = ldaps;
+	if ($port == 636 && $conntype eq "0" || $conntype =~ /SSL/i) {
+		$protocol = "ldaps";
 	}
 	else {
-		$protocol = ldap;
+		$protocol = "ldap";
 	}
 	my ($instance) = $allaliases { "$host:$port" };
 	$instance = "$host:$port" if !$instance;
 	if ($conntype eq "n/a") {
 		$ldapurl = $instance;
-	}
-	else {
-		$ldapurl = "<a href=\"$protocol://$host:$port/\">$instance</a>";
+	} else {
+		if($opt_s){
+			$ldapurl = "$instance $protocol://$host:$port/";
+		} else {
+			$ldapurl = "<a href=\"$protocol://$host:$port/\">$instance</a>";
+		}
 	}
 	return $ldapurl;
 }
@@ -950,7 +1139,8 @@ sub get_color
 	my ($lag_minute) = @_;
 	$lag_minute /= 60;
 	my ($color) = $allcolors { $colorkeys[0] };
-	foreach (@colorkeys) {
+	
+	foreach ( keys %allcolors) {
 		last if ($lag_minute < $_);
 		$color = $allcolors {$_};
 	}
@@ -969,53 +1159,63 @@ sub unescape
 
 sub print_html_header
 {
-	# print the HTML header
-
-	print "Content-type: text/html\n\n";
-	print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\"><html>\n";
-	print "<head><title>Replication Status</title>\n";
-	# print "<link type=text/css rel=stylesheet href=\"master-style.css\">\n";
-	print "<style text/css>\n";
-	print "Body, p, table, td, ul, li {color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 12px;}\n";
-	print "A {color:blue; text-decoration: none;}\n";
-	print "BODY {font-family: arial, helvetica, sans-serif}\n";
-	print "P {font-family: arial, helvetica, sans-serif}\n";
-	print "TH {font-weight: bold; font-family: arial, helvetica, sans-serif}\n";
-	print "TD {font-family: arial, helvetica, sans-serif}\n";
-	print ".bgColor1  {background-color: #003366;}\n";
-	print ".bgColor4  {background-color: #cccccc;}\n";
-	print ".bgColor5  {background-color: #999999;}\n";
-	print ".bgColor9  {background-color: #336699;}\n";
-	print ".bgColor13 {background-color: #ffffff;}\n";
-	print ".bgColor16 {background-color: #6699cc;}\n";
-	print ".text8  {color: #0099cc; font-size: 11px; font-weight: bold;}\n";
-	print ".text28 {color: #ffcc33; font-size: 12px; font-weight: bold;}\n";
-	print ".areatitle {font-weight: bold; color: #ffffff; font-family: arial, helvetica, sans-serif}\n";
-	print ".page-title {font-weight: bold; font-size: larger; font-family: arial, helvetica, sans-serif}\n";
-	print ".page-subtitle {font-weight: bold; font-family: arial, helvetica, sans-serif}\n";
-
-	print "</style></head>\n<body class=bgColor4>\n";
-
-	if ($opt_u) {
-		print "<meta http-equiv=refresh content=$interval; URL=$opt_u>\n";
-	}
-
-	print "<table border=0 cellspacing=0 cellpadding=10 width=100% class=bgColor1>\n";
-	print "<tr><td><font class=text8>$now</font></td>\n";
-	print "<td align=center class=page-title><font color=#0099CC>";
-	print "Directory Server Replication Status</font>\n";
-
-	if ($opt_u) {
-		print "<br><font class=text8>(This page updates every $interval seconds)</font>\n";
-	}
-
-	print "</td><td align=right valign=center width=25%><font class=text8>$version";
-	print "</font></td></table>\n";
+    if(!$opt_s){
+    	# print the HTML header
+    
+    	print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\"><html>\n";
+    	print "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\">\n";
+    	print "<head><title>Replication Status</title>\n";
+    	# print "<link type=text/css rel=stylesheet href=\"master-style.css\">\n";
+    	print "<style text/css>\n";
+    	print "Body, p, table, td, ul, li {color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 12px;}\n";
+    	print "A {color:blue; text-decoration: none;}\n";
+    	print "BODY {font-family: arial, helvetica, sans-serif}\n";
+    	print "P {font-family: arial, helvetica, sans-serif}\n";
+    	print "TH {font-weight: bold; font-family: arial, helvetica, sans-serif}\n";
+    	print "TD {font-family: arial, helvetica, sans-serif}\n";
+    	print ".bgColor1  {background-color: #003366;}\n";
+    	print ".bgColor4  {background-color: #cccccc;}\n";
+    	print ".bgColor5  {background-color: #999999;}\n";
+    	print ".bgColor9  {background-color: #336699;}\n";
+    	print ".bgColor13 {background-color: #ffffff;}\n";
+    	print ".bgColor16 {background-color: #6699cc;}\n";
+    	print ".text8  {color: #0099cc; font-size: 11px; font-weight: bold;}\n";
+    	print ".text28 {color: #ffcc33; font-size: 12px; font-weight: bold;}\n";
+    	print ".areatitle {font-weight: bold; color: #ffffff; font-family: arial, helvetica, sans-serif}\n";
+    	print ".page-title {font-weight: bold; font-size: larger; font-family: arial, helvetica, sans-serif}\n";
+    	print ".page-subtitle {font-weight: bold; font-family: arial, helvetica, sans-serif}\n";
+    	print "</style></head>\n<body class=bgColor4>\n";
+    
+    	if ($opt_u) {
+    		print "<meta http-equiv=refresh content=$interval; URL=$opt_u>\n";
+    	}
+    
+    	print "<table border=0 cellspacing=0 cellpadding=10 width=100% class=bgColor1>\n";
+    	print "<tr><td><font class=text8>$now</font></td>\n";
+    	print "<td align=center class=page-title><font color=#0099CC>";
+    	print "Directory Server Replication Status</font>\n";
+    
+    	if ($opt_u) {
+    		print "<br><font class=text8>(This page updates every $interval seconds)</font>\n";
+    	}
+    
+    	print "</td><td align=right valign=center width=25%><font class=text8>$version";
+    	print "</font></td></table>\n";
+    } else {
+        print "Directory Server Replication Status ($version)\n\n";
+        print "Time: $now";
+        if ($opt_u) {
+		print " - This report updates every $interval seconds\n\n";
+        } else {
+		print "\n\n";
+        }
+    }
 }
 
 sub print_legend
 {
 	my ($nlegends) = $#colorkeys + 1;
+	if($opt_s){ return; }
 	print "\n<center><p><font class=page-subtitle color=#0099cc>Time Lag Legend:</font><p>\n";
 	print "<table cellpadding=6 cols=$nlegends width=40%>\n<tr>\n";
 	my ($i, $j);
@@ -1031,7 +1231,7 @@ sub print_legend
 
 sub print_supplier_end
 {
-	print "</table>\n";
+	if(!$opt_s){ print "</table>\n"; }
 }
 
 # given a string in generalized time format, convert to ascii time
diff --git a/man/man1/repl-monitor.1 b/man/man1/repl-monitor.1
index 424550e..bd0ede1 100644
--- a/man/man1/repl-monitor.1
+++ b/man/man1/repl-monitor.1
@@ -19,8 +19,9 @@
 repl-monitor \- Directory Server replication monitor
 .SH SYNOPSIS
 .B repl\(hymonitor
-\-f configuration\(hyfile [\fI\(hyh host\fR] [\fI\-p port\fR] [\fI\-r\fR] 
-[\fI\-u refresh\(hyurl\fR] [\fI\-t refresh\(hyinterval\fR] [\fI\-v\fR]
+\ [-f configuration\(hyfile] [\fI\(hyh host\fR] [\fI\-p port\fR] [\fI\-r\fR]
+[\fI\-c connection\fR] [\fI\-a alias\fR] [\fI\-k color\fR] [\fI\-u refresh\(hyurl\fR]
+[\fI\-s\fR] [\fI\-t refresh\(hyinterval\fR] [\fI\-v\fR]
 
 .SH DESCRIPTION
 Outputs the status of all of the configured Directory Servers
@@ -33,23 +34,39 @@ are specified in the configuration file.
 .SH OPTIONS
 A summary of options is included below:
 .TP
-.B \-h host
+.B \-h, \-\-host\fR host
 Hostname of DS server
 .TP
-.B \-p port
+.B \-p, \-\-port\fR port
 TCP port
 .TP
-.B \-f configuration\(hyfile
+.B \-f, \-\-configfile\fR configuration-file
 Configuration file 
 .TP
-.B \-r
+.B \-c, \-\-conn\fR connection
+Uses the same format as the configfile directive
+.TP
+.B \-a, \-\-alias\fR alias
+Uses the same format as the configfile directive
+.TP
+.B \-k, --color\fR color
+Uses the same format as the configfile directive
+.TP
+.B \-r, --skip-header\fR
 Removes extra HTML tags
 .TP
-.B \-u refresh\(hyurl
+.B \-u, \-\-refreshurl\fR refresh url
 Refresh url
 .TP
-.B \-t refresh\(hyinterval
+.B \-t, \-\-interval\fR refresh interval
 Refresh interval
+.TP
+.B \-W, \-\-prompt
+Prompt for passwords
+.TP
+.B \-s, \-\-text
+Print plain text report
+
 .br
 .SH AUTHOR
 repl-monitor was written by the 389 Project.
@@ -63,6 +80,8 @@ Copyright \(co 2008 Red Hat, Inc.
 This manual page was written by Michele Baldessari <michele@pupazzo.org>,
 for the Debian project (but may be used by others).
 .br
+Manual page updated by Mark Reynolds <mreynolds@redhat.com> 10/11/13
+.br
 This is free software.  You may redistribute copies of it under the terms of
 the Directory Server license found in the LICENSE file of this
 software distribution.  This license is essentially the GNU General Public
-- 
1.8.1.4