summaryrefslogtreecommitdiffstats
path: root/contrib/slapd-tools
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:35:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:35:32 +0000
commit5ea77a75dd2d2158401331879f3c8f47940a732c (patch)
treed89dc06e9f4850a900f161e25f84e922c4f86cc8 /contrib/slapd-tools
parentInitial commit. (diff)
downloadopenldap-upstream.tar.xz
openldap-upstream.zip
Adding upstream version 2.5.13+dfsg.upstream/2.5.13+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/slapd-tools')
-rw-r--r--contrib/slapd-tools/README23
-rwxr-xr-xcontrib/slapd-tools/statslog171
-rwxr-xr-xcontrib/slapd-tools/wrap_slap_ops162
3 files changed, 356 insertions, 0 deletions
diff --git a/contrib/slapd-tools/README b/contrib/slapd-tools/README
new file mode 100644
index 0000000..9098a20
--- /dev/null
+++ b/contrib/slapd-tools/README
@@ -0,0 +1,23 @@
+Directory contents:
+
+statslog
+ Program to output selected parts of slapd's statslog output
+ (LDAP request/response log), grouping log lines by LDAP
+ connection. Useful to search and inspect the server log.
+
+wrap_slap_ops
+ Update source code to use the wrapper macros SLAP_OP() & co
+ for LDAP-operation backend calls. They can help debug the
+ SlapReply. They compile like the old code by default.
+
+---
+Copyright 2004-2022 The OpenLDAP Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in the file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+<http://www.OpenLDAP.org/license.html>.
+
diff --git a/contrib/slapd-tools/statslog b/contrib/slapd-tools/statslog
new file mode 100755
index 0000000..840bd4e
--- /dev/null
+++ b/contrib/slapd-tools/statslog
@@ -0,0 +1,171 @@
+#!/usr/bin/perl -w
+# statslog - Rearrange and output selected parts of slapd's statslog output.
+# $OpenLDAP$
+# This work is part of OpenLDAP Software <http://www.openldap.org/>.
+#
+# Copyright 1998-2022 The OpenLDAP Foundation.
+# Portions Copyright 2004 Hallvard B. Furuseth.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted only as authorized by the OpenLDAP
+# Public License.
+#
+# A copy of this license is available in the file LICENSE in the
+# top-level directory of the distribution or, alternatively, at
+# <http://www.OpenLDAP.org/license.html>.
+
+sub usage {
+ die join("", @_, <<'EOM');
+Usage: statslog [options] [logfiles; may be .gz or .bz2 files]
+
+ Output selected parts of slapd's statslog output (LDAP request/response
+ log to syslog or stderr; loglevel 256), grouping log lines by LDAP
+ connection. Lines with no connection are excluded by default.
+
+Options:
+ --brief -b Brief output (omit time, host/process name/ID).
+ --exclude=RE -e RE Exclude connections whose output matches REgexp.
+ --include=RE -i RE Only include connections matching REgexp.
+ --EXCLUDE=RE -E RE Case-sensitive '--exclude'.
+ --INCLUDE=RE -I RE Case-sensitive '--include'.
+ --loose -l Include "loose" lines (lines with no connection).
+ --no-loose -L RE Only exclude the "loose" lines that match RE.
+ --join -j Join the inputs as if they were one big log file.
+ Each file must start where the previous left off.
+ --no-join -J Do not --join. (Can be useful with --sort.)
+ --sort -s Sort input files by age. Implies --join.
+ --trace -t Print file names when read. Implies --no-join.
+All --exclude/include options are applied. Note: --exclude/include are
+unreliable without --join/sort for connections spanning several log files.
+EOM
+}
+
+########################################################################
+
+use bytes;
+use strict;
+use Getopt::Long;
+
+# Globals
+my %conns; # Hash (connection number -> output)
+my @loose; # Collected output with no connection number
+
+# Command line options
+my($brief, @filters, @conditions, $no_loose);
+my($join_files, $sort_files, $trace, $getopt_ok);
+
+# Handle --include/INCLUDE/exclude/EXCLUDE options
+sub filter_opt {
+ my($opt, $regexp) = @_;
+ push(@conditions, sprintf('$lines %s /$filters[%d]/om%s',
+ (lc($opt) eq 'include' ? "=~" : "!~"),
+ scalar(@filters),
+ ($opt eq lc($opt) ? "i" : "")));
+ push(@filters, $regexp);
+}
+
+# Parse options at compile time so some can become constants to optimize away
+BEGIN {
+ &Getopt::Long::Configure(qw(bundling no_ignore_case));
+ $getopt_ok = GetOptions("brief|b" => \$brief,
+ "include|i=s" => \&filter_opt,
+ "exclude|e=s" => \&filter_opt,
+ "INCLUDE|I=s" => \&filter_opt,
+ "EXCLUDE|E=s" => \&filter_opt,
+ "join|j" => \$join_files,
+ "no-join|J" => sub { $join_files = 0; },
+ "sort|s" => \$sort_files,
+ "loose|l" => sub { $no_loose = ".^"; },
+ "no-loose|L=s" => \$no_loose,
+ "trace|t" => \$trace);
+}
+usage() unless $getopt_ok;
+usage("--trace is incompatible with --join.\n") if $trace && $join_files;
+
+$join_files = 1 if !defined($join_files) && $sort_files && !$trace;
+use constant BRIEF => !!$brief;
+use constant LOOSE => defined($no_loose) && ($no_loose eq ".^" ? 2 : 1);
+
+# Build sub out(header, connection number) to output one connection's data
+my $out_body = (LOOSE
+ ? ' if (@loose) { print "\n", @loose; @loose = (); } '
+ : '');
+$out_body .= ' print "\n", $_[0], $lines; ';
+$out_body = " if (" . join("\n && ", @conditions) . ") {\n$out_body\n}"
+ if @conditions;
+eval <<EOM;
+sub out {
+ my \$lines = delete(\$conns{\$_[1]});
+ $out_body
+}
+1;
+EOM
+die $@ if $@;
+
+# Read and output log lines from one file
+sub do_file {
+ local(@ARGV) = @_;
+ my($conn, $line, $act);
+ while (<>) {
+ if (BRIEF
+ ? (($conn, $line, $act) = /\bconn=(\d+) (\S+ (\S+).*\n)/)
+ : (($conn, $act) = /\bconn=(\d+) \S+ (\S+)/ )) {
+ $conns{$conn} .= (BRIEF ? $line : $_);
+ out("", $conn) if $act eq 'closed';
+ } elsif (LOOSE && (LOOSE > 1 || !/$no_loose/omi)) {
+ s/^\w{3} [ \d]+:\d\d:\d\d [^:]*: // if BRIEF;
+ push(@loose, $_);
+ }
+ }
+ final() unless $join_files;
+}
+
+# Output log lines for unfinished connections
+sub final {
+ if (%conns) {
+ for my $conn (sort keys %conns) {
+ out("UNFINISHED:\n", $conn);
+ }
+ die if %conns;
+ }
+ if (LOOSE && @loose) { print "\n", @loose; @loose = (); }
+}
+
+# Main program
+if (!@ARGV) {
+ # Read from stdin
+ do_file();
+} else {
+ if ($sort_files && @ARGV > 1) {
+ # Sort files by last modified time; oldest first
+ my @fileinfo;
+ for my $file (@ARGV) {
+ my $age = -M $file;
+ if (defined($age)) {
+ push(@fileinfo, [$age, $file]);
+ } else {
+ print STDERR "File not found: $file\n";
+ }
+ }
+ exit(1) unless @fileinfo;
+ @ARGV = map { $_->[1] } sort { $b->[0] <=> $a->[0] } @fileinfo;
+ }
+
+ # Prepare to pipe .gz, .bz2 and .bz files through gunzip or bunzip2
+ my %type2prog = ("gz" => "gunzip", "bz2" => "bunzip2", "bz" => "bunzip2");
+ for (@ARGV) {
+ if (/\.(gz|bz2?)$/) {
+ my $type = $1;
+ die "Bad filename: $_\n" if /^[+-]|[^\w\/.,:%=+-]|^$/;
+ $_ = "$type2prog{$type} -c $_ |";
+ }
+ }
+
+ # Process the files
+ for my $file (@ARGV) {
+ print "\n$file:\n" if $trace;
+ do_file($file);
+ }
+}
+final();
diff --git a/contrib/slapd-tools/wrap_slap_ops b/contrib/slapd-tools/wrap_slap_ops
new file mode 100755
index 0000000..16b0461
--- /dev/null
+++ b/contrib/slapd-tools/wrap_slap_ops
@@ -0,0 +1,162 @@
+#!/usr/bin/perl -wn0777
+# wrap_slap_ops - Help update code to use SLAP_OP() & co.
+#
+# This work is part of OpenLDAP Software <http://www.openldap.org/>.
+#
+# Copyright 2011-2022 The OpenLDAP Foundation.
+# Portions Copyright 2011-2013 Hallvard B. Furuseth.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted only as authorized by the OpenLDAP
+# Public License.
+#
+# A copy of this license is available in the file LICENSE in the
+# top-level directory of the distribution or, alternatively, at
+# <http://www.OpenLDAP.org/license.html>.
+
+use strict;
+
+sub usage() {
+ warn "Usage: $0 {-l | -u | -U<num>} {file | dir}...
+
+Update slapd source code to wrap LDAP operation calls in the debug
+macros SLAP_OP() & co. They compile like the old code by default.
+Define USE_RS_ASSERT to enable asserts which verify the SlapReply.
+See servers/slapd/result.c.
+
+Options:
+ -u, -U<n> Output unidiffs with n lines of context (-u = default for diff).
+ -l List files which would change. Show remaining cases on stderr.\n";
+ exit(1);
+}
+
+#### File/option handling. Skips symlinks, handles filenames =~ /\.[ch]+p*$/i.
+
+sub ls_R {
+ map { -l $_ ? () : -d _ ? ls_R(<$_/*>) : /\.[ch]+p*$/i ? $_ : () } @_;
+}
+
+use constant Mode => shift(@ARGV) || "";
+use vars qw($ccnt $rcnt);
+INIT {
+ usage() unless Mode =~ /^-(l|[uU]\d*)$/ && ($ARGV[0]||"") =~ /^[^\-]/;
+ exit(0) unless @ARGV = ls_R(@ARGV); # Expand ARGV, exit if no files
+ $| = 1;
+ $ccnt = $rcnt = 0;
+}
+
+sub file_result( $$ ) {
+ my($contents, $changed) = @_;
+ $ccnt++ if $changed;
+ $rcnt += scalar( my @rest = remaining($contents) );
+ if (Mode eq "-l") {
+ print "$ARGV\n" if $changed;
+ print STDERR "$ARGV:\t$_\n" foreach @rest;
+ } elsif ($changed) {
+ (my $file = "$ARGV") =~ s%^-%./-%;
+ print "Index: $file\n";
+ (open(D, "|-", "diff", Mode, $file, "-")
+ && (print D $contents)
+ && (close(D) || $! == 0)) or die "$0: diff failed: $!\n";
+ }
+}
+
+END {
+ print STDERR <<EOMSG if defined $ccnt;
+$ccnt files to change. $rcnt suspicious lines remain. (Expect three in slapd).
+EOMSG
+}
+
+#### Edit the contents of a file
+
+use vars qw($obj_re %addr %func2op $func_re $todo_re);
+INIT {
+ $obj_re = qr/(?:\w+ (?:\s* (?:->|\.) \s* \w+)*?)/x;
+ %addr = ("." => "&", "->" => ""); # x.y => (&x)->y, x->y => x->y
+ %func2op = map { /(\w+) \s+ (?= .*?=>\s* (\w+))/gx } <DATA>;
+ $func_re = '\b(?=b[ei]_)(?:' . join("|", keys %func2op) . ')\b';
+ my %both = (%func2op, reverse %func2op);
+ $todo_re = '\b(?=[bo][eip]_)(?:' . join("|", keys %both) . ')\b';
+}
+next if !/$todo_re/;
+my $orig = "$_";
+
+# x->func(op, rs) ==> slap_bi_op( x, <enum op_func>, op, rs)
+# x. func(op, rs) ==> slap_bi_op(&x, <enum op_func>, op, rs)
+s%( # 1: entire match: "<delim><function>("
+ ((?: [\)!=\;{}\\] | \*/ | \b if\s*\( | \b return \b ) \s*) # 2: delim
+ (\(\s* (?:\* \s*)?)? # 3: optional "(*" or "(" in (*f)()
+ ($obj_re) \s* (->|\.) \s* # 4: object, 5: "->" or "."
+ (?=(b[ie]_))($func_re) \s* # 6: "bi_" or "be_", 7: function
+ (\)\s*)? # 8: optional ")" in (*f),
+ (\(\s*) # 9: "(" + whitespace
+)% (!$3) == (!$8) ? "$2slap_$6op$9$addr{$5}$4, $func2op{$7}, " : $1 %egox;
+
+# (&x->bi_op_bind)[which](op, rs) ==> slap_bi_op(x, which, op, rs)
+# (&x->be_bind)[which](op, rs) ==> slap_be_op(x, which, op, rs)
+s/\(&(\w+(?:(?:->|\.)\w+)*)->b(?=([ei]))(?:e|i_op)_bind\)\[\s* (\w+) \s*\] \((\s*) ([^()]*)\)
+ /slap_b$2_op($4$1, $3, $5)/gox;
+
+# slap_bi_op(x->bd_info, which, op, rs) ==> slap_be_op( x, which, op, rs)
+# slap_bi_op(x. bd_info, which, op, rs) ==> slap_be_op(&x, which, op, rs)
+s/\b slap_bi_op (\(\s*) ($obj_re) \s* (->|\.) \s* bd_info \s*,
+ /slap_be_op$1$addr{$3}$2,/gox;
+
+# slap_be_op(op->o_bd, which, &op, rs) ==> SLAP_OP(which, op, rs)
+# slap_be_op(op. o_bd, which, &op, rs) ==> SLAP_OP(which, &op, rs)
+s/\b(slap_be_op (\(\s*) ($obj_re) \s*(->|\.)\s* o_bd, \s (\w+, \s (&?)\3,))
+ / $addr{$4} eq $6 ? "SLAP_OP$2$5" : die "$ARGV: Bad syntax: $1\n" /egox;
+
+my $changed = $_ ne $orig;
+
+# When changing a file, do some whitespace cleanup too
+if ($changed) {
+ s/\b ((SLAP_OP|slap_b[ei](func)?_op) \b .*?) [\ \t]+$ /$1/gmx;
+ s/\A\s*\n//;
+ s/\s*\z/\n/;
+}
+
+file_result($_, $changed);
+
+####
+
+# Return remaining lines that contain operation method names
+sub remaining {
+ my($contents) = @_;
+ return $contents !~ /$func_re/o ? () : grep {
+ !/^\# [ \t]* define \s+ ($func_re|slap_bi_op\b) /x &&
+ # Skip "if ( (&bi->bi_op_bind)[ which ] )" and variants
+ !/^(\} \s* else \s*)? if \s* \( \s*
+ \(& (\w+ | \(\s*\w+\s*=\s*$obj_re\s*\)) -> bi_op_bind\)
+ \s* \[ \s* \w+ \s* \]
+ \s* [&|\)]/ox;
+ } $contents =~ m% ^[\ \t]* (?=\S) (
+ # The line contains a member opfunction
+ .*? (?:->|\.) \s* $func_re
+
+ # Skip if the member function is assigned, compared,
+ # 'and/or'ed, followed by a word (this is a comment), or by
+ # ') {' or ') word' (function is the boolean in an if/while).
+ (?! \s* (?: [!=&|\w] | \)\s*[\{\w] ))
+
+ .*?
+ ) \s*?$ %gmox;
+}
+
+# %func2op: Member functions => slap_operation_t
+__DATA__
+be_bind bi_op_bind => op_bind
+be_unbind bi_op_unbind => op_unbind
+be_search bi_op_search => op_search
+be_compare bi_op_compare => op_compare
+be_modify bi_op_modify => op_modify
+be_modrdn bi_op_modrdn => op_modrdn
+be_add bi_op_add => op_add
+be_delete bi_op_delete => op_delete
+be_abandon bi_op_abandon => op_abandon
+be_extended bi_extended => op_extended
+be_cancel bi_op_cancel => op_cancel
+be_operational bi_operational => op_aux_operational
+be_chk_referrals bi_chk_referrals => op_aux_chk_referrals
+be_chk_controls bi_chk_controls => op_aux_chk_controls