pgbouncer-1.5.4/0000755000175000017500000000000012055406737010517 500000000000000pgbouncer-1.5.4/lib/0000755000175000017500000000000012055406736011264 500000000000000pgbouncer-1.5.4/lib/mk/0000755000175000017500000000000012055406736011673 500000000000000pgbouncer-1.5.4/lib/mk/install-sh0000755000175000017500000003253711671654225013632 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: pgbouncer-1.5.4/lib/mk/antimake.txt0000644000175000017500000003216311763415244014151 00000000000000= antimake.mk(5) = == NAME == antimake - Minimal Automake syntax on plain GNU Make == DESCRIPTION == Antimake makes possible to use GNU Automake conventions to describe builds in ordinary Makefiles for GNU Make. It's main abstractions are target lists and target variables. Target list describes target type and where to install. Target variables give source files and additional flags for build. == EXAMPLE == ------------------- # target list bin_PROGRAMS = prog # target variables for 'prog' prog_SOURCES = prog.c prog.h prog_LDADD = libutil.a # target list noinst_LIBRARIES = libutil.a # target variables for 'libutil.a' libutil_a_SOURCES = util.c util.h # load Antimake include antimake.mk ------------------- == Terminology == Primary:: target type, describes how to build and install particular type of targets. Target:: a file that needs to be built and/or installed. Distribute:: Include file in source .tar.gz. Non-distributed files are skipped when building .tar.gz and are cleaned during `make distclean`. Source:: Source files are files that appear in `..._SOURCES` per-target variable. They are distributed by default. They may or may not result in object files. It's fine to put both `.h` and `.c` files into _SOURCES. == TARGET LISTS == Target lists are variables that contain file names that need to be built and installed. They are specially named so that the name also describes how they are built, how and where they will be installed. The target list name contains 3 parts, separated with underscore, in following order: 1. Optional flags. Flags are: `nodist`, `dist`, `nobase`, `base`. (Default: `base`, `nodist`) 2. Destination directory name. Destination directory called *bin* actual location is stored in Make variable `$(bindir)`. Some common values: `bin`, `lib`, `include`. There are more and the list can be extended. Special name `noinst` means the target file should not be installed. 3. Target type, also called "primary". This will describe how the target needs to be built. Common values: `PROGRAMS`, `LIBRARIES`, `DATA` For details, what the various values mean, see next sections. .Examples: ---------------- bin_PROGRAMS = prog1 prog2 # flags: base, nodist # dest: $(bindir) # type: PROGRAMS noinst_LIBRARIES = lib1.a lib2.a # flags: base, nodist # dest: noinst # type: LIBRARIES nobase_dist_doc_DATA = docs/README # flags: dist, nobase # dest: $(docdir)/docs # type: DATA ---------------- === Primaries === `PROGRAMS`:: executable programs, linked together from objects built from source files `LIBARIES`:: static libraries, linked together from objects built from source files `LTLIBRARIES`:: dynamic or static libraries, linked together from objects built from source files `HEADERS`:: header files, no default build method, the target files have `dist` flag by default. `MANS`:: man pages, no default build method, installed into manX subdir. `SCRIPTS`:: scripts, executable file, no default build method `DATA`:: data, non-executable file, no default build method === Target list flags === `dist`:: The target should be distributed with other sources. Default for `HEADERS` type, others have `nodist` by default. `nodist`:: Target is not distributed and should be cleaned with distclean. Default for all primaries, except `HEADERS`. `base`:: On install relative path is ignored, all files end up in destination directory. Always default. `nobase`:: On install relative path is kept. Eg: if `includedir=/usr/include` then `nobase_include_HEADERS=mylib/common.h` is installed to `/usr/include/mylib/common.h`. `noinst`:: Target is built as part of build process, but is not installed. `EXTRA`:: Targets in such list are not built, nor installed. Useful to make sure that sources for dynamically configured targets will end up in source tarball. Unlike other target list ariables, `EXTRA_` may contain targets already defined in other target lists, they will be filtered out from this list then. == Target variables == Only big targets take additional variables: `PROGRAMS`/`LIBRARIES`/`LTLIBRARIES`. `_SOURCES`:: All source files, *.c *.h *.cpp *.hpp. `nodist__SOURCES`:: Source files that should not be distributed. `EXTRA__SOURCES`:: In case tgt_SOURCES is dynamic, here is non-dynamic list of sources for distribution. Only dynamic sources need to be listed here. `_DEPENDENCIES`:: Add dependencies that need to be build before target build will start. `_CFLAGS`, `_CPPFLAGS`, `_LDFLAGS`, `_LIBTOOLFLAGS`:: Override corresponging AM_xx variable `_LDADD`:: Add dependencies that are used during linking. For PROGRAMS only. They will be added to linker command line. `_LIBADD`:: Add dependencies that are used during linking. For LIBRARIES/LTLIBRARIES only. They will be added to linker command line. `_AR`:: Overrides $(AR) $(ARFLAGS). For LIBRARIES only. .Example: ------------------- bin_PROGRAMS = prog prog_SOURCE = main.c util.c util.h prog_CFLAGS = $(GTK_CFLAGS) prog_LDADD = $(GTK_LIBS) ------------------- == Global variables == They can be set before `antimake.mk` inclusion to change build behaviour. EXTRA_DIST:: Additional files to include in source archive. CLEANFILES:: Additional files to `make clean`. DISTCLEANFILES:: Additional files to `make distclean`. MAINTAINERCLEANFILES:: Additional files to `make maintainer-clean`. SUBDIRS:: Subdirectories of current directory where Make needs to be recursively launched. If subdirectory `Makefile` is Antimake-base, it should set `SUBLOC`. SUBLOC:: Current diretory location in overall source tree. This can stay unset in top directory. Needed for subdirectiories entered with `SUBDIRS` to find its position in source tree. DIST_SUBDIRS:: Subdirs that only `make dist`, `make distclean` and `make maintainer-clean` will enter. EMBED_SUBDIRS:: Subdirectories that are built non-recursively: they need to contain `Makefile.am` that contains makefile-fragment with Antimake syntax that describes local targets using relative filenames. The fragment is included in main makefile and file and variable names are converted and merged with top-level targets. AM_FEATURES:: List of extensions to load. Extensions are Makefile fragments that are loaded before actual rules are generated, so they can change or add targets. === More details on EMBED_SUBDIRS === It acts like `include $(dir)/Makefile.am` for each directory, except it converts file and variable names. Example: --------------------- Makefile: EMBED_SUBDIRS = src src/Makefile.am: bin_PROGRAMS = hello hello_SOURCES = main.c hello_CPPFLAGS = -I./include --------------------- Conversion results as if top-level `Makefile` had contained following rows: ---------------------- bin_PROGRAMS += src/hello src_hello_SOURCES = src/main.c src_hello_CPPFLAGS = -I./src/include ---------------------- Variables, where file names are converted: * SUBDIRS, DIST_SUBDIRS, EMBED_SUBDIRS * DISTFILES, CLEANFILES, DISTCLEANFILES, MAINTAINERCLEANFILES * target lists * _SOURCES, _LDADD, _LIBADD Variables, where -L and -I flags are converted: * _CFLAGS * _CPPFLAGS * _LDFLAGS Makefile should be written in a way that those conversions would be enough. === Global variables for current location === * srcdir, builddir - relative path to source dir and build dir. * top_srcdir, top_builddir - relative path to top-level source and build dir. * abs_srcdir, abs_builddir - absolute path to source and build dir * abs_top_srcdir, abs_top_builddir - absolute path to top-level source and build dir * nosub_top_srcdir, nosub_top_builddir - relative path from top of builddir to srcdir and builddir. === Global variables that target can override === - AM_CPPFLAGS - AM_CFLAGS - AM_LDFLAGS - AM_LIBTOOLFLAGS - AM_DEFS - AM_MAKEFLAGS === Global variables from autoconf === These variables come usually from autoconf, but also have reasonable defaults: CC, DEFS, CPPFLAGS, CFLAGS, LDFLAGS, LIBS, LIBTOOL, LIBTOOLFLAGS, AR, ARFLAGS, RANLIB, CXX, CXXFLAGS, INSTALL, MKDIR_P, LN_S === Global variables for extending Antimake === AM_DIST_DEFAULT:: Default format(s) for `make dist` target. One or more of: `gzip`, `bzip2`, `xz`, `zip`. Default: `gzip`. AM_DESTINATIONS:: Additional directory names to consider as valid destinations. Expects corresponding `dir`-variable to be set. AM_SMALL_PRIMARIES:: Additional single-file primaries. (Builtin: HEADERS, SCRIPTS, DATA, MANS) AM_BIG_PRIMARIES:: Additional primaries built from objects. (Builtin: PROGRAMS, LIBRARIES, LTLIBRARIES) AM_LANGUAGES:: Additional language names. Antimake expects variables `AM_LANG_$(name)_SRCEXTS`, `AM_LANG_$(name)_COMPILE` and `AM_LANG_$(name)_LINK` to be set. === Variables for command-line usage === DESTDIR:: Relocate installation root. AM_TRACE:: Turns on function-call debug info. Can be set from command-line. === Hacking variables === GNUMAKE380, GNUMAKE381, GNUMAKE382:: If we have at least that version of GNU Make. GNUMAKE380 is always set, others may not be. If Makefile uses features from newer GNU Make it would be good idea to use those flags and error out with clear error message, instead having mysterious failures. === Libtool flags === Useful http://www.gnu.org/software/libtool/manual/html_node/Link-mode.html[Libtool] flags that can be put int tgt_LDFLAGS for a LTLIBRARY: * -export-dynamic * -export-symbols symfile * -export-symbols-regex regex * -module See libtool http://www.gnu.org/software/libtool/manual/html_node/Versioning.html["Versioning"] chapter about those: * -avoid-version * -version-info current[:revision[:age]] * -version-number major[:minor[:revision]] * -release major[:minor[:revision]] == Top-level pseudo-targets == === all === The default target when no other target is given on command-line. Builds all target files. ==== Simple targets ==== These are simple - either the file already exists, or the user needs to give build command. ==== Object-based targets ==== The targets in primaries PROGRAMS, LIBRARIES and LTLIBRARIES consist of multiple source files that need to be compiled into objects. Then the objects need to be linked into final target. The process is roughly following: . Dependencies are built (_LDADD, _LIBADD, _DEPENDENCIES). . Source list is filtered for extensions that can be compiled into object files, object file list is created based on them. The rest of files are used and dependencies for target, but otherwise ignored. . Object files are built. . Linker is picked based on source files - as there can be files in multiple languages, the most advanced language wins (the one that appears later in `AM_LANGUAGES`) . Final executable is linked. === install === Install all targets to their destination directories, which is mentioned in their target list variable name. Eg. `bin_PROGRAMS` will be installed to `$(bindir)`. If destination is named `noinst`, it will not be installed. If the flag `nobase` is given, the relative filename is kept, otherwise basename is taken and it will appear directly under destination directory. .Example: ------ include_HEADERS = func1.h lib/func2.h # Files will end up in: # $(includedir)/func1.h # $(includedir)/func2.h nobase_include_HEADERS = func1.h lib/func2.h # Files will end up in: # $(includedir)/func1.h # $(includedir)/lib/func2.h ------ === clean === - Remove files in `$(CLEANFILES)` - Remove built objects. - Remove target files, unless they are marked as `dist`. (Note: `HEADERS` primary is `dist` by default, all other are `nodist`) === distclean === - Remove files in `$(DISTCLEANFILES)` - Remove sources tagged with `nodist`. All sources as `dist` by default. === maintainer-clean === - Remove files in `$(MAINTAINERCLEANFILES)` === help === Describe top-level targets. === am-test === Regression test for low-level Antimake functions. === am-debug === Show Antimake internal state. == FEATURES == Done: - Big primaries: PROGRAMS, LIBRARIES, LTLIBRARIES - Small primaries: DATA, SCRIPTS, MANS, HEADERS - Flags: base nobase dist nodist noinst EXTRA - Target vars: SOURCES, CPPFLAGS, CFLAGS, LDFLAGS, LDADD/LIBADD - Separate build dir - Per-target objects - Languages: C, CXX - SUBDIRS, DIST_SUBDIRS - EMBED_SUBDIRS Todo: - Improve docs - Standardize and document how to extend - Deps with non-gcc? - Long if-s to support `O=` seems to break GNU Make 3.80. Drop `O=` or drop 3.80? Probably out of scope: - `make uninstall` - `make distcheck` - `make dist` from separate build dir - `install-(exec|data)-hook` - based on dir not primary - Default file list for `EXTRA_DIST`. (Problem: distclean / maintainer-clean) Definitely out of scope: - automake conditionals - automake extras (autoconf macros, ltdl) - automake nanny mode (gnu/gnits) == SEE ALSO == GNU Make Reference: http://www.gnu.org/software/make/manual/make.html#Quick-Reference[] Recursive Make Considered Harmful: http://miller.emu.id.au/pmiller/books/rmch/[] Paul's Rules of Makefiles: http://make.mad-scientist.us/rules.html[] Small BSD-ish build system: https://webkeks.org/hg/buildsys/[] GNU Make Standard Library: http://sourceforge.net/projects/gmsl/[] pgbouncer-1.5.4/lib/mk/amext-libusual.mk0000644000175000017500000000315711763415244015105 00000000000000# # Merge libusual sources with target sources # # Usage: # USUAL_DIR = # # _EMBED_LIBUSUAL = 1 # # It adds module sources into _SOURCES # and -I$(USUAL_DIR) to _CPPFLAGS. # ## ## Utility functions for libusual link ## _USUAL_DIR = $(call JoinPath,$(srcdir),$(USUAL_DIR)) # module names from sources (plus headers) UsualMods = $(trace1)$(shell $(_USUAL_DIR)/find_modules.sh $(_USUAL_DIR) $(wildcard $(addprefix $(srcdir)/,$(1)))) # full-path sources based on module list UsualSrcsFull = $(trace1)$(wildcard $(addprefix $(_USUAL_DIR)/usual/,$(addsuffix *.[ch],$(1)))) # remove USUAL_DIR UsualStrip = $(trace1)$(subst $(_USUAL_DIR)/,,$(1)) # simple-path sources based on module list UsualSrcs = $(call UsualStrip,$(call UsualSrcsFull,$(1))) # usual sources from user source file list UsualSources = $(if $(1),$(call UsualSrcsFull,$(call UsualMods,$(1)))) # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags define EmbedLibUsual $(trace5) # embed libusual objects directly $(IFEQ) ($$($(1)_EMBED_LIBUSUAL),1) $(1)_SOURCES := $$($(1)_SOURCES) $$(call UsualSources, $$($(1)_SOURCES)) EXTRA_$(1)_SOURCES := $$(EXTRA_$(1)_SOURCES) \ $$(call UsualSources, \ $$(EXTRA_$(1)_SOURCES) \ $$(nodist_$(1)_SOURCES) \ $$(nodist_EXTRA_$(1)_SOURCES)) $(1)_CPPFLAGS += -I$$(USUAL_DIR) # add libusual to vpath $(IFEQ) ($$(filter $$(USUAL_DIR),$$(VPATH)),) VPATH += $$(USUAL_DIR) $(IFNEQ) ($$(srcdir),$$(builddir),) VPATH += $$(call JoinPath,$$(srcdir),$$(USUAL_DIR)) $(ENDIF) $(ENDIF) $(ENDIF) endef AM_TARGET_HOOKS += EmbedLibUsual EXTRA_DIST += $(_USUAL_DIR)/find_modules.sh $(_USUAL_DIR)/usual/config.h.in pgbouncer-1.5.4/lib/mk/amext-modes.mk0000644000175000017500000000446211763415244014374 00000000000000# # Custom compilation modes # Compile one target several times with different # configuration variables. # # Sample: # CFLAGS = -O2 # bin_PROGRAM = prog # prog_SOURCES = prog.c # # AM_MODES = debug # CFLAGS_debug = -O0 -g # # Result: # prog - compiled with -O2 # prog-debug - compiled with -O0 -g # AM_MODES ?= # Variables that can be overrided with $(var)_$(mode) AM_MODE_OVERRIDE += CC CXX CFLAGS CPPFLAGS DEFS LDFLAGS LIBS ## add "-MODE" string before file extension # 1-mode, 2-filename ModeName = $(basename $(2))-$(1)$(suffix $(2)) ## add mode suffix to all plain filenames # 1-mode, 2-file names, options ModeFilter = $(foreach f,$(2),$(if $(filter /% -%,$(f)),$(f),$(call ModeName,$(1),$(f)))) ## set per-target var # 1-dbgvar, 2-var, 3-final ModeVarX = $(3): $(2) = $$($(1))$(NewLine) # 1-mode, 2-var, 3-final ModeVarOverride = $(if $($(2)_$(1)),$(call ModeVarX,$(2)_$(1),$(2),$(3))) # 1-mode, 2-final ModeVarOverrideAll = $(foreach v,$(AM_MODE_OVERRIDE),$(call ModeVarOverride,$(1),$(v),$(2))) ## copy target, replace vars # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags,6=mode,7-newtgt,8-cleantgt,9-list define AddModes4 $(trace8) $(IFEQ) ($$(filter $(9),$$(am_TARGETLISTS)),) am_TARGETLISTS += $(9) $(ENDIF) # add new target to old list $(9) += $(7) # copy details, change library names $(8)_SOURCES := $$($(1)_SOURCES) nodist_$$(8)_SOURCES := $$(nodist_$(1)_SOURCES) $(8)_CPPFLAGS := $$($(1)_CPPFLAGS) $(8)_CFLAGS := $$($(1)_CFLAGS) $(8)_LDFLAGS := $$($(1)_LDFLAGS) $(8)_LIBADD := $$(call ModeFilter,$(6),$$($(1)_LIBADD)) $(8)_LDADD := $$(call ModeFilter,$(6),$$($(1)_LDADD)) # add variable replacements $(call ModeVarOverrideAll,$(6),$(call FinalTargetFile,$(8),$(7),$(3))) endef ## add clean name, list name # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags,6-mode,7-raw tgt AddModes3 = $(call AddModes4,$(1),$(2),$(3),$(4),$(5),$(6),$(7),$(call CleanName,$(7)),$(subst $(Space),_,$(5)_$(4)_$(3))) ## loop over modes # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags AddModes2 = $(trace5)$(foreach m,$(AM_MODES),$(call AddModes3,$(1),$(2),$(3),$(4),$(5),$(m),$(call ModeName,$(m),$(2)))) ## ignore small primaries # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags AddModes = $(trace5)$(if $(filter $(3),$(AM_BIG_PRIMARIES)),$(call AddModes2,$(1),$(2),$(3),$(4),$(5))) # Install hook AM_TARGET_HOOKS += AddModes pgbouncer-1.5.4/lib/mk/std-autogen.sh0000755000175000017500000000234311763415244014405 00000000000000#! /bin/sh # autogen for non-automake trees # # - it installs files: config.sub, config.guess, install-sh # - it installs ltmain.sh, if LT_INIT or *LIBTOOL macro is used # set -e USUAL_DIR="$1" test -n "${USUAL_DIR}" || USUAL_DIR="." test -f "${USUAL_DIR}/m4/usual.m4" || { echo usage: $0 USUAL_DIR exit 1 } # default programs ACLOCAL=${ACLOCAL:-aclocal} AUTOCONF=${AUTOCONF:-autoconf} AUTOHEADER=${AUTOHEADER:-autoheader} # detect first glibtoolize then libtoolize if test "x$LIBTOOLIZE" = "x"; then LIBTOOLIZE=glibtoolize which $LIBTOOLIZE >/dev/null 2>&1 \ || LIBTOOLIZE=libtoolize fi # # Workarounds for libtoolize randomness - it does not update # the files if they exist, except it requires install-sh. # rm -f config.guess config.sub install-sh ltmain.sh libtool cp -p ${USUAL_DIR}/mk/install-sh . if ${LIBTOOLIZE} --help | grep "[-][-]install" > /dev/null; then ${LIBTOOLIZE} -i -f -q -c else ${LIBTOOLIZE} -c fi # drop ltmain.sh if libtool is not used grep -E 'LT_INIT|LIBTOOL' configure.ac > /dev/null \ || rm -f ltmain.sh # Now generate configure & config.h ${ACLOCAL} -I ${USUAL_DIR}/m4 grep AC_CONFIG_HEADER configure.ac > /dev/null \ && ${AUTOHEADER} ${AUTOCONF} # clean junk rm -rf autom4te.* aclocal* pgbouncer-1.5.4/lib/mk/usual.mk0000755000175000017500000000224411710647412013275 00000000000000 # libusual sources, for embedded usage USUAL_DIR ?= . VPATH += $(USUAL_DIR) ifneq ($(srcdir),$(builddir)) VPATH += $(call JoinPath,$(srcdir),$(USUAL_DIR)) endif ## ## Utility functions for libusual link ## _USUAL_DIR = $(call JoinPath,$(srcdir),$(USUAL_DIR)) # module names from sources (plus headers) UsualMods = $(trace1)$(shell $(_USUAL_DIR)/find_modules.sh $(_USUAL_DIR) $(wildcard $(addprefix $(srcdir)/,$(1)))) # full-path sources based on module list UsualSrcsFull = $(trace1)$(wildcard $(addprefix $(_USUAL_DIR)/usual/,$(addsuffix *.[ch],$(1)))) # remove USUAL_DIR UsualStrip = $(trace1)$(subst $(_USUAL_DIR)/,,$(1)) # simple-path sources based on module list UsualSrcs = $(call UsualStrip,$(call UsualSrcsFull,$(1))) # objs with objdir from source file list (1-cleantgt, 2-src list) UsualObjs = $(call SourceObjs,$(1),$(call UsualSrcs,$(call UsualMods,$(2)))) # usual sources from user source file list UsualSources = $(call UsualSrcsFull,$(call UsualMods,$(1))) # embed libusual objects directly $(1)_USUAL_SRCS = $$(call UsualSources,$$($(1)_ALLSRCS)) $(1)_OBJS += $$(call UsualObjs,$(1),$$($(1)_SOURCES) $$(nodist_$(1)_SOURCES)) $(1)_CPPFLAGS += -I$$(USUAL_DIR) pgbouncer-1.5.4/lib/mk/antimake.mk0000755000175000017500000012022412055405331013727 00000000000000#! /usr/bin/make -f # # antimake.mk - automake syntax with GNU Make # # Copyright (c) 2011 Marko Kreen # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Goals: # - Clean user Makefiles, by using automake syntax # - Clean output during build # - Optional ties with `autoconf` and `libtool` # - Automatic dependency tracking # - Avoid separate build step for Makefiles # - No extra tools needed except GNU Make # Usage without autoconf: # - copy antimake.mk into source dir, then: include antimake.mk # - copy/link antimake.mk into PATH, then: include $(shell antimake.mk) # # Usage with autoconf: # - Copy to antimake.mk.in at top dir, then process with autoconf # to antimake.mk and include that one in Makefiles. # # - Have config.mak.in that also includes antimake.mk. # Suggestion: the separate file should include antimake.mk # using $(abs_top_srcdir) to support separate build dir. # # - Include config and antimake.mk separately in user Makefiles ## ## Startup hacks ## # detect GNU make version, confuse others $(eval GNUMAKE380=1) GNUMAKE381=$(or ,$(GNUMAKE380)) define GNUMAKE382 = $(GNUMAKE381) endef # give error of too old ifeq ($(GNUMAKE381),) $(error GNU Make 3.81+ required) endif # extra targets if this file is executed directly ifeq ($(words $(MAKEFILE_LIST)), 1) .PHONY: show-location show-config # default: print location. For "include $(shell antimake.mk)"-style usage. show-location: @echo $(MAKEFILE_LIST) # show autoconfigurable variables show-config: @grep '@[^ ]*@$$' $(MAKEFILE_LIST) endif ## ## Allow this file to be processed through autoconf ## # # to extract autoconfigurable values: # $ grep '@[^ ]*@$' antimake.mk > config.mk.in # $ antimake.mk show-config > config.mk.in # ifneq ($(filter-out @%,@PACKAGE_NAME@),) PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PORTNAME = @PORTNAME@ EXEEXT = @EXEEXT@ HAVE_CC_DEPFLAG = @HAVE_CC_DEPFLAG@ # C language CC = @CC@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CFLAGS = @CFLAGS@ DEFS = @DEFS@ WFLAGS = @WFLAGS@ # C++ language CXX = @CXX@ CXXFLAGS = @CXXFLAGS@ # linking LD = @LD@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ # static and shared libs AR = @AR@ ARFLAGS = @ARFLAGS@ RANLIB = @RANLIB@ LIBTOOL = @LIBTOOL@ # other tools SHELL = @SHELL@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_DATA = @INSTALL_DATA@ MKDIR_P = @MKDIR_P@ SED = @SED@ AWK = @AWK@ GREP = @GREP@ EGREP = @EGREP@ STRIP = @STRIP@ # install locations prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ includedir = @includedir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datarootdir = @datarootdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ docdir = @docdir@ mandir = @mandir@ libdir = @libdir@ localedir = @localedir@ pkgdatadir = @pkgdatadir@ pkgconfigdir = @pkgconfigdir@ aclocaldir = @aclocaldir@ # autoconf values for top dir abs_top_srcdir ?= @abs_top_srcdir@ abs_top_builddir ?= @abs_top_builddir@ nosub_top_srcdir ?= @top_srcdir@ nosub_top_builddir ?= @top_builddir@ endif # end of @xx@ values ## ## In case of missing autoconf values, provide sane defaults ## PACKAGE_NAME ?= package PACKAGE_TARNAME ?= $(PACKAGE_NAME) PACKAGE_VERSION ?= 0.0 PACKAGE_STRING ?= $(PACKAGE_NAME) $(PACKAGE_VERSION) PACKAGE_URL ?= PACKAGE_BUGREPORT ?= PORTNAME ?= unix EXEEXT ?= HAVE_CC_DEPFLAG ?= yes # C language CC ?= cc CPP ?= cpp CPPFLAGS ?= CFLAGS ?= -O -g DEFS ?= # C++ language CXX ?= c++ CXXFLAGS ?= -O -g # warning flags are keps separately to allow easy override WFLAGS ?= -Wall # add them to main flags now CFLAGS += $(WFLAGS) CXXFLAGS += $(WFLAGS) # linking LD ?= ld LDFLAGS ?= LIBS ?= # static and shared libs LIBTOOL ?= libtool AR ?= ar ARFLAGS ?= rcs ifeq ($(ARFLAGS),rv) ARFLAGS = rcs endif RANLIB ?= ranlib # other tools SHELL ?= /bin/sh INSTALL ?= install INSTALL_PROGRAM ?= $(INSTALL) INSTALL_SCRIPT ?= $(INSTALL) INSTALL_DATA ?= $(INSTALL) MKDIR_P ?= mkdir -p SED ?= sed AWK ?= awk GREP ?= grep EGREP ?= grep -E STRIP ?= strip # install locations prefix ?= /usr/local exec_prefix ?= ${prefix} bindir ?= ${exec_prefix}/bin includedir ?= ${prefix}/include sbindir ?= ${exec_prefix}/sbin libexecdir ?= ${exec_prefix}/libexec datarootdir ?= ${prefix}/share datadir ?= ${datarootdir} sysconfdir ?= ${prefix}/etc docdir ?= ${datarootdir}/doc/${PACKAGE_TARNAME} mandir ?= ${datarootdir}/man libdir ?= ${exec_prefix}/lib localedir ?= ${datarootdir}/locale pkgdatadir ?= ${datarootdir}/${PACKAGE_TARNAME} pkgconfigdir ?= ${libdir}/pkgconfig aclocaldir ?= ${datarootdir}/aclocal # autoconf values for top dir abs_top_srcdir ?= $(CURDIR) abs_top_builddir ?= $(CURDIR) # make sure nosub vals are not empty ifeq ($(nosub_top_builddir),) nosub_top_builddir = . endif ifeq ($(nosub_top_srcdir),) nosub_top_srcdir = . endif ## ## Variables for user makefiles ## # current subdirectory location from top dir (foo/bar) SUBLOC ?= . # subdirectories in current directory SUBDIRS ?= # extra files for clean targets CLEANFILES ?= DISTCLEANFILES ?= MAINTAINERCLEANFILES ?= # Additional flags for Makefile use, to avoid need # to touch flags coming from autoconf/cmdline AM_DEFS ?= AM_CPPFLAGS ?= AM_CFLAGS ?= AM_LDFLAGS ?= AM_LIBTOOLFLAGS ?= AM_MAKEFLAGS ?= AM_LIBS ?= # libusual sources, for embedded usage USUAL_DIR ?= . # V=1 -> verbose build V ?= 0 # turn on function tracing AM_TRACE ?= # default formats for 'dist' AM_DIST_DEFAULT ?= gzip ## ## Non-user-serviceable area ## # Hacking: # # - Uppercase names are simple (late) variables, lowercase names - targets, # mixedcase - functions that need to be $(call)-ed. # # - Minimal amount of shell should be used here. # # - Minimal amount of := and $(eval) # # - It's useful to indent the expressions for easier understanding. # Later the indendation needs to be removed, as whitespace is significant for Make. # Several functions must not add any extra whitespace. # # GNU Make features in new versions: # # 3.80 - 2002-10-03: base version. $(eval) $(value) $(MAKEFILE_LIST) $(.VARIABLES) $(call fixes) # 3.81 - 2006-04-01: $(or), $(and), $(lastword), $(abspath), $(realpath), $(info), $(flavor) # 3.82 - 2010-07-28: private, undefine, define var := # # This file should use only features from 3.80 ## ## command helpers ## CCLD ?= $(CC) COMPILE ?= $(CC) $(AM_DEFS) $(DEFS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LINK ?= $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_AR ?= $(AR) $(ARFLAGS) LIBTOOLCMD ?= $(LIBTOOL) $(LIBTOOLQ) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) RM = rm -f ## ## Internals ## # varables that can be set per-target with target_VAR # they appear as AM_foo. [Not supported: COMPILE] AM_TARGET_VARIABLES += CFLAGS CPPFLAGS LDFLAGS LIBTOOLFLAGS DEFS LIBS # list of language (rather compiler) names AM_LANGUAGES += C CXX AM_BIG_PRIMARIES += LIBRARIES LTLIBRARIES PROGRAMS AM_SMALL_PRIMARIES += HEADERS SCRIPTS DATA MANS # list of destinations per primary AM_DESTINATIONS += bin lib libexec sbin \ data doc include locale man sysconf \ pkgdata pkgconfig aclocal \ noinst EXTRA # primaries where 'dist' is default AM_DIST_PRIMARIES += HEADERS AM_PRIMARIES = $(AM_BIG_PRIMARIES) $(AM_SMALL_PRIMARIES) # distclean does rm -rf on that OBJDIR = .objs # non-configurable OBJEXT = o # files that need to be converted to objects AM_SRCEXTS = $(foreach lang,$(AM_LANGUAGES),$(AM_LANG_$(lang)_SRCEXTS)) # target types - big/small: with/without objects # list of flags, 'noinst' is taken as dest, 'base' is always default AM_FLAGS = base nobase dist nodist ## configure non-defult target params AM_PROGRAMS_InstFunc = ProgInstall AM_LTLIBRARIES_InstFunc = LTLibInstall AM_LTLIBRARIES_OBJEXT = .lo AM_SCRIPTS_InstFunc = ScriptInstall AM_MANS_InstFunc = ManInstall # files to distribute am_DISTFILES := am_FINAL_DISTFILES = $(sort $(am_DISTFILES)) AM_DIST_BASE = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) AM_ALL_TARGETS = ## ## Make dependencies work ## HAVE_CC_DEPFLAG ?= yes ifeq ($(HAVE_CC_DEPFLAG),yes) OBJDEPS = -MD -MP -MT $@ -MF $@.d endif ## ## Quiet by default, 'make V=1' shows commands ## CTX ?= ifeq ($(V), 0) E = @printf "%-4s %-8s %s\n" "$(CTX)" Q = @ LIBTOOLQ = --silent MAKEFLAGS += --no-print-directory else E = @true Q = LIBTOOLQ = --silent endif ## ## libtool activation ## # libtool activates when detects %.lo / %.la pattern LTCOMPILE = $(if $(filter %.lo,$@),$(LIBTOOLCMD) --mode=compile) LTLINK = $(if $(filter %.la %.lo,$^),$(LIBTOOLCMD) --mode=link) LTCLEAN = $(LIBTOOLCMD) --mode=clean ## ## Default setup for C ## AM_LANG_C_SRCEXTS = .c define AM_LANG_C_COMPILE $(E) "CC" $< $(Q) $(LTCOMPILE) $(COMPILE) $(OBJDEPS) -c -o $@ $< endef define AM_LANG_C_LINK $(E) "CCLD" $@ $(Q) $(LTLINK) $(LINK) $^ $(AM_LIBS) $(LIBS) $(AM_LT_RPATH) endef ## ## Default setup for C++ ## AM_TARGET_VARIABLES += CXXFLAGS CXXLD ?= $(CXX) CXXCOMPILE ?= $(CXX) $(AM_DEFS) $(DEFS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLINK ?= $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_LANG_CXX_SRCEXTS = .cc .cpp cxx define AM_LANG_CXX_COMPILE $(E) "CXX" $< $(Q) $(LTCOMPILE) $(CXXCOMPILE) $(OBJDEPS) -c -o $@ $< endef define AM_LANG_CXX_LINK $(E) "CXXLD" $@ $(Q) $(LTLINK) $(CXXLINK) $^ $(AM_LIBS) $(LIBS) $(AM_LT_RPATH) endef ## ## Various other shortcuts ## define ar_lib @$(MKDIR_P) $(dir $@) $(E) "AR" $@ $(Q) $(AM_AR) $@ $^ $(E) "RANLIB" $@ $(Q) $(RANLIB) $@ endef # 1 - dir define ProgInstall $(E) "INSTALL" "$< $(1)" $(Q) $(MKDIR_P) $(1) $(Q) $(INSTALL_PROGRAM) $< $(1) endef # 1 - dir define ScriptInstall $(E) "INSTALL" "$< $(1)" $(Q) $(MKDIR_P) $(1) $(Q) $(INSTALL_SCRIPT) $< $(1) endef # 1 - dir define DataInstall $(E) "INSTALL" "$< $(1)" $(Q) $(MKDIR_P) $(1) $(Q) $(INSTALL_DATA) $< $(1) endef # 1 - dir, add manX subdir ManInstall = $(call DataInstall,$(1)/man$(call LastWord,$(subst ., ,$<))) # 1 - dir define LTLibInstall $(E) "INSTALL" "$< $(1)" $(Q) $(MKDIR_P) $(1) $(Q) $(LIBTOOLCMD) --mode=install $(INSTALL) $< $(1) endef ## ## Create .srcext -> .obj mapping for a language ## # 1-tgt, 2-name, 3-srcext define LangObjTarget $(trace3) $$(OBJDIR)/$(1)/%.o $$(OBJDIR)/$(1)/%.lo: %$(3) @$$(MKDIR_P) $$(dir $$@) $$(AM_LANG_$(2)_COMPILE) endef # 1=tgt, 2=name define LangSetup $(trace2) $(foreach ext,$(AM_LANG_$(2)_SRCEXTS),$(call LangObjTarget,$(1),$(2),$(ext))$(NewLine)) endef ## ## Utility functions ## # for function debugging, put them at the start of body ifdef AM_TRACE trace1=$(warning $0('$1')) trace2=$(warning $0('$1','$2')) trace3=$(warning $0('$1','$2','$3')) trace4=$(warning $0('$1','$2','$3','$4')) trace5=$(warning $0('$1','$2','$3','$4','$5')) trace6=$(warning $0('$1','$2','$3','$4','$5','$6')) trace7=$(warning $0('$1','$2','$3','$4','$5','$6','$7')) trace8=$(warning $0('$1','$2','$3','$4','$5','$6','$7','$8')) trace9=$(warning $0('$1','$2','$3','$4','$5','$6','$7','$8','$9')) endif # for use inside $(eval) IFDEF = ifdef IFEQ = ifeq IFNEQ = ifneq ELSE = else ENDIF = endif # returns 'true' if $1==$2 Eq = $(if $(1)$(2),$(if $(findstring $(1),$(2)),$(if $(findstring $(2),$(1)),true)),true) Not = $(if $(1),,true) Neq = $(call Not,$(call Eq,$(1),$(2))) # replace [-./] with '_' CleanName = $(subst /,_,$(subst -,_,$(subst .,_,$(1)))) # return last word from word list LastWord = $(if $(1),$(word $(words $(1)),$(1))) Empty = Space = $(Empty) $(Empty) # twice to unconfuse syntax hiliters SQuote = ' SQuote = ' define NewLine endef # quote str for shell ShellQuote = '$(subst $(SQuote),'\$(SQuote)',$(1))' # replace extensions # 1-src ext list # 2-target ext # 3-source list ReplaceExts = $(foreach ext,$(1),$(patsubst %$(ext),%$(2),$(filter %$(ext),$(3)))) # objs with objdir from source list (1-cleantgt, 2-src list) SourceObjs = $(trace1)$(call SourceObjsExt,$(1),.$(OBJEXT),$(2)) # objs with objdir from source list # 1-cleantgt, 2-objext, 3-srcs list SourceObjsExt = $(addprefix $(call JoinPath,$(OBJDIR),$(1))/, $(call ReplaceExts,$(AM_SRCEXTS),$(2),$(3))) # dependency files from object files, must match OBJDEPS DepFiles = $(wildcard $(addsuffix .d,$(1))) # per-target var override, 1=target, 2=varname # if foo_VAR exists, expand to: # build_foo install_foo clean_foo: AM_VAR = $(foo_VAR) # 1-tgt, 2-var, 3-final TgtVar2 = $(3): AM_$(2) = $$($(1)_$(2))$(NewLine) TgtVar = $(if $($(1)_$(2)),$(call TgtVar2,$(1),$(2),$(3))) # loop TgtVar over AM_TARGET_VARIABLES, 1=target, 2-final VarOverride = $(foreach var,$(AM_TARGET_VARIABLES),$(call TgtVar,$(1),$(var),$(2))) # check if actual target (.h, .exe) is nodist based on primary and flags # 1-prim 2-flags TargetNoDist = $(strip $(if $(filter nodist,$(2)), \ true, \ $(if $(filter dist,$(2)), \ , \ $(filter-out $(AM_DIST_PRIMARIES),$(1))))) # return sources that match language # 1-lang # 2-sources LangFiles = $(filter $(addprefix %,$(AM_LANG_$(1)_SRCEXTS)),$(2)) # return list of langs that match sources. # 1-sources LangList = $(strip $(foreach lang,$(AM_LANGUAGES),$(if $(call LangFiles,$(lang),$(1)),$(lang)))) # 1-sources LinkLangList = $(foreach lang,$(call LangList,$(1)),$(if $(AM_LANG_$(lang)_LINK),$(lang))) # pick linker variable based on sources, fallback to C # 1-sources DetectLinkVar = AM_LANG_$(call LastWord,C $(call LinkLangList,$(1)))_LINK # convert 'foo/bar' -> '../..' UpDirStep1 = $(subst /, ,$(1)) UpDirStep2 = $(foreach dir,$(call UpDirStep1,$(1)),../) UpDirStep3 = $(subst / ,/,$(call UpDirStep2,$(1))) UpDirStep4 = $(patsubst %/,%,$(call UpDirStep3,$(1))) UpDir = $(if $(filter-out .,$(1)),$(call UpDirStep4,$(1)),.) # # AntiMake requires that joining clean names must result in clean names. # # Thus: # JoinPath(.,foo) -> foo # JoinPath(foo,/abs) -> /abs # JoinPath(a/b,../c) -> a/c # JoinPath(a,../../b/c) -> ../b/c # # 1-path, 2-last name : foo => . | /foo => / | foo/bar => foo CutLastName = $(if $(filter $(2),$(1)),.,$(if $(filter /$(2),$(1)),/,$(patsubst %/$(2),%,$(1)))) # 1-path component, remove last elem : CutLast = $(call CutLastName,$(1),$(lastword $(subst /, ,$(1)))) # 1/2 : actual place where / is put JoinPathFinal = $(if $(filter /,$(1)),$(1)$(2),$(1)/$(2)) # 1/2 : second starts with ../, remove it and last component of $(1) JoinPath5 = $(call JoinPath,$(call CutLast,$(1)),$(patsubst ../%,%,$(2))) # 1/2: check if first ends with .. JoinPath4 = $(if $(filter .. %/..,$(1)),$(call JoinPathFinal,$(1),$(2)),$(call JoinPath5,$(1),$(2))) # 1/2 : check if second starts with ..; otherwise join JoinPath3 = $(if $(filter ../%,$(2)),$(call JoinPath4,$(1),$(2)),$(call JoinPathFinal,$(1),$(2))) # 1/2 : skips component if '.' JoinPath2 = $(if $(filter-out .,$(1)),$(if $(filter-out .,$(2)),$(call JoinPath3,$(1),$(2)),$(1)),$(2)) # 1/2 : check if b is absolute, otherwise fix minor problems JoinPath = $(trace2)$(if $(filter /%,$(2)),$(2),$(call JoinPath2,$(if $(filter /,$(1)),$(1),$(patsubst %/,%,$(1))),$(patsubst ./%,%,$(2)))) ## ## Parse target list variables ## ## pick out components from name, call function # 1-varname, 2-words, 3-func, 4-func arg # func args: 1-var, 2-prim, 3-dest, 4-flags, 5-arg ParseName = $(call $(3),$(1),$(filter $(AM_PRIMARIES),$(2)),$(filter $(AM_DESTINATIONS),$(2)),$(filter $(AM_FLAGS),$(2)),$(4)) ForEachList = $(foreach var,$(2),$(call ParseName,$(var),$(subst _, ,$(var)),$(1),$(3))) ## try reconstruct name, if fails, its a random variable # 1-var, 2-prim,3-dest,4-flags CheckName = $(if $(call Eq,$(subst _, ,$(1)),$(strip $(4) $(call LastWord,$(3)) $(call LastWord,$(2)))),$(1)) ## also check if variable is filled # 1-var, 2-prim,3-dest,4-flags CheckNameFull = $(if $(call CheckName,$(1),$(2),$(3),$(4)),$(if $($(1)),$(1))) ## ## Loop over targets in list variables ## ## call function on parsed target # 1-var, 2-prim, 3-dest, 4-flags, 5-func # func args: 1-cleantgt, 2-tgt, 3-prim, 4-dest, 5-flags ForEachTarget2 = $(foreach tgt,$($(1)),$(call $(5),$(call CleanName,$(tgt)),$(tgt),$(2),$(3),$(4))) ## ForEachTarget: call function on all targets in lists # 1-func, 2- var list # func args: 1-cleantgt, 2-tgt, 3-prim, 4-dest, 5-flags ForEachTarget = $(call ForEachList,ForEachTarget2,$(2),$(1)) ## EMBED_SUBDIRS relocations ## add subdir to files # 1-subdir, 2-file list RelocFiles = $(foreach f,$(2),$(if $(filter -%,$(f)),$(f),$(call JoinPath,$(1),$(f)))) # 1-dir, 2-pfx, 3-full RelocOneFlag2 = $(2)$(call JoinPath,$(1),$(patsubst $(2)%,%,$(3))) # 1-dir, 2-flag RelocOneFlag = $(if $(filter -L%,$(2)), \ $(call RelocOneFlag2,$(1),-L,$(2)), \ $(if $(filter -I%,$(2)), \ $(call RelocOneFlag2,$(1),-I,$(2)), \ $(2))) ## Relocate relative files, relative -I/-L, ignore -* # 1-dir, 2- flaglist RelocFlags = $(strip $(if $(filter-out .,$(1)), \ $(foreach flg,$(2),$(call RelocOneFlag,$(1),$(flg))), \ $(2))) ## Separate build dir relocation ## non-local source dir: -Isrc/include -> -Isrc/include -I$(srcdir)/src/include # 1-srcdir, 2-flag list FixIncludes = $(strip $(if $(filter-out .,$(1)), \ $(foreach flg,$(2),$(call FixIncludes2,$(1),$(flg))), \ $(2))) # 1-dir, 2-flg FixIncludes2 = $(if $(filter -I%,$(2)), \ $(call FixIncludes3,$(1),$(patsubst -I%,%,$(2))), \ $(2)) # 1-dir, 2-orig dir FixIncludes3 = -I$(2) -I$(call JoinPath,$(srcdir),$(2)) ## ## Makefile fragments ## ### fill values # abs_top_srcdir, abs_top_builddir # nosub_top_builddir, nosub_top_srcdir # 1 - subdir define SetDirs abs_builddir := $$(call JoinPath,$$(abs_top_builddir),$(1)) abs_srcdir := $$(call JoinPath,$$(abs_top_srcdir),$(1)) top_builddir := $$(call UpDir,$(1)) top_srcdir := $$(call JoinPath,$$(top_builddir),$$(nosub_top_srcdir)) builddir := . $(IFEQ) ($$(nosub_top_srcdir),$$(nosub_top_builddir)) srcdir := . $(ELSE) srcdir := $$(call JoinPath,$$(top_srcdir),$(1)) $(ENDIF) endef ## ## Embedded subdirs ## # func args: 1-cleantgt, 2-tgt, 3-prim, 4-dest, 5-flags define RelocBigTarget $(trace5) # move vars: $(foreach var,$(AM_TARGET_VARIABLES),$(NewLine)$$(am_PFX)_$(1)_$(var) := $$($(1)_$(var))) # move and relocate EXTRA_$$(am_PFX)_$(1)_SOURCES := $$(call RelocFiles,$$(am_DIR),$$(EXTRA_$(1)_SOURCES)) $$(am_PFX)_$(1)_SOURCES := $$(call RelocFiles,$$(am_DIR),$$($(1)_SOURCES)) $$(am_PFX)_$(1)_DEPENDENCIES := $$(call RelocFiles,$$(am_DIR),$$($(1)_DEPENDENCIES)) $$(am_PFX)_$(1)_LDADD := $$(call RelocFiles,$$(am_DIR),$$($(1)_LDADD)) $$(am_PFX)_$(1)_LIBADD := $$(call RelocFiles,$$(am_DIR),$$($(1)_LIBADD)) $$(am_PFX)_$(1)_CFLAGS := $$(call RelocFlags,$$(am_DIR),$$($(1)_CFLAGS)) $$(am_PFX)_$(1)_CPPFLAGS := $$(call RelocFlags,$$(am_DIR),$$($(1)_CPPFLAGS)) $$(am_PFX)_$(1)_LDFLAGS := $$(call RelocFlags,$$(am_DIR),$$($(1)_LDFLAGS)) # clean vars $(1)_SOURCES = $(1)_LDADD = $(1)_LIBADD = $(foreach var,$(AM_TARGET_VARIABLES),$(NewLine)$(1)_$(var) = ) endef ## pick actual func # func args: 1-cleantgt, 2-tgt, 3-prim, 4-dest, 5-flags define RelocTarget $(trace5) $(if $(filter $(AM_BIG_PRIMARIES),$(3)),$(call RelocBigTarget,$(1),$(2),$(3),$(4),$(5))) endef ## relocate target list # func args: 1-var, 2-prim, 3-dest, 4-flags, 5-arg define RelocTList $(trace5) # detect top and subdir target conflict - it's easier to detect # and error out than to work around the rare case $(IFNEQ) (,$$(filter $(2),$$(AM_BIG_PRIMARIES))) $(IFEQ) (.,$$(am_DIR)) am_TOP_NAMES += $$(foreach tgt,$$($(1)),$$(call CleanName,$$(tgt))) $(ELSE) $(IFNEQ) (,$$(filter $$(am_TOP_NAMES),$$(foreach tgt,$$($(1)),$$(call CleanName,$$(tgt))))) $$(error $$(NewLine)$$(NewLine)\ *** Target names used in top Makefile cannot be re-used in embedded Makefiles. $$(NewLine)\ *** The target variables (eg. _SOURCES) conflict is not handled yet) $(ENDIF) $(ENDIF) $(ENDIF) # move value under real_% $(IFEQ) ($(real_$(1)),) real_$(1) := $(ENDIF) real_$(1) += $$(call RelocFiles,$$(am_DIR),$$($(1))) $(1) = # remember in proper list $(IFEQ) ($(3),EXTRA) am_EXTRA_TARGETLISTS += real_$(1) $(ELSE) am_TARGETLISTS += real_$(1) $(ENDIF) endef ## process included values # 1-dir, 2-pfx, 3-tlist define EmbedProcess $(trace3) $(IFNEQ) ($$(filter $(1),$$(am_EMBED_DONE)),) $$(error Double entry in EMBED_SUBDIRS: $(1)) $(ENDIF) # init local vars am_DIR := $(1) am_LOC := $$(call JoinPath,$$(SUBLOC),$(1)) am_PFX := $(2) am_EMBED_DONE += $(1) # reloc & save vars am_DISTFILES += $$(call RelocFiles,$$(am_DIR),$$(EXTRA_DIST)) am_CLEANFILES += $$(call RelocFiles,$$(am_DIR),$$(CLEANFILES)) am_DISTCLEANFILES += $$(call RelocFiles,$$(am_DIR),$$(DISTCLEANFILES)) am_MAINTAINERCLEANFILES += $$(call RelocFiles,$$(am_DIR),$$(MAINTAINERCLEANFILES)) am_EMBED_TODO += $$(call RelocFiles,$$(am_DIR),$$(EMBED_SUBDIRS)) am_SUBDIRS += $$(call RelocFiles,$$(am_DIR),$$(SUBDIRS)) am_DIST_SUBDIRS += $$(call RelocFiles,$$(am_DIR),$$(DIST_SUBDIRS)) # clean vars for new dir EXTRA_DIST = CLEANFILES = DISTCLEANFILES = MAINTAINERCLEANFILES = EMBED_SUBDIRS = SUBDIRS = DIST_SUBDIRS = $(call SetDirs,$(call JoinPath,$(SUBLOC),$(1))) $(call ForEachTarget,RelocTarget,$(3)) $(call ForEachList,RelocTList,$(3)) endef ## read Makefile.am, process it # 1 - dir DoEmbed = $(trace1)$(strip \ $(if $(wildcard $(am_srcdir)/$(1)/Makefile.am), \ $(eval include $(am_srcdir)/$(1)/Makefile.am $(NewLine)) \ $(eval $(call EmbedProcess,$(1),$(call CleanName,$(1)),$(AM_NONEXTRA_TLISTS) $(AM_EXTRA_TLISTS))), \ $(error $(SUBLOC)/Makefile failure: $(call JoinPath,$(SUBLOC),$(1)/Makefile.am) not found.))) ## ## Fragments that build targets ## # Note that variable initialization order is important here # as some of them will be used immediately. ## ## Install target object ## # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags define InstallTarget $(trace5) $(1)_DEST := $$(if $$($(4)dir),$$($(4)dir),$$(error '$(4)dir' empty))$(if $(filter nobase,$(5)),/$(dir $(2))) $(1)_InstFunc := $$(if $$(AM_$(3)_InstFunc),$$(AM_$(3)_InstFunc),DataInstall) # actual installation .PHONY: install_$(1) install: install_$(1) install_$(1): $(2) $$(call $$($(1)_InstFunc),$$(DESTDIR)$$($(1)_DEST)) # hack to pass -rpath to LTLIBRARIES on build time (1) $(2): AM_DEST = $$($(1)_DEST) endef # hack to pass -rpath to LTLIBRARIES on build time (2) %.la: AM_LT_RPATH = $(if $(AM_DEST),-rpath $(AM_DEST)) ## ## Rules for big target ## # calculate target file name # 1-clean, 2-raw, 3-prim FinalTargetFile = $(if $(filter PROGRAMS,$(3)$($(1)_EXT)),$(2)$(EXEEXT),$(2)$($(1)_EXT)) # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags define BigTargetBuild $(trace5) AM_ALL_TARGETS += $(1) $(1)_ALLSRCS := $$($(1)_SOURCES) $$(EXTRA_$(1)_SOURCES) $$(nodist_$(1)_SOURCES) $$(nodist_EXTRA_$(1)_SOURCES) # calculate OBJS from SOURCES $(1)_OBJEXT := $$(if $$(AM_$(3)_OBJEXT),$$(AM_$(3)_OBJEXT),.$$(OBJEXT)) $(1)_OBJS := $$(call SourceObjsExt,$(1),$$($(1)_OBJEXT), \ $$($(1)_SOURCES) $$(nodist_$(1)_SOURCES)) # include additional objects, move flags to _LIBS $(IFEQ) ($(3),PROGRAMS) $(1)_OBJS += $$(filter-out -%,$$($(1)_LDADD)) $(1)_LIBS += $$(filter -%,$$($(1)_LDADD)) $(ELSE) $(1)_OBJS += $$(filter-out -%,$$($(1)_LIBADD)) $(1)_LIBS += $$(filter -%,$$($(1)_LIBADD)) $(ENDIF) # autodetect linker, unless given $(IFEQ) ($($(1)_LINK),) $(1)_LINKVAR := $$(call DetectLinkVar,$$($(1)_ALLSRCS)) $(ELSE) $(1)_LINKVAR := $(1)_LINK $(ENDIF) # calculate target file name $(1)_FINAL = $(call FinalTargetFile,$(1),$(2),$(3)) # hook libtool into LTLIBRARIES cleanup $(IFEQ) ($(3),LTLIBRARIES) $(1)_RM = $$(LTCLEAN) $$(RM) $(ELSE) $(1)_RM = $$(RM) $(ENDIF) # fix includes in case of separate build dir $(1)_CPPFLAGS := $$(call FixIncludes,$$(srcdir),$$($(1)_CPPFLAGS)) $(1)_CFLAGS := $$(call FixIncludes,$$(srcdir),$$($(1)_CFLAGS)) # load dependencies -include .dummy. $$(call DepFiles, $$($(1)_OBJS)) # actual build, clean & install targets .PHONY: build_$(1) clean_$(1) # allow target-specific variables $$(eval $$(call VarOverride,$(1),$(call FinalTargetFile,$(1),$(2),$(3)))) # build and clean by default, unless flagged EXTRA $(IFNEQ) ($(4),EXTRA) all: build_$(1) clean: clean_$(1) $(ENDIF) build_$(1): $$($(1)_SOURCES) $$(nodist_$(1)_SOURCES) build_$(1): $$($(1)_DEPENDENCIES) build_$(1): $$($(1)_FINAL) $$($(1)_FINAL): $$($(1)_OBJS) @$$(MKDIR_P) $$(dir $$@) $$($(if $(filter LIBRARIES,$(3)),ar_lib,$$($(1)_LINKVAR))) clean_$(1): $$(E) "CLEAN" "$$($(1)_FINAL)" $$(Q) $$($(1)_RM) -- $$($(1)_OBJS) $(if $(call TargetNoDist,$(3),$(5)),$$($(1)_FINAL)) DISTCLEANFILES += $$(nodist_$(1)_SOURCES) $$(nodist_EXTRA_$(1)_SOURCES) $(foreach lang,$(AM_LANGUAGES),$(call LangSetup,$(1),$(lang))) endef # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags define BigTargetDist am_DISTFILES += $$(filter-out $$(nodist_EXTRA_$(1)_SOURCES) $$(nodist_$(1)_SOURCES),$$($(1)_SOURCES) \ $$(EXTRA_$(1)_SOURCES)) $(if $(call TargetNoDist,$(3),$(5)),,$$($(1)_FINAL)) endef # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags define MakeBigTarget $(trace5) # build if first time $(IFEQ) ($(filter $(1),$(AM_ALL_TARGETS)),) $(call BigTargetBuild,$(1),$(2),$(3),$(4),$(5)) $(call BigTargetDist,$(1),$(2),$(3),$(4),$(5)) $(ELSE) # allow only EXTRA be double $(IFNEQ) ($(4),EXTRA) $$(error Target '$2' described listed several times) $(ENDIF) $(ENDIF) # call InstallTarget, for dest != (EXTRA, noinst) $(IFEQ) ($(filter EXTRA noinst,$(4)),) $(call InstallTarget,$(1),$$($(1)_FINAL),$(3),$(4),$(5)) $(ENDIF) endef ## ## Rules for small target ## # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags define MakeSmallTarget $(trace5) AM_ALL_TARGETS += $(1) # should the target file be distributed or cleaned? $(IFEQ) ($(call TargetNoDist,$(3),$(5)),) am_DISTFILES += $(2) $(ELSE) CLEANFILES += $(2) $(ENDIF) # build if not EXTRA $(IFNEQ) ($(4),EXTRA) all: $(2) # install if not EXTRA or noinst $(IFNEQ) ($(4),noinst) $(call InstallTarget,$(1),$(2),$(3),$(4),$(5)) $(ENDIF) $(ENDIF) endef ## ## Fill GNU-style vars for subdir ## # preferred to top_srcdir/top_builddir topdir = $(top_builddir) ifneq ($(nosub_top_builddir),.) $(error Non-local builddir not supported) endif # initial locaton vars $(eval $(call SetDirs,$(SUBLOC))) ifneq ($(nosub_top_srcdir),$(nosub_top_builddir)) # use VPATH to find non-local sources VPATH += $(srcdir) # fix includes AM_CPPFLAGS := $(call FixIncludes,$(srcdir),$(AM_CPPFLAGS)) AM_CFLAGS := $(call FixIncludes,$(srcdir),$(AM_CFLAGS)) endif ## ## O= ## if given, create wrapper makefiles in target dir ## that include makefiles from source dir, then run ## make from target dir. ## ifneq ($(O),) # 1-makefile define WrapMakeFileCmd @$(MKDIR_P) '$(dir $(O)/$(1))' @printf '%s\n%s\n%s\n%s\n%s\n' \ 'abs_top_srcdir = $(CURDIR)' \ 'abs_top_builddir = $(call JoinPath,$(CURDIR),$(O))' \ 'nosub_top_srcdir = $(call UpDir,$(O))' \ 'nosub_top_builddir = .' \ 'include $(abs_top_srcdir)/$(1)' \ > $(O)/$(1) endef # 1-makefile WrapMakeFile = $(if $(wildcard $(O)/$(1)),,$(call WrapMakeFileCmd,$(1))$(NewLine)) # redirect whatever rule was given .PHONY: all $(MAKECMDGOALS) all $(filter-out all,$(MAKECMDGOALS)): $(if $(wildcard $(O)),,$(error O=$(O): Directory '$(O)' does not exist)) $(foreach mk,$(filter-out /%,$(MAKEFILE_LIST)),$(call WrapMakeFile,$(mk))) $(Q) $(MAKE) O= -C $(O) $(MAKECMDGOALS) # O=empty, this is main makefile else ## ## main targets, tie them with subdir and local targets ## # disable random rules .SUFFIXES: all: sub-all all-local clean: sub-clean clean-local install: sub-install install-local distclean: sub-distclean distclean-local maintainer-clean: sub-maintainer-clean maintainer-clean-local .PHONY: all clean install dist distclean maintainer-clean # -local are empty targets by default .PHONY: all-local clean-local install-local distclean-local maintainer-clean-local all-local clean-local install-local distclean-local maintainer-clean-local: ## ## Actual embedding starts ## AM_ALL_TLISTS2 = $(filter $(addprefix %,$(AM_PRIMARIES)),$(.VARIABLES)) AM_ALL_TLISTS = $(call ForEachList,CheckName,$(AM_ALL_TLISTS2)) AM_NONEXTRA_TLISTS = $(filter-out EXTRA_%,$(AM_ALL_TLISTS)) AM_EXTRA_TLISTS = $(filter EXTRA_%,$(AM_ALL_TLISTS)) am_srcdir := $(srcdir) am_DIR := . am_PFX := am_TARGETLISTS := am_EXTRA_TARGETLISTS := am_TOP_NAMES := # move top-level targets away $(eval $(call ForEachList,RelocTList,$(AM_NONEXTRA_TLISTS))) $(eval $(call ForEachList,RelocTList,$(AM_EXTRA_TLISTS))) am_SUBDIRS := $(SUBDIRS) am_DIST_SUBDIRS := $(DIST_SUBDIRS) am_DISTFILES := $(EXTRA_DIST) am_CLEANFILES := $(CLEANFILES) am_DISTCLEANFILES := $(DISTCLEANFILES) am_MAINTAINERCLEANFILES := $(MAINTAINERCLEANFILES) am_EMBED_NOW := $(EMBED_SUBDIRS) am_EMBED_DONE := am_EMBED_TODO := EXTRA_DIST = CLEANFILES = DISTCLEANFILES = MAINTAINERCLEANFILES = SUBDIRS = DIST_SUBDIRS = EMBED_SUBDIRS = $(foreach dir,$(am_EMBED_NOW),$(call DoEmbed,$(dir))) am_EMBED_NOW := $(am_EMBED_TODO) am_EMBED_TODO := $(foreach dir,$(am_EMBED_NOW),$(call DoEmbed,$(dir))) am_EMBED_NOW := $(am_EMBED_TODO) am_EMBED_TODO := $(foreach dir,$(am_EMBED_NOW),$(call DoEmbed,$(dir))) am_EMBED_NOW := $(am_EMBED_TODO) am_EMBED_TODO := $(if $(am_EMBED_NOW),$(error EMBED_SUBDIRS recursion limit reached...)) # embedding done, move variables back $(eval $(call SetDirs,$(SUBLOC))) CLEANFILES := $(am_CLEANFILES) DISTCLEANFILES := $(am_DISTCLEANFILES) MAINTAINERCLEANFILES := $(am_MAINTAINERCLEANFILES) SUBDIRS := $(am_SUBDIRS) DIST_SUBDIRS := $(am_DIST_SUBDIRS) EMBED_SUBDIRS := $(am_EMBED_DONE) am_CLEANFILES = am_DISTCLEANFILES = am_MAINTAINERCLEANFILES = am_DIST_SUBDIRS = am_SUBDIRS = am_EMBED_DONE = am_TARGETLISTS := $(sort $(am_TARGETLISTS)) am_EXTRA_TARGETLISTS := $(sort $(am_EXTRA_TARGETLISTS)) # allow seeing moved lists AM_FLAGS += real ## EMBED_SUBDIRS end ## ## Launch target hooks ## amdir = $(dir $(realpath $(filter %/antimake.mk antimake.mk,$(MAKEFILE_LIST)))) # 1-feat name FeatFile = $(amdir)/amext-$(1).mk # 1- fname LoadFeature = $(if $(wildcard $(call FeatFile,$(1))),$(eval include $(call FeatFile,$(1))),$(error Feature "$(call FeatFile,$(1))" is not available.)) $(foreach f,$(AM_FEATURES),$(call LoadFeature,$(f))) $(eval $(foreach hook,$(AM_TARGET_HOOKS),$(call ForEachTarget,$(hook),$(am_TARGETLISTS)))) ## ## Now generate the rules ## ## check which target func to call # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags MakeTarget = $(call $(if $(filter $(AM_BIG_PRIMARIES),$(3)),MakeBigTarget,MakeSmallTarget),$(1),$(2),$(3),$(4),$(5)) ## process all targets in one list # 1-list, 2-prim,3-dest,4-flags MakeTargetList = $(foreach tgt,$($(1)),$(call MakeTarget,$(call CleanName,$(tgt)),$(tgt),$(2),$(3),$(4))) ## process all target lists # 1=list names ProcessTargets = $(call ForEachTarget,MakeTarget,$(1)) # process non-EXTRA targets $(eval $(call ProcessTargets,$(am_TARGETLISTS))) # process EXTRA_* last, they may already have been processed $(eval $(call ProcessTargets,$(am_EXTRA_TARGETLISTS))) ## ## clean targets ## clean: ifdef CLEANFILES $(E) "CLEAN" $@ $(Q) $(RM) -- $(CLEANFILES) endif distclean: clean $(E) "DISTCLEAN" $@ $(Q) $(RM) -r -- $(OBJDIR) ifdef DISTCLEANFILES $(Q) $(RM) -- $(DISTCLEANFILES) endif maintainer-clean: clean $(E) "MAINTAINERCLEAN" $@ $(Q) $(RM) -r -- $(OBJDIR) ifdef DISTCLEANFILES $(Q) $(RM) -- $(DISTCLEANFILES) endif ifdef MAINTAINERCLEANFILES $(Q) $(RM) -- $(MAINTAINERCLEANFILES) endif ## ## actual subdir targets ## # 1-dir define MakeSubDir $(trace1) $(E) "MKDIR" "Create $(call JoinPath,$(SUBLOC),$(1))" $(Q) @$(MKDIR_P) $(1) $(Q) @echo "include $(call UpDir,$(1))/$(srcdir)/$(1)/Makefile" > $(1)/Makefile endef # 1-dir, 2-tgt define SubTarget $(trace2) $(if $(wildcard $(1)/Makefile),,$(call MakeSubDir,$(1))) $(E) "-->" "$(call JoinPath,$(SUBLOC),$(1))" $(Q) $(MAKE) -C $(1) $(2) $(E) "<--" "$(call JoinPath,$(SUBLOC),$(1))" endef sub-all sub-install sub-clean: $(foreach dir,$(SUBDIRS),$(call SubTarget,$(dir),$(subst sub-,,$@))$(NewLine)) # Avoid double dirs in DIST_SUBDIRS, without changing order am_DISTDIRS = $(SUBDIRS) $(foreach dir,$(DIST_SUBDIRS),$(if $(filter $(dir),$(SUBDIRS)),,$(dir))) sub-dist sub-distclean sub-maintainer-clean: $(foreach dir,$(am_DISTDIRS),$(call SubTarget,$(dir),$(subst sub-,,$@))$(NewLine)) .PHONY: sub-all sub-clean sub-install sub-dist sub-distclean sub-maintainer-clean ## ## actual dist targets ## DistTarget = $(foreach fmt,$(1),dist-$(fmt)) AM_DIST_ALL ?= gzip bzip2 xz zip AM_DIST_ALL_TGTS = $(call DistTarget,$(AM_DIST_ALL)) AM_DIST_DEF_TGTS = $(call DistTarget,$(AM_DIST_DEFAULT)) AM_FORMAT_gzip_EXT = tar.gz AM_FORMAT_gzip_CMD = tar chof - $(AM_DIST_BASE) | gzip > $(AM_DIST_BASE).$(AM_FORMAT_gzip_EXT) AM_FORMAT_bzip2_EXT = tar.bz2 AM_FORMAT_bzip2_CMD = tar chof - $(AM_DIST_BASE) | bzip2 > $(AM_DIST_BASE).$(AM_FORMAT_bzip2_EXT) AM_FORMAT_xz_EXT = tar.xz AM_FORMAT_xz_CMD = tar chof - $(AM_DIST_BASE) | xz > $(AM_DIST_BASE).$(AM_FORMAT_xz_EXT) AM_FORMAT_zip_EXT = zip AM_FORMAT_zip_CMD = zip -rq $(AM_DIST_BASE).$(AM_FORMAT_zip_EXT) $(AM_DIST_BASE) # 1-name define MakeDist $(E) "CHECK" $@ $(Q) $(MAKE) -s am-check-distfiles $(E) "MKDIR" $(AM_DIST_BASE) $(Q) $(RM) -r -- $(AM_DIST_BASE) $(AM_DIST_BASE).$(AM_DIST_$(1)_EXT) $(Q) $(MKDIR_P) $(AM_DIST_BASE) $(E) "COPY" $(AM_DIST_BASE) $(Q) $(MAKE) -s am-show-distfiles | cpio -pmdL --quiet $(AM_DIST_BASE) $(E) "PACK" $(AM_DIST_BASE).$(AM_FORMAT_$(1)_EXT) $(Q) $(AM_FORMAT_$(1)_CMD) $(Q) $(RM) -r -- $(AM_DIST_BASE) endef .PHONY: dist $(AM_DIST_ALL_TGTS) dist: $(AM_DIST_DEF_TGTS) dist-all: $(AM_DIST_ALL_TGTS) $(AM_DIST_ALL_TGTS): $(call MakeDist,$(subst dist-,,$@)) # show list of files that need to be in final archive .PHONY: am-show-distfiles am-show-distfiles: $(foreach dir,$(am_DISTDIRS),@$(MAKE) $(AM_MAKEFLAGS) --no-print-directory -C $(dir) $@ $(NewLine)) $(foreach file,$(am_FINAL_DISTFILES),@echo "$(call JoinPath,$(SUBLOC),$(file))" $(NewLine)) # do dependencies as separate step, in case building outputs anything .PHONY: am-check-distfiles am-check-distfiles: $(am_FINAL_DISTFILES) $(foreach dir,$(am_DISTDIRS),@$(MAKE) $(AM_MAKEFLAGS) -C $(dir) $@ $(NewLine)) ## ## debug target ## # 1=var define AmDebugShow $(if $($(1)),@echo '$(1) = $($(1))') $(NewLine) endef # 1=cleantgt,2=rawtgt,3=prim,4=dest,5=flags define AmDebugTarget $(trace5) $(foreach var,$(AM_DEBUG_TARGET_VARS),$(call AmDebugShow,$(1)_$(var))) @echo "" endef # func args: 1-var, 2-prim, 3-dest, 4-flags CollectDests = $(filter-out noinst EXTRA,$(3)) AM_USED_DESTS = $(sort $(call ForEachList,CollectDests,$(am_TARGETLISTS))) AM_DEBUG_VARS = GNUMAKE380 GNUMAKE381 GNUMAKE382 MAKEFILE_LIST \ AM_LANGUAGES AM_FLAGS AM_DESTINATIONS \ AM_ALL_TARGETS EXEEXT am_FINAL_DISTFILES \ nosub_top_builddir nosub_top_srcdir \ abs_top_srcdir abs_top_builddir \ srcdir builddir top_srcdir top_builddir \ SUBDIRS EMBED_SUBDIRS DIST_SUBDIRS \ DISTFILES CLEANFILES DISTCLEANFILES MAINTAINERCLEANFILES AM_DEBUG_TARGET_VARS = SOURCES OBJS LINKVAR DEST USUAL_OBJS USUAL_SRCS EXT FINAL \ $(AM_TARGET_VARIABLES) AM_DEBUG_LANG_VARS = SRCEXTS am-debug: @echo ""; echo "==== Global Variables ====" $(foreach var,$(AM_DEBUG_VARS),$(call AmDebugShow,$(var))) @echo ""; echo "==== Per-language Variables ====" $(foreach lg,$(AM_LANGUAGES),$(foreach var,$(AM_DEBUG_LANG_VARS),$(call AmDebugShow,AM_LANG_$(lg)_$(var)))) @echo ""; echo "==== Per-target Variables ====" $(call ForEachTarget,AmDebugTarget,$(am_TARGETLISTS) $(am_EXTRA_TARGETLISTS)) @echo ""; echo "==== Active install directories ====" $(foreach dst,$(AM_USED_DESTS),@echo ' $(dst)dir = $($(dst)dir)'$(NewLine)) ## ## regtests for basic tools ## AM_TESTS = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 AM_TEST_1 = $(call Eq,a b c,a b c),$(call Eq,,),$(call Eq,a,aa),$(call Eq,a,a a) AM_TEST_1_RES = true,true,, AM_TEST_2 = $(call Neq,a,aa),$(call Neq,a,a) AM_TEST_2_RES = true, AM_TEST_3 = $(call CleanName,obj/foo-baz.x) AM_TEST_3_RES = obj_foo_baz_x AM_TEST_4 = $(call LastWord,a),$(call LastWord,a b c),$(call LastWord,) AM_TEST_4_RES = a,c, AM_TEST_5 = $(call ReplaceExts,.c .cpp X.foo,.o,s1.c s2.cpp s3X.foo s4.h) AM_TEST_5_RES = s1.o s2.o s3.o AM_TEST_5 = $(call LangList,foo.c c.foo),$(call LangList,foo.c c.foo f.cpp) AM_TEST_5_RES = C,C CXX AM_TEST_6 = $(call DetectLinkVar,foo.c c.foo),$(call DetectLinkVar,foo.c c.foo x.cpp),$(call DetectLinkVar,foo),$(call DetectLinkVar,) AM_TEST_6_RES = AM_LANG_C_LINK,AM_LANG_CXX_LINK,AM_LANG_C_LINK,AM_LANG_C_LINK AM_TEST_7 = $(call UpDir,foo)|$(call UpDir,)|$(call UpDir,.)|$(call UpDir,foo/bar)|$(call UpDir,a/b/c)| AM_TEST_7_RES = ..|.|.|../..|../../..| AM_TEST_8 = $(call JoinPath,.,.)|$(call JoinPath,,)|$(call JoinPath,a,.)|$(call JoinPath,.,b)|$(call JoinPath,a,b)|$(call JoinPath,a/b,../c)|$(call JoinPath,a/b,../../../c) AM_TEST_8_RES = .||a|b|a/b|a/c|../c define AM_TEST_9_EVAL $(IFEQ) ($$(AM_TEST_9_RES),OK) AM_TEST_9 = OK $(ELSE) AM_TEST_9 = fail $(ENDIF) endef AM_TEST_9_RES = OK $(eval $(AM_TEST_9_EVAL)) AM_TEST_10 = $(call CheckName,nobase_bin_PROGRAMS,PROGRAMS,bin,nobase)|$(call CheckName,a,a,,)|$(call CheckName,bin_bin_DATA,,bin bin,DATA) AM_TEST_10_RES = nobase_bin_PROGRAMS|a| AM_TEST_11_Show = $(4)-$(3)-$(2) AM_TEST_11 = $(call ForEachList,AM_TEST_11_Show,bin_PROGRAMS foo_DATA baz_foo base_nobase_dist_nodist_DATA_PROGRAMS) AM_TEST_11_RES = -bin-PROGRAMS --DATA -- base nobase dist nodist--DATA PROGRAMS AM_TEST_12 = $(call RelocFlags,sub/dir,-I. -I./foo -Lfoo/bar -I/inc -L/lib -lfoo) AM_TEST_12_RES = -Isub/dir -Isub/dir/foo -Lsub/dir/foo/bar -I/inc -L/lib -lfoo AM_TEST_13 = $(call TargetNoDist,HEADERS,)|$(call TargetNoDist,HEADERS,nodist)|$(call TargetNoDist,PROGRAMS,)|$(call TargetNoDist,PROGRAMS,dist) AM_TEST_13_RES = |true|PROGRAMS| AM_TEST_14 = $(call ShellQuote,foo'bar\')|$(call ShellQuote,as!d' \\ $$foo) AM_TEST_14_RES = 'foo'\''bar\'\'''|'as!d'\'' \\ $$foo' AM_TEST_15 = $(call JoinPath,sub/dir,../foo) , \ $(call JoinPath,sub/dir,../../foo) , \ $(call JoinPath,sub/dir,../../../foo) , \ $(call JoinPath,sub/dir/,../foo) , \ $(call JoinPath,/,./foo) , \ $(call JoinPath,..,../foo) , \ $(call JoinPath,/foo,../baz) , \ $(call JoinPath,/foo,../../baz) , \ $(call JoinPath,foo/..,./foo) AM_TEST_15_RES = sub/foo , foo , ../foo , sub/foo , /foo , ../../foo , /baz , /baz , foo/../foo AM_TEST_16_EXT = .foo AM_TEST_16 = $(call FinalTargetFile,prog,prog,PROGRAMS) | $(call FinalTargetFile,AM_TEST_16,AM_TEST_16,PROGRAMS) AM_TEST_16_RES = prog$(EXEEXT) | AM_TEST_16.foo AmTest = $(if $(call Eq,$($(1)),$($(2))),@echo '$(1): OK',@echo '$(1): FAIL: $($(1)) != $($(2))')$(NewLine) am-test: $(Q) test "$(call Eq,a b c,a b c),$(call Eq,,),$(call Eq,a,aa),$(call Eq,a,a a)" = "true,true,," $(foreach nr,$(AM_TESTS),$(call AmTest,AM_TEST_$(nr),AM_TEST_$(nr)_RES)) ## ## help target ## AmHelpNames = targets standalone internal config dests .PHONY: help $(foreach n,$(AmHelpNames),help-$(n) help-$(n)-local) $(foreach n,$(AmHelpNames),help-$(n)-local): help: $(foreach n,$(AmHelpNames),help-$(n) help-$(n)-local) # 1-var, 2-desc AmConf = @printf ' %-27s %s=%s\n' $(call ShellQuote,$(2)) $(call ShellQuote,$(1)) $(call ShellQuote,$($(1))) help-targets: @echo "" @echo "Main targets:" @echo " all Build all targets (default)" @echo " install Install files" @echo " dist Create source archive" @echo " clean Clean built files" @echo " distclean Clean configured files" @echo " maintainer-clean Delete anything that can be generated" help-standalone: @echo "" @echo "Standalone targets: (make -f antimake.mk)" @echo " show-location Prints full path to antimake.mk (default)" @echo " show-config Prints template config.mak.in" help-internal: @echo "" @echo "Internal targets:" @echo " am-show-distfiles Shows files that go into source archive" @echo " am-debug Shows variables that affect the build" @echo " am-test Regtest for internal functions" help-config: @echo "" @echo "Config variables and their current values:" $(call AmConf,CC,C compiler) $(call AmConf,CFLAGS,C compiler flags) $(call AmConf,CPPFLAGS,C pre-processor flags) $(call AmConf,LDFLAGS,Linker flags) help-dests: @echo "" @echo "Destinations for install [ prefix=$(prefix) ]:" $(foreach dst,$(AM_USED_DESTS),@echo ' $(dst)dir = $($(dst)dir)'$(NewLine)) endif # O=empty pgbouncer-1.5.4/lib/m4/0000755000175000017500000000000012055406736011604 500000000000000pgbouncer-1.5.4/lib/m4/usual.m40000644000175000017500000002752012055405655013124 00000000000000 dnl Those depend on correct order: dnl AC_USUAL_INIT dnl AC_USUAL_PROGRAM_CHECK dnl AC_USUAL_HEADER_CHECK dnl AC_USUAL_TYPE_CHECK dnl AC_USUAL_FUNCTION_CHECK dnl Order does not matter: dnl AC_USUAL_CASSERT dnl AC_USUAL_WERROR dnl AC_USUAL_DEBUG dnl dnl AC_USUAL_INIT: dnl - Sets PORTNAME=win32/unix dnl - If building from separate dir, writes top-level Makefile (antimake) dnl dnl Also defines port-specific flags: dnl _GNU_SOURCE, _WIN32_WINNT, WIN32_LEAN_AND_MEAN dnl AC_DEFUN([AC_USUAL_INIT], [ # if building separately from srcdir, write top-level makefile if test "$srcdir" != "."; then echo "include $srcdir/Makefile" > Makefile fi AC_MSG_CHECKING([target host type]) xhost="$host_alias" if test "x$xhost" = "x"; then xhost=`uname -s` fi case "$xhost" in *cygwin* | *mingw* | *pw32* | *MINGW*) LIBS="$LIBS -lws2_32" PORTNAME=win32;; *) PORTNAME=unix ;; esac AC_SUBST(PORTNAME) AC_MSG_RESULT([$PORTNAME]) dnl Set the flags before any feature tests. if test "$PORTNAME" = "win32"; then AC_DEFINE([WIN32_LEAN_AND_MEAN], [1], [Define to request cleaner win32 headers.]) AC_DEFINE([WINVER], [0x0501], [Define to max win32 API version (0x0501=XP).]) else AC_DEFINE([_GNU_SOURCE], [1], [Define to get working glibc.]) fi dnl Package-specific data AC_SUBST([pkgdatadir], ['${datarootdir}'/${PACKAGE_TARNAME}]) dnl pkgconfig files AC_SUBST([pkgconfigdir], ['${libdir}/pkgconfig']) ]) dnl Old name for initial checks AC_DEFUN([AC_USUAL_PORT_CHECK], [AC_USUAL_INIT]) dnl dnl AC_USUAL_PROGRAM_CHECK: Simple C environment: CC, CPP, INSTALL dnl AC_DEFUN([AC_USUAL_PROGRAM_CHECK], [ AC_PROG_CC_STDC AC_PROG_CPP dnl Check if compiler supports __func__ AC_CACHE_CHECK([whether compiler supports __func__], pgac_cv_funcname_func, [AC_TRY_COMPILE([#include ], [printf("%s\n", __func__);], [pgac_cv_funcname_func=yes], [pgac_cv_funcname_func=no])]) if test x"$pgac_cv_funcname_func" = xyes ; then AC_DEFINE(HAVE_FUNCNAME__FUNC, 1, [Define to 1 if your compiler understands __func__.]) fi dnl Check if linker supports -Wl,--as-needed if test "$GCC" = "yes"; then old_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,--as-needed" AC_MSG_CHECKING([whether linker supports --as-needed]) AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; }])], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) LDFLAGS="$old_LDFLAGS"]) fi dnl Check if compiler supports gcc-style dependencies AC_MSG_CHECKING([whether compiler supports dependency generation]) old_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -MD -MP -MT conftest.o -MF conftest.o.d" AC_COMPILE_IFELSE([AC_LANG_SOURCE([void foo(void){}])], [HAVE_CC_DEPFLAG=yes], [HAVE_CC_DEPFLAG=no]) rm -f conftest.d CFLAGS="$old_CFLAGS" AC_MSG_RESULT([$HAVE_CC_DEPFLAG]) AC_SUBST(HAVE_CC_DEPFLAG) dnl Pick good warning flags for gcc WFLAGS="" if test x"$GCC" = xyes; then AC_MSG_CHECKING([for working warning switches]) good_CFLAGS="$CFLAGS" flags="-Wall -Wextra" # turn off noise from Wextra flags="$flags -Wno-unused-parameter -Wno-missing-field-initializers" # Wextra does not turn those on? flags="$flags -Wmissing-prototypes -Wpointer-arith -Wendif-labels" flags="$flags -Wdeclaration-after-statement -Wold-style-definition" flags="$flags -Wstrict-prototypes -Wundef -Wformat=2" flags="$flags -Wuninitialized" for f in $flags; do CFLAGS="$good_CFLAGS $WFLAGS $f" AC_COMPILE_IFELSE([AC_LANG_SOURCE([void foo(void){}])], [WFLAGS="$WFLAGS $f"]) done # avoid -Wextra if missing-field.initializers does not work echo "$WFLAGS" | grep missing-field-initializers > /dev/null \ || WFLAGS=`echo "$WFLAGS"|sed 's/ -Wextra//'` CFLAGS="$good_CFLAGS" AC_MSG_RESULT([done]) fi AC_SUBST(WFLAGS) AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_EGREP AC_PROG_AWK dnl AC_PROG_MKDIR_P and AC_PROG_SED are from newer autotools m4_ifdef([AC_PROG_MKDIR_P], [ AC_PROG_MKDIR_P ], [ MKDIR_P="mkdir -p" AC_SUBST(MKDIR_P) ]) m4_ifdef([AC_PROG_SED], [ AC_PROG_SED ], [ SED="sed" AC_SUBST(SED) ]) AC_CHECK_TOOL([STRIP], [strip]) AC_CHECK_TOOL([RANLIB], [ranlib], [true]) AC_CHECK_TOOL([AR], [ar]) ARFLAGS=rcu AC_SUBST(ARFLAGS) ]) dnl dnl AC_USUAL_TYPE_CHECK: Basic types for C dnl AC_DEFUN([AC_USUAL_TYPE_CHECK], [ AC_C_INLINE AC_C_RESTRICT AC_C_BIGENDIAN AC_SYS_LARGEFILE AC_TYPE_PID_T AC_TYPE_UID_T AC_TYPE_SIZE_T ]) dnl dnl AC_USUAL_HEADER_CHECK: Basic headers dnl AC_DEFUN([AC_USUAL_HEADER_CHECK], [ AC_CHECK_HEADERS([sys/socket.h poll.h sys/poll.h sys/un.h]) AC_CHECK_HEADERS([arpa/inet.h netinet/in.h netinet/tcp.h]) AC_CHECK_HEADERS([sys/param.h sys/uio.h pwd.h grp.h]) AC_CHECK_HEADERS([sys/wait.h sys/mman.h syslog.h netdb.h dlfcn.h]) AC_CHECK_HEADERS([err.h pthread.h endian.h sys/endian.h byteswap.h]) AC_CHECK_HEADERS([malloc.h regex.h getopt.h]) dnl ucred.h may have prereqs AC_CHECK_HEADERS([ucred.h sys/ucred.h], [], [], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif ]) AC_MSG_CHECKING([whether works on char values]) _good_ctype=no AC_RUN_IFELSE([AC_LANG_SOURCE([ #include #define W(c) ((signed char)(c)) int main(void) { int c; /* if char is unsigned, all is ok */ if ((int)(char)255 == (int)255) return 0; for (c = 128; c < 256; c++) { if (isalpha(c) != isalpha(W(c))) return 1; if (isalnum(c) != isalnum(W(c))) return 1; if (isascii(c) != isascii(W(c))) return 1; if (isblank(c) != isblank(W(c))) return 1; if (iscntrl(c) != iscntrl(W(c))) return 1; if (isdigit(c) != isdigit(W(c))) return 1; if (islower(c) != islower(W(c))) return 1; if (isprint(c) != isprint(W(c))) return 1; if (ispunct(c) != ispunct(W(c))) return 1; if (isspace(c) != isspace(W(c))) return 1; if (isupper(c) != isupper(W(c))) return 1; if (isxdigit(c) != isxdigit(W(c))) return 1; } return 0; } ])], [_good_ctype=yes], [_good_ctype=no], [_good_ctype=no]) AC_MSG_RESULT([$_good_ctype]) if test $_good_ctype = yes; then AC_DEFINE(HAVE_CTYPE_ON_CHAR, [1], [Define if macros work on char.]) fi ]) dnl dnl AC_USUAL_FUNCTION_CHECK: Basic functions dnl AC_DEFUN([AC_USUAL_FUNCTION_CHECK], [ ### Functions provided if missing dnl AC_CHECK_FUNCS(basename dirname) # unstable, provide always AC_CHECK_FUNCS(strlcpy strlcat getpeereid sigaction sigqueue) AC_CHECK_FUNCS(inet_ntop inet_pton poll getline memrchr regcomp) AC_CHECK_FUNCS(err errx warn warnx getprogname setprogname) AC_CHECK_FUNCS(posix_memalign memalign valloc) AC_CHECK_FUNCS(getopt getopt_long getopt_long_only) AC_CHECK_FUNCS(fls flsl flsll ffs ffsl ffsll) ### Functions provided only on win32 AC_CHECK_FUNCS(localtime_r gettimeofday recvmsg sendmsg usleep getrusage) ### Functions used by libusual itself AC_CHECK_FUNCS(syslog mmap getpeerucred) ### win32: link with ws2_32 AC_SEARCH_LIBS(WSAGetLastError, ws2_32) AC_FUNC_STRERROR_R ### AC_MSG_CHECKING([for integer enc/dec functions]) AC_LINK_IFELSE([AC_LANG_SOURCE([ #include #ifdef HAVE_SYS_ENDIAN_H #include #endif #ifdef HAVE_ENDIAN_H #include #endif char p[[]] = "01234567"; int main(void) { be16enc(p, 0); be32enc(p, 1); be64enc(p, 2); le16enc(p, 2); le32enc(p, 3); le64enc(p, 4); return (int)(be16dec(p) + be32dec(p) + be64dec(p)) + (int)(le16dec(p) + le32dec(p) + le64dec(p)); } ])], [ AC_MSG_RESULT([found]) AC_DEFINE([HAVE_ENCDEC_FUNCS], [1], [Define if *enc & *dec functions are available]) ], [AC_MSG_RESULT([not found])]) ]) dnl dnl AC_USUAL_CASSERT: --enable-cassert switch to set macro CASSERT dnl AC_DEFUN([AC_USUAL_CASSERT], [ AC_ARG_ENABLE(cassert, AC_HELP_STRING([--enable-cassert],[turn on assert checking in code])) AC_MSG_CHECKING([whether to enable asserts]) if test "$enable_cassert" = "yes"; then AC_DEFINE(CASSERT, 1, [Define to enable assert checking]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ]) dnl dnl AC_USUAL_WERROR: --enable-werror switch to turn warnings into errors dnl AC_DEFUN([AC_USUAL_WERROR], [ AC_ARG_ENABLE(werror, AC_HELP_STRING([--enable-werror],[add -Werror to CFLAGS])) AC_MSG_CHECKING([whether to fail on warnings]) if test "$enable_werror" = "yes"; then CFLAGS="$CFLAGS -Werror" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ]) dnl dnl AC_USUAL_DEBUG: --disable-debug switch to strip binary dnl AC_DEFUN([AC_USUAL_DEBUG], [ AC_ARG_ENABLE(debug, AC_HELP_STRING([--disable-debug],[strip binary]), [], [enable_debug=yes]) AC_MSG_CHECKING([whether to build debug binary]) if test "$enable_debug" = "yes"; then LDFLAGS="-g $LDFLAGS" BININSTALL="$INSTALL" AC_MSG_RESULT([yes]) else BININSTALL="$INSTALL -s" AC_MSG_RESULT([no]) fi AC_SUBST(enable_debug) ]) dnl dnl AC_USUAL_LIBEVENT: --with-libevent dnl dnl AC_USUAL_LIBEVENT - prefer-yes: dnl default - search for libevent, error if not found dnl --with - search for libevent, error if not found dnl --without - use libusual dnl dnl AC_USUAL_LIBEVENT_OPT - prefer-no: dnl default - use libusual dnl --with - search for libevent, error if not found dnl --without - use libusual dnl AC_DEFUN([AC_USUAL_LIBEVENT_OPT], [AC_USUAL_LIBEVENT(1)]) AC_DEFUN([AC_USUAL_LIBEVENT], [ ifelse([$#], [0], [levent=yes], [levent=no]) AC_MSG_CHECKING([for libevent]) AC_ARG_WITH(libevent, AC_HELP_STRING([--with-libevent=prefix],[Specify where libevent is installed]), [ if test "$withval" = "no"; then levent=no elif test "$withval" = "yes"; then levent=yes else levent=yes CPPFLAGS="$CPPFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib" fi ], []) if test "$levent" = "no"; then AC_MSG_RESULT([using usual/event]) AC_DEFINE(HAVE_EVENT_LOOPBREAK, 1, [usual/event.h has it.]) AC_DEFINE(HAVE_EVENT_BASE_NEW, 1, [usual/event.h has it.]) have_libevent=no else # libevent AC_DEFINE(HAVE_LIBEVENT, 1, [Use real libevent.]) LIBS="-levent $LIBS" AC_LINK_IFELSE([AC_LANG_SOURCE([ #include #include #include #include int main(void) { struct event ev; event_init(); event_set(&ev, 1, EV_READ, NULL, NULL); /* this checks for 1.2+ but next we check for 1.3b+ anyway */ /* event_base_free(NULL); */ } ])], [AC_MSG_RESULT([found])], [AC_MSG_ERROR([not found, cannot proceed])]) dnl libevent < 1.3b crashes on event_base_free() dnl no good way to check libevent version. use hack: dnl evhttp.h defines HTTP_SERVUNAVAIL only since 1.3b AC_MSG_CHECKING([whether libevent version >= 1.3b]) AC_EGREP_CPP([HTTP_SERVUNAVAIL], [#include HTTP_SERVUNAVAIL ], [AC_MSG_ERROR([no, cannot proceed])], [AC_MSG_RESULT([yes])]) AC_CHECK_FUNCS(event_loopbreak event_base_new evdns_base_new) have_libevent=yes fi # libevent AC_SUBST(have_libevent) ]) dnl AC_USUAL_LIBEVENT dnl dnl AC_USUAL_UREGEX: --with-uregex dnl dnl Allow override of system regex dnl AC_DEFUN([AC_USUAL_UREGEX], [ AC_MSG_CHECKING([whether to force internal regex]) uregex=no AC_ARG_WITH(uregex, AC_HELP_STRING([--with-uregex],[Force use of internal regex]), [ if test "$withval" = "yes"; then uregex=yes fi ], []) if test "$uregex" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE(USE_INTERNAL_REGEX, 1, [Define to force use of uRegex.]) else AC_MSG_RESULT([no]) fi ]) dnl AC_USUAL_UREGEX dnl dnl AC_USUAL_GETADDRINFO_A - getaddrinfo_a() is required dnl AC_DEFUN([AC_USUAL_GETADDRINFO_A], [ AC_SEARCH_LIBS(getaddrinfo_a, anl) AC_CACHE_CHECK([whether to use native getaddinfo_a], ac_cv_usual_glibc_gaia, [AC_TRY_LINK([ #include #ifdef HAVE_NETDB_H #include #endif ], [ #if __GLIBC_PREREQ(2,9) getaddrinfo_a(0,NULL,0,NULL); #else none or broken #endif ], [ac_cv_usual_glibc_gaia=yes], [ac_cv_usual_glibc_gaia=no])]) if test x"$ac_cv_usual_glibc_gaia" = xyes ; then AC_DEFINE(HAVE_GETADDRINFO_A, 1, [Define to 1 if you have the getaddrinfo_a() function.]) else ACX_PTHREAD(, [AC_MSG_RESULT([Threads not available and fallback getaddrinfo_a() non-functional.])]) CC="$PTHREAD_CC" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$LIBS $PTHREAD_LIBS" fi ]) pgbouncer-1.5.4/lib/m4/acx_pthread.m40000644000175000017500000001613111665176410014251 00000000000000AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE AC_LANG_C acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_TRY_LINK([#include <pthread.h>], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [acx_pthread_ok=yes]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;], [attr_name=$attr; break]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_RESTORE ])dnl ACX_PTHREAD pgbouncer-1.5.4/lib/m4/antimake.m40000644000175000017500000000033611671441215013553 00000000000000 dnl dnl AMK_INIT: Generate initial makefile dnl AC_DEFUN([AMK_INIT], [ # if building separately from srcdir, write top-level makefile if test "$srcdir" != "."; then echo "include $srcdir/Makefile" > Makefile fi ]) pgbouncer-1.5.4/lib/find_modules.sh0000755000175000017500000000161511737344375014224 00000000000000#! /bin/sh set -e top="$1" # sanity check test -n "$top" || { echo "usage: $0 USUAL_DIR SRC ..." >&2 exit 1 } test -f "$top/usual/base.h" || { echo "usage: $0 USUAL_DIR SRC ..." >&2 exit 1 } shift test -n "$1" || exit 0 # return uniq module names, exclude already found ones grep_usual() { excl="config" for m in $m_done; do excl="$excl|$m" done prog=' /^#include[ \t]*[<"]usual\/('"$excl"')[.]h/ { next; } /^#include[ \t]*[<"]usual\// { p1 = index($0, "/"); p2 = index($0,"."); print substr($0, p1+1, p2-p1-1); } ' awk "$prog" "$@" | sort -u } # return module filename globs make_pats() { for m in "$@"; do echo "$top/usual/$m*.[ch]" done } # loop over grep until all mods are found m_done="" m_tocheck=`grep_usual "$@"` while test -n "$m_tocheck"; do m_done="$m_done $m_tocheck" pats=`make_pats $m_tocheck` m_tocheck=`grep_usual $pats` done # done echo $m_done pgbouncer-1.5.4/lib/usual/0000755000175000017500000000000012055406736012415 500000000000000pgbouncer-1.5.4/lib/usual/cfparser.h0000644000175000017500000001413012001575337014305 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * Config file parser. */ #ifndef _USUAL_CFPARSER_H_ #define _USUAL_CFPARSER_H_ #include /** * @name Simple line-by-line parser * @{ */ /** Callback signarure for @ref parse_ini_file() */ typedef bool (*cf_handler_f)(void *arg, bool is_sect, const char *key, const char *val); /** * Simple parser, launches callback for each line */ bool parse_ini_file(const char *fn, cf_handler_f user_handler, void *arg) _MUSTCHECK; /* @} */ /** * @name Complex parser with variable setting. * @{ */ /** @name Per-key flags * @{ */ /** The pointer is absolute */ #define CF_VAL_ABS 0 /** The pointer is relative to base */ #define CF_VAL_REL (1<<1) /** Value must not be changed on reload */ #define CF_NO_RELOAD (1<<2) /** Value can only be read */ #define CF_READONLY (1<<3) /** @} */ /** * Helper structure for passing key info to CfOps */ struct CfValue { void *value_p; const void *extra; const char *key_name; char *buf; int buflen; }; /** * Callbacks for setting and getting a variable value. * * Getter requires temp buf, returns string pointer, which * may or may not point to temp buf. Getter is optional. */ struct CfOps { bool (*setter)(struct CfValue *cv, const char *value); const char *(*getter)(struct CfValue *cv); const void *op_extra; }; /** * Parameter description */ struct CfKey { /** Parameter name */ const char *key_name; /** Type-specific functions, called with absolute pointer */ struct CfOps op; /** Flags: CF_VAL_ABS, CF_VAL_REL */ int flags; /** Absolute or relative offset */ uintptr_t key_ofs; /** Default value as string */ const char *def_value; }; /** * Section description */ struct CfSect { /** Section name */ const char *sect_name; /** Key list */ const struct CfKey *key_list; /** Get base pointer to dynamic sections (optional) */ void *(*base_lookup)(void *top_base, const char *sect_name); /** Set dynamic keys (optional) */ bool (*set_key)(void *base, const char *key, const char *val); /** Get dynamic keys (optional) */ const char *(*get_key)(void *base, const char *key, char *buf, int buflen); /** New section callback (optional) */ bool (*section_start)(void *top_base, const char *sect_name); }; /** * Top-level config information */ struct CfContext { /** Section list */ const struct CfSect *sect_list; /** Top-level base pointer, needed for relative addressing */ void *base; /** If set, then CF_NO_RELOAD keys cannot be changed anymore */ bool loaded; }; /** * @name Type-specific helpers * @{ */ /** Setter for string */ bool cf_set_str(struct CfValue *cv, const char *value); /** Setter for filename */ bool cf_set_filename(struct CfValue *cv, const char *value); /** Setter for int */ bool cf_set_int(struct CfValue *cv, const char *value); /** Setter for unsigned int */ bool cf_set_uint(struct CfValue *cv, const char *value); /** Setter for time-usec */ bool cf_set_time_usec(struct CfValue *cv, const char *value); /** Setter for time-double */ bool cf_set_time_double(struct CfValue *cv, const char *value); /** Setter for lookup */ bool cf_set_lookup(struct CfValue *cv, const char *value); /** Getter for string */ const char *cf_get_str(struct CfValue *cv); /** Getter for int */ const char *cf_get_int(struct CfValue *cv); /** Getter for unsigned int */ const char *cf_get_uint(struct CfValue *cv); /** Getter for time-usec */ const char *cf_get_time_usec(struct CfValue *cv); /** Getter for time-double */ const char *cf_get_time_double(struct CfValue *cv); /** Getter for int lookup */ const char *cf_get_lookup(struct CfValue *cv); /** @} */ /** * @name Shortcut CfOps for well-known types * @{ */ /** Ops for string */ #define CF_STR { cf_set_str, cf_get_str } /** Ops for filename */ #define CF_FILE { cf_set_filename, cf_get_str } /** Ops for integer */ #define CF_INT { cf_set_int, cf_get_int } /** Ops for unsigned integer */ #define CF_UINT { cf_set_uint, cf_get_uint } /** Ops for boolean */ #define CF_BOOL { cf_set_int, cf_get_int } /** Ops for time as usec */ #define CF_TIME_USEC { cf_set_time_usec, cf_get_time_usec } /** Ops for time as double */ #define CF_TIME_DOUBLE { cf_set_time_double, cf_get_time_double } /** Ops for lookup, takes table as argument */ #define CF_LOOKUP(t) { cf_set_lookup, cf_get_lookup, t } /** @} */ /** * Lookup entry for CF_LOOKUP table. */ struct CfLookup { const char *name; int value; }; /** * Helper to describe CfKey with absolute addressing */ #define CF_ABS(name, ops, var, flags, def) \ { name, ops, flags | CF_VAL_ABS, (uintptr_t)&(var), def } /** * Helper to describe CfKey with relative addressing. * * Before using it defined CF_REL_BASE to base struct. * * The var should be field in that struct. * * @code * struct Foo { * char *foo_name; * }; * #define CF_REL_BASE struct Foo * ... * CF_REL("name", CF_STR, foo_name, 0, NULL) * ... * #undef CF_REL_BASE * @endcode */ #define CF_REL(name, ops, var, flags, def) \ { name, ops, flags | CF_VAL_REL, offsetof(CF_REL_BASE, var), def } /** * Load config from file. */ bool cf_load_file(const struct CfContext *cf, const char *fn) _MUSTCHECK; /** * Get single value. */ const char *cf_get(const struct CfContext *cf, const char *sect, const char *var, char *buf, int buflen); /** * Set single value. */ bool cf_set(const struct CfContext *cf, const char *sect, const char *var, const char *val); /* @} */ #endif pgbouncer-1.5.4/lib/usual/shlist.h0000644000175000017500000001034511665176410014016 00000000000000/* * Circular list for shared mem. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Circular list for shared mem. * * Instead of pointers, it uses offsets from list head. */ #ifndef _USUAL_SHLIST_H_ #define _USUAL_SHLIST_H_ #include /** List node/head. Uses offsets from head instead of direct pointers. */ struct SHList { /** Offset to next elem */ uintptr_t next; /** Offset from next elem */ uintptr_t prev; }; /* * Calculate offset relative to base. * * Instead of using some third pointer (eg. shmem start) as base, * we use list itself as base. This results in simpler APi * and also means that empty list appears as zero-filled. */ static inline uintptr_t _ptr2sh(const void *base, const void *ptr) { return (uintptr_t)((char *)ptr - (char *)base); } static inline void *_sh2ptr(const void *base, uintptr_t sh) { return (void *)((char *)base + sh); } /* * List operations. */ /** Initialize list head */ static inline void shlist_init(struct SHList *list) { list->next = _ptr2sh(list, list); list->prev = _ptr2sh(list, list); } /** Insert as last element */ static inline void shlist_append(struct SHList *list, struct SHList *item) { struct SHList *last = _sh2ptr(list, list->prev); item->next = _ptr2sh(list, list); item->prev = _ptr2sh(list, last); list->prev = _ptr2sh(list, item); last->next = _ptr2sh(list, item); } /** Insert as first element */ static inline void shlist_prepend(struct SHList *list, struct SHList *item) { struct SHList *first = _sh2ptr(list, list->next); item->next = _ptr2sh(list, first); item->prev = _ptr2sh(list, list); list->next = _ptr2sh(list, item); first->prev = _ptr2sh(list, item); } /** Remove an item */ static inline void shlist_remove(struct SHList *list, struct SHList *item) { struct SHList *next = _sh2ptr(list, item->next); struct SHList *prev = _sh2ptr(list, item->prev); prev->next = item->next; next->prev = item->prev; item->next = item->prev = 0; /* _ptr2sh(list, item) does not make sense here; */ } /** No elements? */ static inline bool shlist_empty(const struct SHList *list) { return list->next == list->prev; } static inline struct SHList *shlist_next(const struct SHList *list, const struct SHList *elem) { return _sh2ptr(list, elem->next); } static inline struct SHList *shlist_prev(const struct SHList *list, const struct SHList *elem) { return _sh2ptr(list, elem->prev); } /** Return first elem */ static inline struct SHList *shlist_first(const struct SHList *list) { if (shlist_empty(list)) return NULL; return _sh2ptr(list, list->next); } /** Return last elem */ static inline struct SHList *shlist_last(const struct SHList *list) { if (shlist_empty(list)) return NULL; return _sh2ptr(list, list->prev); } /** Remove first elem */ static inline struct SHList *shlist_pop(struct SHList *list) { struct SHList *item = shlist_first(list); if (item) shlist_remove(list, item); return item; } /** Remove and return specific type of elem */ #define shlist_pop_type(list, type, field) ( \ shlist_empty(list) ? NULL : container_of(shlist_pop(list), type, field)) /** Loop over list */ #define shlist_for_each(item, list) \ for ((item) = _sh2ptr((list), (list)->next); \ (item) != (list); \ (item) = _sh2ptr((list), (item)->next)) /** Loop over list and allow removing item */ #define shlist_for_each_safe(item, list, tmp) \ for ((item) = _sh2ptr((list), (list)->next), \ (tmp) = _sh2ptr((list), (item)->next); \ (item) != (list); \ (item) = (tmp), (tmp) = _sh2ptr((list), (tmp)->next)) #endif pgbouncer-1.5.4/lib/usual/string.c0000644000175000017500000001375011665176410014014 00000000000000/* * Random win32 compat. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include /* * Dynamic list of strings. */ struct StrList { struct StatList list; CxMem *ca; }; struct StrItem { struct List node; const char *str; }; bool strlist_empty(struct StrList *slist) { return statlist_empty(&slist->list); } bool strlist_append(struct StrList *slist, const char *str) { const char *nstr = NULL; bool ok; if (str) { nstr = cx_strdup(slist->ca, str); if (!nstr) return false; } ok = strlist_append_ref(slist, nstr); if (!ok) cx_free(slist->ca, nstr); return ok; } bool strlist_append_ref(struct StrList *slist, const char *str) { struct StrItem *item = cx_alloc(slist->ca, sizeof(*item)); if (!item) return false; list_init(&item->node); item->str = str; statlist_append(&slist->list, &item->node); return true; } const char *strlist_pop(struct StrList *slist) { struct StrItem *item; struct List *el; const char *str; el = statlist_pop(&slist->list); if (!el) return NULL; item = container_of(el, struct StrItem, node); str = item->str; cx_free(slist->ca, item); return str; } struct StrList *strlist_new(CxMem *ca) { struct StrList *slist = cx_alloc0(ca, sizeof(*slist)); if (!slist) return NULL; statlist_init(&slist->list, "strlist"); slist->ca = ca; return slist; } void strlist_free(struct StrList *slist) { const char *s; if (!slist) return; while (!strlist_empty(slist)) { s = strlist_pop(slist); if (s) cx_free(slist->ca, s); } cx_free(slist->ca, slist); } bool strlist_foreach(const struct StrList *slist, str_cb func, void *arg) { struct List *el; struct StrItem *item; statlist_for_each(el, &slist->list) { item = container_of(el, struct StrItem, node); if (!func(arg, item->str)) return false; } return true; } /* * Parse comma separated words. */ static inline const char *skip_ws(const char *p) { while (*p && isspace(*p)) p++; return p; } bool parse_word_list(const char *s, str_cb cb_func, void *cb_arg) { struct MBuf buf; const char *p = s; const char *start, *end; mbuf_init_dynamic(&buf); while (*p) { /* parse word */ p = skip_ws(p); start = p; while (*p && *p != ',') p++; end = p; while (end > start && isspace(*(end - 1))) end--; /* parse comma */ if (*p) { if (*p == ',') { p++; } else { goto failed_syntax; } } /* extract string */ if (!mbuf_write(&buf, start, end - start)) goto failed; if (!mbuf_write_byte(&buf, 0)) goto failed; /* launch callback */ if (!cb_func(cb_arg, (const char *)buf.data)) goto failed; /* reset */ mbuf_rewind_writer(&buf); } mbuf_free(&buf); return true; failed_syntax: errno = EINVAL; failed: mbuf_free(&buf); return false; } /* * Minimal spec-conforming implementations of strlcpy(), strlcat(). */ #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t n) { size_t len = strlen(src); if (len < n) { memcpy(dst, src, len + 1); } else if (n > 0) { memcpy(dst, src, n - 1); dst[n - 1] = 0; } return len; } #endif #ifndef HAVE_STRLCAT size_t strlcat(char *dst, const char *src, size_t n) { size_t pos = 0; while (pos < n && dst[pos]) pos++; return pos + strlcpy(dst + pos, src, n - pos); } #endif #ifndef HAVE_MEMRCHR void *memrchr(const void *s, int c, size_t n) { const uint8_t *p = s; while (n--) { if (p[n] == c) return (void *)(p + n); } return NULL; } #endif #ifndef HAVE_BASENAME const char *basename(const char *path) { const char *p, *p2; static char buf[256]; unsigned len; if (path == NULL || path[0] == 0) return memcpy(buf, ".", 2); if ((p = strrchr(path, '/')) == NULL) return path; if (p[1]) return p + 1; /* last char is '/' */ for (p2 = p; p2 > path; p2--) { if (p2[-1] != '/') { len = p2 - path; if (len > sizeof(buf) - 1) len = sizeof(buf) - 1; memcpy(buf, p2 - len, len); buf[len] = 0; return basename(buf); } } /* path contains only '/' chars */ return p; } #endif #ifndef HAVE_DIRNAME const char *dirname(const char *path) { const char *p; size_t len; static char buf[1024]; if (path == NULL || path[0] == 0) return memcpy(buf, ".", 2); /* ignore tailing '/' */ len = strlen(path); while (len && path[len - 1] == '/') len--; if (!len) return memcpy(buf, "/", 2); /* find end of dirname, strip '/' */ if ((p = memrchr(path, '/', len)) == NULL) return memcpy(buf, ".", 2); len = p - path; while (len && path[len - 1] == '/') len--; if (!len) return memcpy(buf, "/", 2); /* return it */ if (len > sizeof(buf) - 1) { errno = ENAMETOOLONG; return NULL; } memcpy(buf, path, len); buf[len] = 0; return buf; } #endif #ifdef WIN32 const char *win32_strerror(int e) { static char buf[1024]; return strerror_r(e, buf, sizeof(buf)); } #endif /* restore original strerror_r() */ #undef strerror_r const char *usual_strerror_r(int e, char *dst, size_t dstlen) { #ifdef WIN32 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), dst, dstlen, NULL); #else /* !WIN32 */ #ifdef STRERROR_R_CHAR_P dst = strerror_r(e, dst, dstlen); #else if (strerror_r(e, dst, dstlen) != 0) strlcpy(dst, "ERR", dstlen); #endif #endif /* !WIN32 */ return dst; } pgbouncer-1.5.4/lib/usual/regex.h0000644000175000017500000001533011665176410013621 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * POSIX regular expession API, provided by either libc or internally. * * The internal regex engine is only activated if OS does not provide * @ref uregex_links "" (eg. Windows) or if * --with-internal-regex is used when configuring @ref libusual. * * @section uregex Features of internal regex (uregex). * * Simple recursive matcher, only features are small size * and POSIX compatibility. Supports both Extended Regular Expressions (ERE) * and Basic Regular Expressions (BRE). * * @section uregex_syntax Supported syntax * @code * Both: . * ^ $ [] [[:cname:]] * ERE: () {} | + ? * BRE: \(\) \{\} \1-9 * @endcode * * With REG_RELAXED_SYNTAX, following common escapes will be available: * @code * Both: \b\B\d\D\s\S\w\W * BRE: \| * ERE: \1-9 * @endcode * * With REG_RELAXED_MATCHING it returns the first match found after applying * leftmost-longest to all elements. It skips the combinatorics to turn it * into guaranteed-longest match. * * @section uregex_skip Skipped POSIX features * - collation classes: [[. .]] * - equivalence classes: [[= =]] * - char ranges by locale order: [a-z] (byte order will be used) * - multi-byte chars: UTF-8 * * @section uregex_globaldefs Global defines * - USUAL_RELAXED_REGEX * - USE_INTERNAL_REGEX * * @section uregex_links Compatibility * * - * POSIX-2008 spec - by default uRegex run in mode where only * features specified by POSIX are available. * * - * AT\&T Research regex(3) regression tests - uRegex follows the interpretation * given there and fully passes the testsuite. */ #ifndef _USUAL_REGEX_H_ #define _USUAL_REGEX_H_ #include #if !defined(USE_INTERNAL_REGEX) && defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) #define USE_SYSTEM_REGEX #endif #ifdef USE_SYSTEM_REGEX #include #else /* * uRegex defines */ /** * @name Standard flags to regcomp() * @{ */ /** Use POSIX Extended Regex Syntax instead of Basic Syntax */ #define REG_EXTENDED (1 << 0) /** Do case-insensitive matching */ #define REG_ICASE (1 << 1) /** Do case-insensitive matching */ #define REG_NOSUB (1 << 2) /** Do case-insensitive matching */ #define REG_NEWLINE (1 << 3) /* @} */ /** * @name Standard flags to regexec() * @{ */ /** The start of string is not beginning of line, so ^ should not match */ #define REG_NOTBOL (1 << 4) /** The end of string is not end of line, so $ should not match */ #define REG_NOTEOL (1 << 5) /* @} */ /** * @name Standard error codes * @{ */ /** Match not found */ #define REG_NOMATCH 1 /** Bad {} repeat specification */ #define REG_BADBR 2 /** General problem with regular expression */ #define REG_BADPAT 3 /** Repeat used without preceding non-repeat element */ #define REG_BADRPT 4 /** Syntax error with {} */ #define REG_EBRACE 5 /** Syntax error with [] */ #define REG_EBRACK 6 /** Bad collation reference */ #define REG_ECOLLATE 7 /** Bad character class reference */ #define REG_ECTYPE 8 /** Trailing backslack */ #define REG_EESCAPE 9 /** Syntax error with () */ #define REG_EPAREN 10 /** Bad endpoint in range */ #define REG_ERANGE 11 /** No memory */ #define REG_ESPACE 12 /** Bad subgroup reference */ #define REG_ESUBREG 13 /* @} */ /** * @name Other defines * @{ */ #undef RE_DUP_MAX /** Max count user can enter via {} */ #define RE_DUP_MAX 0x7ffe /* @} */ /** * @name Non-standard flags for regcomp() * @{ */ /** * Allow few common non-standard escapes: * @code * \b - word-change * \B - not word change * \d - digit * \D - non-digit * \s - space * \S - non-space * \w - word char * \W - non-word char * \/ - / * @endcode */ #define REG_RELAXED_SYNTAX (1 << 14) /** * Dont permute groups in attempt to get longest match. * * May give minor speed win at the expense of strict * POSIX compatibility. */ #define REG_RELAXED_MATCHING (1 << 15) /** Turn on both REG_RELAXED_SYNTAX and REG_RELAXED_MATCHING */ #define REG_RELAXED (REG_RELAXED_SYNTAX | REG_RELAXED_MATCHING) /* @} */ /* turn them permanently on */ #ifdef USUAL_RELAXED_REGEX #undef REG_EXTENDED #define REG_EXTENDED (1 | REG_RELAXED) #endif /** * Compiled regex. * * It has only one standard field - re_nsub, * rest are implementation-specific. */ typedef struct { /** Number of subgroups in expression */ int re_nsub; void *internal; } regex_t; /** Type for offset in match */ typedef long regoff_t; /** Match location */ typedef struct { regoff_t rm_so; /**< Start offset */ regoff_t rm_eo; /**< End offset */ } regmatch_t; /* avoid name conflicts */ #define regcomp(a,b,c) usual_regcomp(a,b,c) #define regexec(a,b,c,d,e) usual_regexec(a,b,c,d,e) #define regerror(a,b,c,d) usual_regerror(a,b,c,d) #define regfree(a) usual_regfree(a) /** * Compile regex. * * @param rx Pre-allocated @ref regex_t structure to fill. * @param re Regex as zero-terminated string. * @param flags See above for regcomp() flags. */ int regcomp(regex_t *rx, const char *re, int flags); /** * Execute regex on a string. * * @param rx Regex previously initialized with regcomp() * @param str Zero-terminated string to match * @param nmatch Number of matches in pmatch * @param pmatch Array of matches. * @param eflags Execution flags. Supported flags: @ref REG_NOTBOL, @ref REG_NOTEOL */ int regexec(const regex_t *rx, const char *str, size_t nmatch, regmatch_t pmatch[], int eflags); /** * Give error description. * * @param err Error code returned by regcomp() or regexec() * @param rx Regex structure used in regcomp() or regexec() * @param dst Destination buffer * @param dstlen Size of dst */ size_t regerror(int err, const regex_t *rx, char *dst, size_t dstlen); /** * Free resources allocated by regcomp(). * @param rx Regex previously filled by regcomp() */ void regfree(regex_t *rx); #endif /* !USE_SYSTEM_REGEX */ #endif /* _USUAL_REGEX_H_ */ pgbouncer-1.5.4/lib/usual/sha1.c0000644000175000017500000000665511665176410013350 00000000000000/* * SHA1 implementation based on RFC3174. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #define bufpos(ctx) ((ctx)->nbytes & (SHA1_BLOCK_SIZE - 1)) /* * SHA1 core. */ #define W(n) (buf[(n) & 15]) #define setW(n, val) W(n) = val /* base SHA1 operation */ #define SHA1OP(_t, fn, K) do { \ uint32_t tmp, t = (_t); \ if (t >= 16) { \ tmp = W(t - 3) ^ W(t - 8) ^ W(t - 14) ^ W(t - 16); \ setW(t, rol32(tmp, 1)); \ } else { \ /* convert endianess on first go */ \ setW(t, be32toh(W(t))); \ } \ tmp = rol32(a, 5) + fn(b, c, d) + e + W(t) + K; \ e = d; d = c; c = rol32(b, 30); b = a; a = tmp; \ } while (0) /* mix functions */ #define F0(b, c, d) (d ^ (b & (c ^ d))) #define F1(b, c, d) (b ^ c ^ d) #define F2(b, c, d) ((b & c) | (b & d) | (c & d)) #define F3(b, c, d) (b ^ c ^ d) /* operation details for each round */ #define SHA1R0(t) SHA1OP(t, F0, 0x5a827999) #define SHA1R1(t) SHA1OP(t, F1, 0x6ed9eba1) #define SHA1R2(t) SHA1OP(t, F2, 0x8f1bbcdc) #define SHA1R3(t) SHA1OP(t, F3, 0xca62c1d6) /* repeat with increasing offset */ #define R4(R, t) R(t+0); R(t+1); R(t+2); R(t+3) #define R16(R, t) R4(R, t+0); R4(R, t+4); R4(R, t+8); R4(R, t+12) #define R20(R, t) R16(R, t+0); R4(R, t+16) static void sha1_core(struct sha1_ctx * ctx, uint32_t *buf) { uint32_t a, b, c, d, e; a = ctx->a; b = ctx->b; c = ctx->c; d = ctx->d; e = ctx->e; R20(SHA1R0, 0); R20(SHA1R1, 20); R20(SHA1R2, 40); R20(SHA1R3, 60); ctx->a += a; ctx->b += b; ctx->c += c; ctx->d += d; ctx->e += e; } /* * Public API. */ void sha1_reset(struct sha1_ctx *ctx) { ctx->nbytes = 0; ctx->a = 0x67452301; ctx->b = 0xefcdab89; ctx->c = 0x98badcfe; ctx->d = 0x10325476; ctx->e = 0xc3d2e1f0; } void sha1_update(struct sha1_ctx *ctx, const void *data, unsigned int len) { unsigned int n; const uint8_t *src = data; uint8_t *dst = (uint8_t *)ctx->buf; while (len > 0) { n = SHA1_BLOCK_SIZE - bufpos(ctx); if (n > len) n = len; memcpy(dst + bufpos(ctx), src, n); src += n; len -= n; ctx->nbytes += n; if (bufpos(ctx) == 0) sha1_core(ctx, ctx->buf); } } void sha1_final(uint8_t *dst, struct sha1_ctx *ctx) { static const uint8_t padding[SHA1_BLOCK_SIZE] = { 0x80 }; uint64_t nbits = ctx->nbytes * 8; int pad_len, pos = bufpos(ctx); /* add padding */ pad_len = SHA1_BLOCK_SIZE - 8 - pos; if (pad_len <= 0) pad_len += SHA1_BLOCK_SIZE; sha1_update(ctx, padding, pad_len); /* add length */ ctx->buf[14] = htobe32(nbits >> 32); ctx->buf[15] = htobe32(nbits); /* final result */ sha1_core(ctx, ctx->buf); be32enc(dst + 0*4, ctx->a); be32enc(dst + 1*4, ctx->b); be32enc(dst + 2*4, ctx->c); be32enc(dst + 3*4, ctx->d); be32enc(dst + 4*4, ctx->e); } pgbouncer-1.5.4/lib/usual/getopt.c0000644000175000017500000003245211665176410014010 00000000000000/* $OpenBSD: getopt_long.c,v 1.24 2010/07/22 19:31:53 blambert Exp $ */ /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ /* * Copyright (c) 2002 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #ifdef NEED_USUAL_GETOPT #include #include char *optarg; /* argument associated with option */ int opterr = 1; /* if error message should be printed */ int optind = 1; /* index into parent argv vector */ int optopt = '?'; /* character checked for validity */ #define PRINT_ERROR ((opterr) && (*options != ':')) #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ /* return values */ #define BADCH (int)'?' #define BADARG ((*options == ':') ? (int)':' : (int)'?') #define INORDER (int)1 #define EMSG "" static char *place = EMSG; /* option letter processing */ /* XXX: set optreset to 1 rather than these two */ static int nonopt_start = -1; /* first non option argument (for permute) */ static int nonopt_end = -1; /* first option after non options (for permute) */ /* Error messages */ static const char recargchar[] = "option requires an argument -- %c"; static const char recargstring[] = "option requires an argument -- %s"; static const char ambig[] = "ambiguous option -- %.*s"; static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptchar[] = "unknown option -- %c"; static const char illoptstring[] = "unknown option -- %s"; /* * Compute the greatest common divisor of a and b. */ static int gcd(int a, int b) { int c; c = a % b; while (c != 0) { a = b; b = c; c = a % b; } return (b); } /* * Exchange the block from nonopt_start to nonopt_end with the block * from nonopt_end to opt_end (keeping the same order of arguments * in each block). */ static void permute_args(int panonopt_start, int panonopt_end, int opt_end, char * const *nargv) { int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; char *swap; /* * compute lengths of blocks and number and size of cycles */ nnonopts = panonopt_end - panonopt_start; nopts = opt_end - panonopt_end; ncycle = gcd(nnonopts, nopts); cyclelen = (opt_end - panonopt_start) / ncycle; for (i = 0; i < ncycle; i++) { cstart = panonopt_end+i; pos = cstart; for (j = 0; j < cyclelen; j++) { if (pos >= panonopt_end) pos -= nnonopts; else pos += nopts; swap = nargv[pos]; /* LINTED const cast */ ((char **) nargv)[pos] = nargv[cstart]; /* LINTED const cast */ ((char **)nargv)[cstart] = swap; } } } /* * parse_long_options -- * Parse long options in argc/argv argument vector. * Returns -1 if short_too is set and the option does not match long_options. */ static int parse_long_options(char * const *nargv, const char *options, const struct option *long_options, int *idx, int short_too) { char *current_argv, *has_equal; size_t current_argv_len; int i, match; current_argv = place; match = -1; optind++; if ((has_equal = strchr(current_argv, '=')) != NULL) { /* argument found (--option=arg) */ current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { /* find matching long option */ if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == current_argv_len) { /* exact match */ match = i; break; } /* * If this is a known short option, don't allow * a partial match of a single character. */ if (short_too && current_argv_len == 1) continue; if (match == -1) /* partial match */ match = i; else { /* ambiguous abbreviation */ if (PRINT_ERROR) warnx(ambig, (int)current_argv_len, current_argv); optopt = 0; return (BADCH); } } if (match != -1) { /* option found */ if (long_options[match].has_arg == no_argument && has_equal) { if (PRINT_ERROR) warnx(noarg, (int)current_argv_len, current_argv); /* * XXX: GNU sets optopt to val regardless of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; return (BADARG); } if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else if (long_options[match].has_arg == required_argument) { /* * optional argument doesn't use next nargv */ optarg = nargv[optind++]; } } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument; leading ':' indicates no error * should be generated. */ if (PRINT_ERROR) warnx(recargstring, current_argv); /* * XXX: GNU sets optopt to val regardless of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; --optind; return (BADARG); } } else { /* unknown option */ if (short_too) { --optind; return (-1); } if (PRINT_ERROR) warnx(illoptstring, current_argv); optopt = 0; return (BADCH); } if (idx) *idx = match; if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; return (0); } else return (long_options[match].val); } /* * getopt_internal -- * Parse argc/argv argument vector. Called by user level routines. */ static int getopt_internal(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx, int flags) { char *oli; /* option letter list index */ int optchar, short_too; static int posixly_correct = -1; int optreset = 0; if (options == NULL) return (-1); /* * Disable GNU extensions if POSIXLY_CORRECT is set or options * string begins with a '+'. */ if (posixly_correct == -1) posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); if (posixly_correct || *options == '+') flags &= ~FLAG_PERMUTE; else if (*options == '-') flags |= FLAG_ALLARGS; if (*options == '+' || *options == '-') options++; /* * reset if requested */ if (optind == 0) optind = optreset = 1; optarg = NULL; if (optreset) nonopt_start = nonopt_end = -1; start: if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc) { /* end of argument vector */ place = EMSG; if (nonopt_end != -1) { /* do permutation, if we have to */ permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } else if (nonopt_start != -1) { /* * If we skipped non-options, set optind * to the first of them. */ optind = nonopt_start; } nonopt_start = nonopt_end = -1; return (-1); } if (*(place = nargv[optind]) != '-' || (place[1] == '\0' && strchr(options, '-') == NULL)) { place = EMSG; /* found non-option */ if (flags & FLAG_ALLARGS) { /* * GNU extension: * return non-option as argument to option 1 */ optarg = nargv[optind++]; return (INORDER); } if (!(flags & FLAG_PERMUTE)) { /* * If no permutation wanted, stop parsing * at first non-option. */ return (-1); } /* do permutation */ if (nonopt_start == -1) nonopt_start = optind; else if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); nonopt_start = optind - (nonopt_end - nonopt_start); nonopt_end = -1; } optind++; /* process next argument */ goto start; } if (nonopt_start != -1 && nonopt_end == -1) nonopt_end = optind; /* * If we have "-" do nothing, if "--" we are done. */ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { optind++; place = EMSG; /* * We found an option (--), so if we skipped * non-options, we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; return (-1); } } /* * Check long options if: * 1) we were passed some * 2) the arg is not just "-" * 3) either the arg starts with -- we are getopt_long_only() */ if (long_options != NULL && place != nargv[optind] && (*place == '-' || (flags & FLAG_LONGONLY))) { short_too = 0; if (*place == '-') place++; /* --foo long option */ else if (*place != ':' && strchr(options, *place) != NULL) short_too = 1; /* could be short option too */ optchar = parse_long_options(nargv, options, long_options, idx, short_too); if (optchar != -1) { place = EMSG; return (optchar); } } if ((optchar = (int)*place++) == (int)':' || (optchar == (int)'-' && *place != '\0') || (oli = strchr(options, optchar)) == NULL) { /* * If the user specified "-" and '-' isn't listed in * options, return -1 (non-option) as per POSIX. * Otherwise, it is an unknown option character (or ':'). */ if (optchar == (int)'-' && *place == '\0') return (-1); if (!*place) ++optind; if (PRINT_ERROR) warnx(illoptchar, optchar); optopt = optchar; return (BADCH); } if (long_options != NULL && optchar == 'W' && oli[1] == ';') { /* -W long-option */ if (*place) /* no space */ /* NOTHING */; else if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return (BADARG); } else /* white space */ place = nargv[optind]; optchar = parse_long_options(nargv, options, long_options, idx, 0); place = EMSG; return (optchar); } if (*++oli != ':') { /* doesn't take argument */ if (!*place) ++optind; } else { /* takes (optional) argument */ optarg = NULL; if (*place) /* no white space */ optarg = place; else if (oli[1] != ':') { /* arg not optional */ if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return (BADARG); } else optarg = nargv[optind]; } place = EMSG; ++optind; } /* dump back option letter */ return (optchar); } /* * getopt -- * Parse argc/argv argument vector. */ int getopt(int nargc, char *nargv[], const char *options) { return getopt_internal(nargc, nargv, options, NULL, NULL, FLAG_PERMUTE); } /* * getopt_long -- * Parse argc/argv argument vector. */ int getopt_long(int nargc, char *nargv[], const char *options, const struct option *long_options, int *idx) { return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE)); } /* * getopt_long_only -- * Parse argc/argv argument vector. */ int getopt_long_only(int nargc, char *nargv[], const char *options, const struct option *long_options, int *idx) { return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE|FLAG_LONGONLY)); } #endif /* NEED_USUAL_GETOPT */ pgbouncer-1.5.4/lib/usual/err.c0000644000175000017500000000515211665176410013273 00000000000000/* * Cmdline error reporting. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #ifndef HAVE_SETPROGNAME static const char *progname; #endif #ifndef HAVE_ERR void err(int e, const char *fmt, ...) { char buf[1024], ebuf[256]; va_list ap; int olderrno = errno; if (fmt) { va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); errx(e, "%s: %s", buf, strerror_r(olderrno, ebuf, sizeof(ebuf))); } else { errx(e, "%s", strerror_r(olderrno, ebuf, sizeof(ebuf))); } } #endif #ifndef HAVE_ERRX void errx(int e, const char *fmt, ...) { va_list ap; if (progname) fprintf(stderr, "%s: ", progname); if (fmt) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } fprintf(stderr, "\n"); exit(e); } #endif #ifndef HAVE_WARN void warn(const char *fmt, ...) { char buf[1024], ebuf[256]; va_list ap; int olderrno = errno; if (fmt) { va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); warnx("%s: %s", buf, strerror_r(olderrno, ebuf, sizeof(ebuf))); } else { warnx("%s", strerror_r(olderrno, ebuf, sizeof(ebuf))); } } #endif #ifndef HAVE_WARNX void warnx(const char *fmt, ...) { va_list ap; if (progname) fprintf(stderr, "%s: ", progname); if (fmt) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } } #endif #ifndef HAVE_SETPROGNAME void setprogname(const char *s) { const char *ss = strrchr(s, '/'); progname = ss ? (ss + 1) : s; } #endif #ifndef HAVE_GETPROGNAME const char *getprogname(void) { return progname; } #endif void *xmalloc(size_t len) { void *p = malloc(len); if (!p) err(1, "no mem"); return p; } void *xrealloc(void *p, size_t len) { void *p2 = realloc(p, len); if (!p2) err(1, "no mem"); return p2; } char *xstrdup(const char *s) { void *s2 = strdup(s); if (!s2) err(1, "no mem"); return s2; } pgbouncer-1.5.4/lib/usual/pgutil.h0000644000175000017500000000276611665176410014024 00000000000000/* * libusual - Utility library for C * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Utility functions for PostgreSQL data formats. */ #ifndef _USUAL_PGUTIL_H_ #define _USUAL_PGUTIL_H_ #include /** Check if string is reserver word for PostgreSQL. */ bool pg_is_reserved_word(const char *str); /** Quote value as string for PostgreSQL */ bool pg_quote_literal(char *_dst, const char *_src, int dstlen); /** Quote value as ident for PostgreSQL */ bool pg_quote_ident(char *_dst, const char *_src, int dstlen); /** Quote fully-qualified ident for PostgreSQL */ bool pg_quote_fqident(char *_dst, const char *_src, int dstlen); /** Parse PostgreSQL array. */ struct StrList *pg_parse_array(const char *pgarr, CxMem *cx); #endif pgbouncer-1.5.4/lib/usual/mbuf.c0000644000175000017500000000117411665176410013434 00000000000000 /* * Safe and easy access to memory buffer. */ #include bool mbuf_make_room(struct MBuf *buf, unsigned len) { unsigned new_alloc = buf->alloc_len; void *ptr; /* is it a dynamic buffer */ if (buf->reader || buf->fixed) return false; /* maybe there is enough room already */ if (buf->write_pos + len <= buf->alloc_len) return true; if (new_alloc == 0) new_alloc = 128; /* calc new alloc size */ while (new_alloc < buf->write_pos + len) new_alloc *= 2; /* realloc */ ptr = realloc(buf->data, new_alloc); if (!ptr) return false; buf->data = ptr; buf->alloc_len = new_alloc; return true; } pgbouncer-1.5.4/lib/usual/list.c0000644000175000017500000000373311665176410013461 00000000000000/* * Circular doubly linked list implementation. * * Copyright (c) 2010 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include /* merge 2 ordered arrays into one */ static struct List *merge(list_cmp_f cmp_func, struct List *p, struct List *q) { struct List res[1], *tail = res, *e; while (p && q) { if (cmp_func(p, q) <= 0) { e = p; p = p->next; } else { e = q; q = q->next; } tail->next = e; tail = e; } tail->next = p ? p : q; return res->next; } /* * non-recursive merge sort * * uses singly-linked NULL-terminated arrays internally. */ void list_sort(struct List *list, list_cmp_f cmp_func) { int i, top = 0; struct List *p; struct List *stack[64]; if (list_empty(list)) return; /* merge small sorted fragments into larger ones */ while (list->next != list) { p = list->next; list->next = p->next; p->next = NULL; for (i = 0; (i < top) && stack[i]; i++) { p = merge(cmp_func, stack[i], p); stack[i] = NULL; } stack[i] = p; if (i == top) top++; } /* merge remaining fragments */ for (p = NULL, i = 0; i < top; i++) p = merge(cmp_func, stack[i], p); /* restore proper List */ list->next = p; for (p = list; p->next; p = p->next) p->next->prev = p; list->prev = p; p->next = list; } pgbouncer-1.5.4/lib/usual/aatree.h0000644000175000017500000000533511665176410013754 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * * AA-Tree - Binary tree with embeddable nodes. * * AA-Tree (Arne Andersson tree) is a simplified Red-Black tree. */ #ifndef _USUAL_AATREE_H_ #define _USUAL_AATREE_H_ #include struct AATree; struct AANode; /** Callback for node comparision against value */ typedef int (*aatree_cmp_f)(uintptr_t, struct AANode *node); /** Callback for walking the tree */ typedef void (*aatree_walker_f)(struct AANode *n, void *arg); /** * Tree header, for storing helper functions. */ struct AATree { struct AANode *root; int count; aatree_cmp_f node_cmp; aatree_walker_f release_cb; }; /** * Tree node. Embeddable, parent structure should be taken * with container_of(). * * Techinally, the full level is not needed and 2-lowest * bits of either ->left or ->right would be enough * to keep track of structure. Currently this is not * done to keep code simple. */ struct AANode { struct AANode *left; /**< smaller values */ struct AANode *right; /**< larger values */ int level; /**< number of black nodes to leaf */ }; /** * Walk order types. */ enum AATreeWalkType { AA_WALK_IN_ORDER = 0, /* left->self->right */ AA_WALK_PRE_ORDER = 1, /* self->left->right */ AA_WALK_POST_ORDER = 2, /* left->right->self */ }; /** Initialize structure */ void aatree_init(struct AATree *tree, aatree_cmp_f cmpfn, aatree_walker_f release_cb); /** Search for node */ struct AANode *aatree_search(struct AATree *tree, uintptr_t value); /** Insert new node */ void aatree_insert(struct AATree *tree, uintptr_t value, struct AANode *node); /** Remote node */ void aatree_remove(struct AATree *tree, uintptr_t value); /** Walk over all nodes */ void aatree_walk(struct AATree *tree, enum AATreeWalkType wtype, aatree_walker_f walker, void *arg); /** Free */ void aatree_destroy(struct AATree *tree); /** Check if terminal node. */ static inline int aatree_is_nil_node(const struct AANode *node) { return (node->left == node); } #endif pgbouncer-1.5.4/lib/usual/list.h0000644000175000017500000000757511665176410013476 00000000000000/* * Circular doubly linked list implementation. * * Copyright (c) 2007 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * Circular doubly linked list. */ #ifndef _USUAL_LIST_H_ #define _USUAL_LIST_H_ #include /** * Structure for both list nodes and heads. * * It is meant to be embedded in parent structure, * which can be acquired with container_of(). */ struct List { /** Pointer to next node or head. */ struct List *next; /** Pointer to previous node or head. */ struct List *prev; }; /** Define and initialize emtpy list head */ #define LIST(var) struct List var = { &var, &var } /** Initialize empty list head. */ static inline void list_init(struct List *list) { list->next = list->prev = list; } /** Is list empty? */ static inline int list_empty(const struct List *list) { return list->next == list; } /** Add item to the start of the list */ static inline struct List *list_prepend(struct List *list, struct List *item) { item->next = list->next; item->prev = list; list->next->prev = item; list->next = item; return item; } /** Add item to the end of the list */ static inline struct List *list_append(struct List *list, struct List *item) { item->next = list; item->prev = list->prev; list->prev->next = item; list->prev = item; return item; } /** Remove item from list */ static inline struct List *list_del(struct List *item) { item->prev->next = item->next; item->next->prev = item->prev; item->next = item->prev = item; return item; } /** Remove first from list and return */ static inline struct List *list_pop(struct List *list) { if (list_empty(list)) return NULL; return list_del(list->next); } /** Get first elem from list */ static inline struct List *list_first(const struct List *list) { if (list_empty(list)) return NULL; return list->next; } /** Get last elem from list */ static inline struct List *list_last(const struct List *list) { if (list_empty(list)) return NULL; return list->prev; } /** Remove first elem from list and return with casting */ #define list_pop_type(list, typ, field) \ (list_empty(list) ? NULL \ : container_of(list_del((list)->next), typ, field)) /** Loop over list */ #define list_for_each(item, list) \ for ((item) = (list)->next; \ (item) != (list); \ (item) = (item)->next) /** Loop over list backwards */ #define list_for_each_reverse(item, list) \ for ((item) = (list)->prev; \ (item) != (list); \ (item) = (item)->prev) /** Loop over list and allow removing item */ #define list_for_each_safe(item, list, tmp) \ for ((item) = (list)->next, (tmp) = (list)->next->next; \ (item) != (list); \ (item) = (tmp), (tmp) = (tmp)->next) /** Loop over list backwards and allow removing item */ #define list_for_each_reverse_safe(item, list, tmp) \ for ((item) = (list)->prev, (tmp) = (list)->prev->prev; \ (item) != (list); \ (item) = (tmp), (tmp) = (tmp)->prev) /** Comparator function signature for list_sort() */ typedef int (*list_cmp_f)(const struct List *a, const struct List *b); /** * Sort list. * * This implementation uses stable merge sort which operates in-place. */ void list_sort(struct List *list, list_cmp_f cmp_func); #endif pgbouncer-1.5.4/lib/usual/sha1.h0000644000175000017500000000316211665176410013343 00000000000000/* * SHA1 implementation based on RFC3174. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * SHA1 implementation. */ #ifndef _USUAL_SHA1_H_ #define _USUAL_SHA1_H_ #include /** Block length for SHA1 */ #define SHA1_BLOCK_SIZE 64 /** Result length for SHA1 */ #define SHA1_DIGEST_LENGTH 20 /** SHA1 state */ struct sha1_ctx { uint64_t nbytes; uint32_t a, b, c, d, e; uint32_t buf[SHA1_BLOCK_SIZE / 4]; }; /** Clean state */ void sha1_reset(struct sha1_ctx *ctx); /** Update state with more data */ void sha1_update(struct sha1_ctx *ctx, const void *data, unsigned int len); /** Get final result */ void sha1_final(uint8_t *dst, struct sha1_ctx *ctx); #ifndef AVOID_SHA1_COMPAT typedef struct sha1_ctx SHA1_CTX; #define SHA1Init(ctx) sha1_reset(ctx) #define SHA1Update(ctx, data, len) sha1_update(ctx, data, len) #define SHA1Final(dst, ctx) sha1_final(dst, ctx) #endif #endif pgbouncer-1.5.4/lib/usual/time.h0000644000175000017500000000462511665176410013452 00000000000000/* * Theme include for time. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Time-related functionality. */ #ifndef _USUAL_TIME_H_ #define _USUAL_TIME_H_ #include #include #include /** Type to hold microseconds. */ typedef uint64_t usec_t; /** How many microseconds in a second. */ #define USEC ((usec_t)1000000) /** Convert usec timestamp to ISO timestamp with millisecond precision: YYYY-mm-dd hh:mm:ss.SSS */ char *format_time_ms(usec_t time, char *dst, unsigned dstlen); /** Convert usec timestamp to ISO timestamp with second precision: YYYY-mm-dd hh:mm:ss */ char *format_time_s(usec_t time, char *dst, unsigned dstlen); /** Query system time */ usec_t get_time_usec(void); /** Query cached system time */ usec_t get_cached_time(void); /** Forget cached system time, next call will fill it. */ void reset_time_cache(void); #ifdef WIN32 #ifndef HAVE_GETTIMEOFDAY #define gettimeofday(t,z) usual_gettimeofday(t,z) /** Compat: gettimeofday() */ int gettimeofday(struct timeval * tp, void * tzp); #endif #ifndef HAVE_LOCALTIME_R #define localtime_r(t,b) usual_localtime_r(t,b) /** Compat: localtime_r() */ struct tm *localtime_r(const time_t *tp, struct tm *buf); #endif #ifndef HAVE_USLEEP #define usleep(x) usual_usleep(x) /** Compat: usleep() */ static inline void usleep(long usec) { Sleep(usec / 1000); } #endif #ifndef HAVE_GETRUSAGE #define getrusage(w,d) usual_getrusage(w,d) #define RUSAGE_SELF 0 /** Compat: rusage for win32 */ struct rusage { struct timeval ru_utime; struct timeval ru_stime; }; /** Compat: getrusage() for win32 */ int getrusage(int who, struct rusage *dst); #endif #endif #endif pgbouncer-1.5.4/lib/usual/hmac.h0000644000175000017500000000266511763415244013426 00000000000000/* * HMAC implementation based on OpenBSD * * Copyright (c) 2012 Daniel Farina * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * HMAC-SHA1 implementation (RFC2104). */ #ifndef _USUAL_HMAC_H_ #define _USUAL_HMAC_H_ #include #include /** HMAC-SHA1 Context */ struct hmac_sha1_ctx { struct sha1_ctx ctx; uint8_t key[SHA1_BLOCK_SIZE]; unsigned int key_len; }; /** Initialize context with new key */ void hmac_sha1_reset(struct hmac_sha1_ctx *ctx, const uint8_t *key, unsigned int key_len); /** Hash more data */ void hmac_sha1_update(struct hmac_sha1_ctx *ctx, const void *data, unsigned int len); /** Get final result */ void hmac_sha1_final(uint8_t *dst, struct hmac_sha1_ctx *ctx); #endif /* _USUAL_HMAC_H_ */ pgbouncer-1.5.4/lib/usual/socket_win32.h0000644000175000017500000001267211665176410015027 00000000000000/* * Socket compat code for win32. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _USUAL_SOCKET_WIN32_H_ #define _USUAL_SOCKET_WIN32_H_ typedef int socklen_t; #define in_addr_t uint32_t /* * make recvmsg/sendmsg and fd related code compile */ struct iovec { void *iov_base; /* Base address. */ size_t iov_len; /* Length. */ }; struct msghdr { void *msg_name; int msg_namelen; struct iovec *msg_iov; int msg_iovlen; void *msg_control; int msg_controllen; int msg_flags; }; struct cmsghdr { int cmsg_len; int cmsg_level; int cmsg_type; }; #define SCM_RIGHTS 1 #define CMSG_DATA(cmsg) ((unsigned char *) ((struct cmsghdr *) (cmsg) + 1)) #define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \ & ~(sizeof (size_t) - 1)) #define CMSG_LEN(len) ((int)(CMSG_ALIGN(sizeof(struct cmsghdr))+(len))) #define CMSG_FIRSTHDR(mhdr) \ ((mhdr)->msg_controllen >= (int)sizeof(struct cmsghdr) ? \ (struct cmsghdr *)(mhdr)->msg_control : \ (struct cmsghdr *)NULL) #define CMSG_NXTHDR(mhdr, cmsg) \ (((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \ (((u_char *)(cmsg) + CMSG_ALIGN((cmsg)->cmsg_len) \ + CMSG_ALIGN(sizeof(struct cmsghdr)) > \ (u_char *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \ (struct cmsghdr *)NULL : \ (struct cmsghdr *)((u_char *)(cmsg) + CMSG_ALIGN((cmsg)->cmsg_len)))) #define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+CMSG_ALIGN(len)) /* * unify WSAGetLastError() with errno. * * and convert int <-> SOCKET. */ /* int <-> socket */ #define FD2S(fd) ((intptr_t)(fd)) #define S2FD(fd) ((int)(fd)) /* socket <-> HANDLE, plain casts */ #define FD2H(fd) ((HANDLE)FD2S(fd)) #define H2FD(h) S2FD((SOCKET)(h)) static inline int ewrap(int res) { if (res < 0) errno = WSAGetLastError(); return res; } /* proper signature for setsockopt */ static inline int w_setsockopt(int fd, int level, int optname, const void *optval, int optlen) { return ewrap(setsockopt(FD2S(fd), level, optname, optval, optlen)); } #define setsockopt(a,b,c,d,e) w_setsockopt(a,b,c,d,e) /* proper signature for send */ static inline ssize_t w_send(int fd, const void *buf, size_t len, int flags) { return ewrap(send(FD2S(fd), buf, len, flags)); } #define send(a,b,c,d) w_send(a,b,c,d) /* proper signature for recv */ static inline ssize_t w_recv(int fd, void *buf, size_t len, int flags) { return ewrap(recv(FD2S(fd), buf, len, flags)); } #define recv(a,b,c,d) w_recv(a,b,c,d) #define getsockopt(a,b,c,d,e) ewrap(getsockopt(FD2S(a),b,c,d,e)) #define connect(a,b,c) ewrap(connect(FD2S(a),b,c)) #define socket(a,b,c) ewrap(S2FD(socket(a,b,c))) #define bind(a,b,c) ewrap(bind(FD2S(a),b,c)) #define listen(a,b) ewrap(listen(FD2S(a),b)) #define accept(a,b,c) ewrap(accept(FD2S(a),b,c)) #define getpeername(a,b,c) ewrap(getpeername(FD2S(a),b,c)) #define getsockname(a,b,c) ewrap(getsockname(FD2S(a),b,c)) #define select(a,b,c,d,e) ewrap(select(a,b,c,d,e)) static inline struct hostent *w_gethostbyname(const char *n) { struct hostent *res = gethostbyname(n); if (!res) errno = WSAGetLastError(); return res; } #define gethostbyname(a) w_gethostbyname(a) /* make unix socket related code compile */ struct sockaddr_un { short sun_family; char sun_path[128]; }; /* sendmsg is not used */ static inline int sendmsg(int s, const struct msghdr *m, int flags) { if (m->msg_iovlen != 1) { errno = EINVAL; return -1; } return send(s, m->msg_iov[0].iov_base, m->msg_iov[0].iov_len, flags); } /* recvmsg() is, but only with one iov */ static inline int recvmsg(int s, struct msghdr *m, int flags) { if (m->msg_iovlen != 1) { errno = EINVAL; return -1; } if (m->msg_controllen) m->msg_controllen = 0; return recv(s, m->msg_iov[0].iov_base, m->msg_iov[0].iov_len, flags); } /* * fcntl */ #define F_GETFD 1 #define F_SETFD 2 #define F_GETFL 3 #define F_SETFL 4 #define O_NONBLOCK 1 #define FD_CLOEXEC HANDLE_FLAG_INHERIT static inline int fcntl(int fd, int cmd, long arg) { ULONG lval; DWORD dval; switch (cmd) { case F_GETFD: if (GetHandleInformation(FD2H(fd), &dval)) return dval; errno = EINVAL; return -1; case F_SETFD: /* set FD_CLOEXEC */ if (SetHandleInformation(FD2H(fd), FD_CLOEXEC, arg)) return 0; errno = EINVAL; return -1; case F_GETFL: /* O_NONBLOCK? */ return 0; case F_SETFL: /* set O_NONBLOCK */ lval = (arg & O_NONBLOCK) ? 1 : 0; if (ioctlsocket(FD2S(fd), FIONBIO, &lval) == SOCKET_ERROR) { errno = WSAGetLastError(); return -1; } return 0; default: errno = EINVAL; return -1; } } /* * SIO_KEEPALIVE_VALS for mingw32 */ #if !defined(SIO_KEEPALIVE_VALS) #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) struct tcp_keepalive { u_long onoff; u_long keepalivetime; u_long keepaliveinterval; }; #endif #endif pgbouncer-1.5.4/lib/usual/pgsocket.c0000644000175000017500000002021011665176410014312 00000000000000/* * Async Postgres connection. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #define MAX_QRY_ARGS 32 /* PgSocket.wait_type */ enum WType { W_NONE = 0, W_SOCK, W_TIME }; typedef void (*libev_cb)(int sock, short flags, void *arg); struct PgSocket { /* libevent state */ struct event ev; /* track wait state */ enum WType wait_type; uint8_t wait_event; // EV_READ / EV_WRITE /* should connect after sleep */ bool reconnect; /* current connection */ PGconn *con; /* user handler */ pgs_handler_f handler_func; void *handler_arg; /* saved connect string */ const char *connstr; /* custom base or NULL */ struct event_base *base; /* temp place for resultset */ PGresult *last_result; usec_t connect_time; usec_t lifetime; }; /* report event to user callback */ static void send_event(struct PgSocket *db, enum PgEvent ev) { db->handler_func(db, db->handler_arg, ev, NULL); } /* wait socket event from libevent */ static void wait_event(struct PgSocket *db, short ev, libev_cb fn) { Assert(!db->wait_type); event_set(&db->ev, PQsocket(db->con), ev, fn, db); if (db->base) event_base_set(db->base, &db->ev); if (event_add(&db->ev, NULL) < 0) fatal_perror("event_add"); db->wait_type = W_SOCK; db->wait_event = ev; } /* wait timeout from libevent */ static void timeout_cb(int sock, short flags, void *arg) { struct PgSocket *db = arg; db->wait_type = W_NONE; if (db->reconnect) { db->reconnect = false; pgs_connect(db); } else { send_event(db, PGS_TIMEOUT); } } /* some error happened */ static void conn_error(struct PgSocket *db, enum PgEvent ev, const char *desc) { log_error("connection error: %s", desc); log_error("libpq: %s", PQerrorMessage(db->con)); send_event(db, ev); } /* report previously stored result */ static void report_last_result(struct PgSocket *db) { PGresult *res = db->last_result; if (!res) return; db->last_result = NULL; switch (PQresultStatus(res)) { default: log_error("%s: %s", PQdb(db->con), PQresultErrorMessage(res)); case PGRES_COMMAND_OK: case PGRES_TUPLES_OK: case PGRES_COPY_OUT: case PGRES_COPY_IN: db->handler_func(db, db->handler_arg, PGS_RESULT_OK, res); } PQclear(res); } /* * Called when select() told that conn is avail for reading. * * It should call postgres handlers and then change state if needed. * * Because the callback may want to close the connection when processing * last resultset, the PGresult handover is delayed one step. */ static void result_cb(int sock, short flags, void *arg) { struct PgSocket *db = arg; PGresult *res; db->wait_type = W_NONE; if (!PQconsumeInput(db->con)) { conn_error(db, PGS_RESULT_BAD, "PQconsumeInput"); return; } /* loop until PQgetResult returns NULL */ while (db->con) { /* incomplete result? */ if (PQisBusy(db->con)) { wait_event(db, EV_READ, result_cb); return; } /* next result */ res = PQgetResult(db->con); if (!res) break; report_last_result(db); db->last_result = res; } report_last_result(db); } static void flush(struct PgSocket *db); static void send_cb(int sock, short flags, void *arg) { struct PgSocket *db = arg; db->wait_type = W_NONE; flush(db); } /* handle connect states */ static void connect_cb(int sock, short flags, void *arg) { struct PgSocket *db = arg; PostgresPollingStatusType poll_res; db->wait_type = W_NONE; poll_res = PQconnectPoll(db->con); switch (poll_res) { case PGRES_POLLING_WRITING: wait_event(db, EV_WRITE, connect_cb); break; case PGRES_POLLING_READING: wait_event(db, EV_READ, connect_cb); break; case PGRES_POLLING_OK: db->connect_time = get_time_usec(); send_event(db, PGS_CONNECT_OK); break; default: conn_error(db, PGS_CONNECT_FAILED, "PQconnectPoll"); } } /* send query to server */ static void flush(struct PgSocket *db) { int res = PQflush(db->con); if (res > 0) { wait_event(db, EV_WRITE, send_cb); } else if (res == 0) { wait_event(db, EV_READ, result_cb); } else conn_error(db, PGS_RESULT_BAD, "PQflush"); } /* override default notice receiver */ static void custom_notice_receiver(void *arg, const PGresult *res) { /* do nothing */ } /* * Public API */ struct PgSocket *pgs_create(const char *connstr, pgs_handler_f fn, void *handler_arg) { struct PgSocket *db; db = calloc(1, sizeof(*db)); if (!db) return NULL; db->handler_func = fn; db->handler_arg = handler_arg; db->connstr = strdup(connstr); if (!db->connstr) { pgs_free(db); return NULL; } return db; } void pgs_set_event_base(struct PgSocket *pgs, struct event_base *base) { pgs->base = base; } void pgs_set_lifetime(struct PgSocket *pgs, double lifetime) { pgs->lifetime = USEC * lifetime; } void pgs_connect(struct PgSocket *db) { if (db->con) pgs_disconnect(db); db->con = PQconnectStart(db->connstr); if (db->con == NULL) { conn_error(db, PGS_CONNECT_FAILED, "PQconnectStart"); return; } if (PQstatus(db->con) == CONNECTION_BAD) { conn_error(db, PGS_CONNECT_FAILED, "PQconnectStart"); return; } PQsetNoticeReceiver(db->con, custom_notice_receiver, db); wait_event(db, EV_WRITE, connect_cb); } void pgs_disconnect(struct PgSocket *db) { if (db->wait_type) { event_del(&db->ev); db->wait_type = W_NONE; db->reconnect = false; } if (db->con) { PQfinish(db->con); db->con = NULL; } if (db->last_result) { PQclear(db->last_result); db->last_result = NULL; } } void pgs_free(struct PgSocket *db) { if (db) { pgs_disconnect(db); free(db->connstr); free(db); } } void pgs_sleep(struct PgSocket *db, double timeout) { struct timeval tv; Assert(!db->wait_type); if (db->con && db->lifetime) { usec_t now = get_time_usec(); if (db->connect_time + db->lifetime < now) { pgs_disconnect(db); db->reconnect = true; } } tv.tv_sec = timeout; tv.tv_usec = (timeout - tv.tv_sec) * USEC; evtimer_set(&db->ev, timeout_cb, db); if (db->base) event_base_set(db->base, &db->ev); if (evtimer_add(&db->ev, &tv) < 0) fatal_perror("event_add"); db->wait_type = W_TIME; } void pgs_reconnect(struct PgSocket *db, double timeout) { pgs_disconnect(db); pgs_sleep(db, timeout); db->reconnect = true; } void pgs_send_query_simple(struct PgSocket *db, const char *q) { int res; log_noise("%s", q); res = PQsendQuery(db->con, q); if (!res) { conn_error(db, PGS_RESULT_BAD, "PQsendQuery"); return; } flush(db); } void pgs_send_query_params(struct PgSocket *db, const char *q, int cnt, ...) { int i; va_list ap; const char * args[MAX_QRY_ARGS]; if (cnt < 0 || cnt > MAX_QRY_ARGS) { log_warning("bad query arg cnt"); send_event(db, PGS_RESULT_BAD); return; } va_start(ap, cnt); for (i = 0; i < cnt; i++) args[i] = va_arg(ap, char *); va_end(ap); pgs_send_query_params_list(db, q, cnt, args); } void pgs_send_query_params_list(struct PgSocket *db, const char *q, int cnt, const char *args[]) { int res; log_noise("%s", q); res = PQsendQueryParams(db->con, q, cnt, NULL, args, NULL, NULL, 0); if (!res) { conn_error(db, PGS_RESULT_BAD, "PQsendQueryParams"); return; } flush(db); } int pgs_connection_valid(struct PgSocket *db) { return (db->con != NULL); } PGconn *pgs_get_connection(struct PgSocket *db) { return db->con; } bool pgs_waiting_for_reply(struct PgSocket *db) { if (!db->con) return false; if (PQstatus(db->con) != CONNECTION_OK) return false; return (db->wait_type == W_SOCK) && (db->wait_event == EV_READ); } pgbouncer-1.5.4/lib/usual/pgsocket.h0000644000175000017500000000572411665176410014334 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * * Async Postgres connection framework. */ #ifndef _USUAL_PGSOCKET_H_ #define _USUAL_PGSOCKET_H_ #include #include /** * Event types reported to user handler function. */ enum PgEvent { /** Connection establishing finished */ PGS_CONNECT_OK, /** Connection establishing failed */ PGS_CONNECT_FAILED, /** Got result from query either resultset or DB error */ PGS_RESULT_OK, /** Query execution failed */ PGS_RESULT_BAD, /** Wakeup from timed sleep */ PGS_TIMEOUT, }; struct PgSocket; struct event_base; typedef void (*pgs_handler_f)(struct PgSocket *pgs, void *arg, enum PgEvent dbev, PGresult *res); /** Create PgSocket. * * It does not launch connection yet, use \ref pgs_connect() for that. * * @param connstr libpq connect string * @param fn callback function for event handling * @param arg extra context for callback * @return Initialized PgSocket structure */ struct PgSocket *pgs_create(const char *connstr, pgs_handler_f fn, void *arg); /** Release PgSocket */ void pgs_free(struct PgSocket *db); /** Change the event base for PgSocket */ void pgs_set_event_base(struct PgSocket *pgs, struct event_base *base); /** Set connection lifetime (in seconds) */ void pgs_set_lifetime(struct PgSocket *pgs, double lifetime); /** Launch connection */ void pgs_connect(struct PgSocket *db); /** Drop connection */ void pgs_disconnect(struct PgSocket *db); /** Send simple query */ void pgs_send_query_simple(struct PgSocket *db, const char *query); /** Send extended query, args from varargs */ void pgs_send_query_params(struct PgSocket *db, const char *query, int nargs, ...); /** Send extended query, args from list */ void pgs_send_query_params_list(struct PgSocket *db, const char *query, int nargs, const char *argv[]); /** Ignore the connection for specified time */ void pgs_sleep(struct PgSocket *db, double timeout); /** Disconnect, sleep, reconnect */ void pgs_reconnect(struct PgSocket *db, double timeout); /** Does PgSocket have established connection */ int pgs_connection_valid(struct PgSocket *db); /** Return underlying Postgres connection */ PGconn *pgs_get_connection(struct PgSocket *db); bool pgs_waiting_for_reply(struct PgSocket *db); #endif pgbouncer-1.5.4/lib/usual/base_win32.h0000644000175000017500000000523711705771754014457 00000000000000/* * Random win32 compat. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _USUAL_BASE_WIN32_H_ #define _USUAL_BASE_WIN32_H_ #include #define ECONNABORTED WSAECONNABORTED #define EMSGSIZE WSAEMSGSIZE #define EINPROGRESS WSAEWOULDBLOCK // WSAEINPROGRESS #undef EAGAIN #define EAGAIN WSAEWOULDBLOCK // WSAEAGAIN #ifndef EAFNOSUPPORT #define EAFNOSUPPORT ENOSYS #endif /* dummy types / functions */ #define hstrerror strerror #define getuid() (6667) #define setsid() getpid() #define setgid(x) (-1) #define setuid(x) (-1) #define fork() (-1) #define geteuid() getuid() #define setgroups(s, p) (-1) #define chown(f, u, g) (-1) #define srandom(s) srand(s) #define random() rand() /* getrlimit() */ #define RLIMIT_NOFILE -1 struct rlimit { int rlim_cur; int rlim_max; }; static inline int getrlimit(int res, struct rlimit *dst) { dst->rlim_cur = dst->rlim_max = -1; return 0; } /* dummy getpwnam() */ struct passwd { char *pw_name; char *pw_passwd; uid_t pw_uid; pid_t pw_gid; char *pw_gecos; char *pw_dir; char *pw_shell; }; static inline struct passwd *getpwnam(const char *u) { return NULL; } static inline struct passwd *getpwuid(uid_t uid) { return NULL; } /* dummy getgrnam() */ struct group { char *gr_name; char *gr_passwd; gid_t gr_gid; char **gr_mem; }; static inline struct group *getgrnam(const char *g) { return NULL; } static inline struct group *getgrgid(gid_t gid) { return NULL; } /* * Minimal dlopen, dlsym, dlclose, dlerror compat. */ #define RTLD_LAZY 1 #define RTLD_NOW 2 static inline void *dlopen(const char *fn, int flag) { HMODULE h = LoadLibraryEx(fn, NULL, 0); return h; } static inline void *dlsym(void *hptr, const char *fname) { HMODULE h = hptr; FARPROC f = GetProcAddress(h, fname); return f; } static inline int dlclose(void *hptr) { HMODULE h = hptr; return FreeLibrary(h) ? 0 : -1; } static inline const char *dlerror(void) { return strerror(GetLastError()); } #endif pgbouncer-1.5.4/lib/usual/ctype.h0000644000175000017500000000571611665176410013642 00000000000000/* * ctype wrappers * * Copyright (c) 2011 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * ctype compat. * * Provides wrappers that make sure the functions work on 'char' values. * * @note * POSIX requires that these functions accept EOF/-1 in addition * to ordinary byte values. That means when working on 'char', * the functions cannot differetiate between 0xFF and EOF. * As no code should give EOF to functions and no code * should depend whether 0xFF is labeled ispunct() or not, * it seems no worthwhile to fix it. */ #ifndef _USUAL_CTYPE_H_ #define _USUAL_CTYPE_H_ #include #include #ifndef HAVE_CTYPE_ON_CHAR #define _WRAP_CTYPE_FN(name) \ static inline int safe_ ## name (int c) { \ return name((unsigned char)(c)); \ } _WRAP_CTYPE_FN(isalnum) #undef isalnum /** Safe isalnum */ #define isalnum(c) safe_isalnum(c) _WRAP_CTYPE_FN(isalpha) #undef isalpha /** Safe isalpha */ #define isalpha(c) safe_isalpha(c) _WRAP_CTYPE_FN(isascii) #undef isascii /** Safe isascii */ #define isascii(c) safe_isascii(c) _WRAP_CTYPE_FN(isblank) #undef isblank /** Safe isblank */ #define isblank(c) safe_isblank(c) _WRAP_CTYPE_FN(iscntrl) #undef iscntrl /** Safe iscntrl */ #define iscntrl(c) safe_iscntrl(c) _WRAP_CTYPE_FN(isdigit) #undef isdigit /** Safe isdigit */ #define isdigit(c) safe_isdigit(c) _WRAP_CTYPE_FN(isgraph) #undef isgraph /** Safe isgraph */ #define isgraph(c) safe_isgraph(c) _WRAP_CTYPE_FN(islower) #undef islower /** Safe islower */ #define islower(c) safe_islower(c) _WRAP_CTYPE_FN(isprint) #undef isprint /** Safe isprint */ #define isprint(c) safe_isprint(c) _WRAP_CTYPE_FN(ispunct) #undef ispunct /** Safe ispunct */ #define ispunct(c) safe_ispunct(c) _WRAP_CTYPE_FN(isspace) #undef isspace /** Safe isspace */ #define isspace(c) safe_isspace(c) _WRAP_CTYPE_FN(isupper) #undef isupper /** Safe isupper */ #define isupper(c) safe_isupper(c) _WRAP_CTYPE_FN(isxdigit) #undef isxdigit /** Safe isxdigit */ #define isxdigit(c) safe_isxdigit(c) _WRAP_CTYPE_FN(tolower) #undef tolower /** Safe tolower */ #define tolower(c) safe_tolower(c) _WRAP_CTYPE_FN(toupper) #undef toupper /** Safe toupper */ #define toupper(c) safe_toupper(c) #undef _WRAP_CTYPE_FN #endif /* HAVE_BROKEN_CTYPE */ #endif /* _USUAL_CTYPE_H_ */ pgbouncer-1.5.4/lib/usual/crc32.c0000644000175000017500000001020111665176410013406 00000000000000/* * CRC32. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include static const uint32_t crc_tab[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; static inline uint32_t crc32(uint32_t prev, uint8_t c) { return crc_tab[(prev ^ c) & 0xFF] ^ (prev >> 8); } uint32_t calc_crc32(const void *data, size_t len, uint32_t init) { const uint8_t *p = data; uint32_t crc = init ^ (~0); while (len--) crc = crc32(crc, *p++); return crc ^ (~0); } pgbouncer-1.5.4/lib/usual/string.h0000644000175000017500000000633411671474252014023 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * \file * Theme include for strings. */ #ifndef _USUAL_STRING_H_ #define _USUAL_STRING_H_ #include #include /** * @name List of strings. * @{ */ /** Callback signature */ typedef bool (*str_cb)(void *arg, const char *s); struct StrList; /** Allocate new string list */ struct StrList *strlist_new(CxMem *ca); /** Free string string */ void strlist_free(struct StrList *slist); /** Check if empty */ bool strlist_empty(struct StrList *slist); /** Append copy of string. */ bool strlist_append(struct StrList *slist, const char *str); /** Append reference, strlist now owns it. */ bool strlist_append_ref(struct StrList *slist, const char *str); /** Call function on each element */ bool strlist_foreach(const struct StrList *slist, str_cb cb_func, void *cb_arg); /** Remove and return first element */ const char *strlist_pop(struct StrList *slist); /* @} */ /** Parse comma-separated elements from string and launch callback for each of them. */ bool parse_word_list(const char *s, str_cb cb_func, void *cb_arg); #ifndef HAVE_STRLCPY #define strlcpy(a,b,c) usual_strlcpy(a,b,c) /** Compat: Safely copy string to fixed-length buffer. */ size_t strlcpy(char *dst, const char *src, size_t n); #endif #ifndef HAVE_STRLCAT #define strlcat(a,b,c) usual_strlcat(a,b,c) /** Compat: Safely append string to fixed-length buffer. */ size_t strlcat(char *dst, const char *src, size_t n); #endif #ifndef HAVE_MEMRCHR #define memrchr(a,b,c) usual_memrchr(a,b,c) /** Compat: find byte in reverse direction */ void *memrchr(const void *s, int c, size_t n); #endif #ifndef HAVE_BASENAME #undef basename #define basename(a) usual_basename(a) /** Compat: Return pointer to last non-path element. Never modifies path, returns either pointer inside path or static buffer. */ const char *basename(const char *path); #endif #ifndef HAVE_DIRNAME #undef dirname #define dirname(a) usual_dirname(a) /** Compat: Return directory part of pathname. Never modifies path, returns either pointer inside path or static buffer. */ const char *dirname(const char *path); #endif /* * strerror, strerror_r */ #ifdef WIN32 const char *win32_strerror(int e); /** Compat: strerror() for win32 */ #define strerror(x) win32_strerror(x) #endif const char *usual_strerror_r(int e, char *dst, size_t dstlen); /** Compat: Provide GNU-style API: const char *strerror_r(int e, char *dst, size_t dstlen) */ #define strerror_r(a,b,c) usual_strerror_r(a,b,c) #endif pgbouncer-1.5.4/lib/usual/slab.h0000644000175000017500000000447311665176410013436 00000000000000/* * Primitive slab allocator. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Slab allocator for same-size objects. * * Basic behaviour: * - On each alloc initializer is called. * - if init func is not given, memset() is done * - init func gets either zeroed obj or old obj from _free(). * 'struct List' on obj start is non-zero. * * ATM custom 'align' larger than malloc() alignment does not work. */ #ifndef _USUAL_SLAB_H_ #define _USUAL_SLAB_H_ #include /** Reference to main */ struct Slab; /** Signature for object init function */ typedef void (*slab_init_fn)(void *obj); /** Create new slab context for specific size */ struct Slab *slab_create(const char *name, unsigned obj_size, unsigned align, slab_init_fn init_func, CxMem *cx); /** Free whole context */ void slab_destroy(struct Slab *slab); /** Allocate single object from slab cache */ void *slab_alloc(struct Slab *slab) _MALLOC _MUSTCHECK; /** Release single object back */ void slab_free(struct Slab *slab, void *obj); /** Return sum of free and used objects */ int slab_total_count(const struct Slab *slab); /** Return number of free objects in cache */ int slab_free_count(const struct Slab *slab); /** Return number of used objects */ int slab_active_count(const struct Slab *slab); /** Signature for stat info callback */ typedef void (*slab_stat_fn)(void *arg, const char *slab_name, unsigned size, unsigned free, unsigned total); /** Run stat info callback on all slabs */ void slab_stats(slab_stat_fn cb_func, void *cb_arg); #endif pgbouncer-1.5.4/lib/usual/netdb.h0000644000175000017500000000363011665176410013603 00000000000000/* * libusual - Utility library for C * * Copyright (c) 2010 Marko Kreen, Skype Technologies * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * * DNS lookup. */ #ifndef _USUAL_NETDB_H_ #define _USUAL_NETDB_H_ #include #ifdef HAVE_NETDB_H #include #endif #ifndef HAVE_GETADDRINFO_A /** Async execution */ #ifndef GAI_WAIT #define GAI_WAIT 0 #endif /** Synchronous execution */ #ifndef GAI_NOWAIT #define GAI_NOWAIT 1 #endif /* avoid name conflicts */ #define gaicb usual_gaicb #define getaddrinfo_a(a,b,c,d) usual_getaddrinfo_a(a,b,c,d) /** * Request data for getaddrinfo_a(). * * Fields correspond to getaddrinfo() parameters. */ struct gaicb { /** node name */ const char *ar_name; /** service name */ const char *ar_service; /** hints */ const struct addrinfo *ar_request; /** result */ struct addrinfo *ar_result; /* internal state */ int _state; }; #ifndef EAI_INPROGRESS #define EAI_INPROGRESS -100 #endif #ifndef EAI_SYSTEM #define EAI_SYSTEM -10 #endif #define gai_error(gcb) ((gcb)->_state) /** * Compat: Async DNS lookup. */ int getaddrinfo_a(int mode, struct gaicb *list[], int nitems, struct sigevent *sevp); #endif /* HAVE_GETADDRINFO_A */ #endif /* _USUAL_NETDB_H_ */ pgbouncer-1.5.4/lib/usual/crc32.h0000644000175000017500000000174311665176410013426 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * CRC32 checksum. */ #ifndef _USUAL_CRC32_H_ #define _USUAL_CRC32_H_ #include /** Calculate CRC32 checksum */ uint32_t calc_crc32(const void *data, size_t len, uint32_t init); #endif pgbouncer-1.5.4/lib/usual/safeio.c0000644000175000017500000001162011737344375013755 00000000000000/* * libusual - Utility library for C * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Wrappers around regular I/O functions (send/recv/read/write) * that survive EINTR and also can log problems. */ #include #include #include #include #include int safe_read(int fd, void *buf, int len) { int res; loop: res = read(fd, buf, len); if (res < 0 && errno == EINTR) goto loop; return res; } int safe_write(int fd, const void *buf, int len) { int res; loop: res = write(fd, buf, len); if (res < 0 && errno == EINTR) goto loop; return res; } int safe_recv(int fd, void *buf, int len, int flags) { int res; char ebuf[128]; loop: res = recv(fd, buf, len, flags); if (res < 0 && errno == EINTR) goto loop; if (res < 0) log_noise("safe_recv(%d, %d) = %s", fd, len, strerror_r(errno, ebuf, sizeof(ebuf))); else if (cf_verbose > 2) log_noise("safe_recv(%d, %d) = %d", fd, len, res); return res; } int safe_send(int fd, const void *buf, int len, int flags) { int res; char ebuf[128]; loop: res = send(fd, buf, len, flags); if (res < 0 && errno == EINTR) goto loop; if (res < 0) log_noise("safe_send(%d, %d) = %s", fd, len, strerror_r(errno, ebuf, sizeof(ebuf))); else if (cf_verbose > 2) log_noise("safe_send(%d, %d) = %d", fd, len, res); return res; } int safe_close(int fd) { int res; #ifndef WIN32 /* * POSIX says close() can return EINTR but fd state is "undefined" * later. Seems Linux and BSDs close the fd anyway and EINTR is * simply informative. Thus retry is dangerous. */ res = close(fd); #else /* * Seems on windows it can returns proper EINTR but only when * WSACancelBlockingCall() is called. As we don't do it, * ignore EINTR on win32 too. */ res = closesocket(fd); #endif if (res < 0) { char ebuf[128]; log_warning("safe_close(%d) = %s", fd, strerror_r(errno, ebuf, sizeof(ebuf))); } else if (cf_verbose > 2) { log_noise("safe_close(%d) = %d", fd, res); } /* ignore EINTR */ if (res < 0 && errno == EINTR) return 0; return res; } int safe_recvmsg(int fd, struct msghdr *msg, int flags) { int res; char ebuf[128]; loop: res = recvmsg(fd, msg, flags); if (res < 0 && errno == EINTR) goto loop; if (res < 0) log_warning("safe_recvmsg(%d, msg, %d) = %s", fd, flags, strerror_r(errno, ebuf, sizeof(ebuf))); else if (cf_verbose > 2) log_noise("safe_recvmsg(%d, msg, %d) = %d", fd, flags, res); return res; } int safe_sendmsg(int fd, const struct msghdr *msg, int flags) { int res; int msgerr_count = 0; char ebuf[128]; loop: res = sendmsg(fd, msg, flags); if (res < 0 && errno == EINTR) goto loop; if (res < 0) { log_warning("safe_sendmsg(%d, msg[%d,%d], %d) = %s", fd, (int)msg->msg_iov[0].iov_len, (int)msg->msg_controllen, flags, strerror_r(errno, ebuf, sizeof(ebuf))); /* with ancillary data on blocking socket OSX returns * EMSGSIZE instead of blocking. try to solve it by waiting */ if (errno == EMSGSIZE && msgerr_count < 20) { struct timeval tv = {1, 0}; log_warning("trying to sleep a bit"); select(0, NULL, NULL, NULL, &tv); msgerr_count++; goto loop; } } else if (cf_verbose > 2) log_noise("safe_sendmsg(%d, msg, %d) = %d", fd, flags, res); return res; } int safe_connect(int fd, const struct sockaddr *sa, socklen_t sa_len) { int res; char buf[128]; char ebuf[128]; loop: res = connect(fd, sa, sa_len); if (res < 0 && errno == EINTR) goto loop; if (res < 0 && (errno != EINPROGRESS || cf_verbose > 2)) log_noise("connect(%d, %s) = %s", fd, sa2str(sa, buf, sizeof(buf)), strerror_r(errno, ebuf, sizeof(ebuf))); else if (cf_verbose > 2) log_noise("connect(%d, %s) = %d", fd, sa2str(sa, buf, sizeof(buf)), res); return res; } int safe_accept(int fd, struct sockaddr *sa, socklen_t *sa_len_p) { int res; char buf[128]; char ebuf[128]; loop: res = accept(fd, sa, sa_len_p); if (res < 0 && errno == EINTR) goto loop; if (res < 0) log_noise("safe_accept(%d) = %s", fd, strerror_r(errno, ebuf, sizeof(ebuf))); else if (cf_verbose > 2) log_noise("safe_accept(%d) = %d (%s)", fd, res, sa2str(sa, buf, sizeof(buf))); return res; } pgbouncer-1.5.4/lib/usual/bits.h0000644000175000017500000000745411665176410013460 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * Bit arithmetics. * * - is_power_of_2 * - ffs, ffsl, ffsll * - fls, flsl, flsll * - rol16, rol32, rol64 * - ror16, ror32, ror64 */ #ifndef _USUAL_BITS_H_ #define _USUAL_BITS_H_ #include #include /** Checks if integer has only one bit set */ static inline int is_power_of_2(int n) { return (n > 0) && !(n & (n - 1)); } /* * Single-eval and type-safe rol/ror */ /** Rotate 16-bit int to left */ static inline uint16_t rol16(uint16_t v, int s) { return (v << s) | (v >> (16 - s)); } /** Rotate 32-bit int to left */ static inline uint32_t rol32(uint32_t v, int s) { return (v << s) | (v >> (32 - s)); } /** Rotate 64-bit int to left */ static inline uint64_t rol64(uint64_t v, int s) { return (v << s) | (v >> (64 - s)); } /** Rotate 16-bit int to right */ static inline uint16_t ror16(uint16_t v, int s) { return rol16(v, 16 - s); } /** Rotate 32-bit int to right */ static inline uint32_t ror32(uint32_t v, int s) { return rol32(v, 32 - s); } /** Rotate 64-bit int to right */ static inline uint64_t ror64(uint64_t v, int s) { return rol64(v, 64 - s); } /* * fls(int) * flsl(long) * flsll(long long) * * find MSB bit set, 1-based ofs, 0 if arg == 0 */ #if defined(__GNUC__) && (__GNUC__ >= 4) #define _FLS(sfx, type) \ return (x == 0) ? 0 : ((8*sizeof(type)) - __builtin_clz ## sfx(x)) #else #define _FLS(sfx, type) \ unsigned type u = x; \ unsigned int bit; \ if (x == 0) return 0; \ /* count from smallest bit, assuming small values */ \ for (bit = 1; u > 1; bit++) u >>= 1; \ return bit #endif #ifndef HAVE_FLS #define fls(x) usual_fls(x) /** Compat: Find last (MSB) set bit, 1-based ofs, 0 if arg == 0 */ static inline int fls(int x) { _FLS(, int); } #endif #ifndef HAVE_FLSL #define flsl(x) usual_flsl(x) /** Compat: Find last (MSB) set bit, 1-based ofs, 0 if arg == 0 */ static inline int flsl(long x) { _FLS(l, long); } #endif #ifndef HAVE_FLSLL #define flsll(x) usual_flsll(x) /** Compat: Find last (MSB) set bit, 1-based ofs, 0 if arg == 0 */ static inline int flsll(long long x) { _FLS(ll, long long); } #endif #undef _FLS /* * ffs(int) * ffsl(long) * ffsll(long long) * * find LSB bit set, 1-based ofs, 0 if arg == 0 */ #if defined(__GNUC__) && (__GNUC__ >= 4) #define _FFS(sfx, type) \ return __builtin_ffs ## sfx((unsigned type)(x)) #else #define _FFS(sfx, type) \ unsigned int bit; \ unsigned type u = x; \ if (!x) return 0; \ /* count from smallest bit, assuming small values */ \ for (bit = 1; !(u & 1); bit++) { \ u >>= 1; \ } \ return bit #endif #ifndef HAVE_FFS #define ffs(x) usual_ffs(x) /** Compat: Find first (LSB) set bit, 1-based ofs, 0 if arg == 0 */ static inline int ffs(int x) { _FFS(, int); } #endif #ifndef HAVE_FFSL #define ffsl(x) usual_ffsl(x) /** Compat: Find first (LSB) set bit, 1-based ofs, 0 if arg == 0 */ static inline int ffsl(long x) { _FFS(l, long); } #endif #ifndef HAVE_FFSLL #define ffsll(x) usual_ffsll(x) /** Compat: Find first (LSB) set bit, 1-based ofs, 0 if arg == 0 */ static inline int ffsll(long long x) { _FFS(ll, long long); } #endif #undef _FFS #endif pgbouncer-1.5.4/lib/usual/event.h0000644000175000017500000001110711665176410013626 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * libevent compat. * * This module adds few functions to older libevent versions, * or provides it's own libevent-compatible event loop * for cases where performance and features of full libevent * are not needed. */ #ifndef _USUAL_EVENT_H_ #define _USUAL_EVENT_H_ #include #include #ifdef HAVE_LIBEVENT /* * Real libevent */ #include #ifndef HAVE_EVENT_BASE_NEW /** Compat: make sure event_base_new() always available */ static inline struct event_base *event_base_new(void) { return event_init(); } #endif #ifndef HAVE_EVENT_LOOPBREAK /** Compat: dummy event_loopbreak for libevent 1.3 */ static inline void event_loopbreak(void) { } #endif #else /* * internal libevent */ #include #include /** * Flags for event_set() / event_assign(): * EV_READ, EV_WRITE, EV_SIGNAL, EV_PERSIST * * Flags given to user callback: * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT. */ enum EventFlags { EV_TIMEOUT = 1, EV_READ = 2, EV_WRITE = 4, EV_SIGNAL = 8, EV_PERSIST = 16, }; /** Flags for event_loop() */ enum EventLoopType { EVLOOP_ONCE = 1, EVLOOP_NONBLOCK = 2, }; /** Event context. event_base contents are not open */ struct event_base; /** user callback signature */ typedef void (*uevent_cb_f)(int fd, short flags, void *arg); /** Read fd value from struct event */ #define EVENT_FD(ev) ((ev)->fd) /** Read signal value from struct event */ #define EVENT_SIGNAL(ev) ((ev)->fd) /** * Event structure for internal event loop. * * Although the struct is open, no direct accesses should be done. * Thus also the fields are incompatible with libevent. */ struct event { /* node for fd or signal lists */ struct List node; /* timeout info */ usec_t timeout_val; int timeout_idx; /* back-pointer into pollfd list */ int ev_idx; /* event base it is attached to */ struct event_base *base; /* user callback */ uevent_cb_f cb_func; void *cb_arg; /* fd or signal */ int fd; /* both user and internal flags */ short flags; }; struct event_base *event_init(void) _MUSTCHECK; struct event_base *event_base_new(void) _MUSTCHECK; void event_base_free(struct event_base *base); void event_set(struct event *ev, int fd, short flags, uevent_cb_f cb, void *arg); int event_loop(int loop_flags) _MUSTCHECK; int event_loopbreak(void); int event_add(struct event *ev, struct timeval *timeout) _MUSTCHECK; int event_del(struct event *ev); void event_assign(struct event *ev, struct event_base *base, int fd, short flags, uevent_cb_f cb, void *cb_arg); int event_base_loop(struct event_base *base, int loop_flags) _MUSTCHECK; int event_base_loopbreak(struct event_base *base); #define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) #define evtimer_add(ev, tv) event_add(ev, tv) #define evtimer_del(ev) event_del(ev) #define signal_set(ev, sig, cb, arg) event_set(ev, sig, EV_SIGNAL | EV_PERSIST, cb, arg) #define signal_add(ev, tv) event_add(ev, tv) #define signal_del(ev) event_del(ev) /* random compat */ int event_once(int fd, short flags, uevent_cb_f cb_func, void *cb_arg, struct timeval *timeout); int event_base_once(struct event_base *base, int fd, short flags, uevent_cb_f cb_func, void *cb_arg, struct timeval *timeout); int event_loopexit(struct timeval *timeout); int event_base_loopexit(struct event_base *base, struct timeval *timeout); int event_base_set(struct event_base *base, struct event *ev); const char *event_get_version(void); const char *event_get_method(void); /* pointless compat */ #define event_dispatch() event_loop(0) #define event_base_dispatch(base) event_base_loop(base, 0) #define event_initialized(ev) is_event_active(ev) #define signal_initialized(ev) is_event_active(ev) #define evtimer_initialized(ev) is_event_active(ev) int is_event_active(struct event *ev); #endif /* internal libevent */ #endif /* _USUAL_EVENT_H_ */ pgbouncer-1.5.4/lib/usual/socket_ntop.c0000644000175000017500000001235611763415244015037 00000000000000/* $OpenBSD: inet_ntop.c,v 1.8 2008/12/09 19:38:38 otto Exp $ */ /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #include #ifndef HAVE_INET_NTOP #ifndef INADDRSZ #define INADDRSZ 4 #endif #ifndef IN6ADDRSZ #define IN6ADDRSZ 16 #endif #ifndef INT16SZ #define INT16SZ 2 #endif #define u_char uint8_t #define u_int unsigned int /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static const char *inet_ntop4(const u_char *src, char *dst, int size); static const char *inet_ntop6(const u_char *src, char *dst, int size); /* char * * inet_ntop(af, src, dst, size) * convert a network format address to presentation format. * return: * pointer to presentation format address (`dst'), or NULL (see errno). * author: * Paul Vixie, 1996. */ const char * inet_ntop(int af, const void *src, char *dst, int size) { if (size < 0) { errno = ENOSPC; return NULL; } switch (af) { case AF_INET: return (inet_ntop4(src, dst, size)); case AF_INET6: return (inet_ntop6(src, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); } /* NOTREACHED */ } /* const char * * inet_ntop4(src, dst, size) * format an IPv4 address, more or less like inet_ntoa() * return: * `dst' (as a const) * notes: * (1) uses no statics * (2) takes a u_char* not an in_addr as input * author: * Paul Vixie, 1996. */ static const char * inet_ntop4(const u_char *src, char *dst, int size) { static const char fmt[] = "%u.%u.%u.%u"; char tmp[sizeof "255.255.255.255"]; int l; l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); if (l <= 0 || l >= size) { errno = ENOSPC; return (NULL); } strlcpy(dst, tmp, size); return (dst); } /* const char * * inet_ntop6(src, dst, size) * convert IPv6 binary address into presentation (printable) format * author: * Paul Vixie, 1996. */ static const char * inet_ntop6(const u_char *src, char *dst, int size) { /* * Note that int32_t and int16_t need only be "at least" large enough * to contain a value of the specified size. On some systems, like * Crays, there is no such thing as an integer variable with 16 bits. * Keep this in mind if you think this function should have been coded * to use pointer overlays. All the world's not a VAX. */ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; char *tp, *ep; struct { int base, len; } best, cur; u_int words[IN6ADDRSZ / INT16SZ]; int i; int advance; /* * Preprocess: * Copy the input (bytewise) array into a wordwise array. * Find the longest run of 0x00's in src[] for :: shorthanding. */ memset(words, '\0', sizeof words); for (i = 0; i < IN6ADDRSZ; i++) words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); best.base = best.len = -1; cur.base = cur.len = -1; for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { if (words[i] == 0) { if (cur.base == -1) cur.base = i, cur.len = 1; else cur.len++; } else { if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; cur.base = -1; } } } if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; } if (best.base != -1 && best.len < 2) best.base = -1; /* * Format the result. */ tp = tmp; ep = tmp + sizeof(tmp); for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) { /* Are we inside the best run of 0x00's? */ if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { if (i == best.base) { if (tp + 1 >= ep) return (NULL); *tp++ = ':'; } continue; } /* Are we following an initial run of 0x00s or any real hex? */ if (i != 0) { if (tp + 1 >= ep) return (NULL); *tp++ = ':'; } /* Is this address an encapsulated IPv4? */ if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) return (NULL); tp += strlen(tp); break; } advance = snprintf(tp, ep - tp, "%x", words[i]); if (advance <= 0 || advance >= ep - tp) return (NULL); tp += advance; } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { if (tp + 1 >= ep) return (NULL); *tp++ = ':'; } if (tp + 1 >= ep) return (NULL); *tp++ = '\0'; /* * Check for overflow, copy, and we're done. */ if ((tp - tmp) > size) { errno = ENOSPC; return (NULL); } strlcpy(dst, tmp, size); return (dst); } #endif pgbouncer-1.5.4/lib/usual/md5.h0000644000175000017500000000310511665176410013171 00000000000000/* * MD5 implementation based on RFC1321. * * Copyright (c) 2008 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * MD5 cryptographic hash. */ #ifndef _USUAL_MD5_H_ #define _USUAL_MD5_H_ #include /** Block length for MD5 */ #define MD5_BLOCK_LENGTH 64 /** Result length for MD5 */ #define MD5_DIGEST_LENGTH 16 /** MD5 state */ struct md5_ctx { uint64_t nbytes; uint32_t a, b, c, d; uint32_t buf[16]; }; /** Clean state */ void md5_reset(struct md5_ctx *ctx); /** Update state with more data */ void md5_update(struct md5_ctx *ctx, const void *data, unsigned int len); /** Get final result */ void md5_final(uint8_t *dst, struct md5_ctx *ctx); #ifdef MD5_COMPAT typedef struct md5_ctx MD5_CTX; #define MD5_Init(c) md5_reset(c) #define MD5_Update(c, d, l) md5_update(c, d, l) #define MD5_Final(d, c) md5_final(d, c) #endif #endif pgbouncer-1.5.4/lib/usual/hmac.c0000644000175000017500000000462311763415244013415 00000000000000/* * HMAC-SHA1 implementation based on OpenBSD hmac.c * * Copyright (c) 2012 Daniel Farina * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include /* Clean HMAC-SHA1 state */ void hmac_sha1_reset(struct hmac_sha1_ctx *ctx, const uint8_t *key, unsigned int key_len) { uint8_t k_ipad[SHA1_BLOCK_SIZE]; int i; if (key_len > SHA1_BLOCK_SIZE) { sha1_reset(&ctx->ctx); sha1_update(&ctx->ctx, key, key_len); sha1_final(ctx->key, &ctx->ctx); ctx->key_len = SHA1_DIGEST_LENGTH; } else { memcpy(ctx->key, key, key_len); ctx->key_len = key_len; } memset(k_ipad, 0, sizeof k_ipad); memcpy(k_ipad, ctx->key, ctx->key_len); for (i = 0; i < SHA1_BLOCK_SIZE; i += 1) k_ipad[i] ^= 0x36; sha1_reset(&ctx->ctx); sha1_update(&ctx->ctx, k_ipad, SHA1_BLOCK_SIZE); /* * Seen in OpenBSD source, presumably to prevent key leakage through * uninitialized memory. */ memset(k_ipad, 0, sizeof k_ipad); } /* Update HMAC-SHA1 state with more data */ void hmac_sha1_update(struct hmac_sha1_ctx *ctx, const void *data, unsigned int len) { sha1_update(&ctx->ctx, data, len); } /* Get final HMAC-SHA1 result */ void hmac_sha1_final(uint8_t *dst, struct hmac_sha1_ctx *ctx) { uint8_t k_opad[SHA1_BLOCK_SIZE]; int i; sha1_final(dst, &ctx->ctx); memset(k_opad, 0, sizeof k_opad); memcpy(k_opad, ctx->key, ctx->key_len); for (i = 0; i < SHA1_BLOCK_SIZE; i += 1) k_opad[i] ^= 0x5c; sha1_reset(&ctx->ctx); sha1_update(&ctx->ctx, k_opad, SHA1_BLOCK_SIZE); sha1_update(&ctx->ctx, dst, SHA1_DIGEST_LENGTH); sha1_final(dst, &ctx->ctx); /* * Seen in OpenBSD source, presumably to prevent key leakage through * uninitialized memory. */ memset(k_opad, 0, sizeof k_opad); } pgbouncer-1.5.4/lib/usual/safeio.h0000644000175000017500000000324111665176410013753 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * * EINTR-safe I/O functions. */ #ifndef _USUAL_SAFEIO_H_ #define _USUAL_SAFEIO_H_ #include /** read */ int safe_read(int fd, void *buf, int len) _MUSTCHECK; /** write */ int safe_write(int fd, const void *buf, int len) _MUSTCHECK; /** recv */ int safe_recv(int fd, void *buf, int len, int flags) _MUSTCHECK; /** send */ int safe_send(int fd, const void *buf, int len, int flags) _MUSTCHECK; /** close */ int safe_close(int fd); /** recvmsg */ int safe_recvmsg(int fd, struct msghdr *msg, int flags) _MUSTCHECK; /** sendmsg */ int safe_sendmsg(int fd, const struct msghdr *msg, int flags) _MUSTCHECK; /** connect */ int safe_connect(int fd, const struct sockaddr *sa, socklen_t sa_len) _MUSTCHECK; /** accept */ int safe_accept(int fd, struct sockaddr *sa, socklen_t *sa_len) _MUSTCHECK; #endif pgbouncer-1.5.4/lib/usual/signal.c0000644000175000017500000000545711665176410013770 00000000000000/* * Signal compat. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include /* * alarm() for win32 */ #ifdef WIN32 struct AlarmCtx { struct sigaction sa; HANDLE event; HANDLE thread; int secs; }; static volatile struct AlarmCtx actx; static DWORD WINAPI w32_alarm_thread(LPVOID arg) { DWORD wres; unsigned msecs; loop: if (actx.secs > 0) { msecs = actx.secs * 1000; } else { msecs = INFINITE; } wres = WaitForSingleObject(actx.event, msecs); if (wres == WAIT_OBJECT_0) { goto loop; } else if (wres == WAIT_TIMEOUT) { actx.secs = 0; if (actx.sa.sa_handler) actx.sa.sa_handler(SIGALRM); goto loop; } else { Sleep(1000); goto loop; } return 0; } unsigned int alarm(unsigned int secs) { actx.secs = secs; /* create event */ if (!actx.event) { actx.event = CreateEvent(NULL, FALSE, FALSE, NULL); if (!actx.event) return 0; } /* create or notify thread */ if (!actx.thread) { actx.thread = CreateThread(NULL, 0, w32_alarm_thread, NULL, 0, NULL); } else { SetEvent(actx.event); } return 0; } #endif #ifndef HAVE_SIGACTION int sigaction(int sig, const struct sigaction *sa, struct sigaction *old) { #ifdef WIN32 if (sig == SIGALRM) { if (old) *old = actx.sa; if (sa) actx.sa = *sa; else actx.sa.sa_handler = NULL; return 0; } #endif old->sa_handler = signal(sig, sa->sa_handler); if (old->sa_handler == SIG_ERR) return -1; return 0; } #endif #ifdef WIN32 /* Only sig=0 is supported, to detect if process is running (ESRCH->not) */ int kill(int pid, int sig) { HANDLE hProcess; DWORD exitCode; int ret = 0; /* handle only sig == 0 */ if (sig != 0) { errno = EINVAL; return -1; } hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); if (hProcess == NULL) { if (GetLastError() == ERROR_INVALID_PARAMETER) ret = ESRCH; else ret = EPERM; } else { /* OpenProcess may succed for exited processes */ if (GetExitCodeProcess(hProcess, &exitCode)) { if (exitCode != STILL_ACTIVE) ret = ESRCH; } CloseHandle(hProcess); } if (ret) { errno = ret; return -1; } else return 0; } #endif pgbouncer-1.5.4/lib/usual/cxextra.c0000644000175000017500000001323611665176410014163 00000000000000 /* * Extra allocators */ #include #include #include /* * Tools for allocators. */ static inline void *p_move(const void *p, int ofs) { return (char *)p + ofs; } /* * sample exit-on-failure wrapper */ static void *nofail_alloc(void *next, size_t len) { void *p = cx_alloc(next, len); if (!p) exit(1); return p; } static void *nofail_realloc(void *next, void *ptr, size_t len) { void *p = cx_realloc(next, ptr, len); if (!p) exit(1); return p; } static void nofail_free(void *next, const void *ptr) { cx_free(next, ptr); } static void nofail_destroy(void *next) { cx_destroy(next); } const struct CxOps cx_nofail_ops = { .c_alloc = nofail_alloc, .c_realloc = nofail_realloc, .c_free = nofail_free, .c_destroy = nofail_destroy, }; const struct CxMem cx_libc_nofail = { .ops = &cx_nofail_ops, .ctx = (void*)&cx_libc_allocator, }; /* * Append-only pool. */ struct CxPoolSeg { struct CxPoolSeg *prev; unsigned size; unsigned used; }; struct CxPool { struct CxMem this; const struct CxMem *parent; struct CxPoolSeg *last; void *last_ptr; }; #define POOL_HDR ALIGN(sizeof(struct CxPoolSeg)) static void *pool_alloc(void *ctx, size_t size) { struct CxPool *pool = ctx; struct CxPoolSeg *seg = pool->last; void *ptr; unsigned nsize; size = ALIGN(size); if (seg && seg->used + size <= seg->size) { ptr = p_move(seg, POOL_HDR + seg->used); seg->used += size; pool->last_ptr = ptr; return ptr; } else { nsize = seg ? (2 * seg->size) : 512; while (nsize < size) nsize *= 2; seg = cx_alloc(pool->parent, POOL_HDR + nsize); if (seg == NULL) return NULL; seg->used = size; seg->size = nsize; seg->prev = pool->last; pool->last = seg; ptr = p_move(seg, POOL_HDR); pool->last_ptr = ptr; return ptr; } } /* free only last item */ static void pool_free(void *ctx, const void *ptr) { struct CxPool *pool = ctx; struct CxPoolSeg *cur = pool->last; const char *cstart; if (pool->last_ptr != ptr) return; cstart = p_move(cur, POOL_HDR); cur->used = (char *)ptr - cstart; pool->last_ptr = NULL; } /* realloc only last item */ static void *pool_realloc(void *ctx, void *ptr, size_t len) { struct CxPool *pool = ctx; struct CxPoolSeg *seg = pool->last; char *cstart, *cused, *p = ptr; size_t olen; if (pool->last_ptr != ptr) return NULL; cstart = p_move(seg, POOL_HDR); cused = cstart + seg->used; olen = cused - p; if (seg->used - olen + len <= seg->size) { seg->used = p + len - cstart; return p; } else { p = pool_alloc(ctx, len); if (!p) return NULL; memcpy(p, ptr, olen); return p; } } static void pool_destroy(void *ctx) { struct CxPool *pool = ctx; struct CxPoolSeg *cur, *tmp; if (!pool) return; for (cur = pool->last; cur; ) { tmp = cur->prev; cx_free(pool->parent, cur); cur = tmp; } cx_free(pool->parent, pool); } static const struct CxOps pool_ops = { .c_alloc = pool_alloc, .c_realloc = pool_realloc, .c_free = pool_free, .c_destroy = pool_destroy, }; /* * public functions */ CxMem *cx_new_pool(CxMem *parent) { struct CxPool *head; head = cx_alloc(parent, sizeof(*head)); if (!head) return NULL; head->parent = parent; head->this.ops = &pool_ops; head->this.ctx = head; head->last = NULL; return &head->this; } /* * tree alloc */ #define TREE_HDR (int)(sizeof(struct CxTreeItem)) struct CxTree { struct CxMem this; CxMem *real; struct List alloc_list; struct List subtree_node; struct List subtree_list; }; /* header for each allocation */ struct CxTreeItem { struct List node; }; static void *tree_alloc(void *ctx, size_t len) { struct CxTree *tree = ctx; struct CxTreeItem *item; item = cx_alloc(tree->real, TREE_HDR + len); if (!item) return NULL; list_init(&item->node); list_append(&tree->alloc_list, &item->node); return p_move(item, TREE_HDR); } static void *tree_realloc(void *ctx, void *ptr, size_t len) { struct CxTree *t = ctx; struct CxTreeItem *item, *item2; item = p_move(ptr, -TREE_HDR); list_del(&item->node); item2 = cx_realloc(t->real, item, TREE_HDR + len); if (item2) { list_append(&t->alloc_list, &item2->node); return p_move(item2, TREE_HDR); } else { list_append(&t->alloc_list, &item->node); return NULL; } } static void tree_free(void *ctx, const void *ptr) { struct CxTree *t = ctx; struct CxTreeItem *item; item = p_move(ptr, -TREE_HDR); list_del(&item->node); cx_free(t->real, item); } static void tree_destroy(void *ctx) { struct CxTree *tree = ctx, *sub; struct CxTreeItem *item; struct List *el, *tmp; /* unregister from parent */ list_del(&tree->subtree_node); /* free elements */ list_for_each_safe(el, &tree->alloc_list, tmp) { list_del(el); item = container_of(el, struct CxTreeItem, node); cx_free(tree->real, item); } /* free subtrees */ list_for_each_safe(el, &tree->subtree_list, tmp) { sub = container_of(el, struct CxTree, subtree_node); tree_destroy(sub); } /* free base struct */ cx_free(tree->real, tree); } static const struct CxOps tree_ops = { .c_alloc = tree_alloc, .c_realloc = tree_realloc, .c_free = tree_free, .c_destroy = tree_destroy, }; CxMem *cx_new_tree(CxMem *cx) { struct CxTree *t, *parent = NULL; CxMem *real = cx; /* * Try to allocate from real allocator. Otherwise allocations * will have double headers. */ if (cx->ops == &tree_ops) { parent = cx->ctx; real = parent->real; } /* initialize */ t = cx_alloc(real, sizeof(*t)); if (!t) return NULL; t->real = real; t->this.ops = &tree_ops; t->this.ctx = t; list_init(&t->alloc_list); list_init(&t->subtree_node); list_init(&t->subtree_list); /* register at parent */ if (parent) list_append(&parent->subtree_list, &t->subtree_node); return &t->this; } pgbouncer-1.5.4/lib/usual/mdict.h0000644000175000017500000000555711665176410013621 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * * Minimal dict. */ #ifndef _USUAL_MDICT_H_ #define _USUAL_MDICT_H_ #include #include /** Dict reference */ struct MDict; /** Create new emtpy dict */ struct MDict *mdict_new(CxMem *cx); /** Free dict */ void mdict_free(struct MDict *dict); /** Get value as MBuf from string */ const struct MBuf *mdict_get_buf(struct MDict *dict, const char *key, unsigned klen); /** Get value from dict */ const char *mdict_get_str(struct MDict *dict, const char *key, unsigned klen); /** Put string to dict */ bool mdict_put_str(struct MDict *dict, const char *key, unsigned klen, const char *val, unsigned vlen); /** Remove a key from dict */ bool mdict_del_key(struct MDict *dict, const char *key, unsigned klen); /** Signature for walker callback */ typedef bool (*mdict_walker_f)(void *arg, const struct MBuf *k, const struct MBuf *v); /** Walk over dict */ bool mdict_walk(struct MDict *dict, mdict_walker_f cb_func, void *cb_arg); /* * Simple API that calculates strlen inline. */ /** Get value from dict */ static inline const char *mdict_get(struct MDict *dict, const char *key) { return mdict_get_str(dict, key, strlen(key)); } /** Put zero-terminated key and value to dict */ static inline bool mdict_put(struct MDict *dict, const char *key, const char *val) { unsigned klen = strlen(key); unsigned vlen = val ? strlen(val) : 0; return mdict_put_str(dict, key, klen, val, vlen); } /** Put MBuf to dict */ static inline bool mdict_put_buf(struct MDict *dict, const char *key, const struct MBuf *buf) { unsigned klen = strlen(key); const char *val = buf ? mbuf_data(buf) : NULL; unsigned vlen = buf ? mbuf_written(buf) : 0; return mdict_put_str(dict, key, klen, val, vlen); } /** Remove value from dict */ static inline bool mdict_del(struct MDict *dict, const char *key) { return mdict_del_key(dict, key, strlen(key)); } /** Urldecode string and add keys with values to dict */ bool mdict_urldecode(struct MDict *dict, const char *str, unsigned len); /** Urlencode dict to string */ bool mdict_urlencode(struct MDict *dict, struct MBuf *dst); #endif pgbouncer-1.5.4/lib/usual/daemon.h0000644000175000017500000000220511665176410013747 00000000000000/** @file * Daemonization & pidfile handling. */ /* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _USUAL_DAEMON_H_ #define _USUAL_DAEMON_H_ #include /** * Read a pid from pidfile and send a signal to it. */ bool signal_pidfile(const char *pidfile, int sig); /** * Daemonize process and write pidfile. */ void daemonize(const char *pidfile, bool go_background); #endif pgbouncer-1.5.4/lib/usual/cxextra.h0000644000175000017500000000304211665176410014162 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Extra allocators for cxalloc. */ #ifndef _USUAL_CXEXTRA_H_ #define _USUAL_CXEXTRA_H_ #include /** Allocator that exits on error. .ctx should be pointer to actual allocator */ extern const struct CxOps cx_nofail_ops; /** nofail for libc */ extern CxMem cx_libc_nofail; /** * Creates allocator that pools all memory together, * without keeping track of single objects, to be * freed all together in one shot. * * realloc(), free() are partially supported for the last * objec only. */ CxMem *cx_new_pool(CxMem *parent); /** * Creates allocator that remebers all allocations done * under it and allows all of it to be freed together. * * Supports hierarchical trees. */ CxMem *cx_new_tree(CxMem *parent); #endif pgbouncer-1.5.4/lib/usual/pgutil_kwlookup.g0000644000175000017500000000242511665176410015746 00000000000000/* gperf header for kwlookup */ %language=ANSI-C %readonly-tables %pic %enum %define lookup-function-name pg_keyword_lookup_real %define hash-function-name pg_keyword_lookup_hash %define string-pool-name pgkw %% all analyse analyze and any array as asc asymmetric authorization between bigint binary bit boolean both case cast char character check coalesce collate column concurrently constraint create cross current_catalog current_date current_role current_schema current_time current_timestamp current_user dec decimal default deferrable desc distinct do else end except exists extract false fetch float for foreign freeze from full grant greatest group having ilike in initially inner inout int integer intersect interval into is isnull join leading least left like limit localtime localtimestamp national natural nchar new none not notnull null nullif numeric off offset old on only or order out outer over overlaps overlay placing position precision primary real references returning right row select session_user setof similar smallint some substring symmetric table then time timestamp to trailing treat trim true union unique user using values varchar variadic verbose when where window with xmlattributes xmlconcat xmlelement xmlexists xmlforest xmlparse xmlpi xmlroot xmlserialize pgbouncer-1.5.4/lib/usual/lookup3.h0000644000175000017500000000036611665176410014106 00000000000000/** * @file * * Jenkins' lookup3 non-cryptographic hash. */ #ifndef _USUAL_LOOKUP3_H_ #define _USUAL_LOOKUP3_H_ #include /** * Calculate 64-bit hash over data */ uint64_t hash_lookup3(const void *data, size_t len); #endif pgbouncer-1.5.4/lib/usual/hashtab-impl.h0000644000175000017500000001353111665176410015061 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * Simple customizable hashtable implementation. * * - Fixed-size hash table, open-addressed * - Extended by linking several together * - Resizable by copying. * - Can be lockless in multi-reader, one-writer situation if * mempory barrier macros are defined. This also requires that * HashItem must not be split across cachelines. */ #include #include #ifndef HTAB_KEY_T /** Overridable type for key */ #define HTAB_KEY_T unsigned long #endif #ifndef HTAB_VAL_T /** Overridable type for value */ #define HTAB_VAL_T void * #endif #ifndef HTAB_RMB #define HTAB_RMB #endif #ifndef HTAB_WMB #define HTAB_WMB #endif /** Typedef for key */ typedef HTAB_KEY_T htab_key_t; /** Typedef for value */ typedef HTAB_VAL_T htab_val_t; #ifndef HTAB_ITEM #define HTAB_ITEM /** HashTab slot */ struct HashItem { htab_key_t key; htab_val_t value; }; #endif /** Signature for comparision function */ typedef bool (*hash_cmp_fn)(const htab_val_t curval, const void *arg); #ifndef HTAB_MAX_FILL /** Max fill percentage */ #define HTAB_MAX_FILL 75 #endif #define MASK(h) ((h)->size - 1) #define CALC_POS(h, key) ((key) & MASK(h)) #define NEXT_POS(h, pos) (((pos) * 5 + 1) & MASK(h)) #define MAX_USED(h) ((h)->size * HTAB_MAX_FILL / 100) /** Single HashTab segment */ struct HashTab { struct HashTab *next; hash_cmp_fn cmp_fn; CxMem *ca; unsigned size; unsigned used; struct HashItem tab[FLEX_ARRAY]; }; /** Initialize HashTab */ static struct HashTab *hashtab_create(unsigned size, hash_cmp_fn cmp_fn, CxMem *ca) { struct HashTab *h; unsigned len = size * sizeof(struct HashItem) + offsetof(struct HashTab, tab); h = cx_alloc0(ca, len); if (h) { h->size = size; h->cmp_fn = cmp_fn; h->ca = ca; } return h; } /** Free HashTab */ static void hashtab_destroy(struct HashTab *h) { struct HashTab *tmp; while (h) { tmp = h->next; cx_free(h->ca, h); h = tmp; } } /** Element lookup, optionally inserting new slot */ static htab_val_t *hashtab_lookup(struct HashTab *h, htab_key_t key, bool do_insert, const void *arg) { unsigned pos; struct HashItem *i; loop: /* find key, starting from pos */ pos = CALC_POS(h, key); while (h->tab[pos].value) { i = &h->tab[pos]; HTAB_RMB; if (i->key == key) { if (arg && h->cmp_fn(i->value, arg)) return &i->value; } pos = NEXT_POS(h, pos); } /* not found in this one, check chained tables */ if (h->next) { h = h->next; goto loop; } /* just lookup? */ if (!do_insert) return NULL; /* insert */ if (h->used >= MAX_USED(h)) { struct HashTab *tmp; tmp = hashtab_create(h->size, h->cmp_fn, h->ca); if (!tmp) return NULL; h->next = tmp; h = tmp; pos = CALC_POS(h, key); } h->used++; h->tab[pos].key = key; HTAB_WMB; return &h->tab[pos].value; } /* if proper pos is between src and dst, cannot move */ static bool _hashtab_slot_can_move(struct HashTab *h, unsigned dstpos, unsigned srcpos) { htab_key_t key = h->tab[srcpos].key; unsigned pos, kpos = CALC_POS(h, key); if (kpos == srcpos) return false; if (kpos == dstpos) return true; for (pos = NEXT_POS(h, dstpos); pos != srcpos; pos = NEXT_POS(h, pos)) { if (pos == kpos) return false; } return true; } /** Delete an element */ static void hashtab_delete(struct HashTab *h, htab_key_t key, void *arg) { htab_val_t *vptr; struct HashItem *hd; unsigned pos, dstpos; /* find it */ vptr = hashtab_lookup(h, key, false, arg); if (!vptr) return; /* find right tab */ hd = container_of(vptr, struct HashItem, value); while (h && ((hd < h->tab) || (hd >= h->tab + h->size))) h = h->next; /* calculate index */ dstpos = hd - h->tab; loop: /* move slot */ for (pos = NEXT_POS(h, dstpos); h->tab[pos].value; pos = NEXT_POS(h, pos)) { if (_hashtab_slot_can_move(h, dstpos, pos)) { h->tab[dstpos].key = h->tab[pos].key; h->tab[dstpos].value = h->tab[pos].value; dstpos = pos; goto loop; } } h->tab[dstpos].value = 0; HTAB_WMB; h->tab[dstpos].key = 0; h->used--; } /** Count elements and fragments */ static void hashtab_stats(struct HashTab *h, unsigned *nitem_p, unsigned *ntab_p) { unsigned n = 0, l = 0; while (h) { l++; n += h->used; h = h->next; } *nitem_p = n; *ntab_p = l; } /** Copy elements to new hashtab, perhaps with different size */ static struct HashTab *hashtab_copy(struct HashTab *h_old, unsigned newsize) { struct HashTab *h_new; unsigned i; h_new = hashtab_create(newsize, h_old->cmp_fn, h_old->ca); for (; h_old; h_old = h_old->next) { for (i = 0; i < h_old->size; i++) { struct HashItem *s = &h_old->tab[i]; htab_val_t *new_pos; if (s->value) { new_pos = hashtab_lookup(h_new, s->key, true, NULL); if (!new_pos) goto err; *new_pos = s->value; } } } return h_new; err: hashtab_destroy(h_new); return NULL; } /* example, and avoid "unused" warnings */ static inline void _hashtab_example(void) { unsigned nitem, nlink; struct HashTab *h, *h2; h = hashtab_create(1024, NULL, USUAL_ALLOC); hashtab_lookup(h, 123, true, NULL); hashtab_stats(h, &nitem, &nlink); h2 = hashtab_copy(h, 2048); hashtab_delete(h, 123, NULL); hashtab_destroy(h); hashtab_destroy(h2); } pgbouncer-1.5.4/lib/usual/cbtree.c0000644000175000017500000001743011665176410013751 00000000000000/* * Crit-bit tree / binary radix tree. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Associates a C string with user pointer (called "obj"). * * Requires it's own internal nodes, thus not embeddable * to user structs. */ #include #include /* * - Childs are either other nodes or user pointers. * User pointers have lowest bit set. * * - All nodes have both childs. * * - Keys are handled as having infinite length, * zero-filled after actual end. */ struct Node { struct Node *child[2]; unsigned bitpos; }; struct CBTree { struct Node *root; cbtree_getkey_func obj_key_cb; cbtree_walker_func obj_free_cb; void *cb_ctx; CxMem *cx; }; #define SAME_KEY 0xFFFFFFFF /* * Low-level operations. */ /* does ptr point to user object or slot */ static inline int is_node(void *ptr) { return ((uintptr_t)(ptr) & 1) == 0; } /* flag pointer as pointing to user object */ static inline void *set_external(const void *obj) { return (void*)((uintptr_t)(obj) | 1); } /* remove flag from user pointer */ static inline void *get_external(void *extval) { return (void*)((uintptr_t)(extval) & (~1)); } /* get specific bit from string */ static inline unsigned get_bit(unsigned bitpos, const unsigned char *key, unsigned klen) { unsigned pos = bitpos / 8; unsigned bit = 7 - (bitpos % 8); return (pos < klen) && (key[pos] & (1 << bit)); } /* use callback to get key for a stored object */ static inline unsigned get_key(struct CBTree *tree, void *obj, const void **key_p) { return tree->obj_key_cb(tree->cb_ctx, obj, key_p); } /* check if object key matches argument */ static inline bool key_matches(struct CBTree *tree, void *obj, const void *key, unsigned klen) { const void *o_key; unsigned o_klen; o_klen = get_key(tree, obj, &o_key); return (o_klen == klen) && (memcmp(key, o_key, klen) == 0); } /* Find first differing bit on 2 strings. */ static unsigned find_crit_bit(const unsigned char *a, unsigned alen, const unsigned char *b, unsigned blen) { unsigned i, c, pos, av, bv; unsigned minlen = (alen > blen) ? blen : alen; unsigned maxlen = (alen > blen) ? alen : blen; /* find differing byte in common data */ for (i = 0; i < minlen; i++) { av = a[i]; bv = b[i]; if (av != bv) goto found; } /* find differing byte when one side is zero-filled */ for (; i < maxlen; i++) { av = (i < alen) ? a[i] : 0; bv = (i < blen) ? b[i] : 0; if (av != bv) goto found; } return SAME_KEY; found: /* calculate bits that differ */ c = av ^ bv; /* find the first one */ pos = 8 - fls(c); return i * 8 + pos; } /* * Lookup */ /* walk nodes until external pointer is found */ static void *raw_lookup(struct CBTree *tree, const void *key, unsigned klen) { struct Node *node = tree->root; unsigned bit; while (is_node(node)) { bit = get_bit(node->bitpos, key, klen); node = node->child[bit]; } return get_external(node); } /* actual lookup. returns obj ptr or NULL of not found */ void *cbtree_lookup(struct CBTree *tree, const void *key, unsigned klen) { void *obj; if (!tree->root) return NULL; /* find match based on bits we know about */ obj = raw_lookup(tree, key, klen); /* need to check if the object actually matches */ if (key_matches(tree, obj, key, klen)) return obj; return NULL; } /* * Insertion. */ /* node allocation */ static struct Node *new_node(struct CBTree *tree) { struct Node *node = cx_alloc(tree->cx, sizeof(*node)); memset(node, 0, sizeof(*node)); return node; } /* insert into empty tree */ static bool insert_first(struct CBTree *tree, void *obj) { tree->root = set_external(obj); return true; } /* insert into specific bit-position */ static bool insert_at(struct CBTree *tree, unsigned newbit, const void *key, unsigned klen, void *obj) { /* location of current node/obj pointer under examination */ struct Node **pos = &tree->root; struct Node *node; unsigned bit; while (is_node(*pos) && ((*pos)->bitpos < newbit)) { bit = get_bit((*pos)->bitpos, key, klen); pos = &(*pos)->child[bit]; } bit = get_bit(newbit, key, klen); node = new_node(tree); if (!node) return false; node->bitpos = newbit; node->child[bit] = set_external(obj); node->child[bit ^ 1] = *pos; *pos = node; return true; } /* actual insert: returns true -> insert ok or key found, false -> alloc failure */ bool cbtree_insert(struct CBTree *tree, void *obj) { const void *key, *old_key; unsigned newbit, klen, old_klen; void *old_obj; if (!tree->root) return insert_first(tree, obj); /* current key */ klen = get_key(tree, obj, &key); /* nearest key in tree */ old_obj = raw_lookup(tree, key, klen); old_klen = get_key(tree, old_obj, &old_key); /* first differing bit is the target position */ newbit = find_crit_bit(key, klen, old_key, old_klen); if (newbit == SAME_KEY) return true; return insert_at(tree, newbit, key, klen, obj); } /* * Key deletion. */ /* true -> object was found and removed, false -> not found */ bool cbtree_delete(struct CBTree *tree, const void *key, unsigned klen) { void *obj, *tmp; unsigned bit = 0; /* location of current node/obj pointer under examination */ struct Node **pos = &tree->root; /* if 'pos' has user obj, prev_pos has internal node pointing to it */ struct Node **prev_pos = NULL; if (!tree->root) return false; /* match bits we know about */ while (is_node(*pos)) { bit = get_bit((*pos)->bitpos, key, klen); prev_pos = pos; pos = &(*pos)->child[bit]; } /* does the key actually matches */ obj = get_external(*pos); if (!key_matches(tree, obj, key, klen)) return false; if (tree->obj_free_cb) tree->obj_free_cb(tree->cb_ctx, obj); /* drop the internal node pointing to our key */ if (prev_pos) { tmp = *prev_pos; *prev_pos = (*prev_pos)->child[bit ^ 1]; cx_free(tree->cx, tmp); } else { tree->root = NULL; } return true; } /* * Management. */ struct CBTree *cbtree_create(cbtree_getkey_func obj_key_cb, cbtree_walker_func obj_free_cb, void *cb_ctx, CxMem *cx) { struct CBTree *tree = cx_alloc(cx, sizeof(*tree)); if (!tree) return NULL; tree->root = NULL; tree->cb_ctx = cb_ctx; tree->obj_key_cb = obj_key_cb; tree->obj_free_cb = obj_free_cb; tree->cx = cx; return tree; } /* recursive freeing */ static void destroy_node(struct CBTree *tree, struct Node *node) { if (is_node(node)) { destroy_node(tree, node->child[0]); destroy_node(tree, node->child[1]); cx_free(tree->cx, node); } else if (tree->obj_free_cb) { void *obj = get_external(node); tree->obj_free_cb(tree->cb_ctx, obj); } } /* Free tree and all it's internal nodes. */ void cbtree_destroy(struct CBTree *tree) { if (tree->root) destroy_node(tree, tree->root); tree->root = NULL; cx_free(tree->cx, tree); } /* * walk over tree */ static bool walk(struct Node *node, cbtree_walker_func cb_func, void *cb_arg) { if (!is_node(node)) return cb_func(cb_arg, get_external(node)); return walk(node->child[0], cb_func, cb_arg) && walk(node->child[1], cb_func, cb_arg); } bool cbtree_walk(struct CBTree *tree, cbtree_walker_func cb_func, void *cb_arg) { if (!tree->root) return true; return walk(tree->root, cb_func, cb_arg); } pgbouncer-1.5.4/lib/usual/config.h.in0000644000175000017500000002535312002231436014351 00000000000000/* lib/usual/config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* Define to enable assert checking */ #undef CASSERT /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_BYTESWAP_H /* Define to 1 if you have the `crypt' function. */ #undef HAVE_CRYPT /* Define to 1 if you have the header file. */ #undef HAVE_CRYPT_H /* Define if macros work on char. */ #undef HAVE_CTYPE_ON_CHAR /* Define to 1 if you have the declaration of `strerror_r', and to 0 if you don't. */ #undef HAVE_DECL_STRERROR_R /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define if *enc & *dec functions are available */ #undef HAVE_ENCDEC_FUNCS /* Define to 1 if you have the header file. */ #undef HAVE_ENDIAN_H /* Define to 1 if you have the `err' function. */ #undef HAVE_ERR /* Define to 1 if you have the `errx' function. */ #undef HAVE_ERRX /* Define to 1 if you have the header file. */ #undef HAVE_ERR_H /* Define to 1 if you have the `evdns_base_new' function. */ #undef HAVE_EVDNS_BASE_NEW /* Define to 1 if you have the `event_base_new' function. */ #undef HAVE_EVENT_BASE_NEW /* Define to 1 if you have the `event_loopbreak' function. */ #undef HAVE_EVENT_LOOPBREAK /* Define to 1 if you have the `ffs' function. */ #undef HAVE_FFS /* Define to 1 if you have the `ffsl' function. */ #undef HAVE_FFSL /* Define to 1 if you have the `ffsll' function. */ #undef HAVE_FFSLL /* Define to 1 if you have the `fls' function. */ #undef HAVE_FLS /* Define to 1 if you have the `flsl' function. */ #undef HAVE_FLSL /* Define to 1 if you have the `flsll' function. */ #undef HAVE_FLSLL /* Define to 1 if your compiler understands __func__. */ #undef HAVE_FUNCNAME__FUNC /* Define to 1 if you have the getaddrinfo_a() function. */ #undef HAVE_GETADDRINFO_A /* Define to 1 if you have the `getline' function. */ #undef HAVE_GETLINE /* Define to 1 if you have the `getopt' function. */ #undef HAVE_GETOPT /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define to 1 if you have the `getopt_long' function. */ #undef HAVE_GETOPT_LONG /* Define to 1 if you have the `getopt_long_only' function. */ #undef HAVE_GETOPT_LONG_ONLY /* Define to 1 if you have the `getpeereid' function. */ #undef HAVE_GETPEEREID /* Define to 1 if you have the `getpeerucred' function. */ #undef HAVE_GETPEERUCRED /* Define to 1 if you have the `getprogname' function. */ #undef HAVE_GETPROGNAME /* Define to 1 if you have the `getrusage' function. */ #undef HAVE_GETRUSAGE /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H /* Define to 1 if you have the `inet_ntop' function. */ #undef HAVE_INET_NTOP /* Define to 1 if you have the `inet_pton' function. */ #undef HAVE_INET_PTON /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Use real libevent. */ #undef HAVE_LIBEVENT /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if you have the `lstat' function. */ #undef HAVE_LSTAT /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the `memalign' function. */ #undef HAVE_MEMALIGN /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memrchr' function. */ #undef HAVE_MEMRCHR /* Define to 1 if you have the `mmap' function. */ #undef HAVE_MMAP /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_TCP_H /* Define to 1 if you have the `poll' function. */ #undef HAVE_POLL /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H /* Define to 1 if you have the `posix_memalign' function. */ #undef HAVE_POSIX_MEMALIGN /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H /* Define to 1 if you have the header file. */ #undef HAVE_PWD_H /* Define to 1 if you have the `recvmsg' function. */ #undef HAVE_RECVMSG /* Define to 1 if you have the `regcomp' function. */ #undef HAVE_REGCOMP /* Define to 1 if you have the header file. */ #undef HAVE_REGEX_H /* Define to 1 if you have the `sendmsg' function. */ #undef HAVE_SENDMSG /* Define to 1 if you have the `setprogname' function. */ #undef HAVE_SETPROGNAME /* Define to 1 if you have the `sigaction' function. */ #undef HAVE_SIGACTION /* Define to 1 if you have the `sigqueue' function. */ #undef HAVE_SIGQUEUE /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strerror_r' function. */ #undef HAVE_STRERROR_R /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `syslog' function. */ #undef HAVE_SYSLOG /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ENDIAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_POLL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UCRED_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_UCRED_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP /* Define to 1 if you have the `valloc' function. */ #undef HAVE_VALLOC /* Define to 1 if you have the `warn' function. */ #undef HAVE_WARN /* Define to 1 if you have the `warnx' function. */ #undef HAVE_WARNX /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #undef PTHREAD_CREATE_JOINABLE /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if strerror_r returns char *. */ #undef STRERROR_R_CHAR_P /* Use libevent for DNS lookups. */ #undef USE_EVDNS /* Use UDNS for name resolution. */ #undef USE_UDNS /* Define to request cleaner win32 headers. */ #undef WIN32_LEAN_AND_MEAN /* Define to max win32 API version (0x0501=XP). */ #undef WINVER /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define to get working glibc. */ #undef _GNU_SOURCE /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to `int' if does not define. */ #undef pid_t /* Define to the equivalent of the C99 'restrict' keyword, or to nothing if this is not supported. Do not define if restrict is supported directly. */ #undef restrict /* Work around a bug in Sun C++: it does not support _Restrict or __restrict__, even though the corresponding Sun C compiler ends up with "#define restrict _Restrict" or "#define restrict __restrict__" in the previous line. Perhaps some future version of Sun C++ will work with restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ #if defined __SUNPRO_CC && !defined __RESTRICT # define _Restrict # define __restrict__ #endif /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if doesn't define. */ #undef uid_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t pgbouncer-1.5.4/lib/usual/fileutil.h0000644000175000017500000000332111665176410014321 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * File access utils. */ #ifndef _USUAL_FILEUTIL_H_ #define _USUAL_FILEUTIL_H_ #include #include /** Info about mapped file */ struct MappedFile { int fd; unsigned len; void *ptr; }; /** Signature for per-line callback */ typedef bool (*procline_cb)(void *arg, const char *line, ssize_t len); /** Read file into memory */ void *load_file(const char *fn, size_t *len_p); /** Loop over lines in file */ bool foreach_line(const char *fn, procline_cb proc_line, void *arg); /** Get file size */ ssize_t file_size(const char *fn); /** Map file into memory */ int map_file(struct MappedFile *m, const char *fname, int rw) _MUSTCHECK; /** Unmap previously mapped file */ void unmap_file(struct MappedFile *m); #if !defined(HAVE_GETLINE) #define getline(a,b,c) compat_getline(a,b,c) /** * Compat: Read line from file */ int getline(char **line_p, size_t *size_p, void *f); #endif #endif pgbouncer-1.5.4/lib/usual/err.h0000644000175000017500000000375011665176410013302 00000000000000/* * Cmdline error reporting. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Error printing for command-line utilities. */ #ifndef _USUAL_ERR_H_ #define _USUAL_ERR_H_ #include #ifdef HAVE_ERR_H #include #endif #ifndef HAVE_ERR /** Print formatted message and strerror(errno) to stderr and exit with given error code */ void err(int e, const char *fmt, ...) _PRINTF(2, 3); #endif #ifndef HAVE_ERRX /** Print formatted message to stderr and exit with given error code */ void errx(int e, const char *fmt, ...) _PRINTF(2, 3); #endif #ifndef HAVE_WARN /** Print formatted message and strerror(errno) to stderr */ void warn(const char *fmt, ...) _PRINTF(1, 2); #endif #ifndef HAVE_WARNX /** Print formatted message to stderr */ void warnx(const char *fmt, ...) _PRINTF(1, 2); #endif #ifndef HAVE_SETPROGNAME /** Set program name to that will printed as prefix to error messages */ void setprogname(const char *s); #endif #ifndef HAVE_GETPROGNAME /** Return program name set with @ref setprogname */ const char *getprogname(void); #endif /** Malloc that exits on failure */ void *xmalloc(size_t len); /** Realloc that exits on failure */ void *xrealloc(void *p, size_t len); /** strdup that exits on failure */ char *xstrdup(const char *s); #endif pgbouncer-1.5.4/lib/usual/mdict.c0000644000175000017500000001424611665176410013607 00000000000000/* * A string to string dictionary. */ #include #include #include #include #include struct MDict { struct CBTree *tree; CxMem *cx; }; struct MDictElem { struct MBuf key; struct MBuf val; }; /* hook for CBTree */ static unsigned int mdict_getkey(void *ctx, void *obj, const void **dst_p) { struct MDictElem *el = obj; *dst_p = mbuf_data(&el->key); return mbuf_written(&el->key); } static bool mdict_free_obj(void *ctx, void *obj) { struct MDictElem *el = obj; struct MDict *dict = ctx; cx_free(dict->cx, mbuf_data(&el->key)); cx_free(dict->cx, mbuf_data(&el->val)); cx_free(dict->cx, el); return true; } struct MDict *mdict_new(CxMem *cx) { struct MDict *dict; dict = cx_alloc(cx, sizeof(struct MDict)); if (!dict) return NULL; dict->cx = cx; dict->tree = cbtree_create(mdict_getkey, mdict_free_obj, dict, cx); if (!dict->tree) { cx_free(cx, dict); return NULL; } return dict; } void mdict_free(struct MDict *dict) { if (dict) { cbtree_destroy(dict->tree); cx_free(dict->cx, dict); } } const struct MBuf *mdict_get_buf(struct MDict *dict, const char *key, unsigned klen) { struct MDictElem *el = cbtree_lookup(dict->tree, key, klen); if (!el) return NULL; return &el->val; } const char *mdict_get_str(struct MDict *dict, const char *key, unsigned klen) { const struct MBuf *val = mdict_get_buf(dict, key, klen); return val ? mbuf_data(val) : NULL; } bool mdict_put_str(struct MDict *dict, const char *key, unsigned klen, const char *val, unsigned vlen) { char *kptr, *vptr = NULL; struct MDictElem *el; if (val) { vptr = cx_alloc(dict->cx, vlen + 1); if (!vptr) return false; memcpy(vptr, val, vlen); vptr[vlen] = 0; } el = cbtree_lookup(dict->tree, key, klen); if (el) { cx_free(dict->cx, mbuf_data(&el->val)); mbuf_init_fixed_reader(&el->val, vptr, vlen); } else { kptr = cx_alloc(dict->cx, klen + 1); if (!kptr) return false; memcpy(kptr, key, klen); kptr[klen] = 0; el = cx_alloc(dict->cx, sizeof(*el)); if (!el) return false; mbuf_init_fixed_reader(&el->key, kptr, klen); mbuf_init_fixed_reader(&el->val, vptr, vlen); if (!cbtree_insert(dict->tree, el)) return false; } return true; } bool mdict_del_key(struct MDict *dict, const char *key, unsigned klen) { return cbtree_delete(dict->tree, key, klen); } /* * walk over key-val pairs */ struct WalkerCtx { mdict_walker_f cb_func; void *cb_arg; }; static bool walk_helper(void *arg, void *elem) { struct WalkerCtx *ctx = arg; struct MDictElem *el = elem; return ctx->cb_func(ctx->cb_arg, &el->key, &el->val); } bool mdict_walk(struct MDict *dict, mdict_walker_f cb_func, void *cb_arg) { struct WalkerCtx ctx; ctx.cb_func = cb_func; ctx.cb_arg = cb_arg; return cbtree_walk(dict->tree, walk_helper, &ctx); } /* * urldecode */ static int gethex(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static void *urldec_str(CxMem *cx, const char **src_p, const char *end, unsigned *len_p) { const char *s; char *d, *dst; int c, len = 0; /* estimate size */ for (s = *src_p; s < end; s++) { if (*s == '%') s += 2; else if (*s == '&' || *s == '=') break; len++; } /* allocate room */ d = dst = cx_alloc(cx, len + 1); if (!dst) return NULL; /* write out */ for (s = *src_p; s < end; ) { if (*s == '%') { if (s + 3 > end) goto err; c = gethex(s[1]) << 4; c |= gethex(s[2]); if (c < 0) goto err; s += 3; *d++ = c; } else if (*s == '+') { *d++ = ' '; s++; } else if (*s == '&' || *s == '=') { break; } else { *d++ = *s++; } } *d = 0; *len_p = d - dst; *src_p = s; return dst; err: cx_free(cx, dst); return NULL; } bool mdict_urldecode(struct MDict *dict, const char *str, unsigned len) { const char *s = str; const char *end = s + len; const char *k, *v; unsigned klen, vlen; struct MDictElem *el; while (s < end) { v = NULL; vlen = 0; el = NULL; /* read key */ k = urldec_str(dict->cx, &s, end, &klen); if (!k) goto fail; /* read value */ if (s < end && *s == '=') { s++; v = urldec_str(dict->cx, &s, end, &vlen); if (!v) goto fail; } if (s < end && *s == '&') s++; /* insert value */ el = cbtree_lookup(dict->tree, k, klen); if (el) { cx_free(dict->cx, mbuf_data(&el->val)); mbuf_init_fixed_reader(&el->val, v, vlen); } else { el = cx_alloc(dict->cx, sizeof(*el)); if (!el) goto fail; mbuf_init_fixed_reader(&el->key, k, klen); mbuf_init_fixed_reader(&el->val, v, vlen); if (!cbtree_insert(dict->tree, el)) goto fail; } } return true; fail: if (k) cx_free(dict->cx, k); if (v) cx_free(dict->cx, v); if (el) cx_free(dict->cx, el); return false; } /* * urlencode */ struct UrlEncCtx { struct MBuf *dst; bool is_first; }; static bool urlenc_str(struct MBuf *dst, const struct MBuf *str) { static const char hextbl[] = "0123456789abcdef"; unsigned len = mbuf_written(str); const unsigned char *s = mbuf_data(str); const unsigned char *end = s + len; bool ok; for (; s < end; s++) { if (*s == ' ') { ok = mbuf_write_byte(dst, '+'); } else if ((*s < 128) && isalnum(*s)) { ok = mbuf_write_byte(dst, *s); } else if (*s == '.' || *s == '_') { ok = mbuf_write_byte(dst, *s); } else { ok = mbuf_write_byte(dst, '%'); ok = ok && mbuf_write_byte(dst, hextbl[*s >> 4]); ok = ok && mbuf_write_byte(dst, hextbl[*s & 15]); } if (!ok) return false; } return true; } static bool urlenc_elem(void *arg, const struct MBuf *key, const struct MBuf *val) { struct UrlEncCtx *ctx = arg; bool ok; if (ctx->is_first) { ctx->is_first = false; } else { ok = mbuf_write_byte(ctx->dst, '&'); if (!ok) return false; } ok = urlenc_str(ctx->dst, key); if (!ok) return false; if (mbuf_data(val) != NULL) { ok = mbuf_write_byte(ctx->dst, '='); if (!ok) return false; ok = urlenc_str(ctx->dst, val); if (!ok) return false; } return true; } bool mdict_urlencode(struct MDict *dict, struct MBuf *dst) { struct UrlEncCtx ctx; ctx.is_first = true; ctx.dst = dst; return mdict_walk(dict, urlenc_elem, &ctx); } pgbouncer-1.5.4/lib/usual/strpool.c0000644000175000017500000000557111665176410014212 00000000000000/* * Pool for shared strings. * * Copyright (c) 2010 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include /* * Put all strings into cbtree. */ struct StrPool { CxMem *ca; struct CBTree *tree; int count; }; /* pass key info to cbtree */ static unsigned get_key(void *ctx, void *obj, const void **dst_p) { struct PStr *s = obj; *dst_p = s->str; return s->len; } /* free PStr obj */ static bool free_str(void *arg, void *obj) { struct PStr *p = obj; struct StrPool *sp = p->pool; memset(p, 0, offsetof(struct PStr, str) + 1); cx_free(sp->ca, obj); return true; } /* create main structure */ struct StrPool *strpool_create(CxMem *ca) { struct StrPool *sp; sp = cx_alloc(ca, sizeof(*sp)); if (!sp) return NULL; sp->count = 0; sp->ca = ca; sp->tree = cbtree_create(get_key, NULL, NULL, ca); if (!sp->tree) { cx_free(ca, sp); return NULL; } return sp; } /* free main structure */ void strpool_free(struct StrPool *sp) { if (sp) { cbtree_walk(sp->tree, free_str, sp); cbtree_destroy(sp->tree); cx_free(sp->ca, sp); } } /* return total count of strings in pool */ int strpool_total(struct StrPool *sp) { return sp->count; } /* get new reference to str */ struct PStr *strpool_get(struct StrPool *sp, const char *str, int len) { struct PStr *cstr; bool ok; if (len < 0) len = strlen(str); /* search */ cstr = cbtree_lookup(sp->tree, str, len); if (cstr) { cstr->refcnt++; return cstr; } /* create */ cstr = cx_alloc(sp->ca, sizeof(*cstr) + len + 1); if (!cstr) return NULL; cstr->pool = sp; cstr->refcnt = 1; cstr->len = len; memcpy(cstr->str, str, len + 1); /* insert */ ok = cbtree_insert(sp->tree, cstr); if (!ok) { cx_free(sp->ca, cstr); return NULL; } sp->count++; return cstr; } /* add reference */ void strpool_incref(struct PStr *s) { if (s) s->refcnt++; } /* drop reference, free if none left */ void strpool_decref(struct PStr *s) { struct StrPool *sp; if (!s) return; Assert(s->refcnt > 0); s->refcnt--; if (s->refcnt > 0) return; /* remove */ sp = s->pool; sp->count--; cbtree_delete(sp->tree, s->str, s->len); free_str(NULL, s); } pgbouncer-1.5.4/lib/usual/socket.h0000644000175000017500000000734511665176410014006 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * * Socket compat, few utils. * * Socket headers included: * - win32: * - win32: * - * - * - * - * - * - * - * - */ #ifndef _USUAL_SOCKET_H_ #define _USUAL_SOCKET_H_ #include #ifdef WIN32 #include #include #include #endif #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif #ifdef HAVE_SYS_UIO_H #include #endif #ifdef HAVE_SYS_UN_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifndef INADDR_NONE /** Compat: Some systems (Solaris) does not define INADDR_NONE */ #define INADDR_NONE ((unsigned long) -1) #endif /** * Usual socket setup. * * - Disallow SIGPIPE * - Set close-on-exec flag * - Call \ref socket_set_nonblocking() with given flag */ bool socket_setup(int sock, bool non_block); /** * Flip sockets non-blocking flag */ bool socket_set_nonblocking(int sock, bool non_block); /** * Set sockets keepalive flags. * * @param fd TCP socket * @param onoff Whether to set keepalive on or off. * @param keepidle How long the socket must be idle before keepalive packets are sent * @param keepintvl How big period between consecutive keepalive packets. * @param keepcnt How many keepalive packets to send before considering socket dead. */ bool socket_set_keepalive(int fd, int onoff, int keepidle, int keepintvl, int keepcnt); /** * Convert struct sockaddr to stirng. * * Supports: ipv4, ipv5, unix sockets. */ const char *sa2str(const struct sockaddr *sa, char *buf, int buflen); #ifndef HAVE_INET_NTOP #define inet_ntop(a,b,c,d) usual_inet_ntop(a,b,c,d) /** Compat: inet_ntop() */ const char *inet_ntop(int af, const void *src, char *dst, int cnt); #endif #ifndef HAVE_INET_PTON #define inet_pton(a,b,c) usual_inet_pton(a,b,c) /** Compat: inet_pton() */ int inet_pton(int af, const char *src, void *dst); #endif #ifndef HAVE_GETPEEREID #define getpeereid(a,b,c) compat_getpeereid(a,b,c) /** Get user id of UNIX socket peer */ int getpeereid(int fd, uid_t *uid_p, gid_t *gid_p); #endif #if !defined(HAVE_POLL) #define POLLIN (1 << 0) #define POLLOUT (1 << 1) #define POLLHUP (1 << 2) #define POLLPRI (1 << 3) #define POLLNVAL (1 << 4) #define POLLERR (1 << 5) #define poll(a,b,c) compat_poll(a,b,c) struct pollfd { int fd; short events; short revents; }; typedef unsigned long nfds_t; /** Compat: select-based poll() */ int poll(struct pollfd *fds, nfds_t nfds, int timeout_ms); #endif #ifdef WIN32 #define socketpair(a,b,c,d) win32_socketpair(a,b,c,d) /** Compat: socketpair() for win32 */ int socketpair(int d, int typ, int proto, int sv[2]); #endif #endif pgbouncer-1.5.4/lib/usual/base.h0000644000175000017500000001432611737344375013434 00000000000000/** @file * Basic C environment. */ /* * Copyright (c) 2007-2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _USUAL_BASE_H_ #define _USUAL_BASE_H_ #ifdef USUAL_TEST_CONFIG #include "test_config.h" #else #include #endif /* solaris is broken otherwise */ #if defined(__sun) #define _XPG4_2 #define __EXTENSIONS__ #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #define DLLEXPORT __declspec(dllexport) #define DLLIMPORT __declspec(dllimport) #else #define DLLEXPORT #define DLLIMPORT #endif /** give offset of a field inside struct */ #ifndef offsetof #define offsetof(type, field) ((unsigned long)&(((type *)0)->field)) #endif /** given pointer to field inside struct, return pointer to struct */ #ifndef container_of #define container_of(ptr, type, field) ((type *)((char *)(ptr) - offsetof(type, field))) #endif /** get alignment requirement for a type */ #ifndef alignof #define alignof(type) offsetof(struct { char c; type t; }, t) #endif /** power-of-2 alignment */ #ifndef CUSTOM_ALIGN #define CUSTOM_ALIGN(x, a) (((uintptr_t)(x) + (uintptr_t)(a) - 1) & ~((uintptr_t)(a) - 1)) #endif /** preferred alignment */ #ifndef ALIGN #define ALIGN(x) CUSTOM_ALIGN(x, sizeof(long)) #endif /** number of elements in array */ #define ARRAY_NELEM(a) (sizeof(a) / sizeof((a)[0])) /* how to specify array with unknown length */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) #define FLEX_ARRAY #elif defined(__GNUC__) && (__GNUC__ >= 3) #define FLEX_ARRAY #else #define FLEX_ARRAY 1 #endif /** Make string token from C expression */ #define STR(x) _STR_(x) #define _STR_(x) #x /** Make single C token from 2 separate tokens */ #define CONCAT(a, b) _CONCAT_(a, b) #define _CONCAT_(a, b) a ## b /** Make single C token from 3 separate tokens */ #define CONCAT3(a, b, c) _CONCAT3_(a, b, c) #define _CONCAT3_(a, b, c) a ## b ## c /** Make single C token from 4 separate tokens */ #define CONCAT4(a, b, c, d) _CONCAT4_(a, b, c, d) #define _CONCAT4_(a, b, c, d) a ## b ## c ## d /** * @name Compiler attributes. */ /* Compiler detection for internal usage. */ #define _COMPILER_GNUC(maj,min) (defined(__GNUC__) && \ ((__GNUC__ > (maj)) || (__GNUC__ == (maj) && __GNUC_MINOR__ >= (min)))) #define _COMPILER_CLANG(maj,min) (defined(__clang__) && \ ((__clang_major__ > (maj)) || (__clang_major__ == (maj) && __clang_minor__ >= (min)))) #define _COMPILER_MSC(ver) (defined(_MSC_VER) && (_MSC_VER >= (ver))) #define _COMPILER_ICC(ver) (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= (ver))) /** Disable padding for structure */ #define _PACKED __attribute__((packed)) /* * Make sure __func__ works. */ #ifndef HAVE_FUNCNAME__FUNC #define __func__ __FUNCTION__ #endif /* * make compiler do something useful */ #ifndef _MUSTCHECK #if defined(__GNUC__) && (__GNUC__ >= 4) /** Show warning if function result is not used */ #define _MUSTCHECK __attribute__((warn_unused_result)) /** Show warning if used */ #define _DEPRECATED __attribute__((deprecated)) /** Check printf-style format and arg sanity */ #define _PRINTF(fmtpos, argpos) __attribute__((format(printf, fmtpos, argpos))) /** Function returns new pointer */ #define _MALLOC __attribute__((malloc)) /** Disable 'unused' warning for function/argument. */ #define _UNUSED __attribute__((unused)) /** Do not inline function. */ #define _NOINLINE __attribute__((noinline)) /** Indicates that function never returns */ #define _NORETURN __attribute__((noreturn)) /* compiler hints - those do not seem to work well */ #define unlikely(x) __builtin_expect(!!(x), 0) #define likely(x) __builtin_expect(!!(x), 1) #else /* non gcc */ #define _MUSTCHECK #define _DEPRECATED #define _PRINTF(x,y) #define _MALLOC #define _UNUSED #define _NOINLINE #define _NORETURN #define unlikely(x) x #define likely(x) x #endif #endif /* @} */ /** * Compile-time assert. * * Expression must be evaluatable at compile time. * If false, stop compilation with message. * * It can be used in either global or function scope. */ #ifndef static_assert #if _COMPILER_GNUC(4,6) || _COMPILER_CLANG(3,0) || _COMPILER_MSC(1600) /* Version for new compilers */ #define static_assert(expr, msg) _Static_assert(expr, msg) #else /* Version for old compilers */ #define static_assert(expr, msg) enum { CONCAT4(static_assert_failure_, __LINE__, _, __COUNTER__) = 1/(1 != (1 + (expr))) } #endif #endif /* !static_assert */ /** assert() that uses module */ #ifndef Assert #ifdef CASSERT void log_fatal(const char *file, int line, const char *func, bool show_perror, void *ctx, const char *s, ...) _PRINTF(6, 7); #define Assert(e) \ do { \ if (unlikely(!(e))) { \ log_fatal(__FILE__, __LINE__, __func__, false, NULL, \ "Assert(%s) failed", #e); \ abort(); \ } \ } while (0) #else #define Assert(e) #endif #endif /* Fix posix bug by accepting const pointer. */ static inline void _const_free(const void *p) { free((void *)p); } /** Compat: make free() accept const pointer */ #define free(x) _const_free(x) /** Zeroing malloc */ _MUSTCHECK static inline void *zmalloc(size_t len) { return calloc(1, len); } #ifndef HAVE_POSIX_MEMALIGN #define posix_memalign(a,b,c) usual_memalign(a,b,c) /** Compat: posix_memalign() */ int posix_memalign(void **ptr_p, size_t align, size_t len); #endif #endif pgbouncer-1.5.4/lib/usual/base.c0000644000175000017500000000272211665176410013415 00000000000000/* * Basic C environment. * * Copyright (c) 2007-2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #if defined(HAVE_MALLOC_H) && defined(__darwin__) #include #endif /* define posix_memalign() only when possible to emulate */ #if !defined(HAVE_POSIX_MEMALIGN) \ && (defined(HAVE_MEMALIGN) || defined(HAVE_VALLOC)) int posix_memalign(void **ptr_p, size_t align, size_t len) { void *p; int ret, old_errno = errno; #ifdef HAVE_MEMALIGN p = memalign(align, len); #else /* !HAVE_MEMALIGN */ #ifdef HAVE_VALLOC /* assuming less than pagesize alignment */ p = valloc(len); #endif /* !VALLOC */ #endif /* !MEMALIGN */ *ptr_p = p; if (p) return 0; /* on error restore old errno */ ret = errno; errno = old_errno; return ret; } #endif pgbouncer-1.5.4/lib/usual/netdb.c0000644000175000017500000001104611665176410013576 00000000000000/* * libusual - Utility library for C * * Copyright (c) 2010 Marko Kreen, Skype Technologies * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include /* is compat function needed? */ #ifndef HAVE_GETADDRINFO_A /* full compat if threads are available */ #ifdef HAVE_PTHREAD #include #include /* * Basic blocking lookup */ static void gaia_lookup(pthread_t origin, struct gaicb *list[], int nitems, struct sigevent *sevp) { struct gaicb *g; int i, res; for (i = 0; i < nitems; i++) { g = list[i]; res = getaddrinfo(g->ar_name, g->ar_service, g->ar_request, &g->ar_result); g->_state = res; } if (!sevp || sevp->sigev_notify == SIGEV_NONE) { /* do nothing */ } else if (sevp->sigev_notify == SIGEV_SIGNAL) { /* send signal */ pthread_kill(origin, sevp->sigev_signo); } else if (sevp->sigev_notify == SIGEV_THREAD) { /* call function */ sevp->sigev_notify_function(sevp->sigev_value); } } /* * Thread to run blocking lookup in */ struct GAIAContext { struct List req_list; pthread_cond_t cond; pthread_mutex_t lock; pthread_t thread; }; struct GAIARequest { struct List node; pthread_t origin; int nitems; struct sigevent sev; struct gaicb *list[FLEX_ARRAY]; }; #define RQ_SIZE(n) (offsetof(struct GAIARequest,list) + (n)*(sizeof(struct gaicb *))) static void gaia_lock_reqs(struct GAIAContext *ctx) { pthread_mutex_lock(&ctx->lock); } static void gaia_unlock_reqs(struct GAIAContext *ctx) { pthread_mutex_unlock(&ctx->lock); } static void *gaia_lookup_thread(void *arg) { struct GAIAContext *ctx = arg; struct GAIARequest *rq; struct List *el; gaia_lock_reqs(ctx); while (1) { el = list_pop(&ctx->req_list); if (!el) { pthread_cond_wait(&ctx->cond, &ctx->lock); continue; } gaia_unlock_reqs(ctx); rq = container_of(el, struct GAIARequest, node); gaia_lookup(rq->origin, rq->list, rq->nitems, &rq->sev); free(rq); gaia_lock_reqs(ctx); } return NULL; } /* * Functions run in user thread */ static int gaia_post_request(struct GAIAContext *ctx, struct gaicb *list[], int nitems, struct sigevent *sevp) { struct GAIARequest *rq; rq = malloc(RQ_SIZE(nitems)); if (!rq) return EAI_MEMORY; list_init(&rq->node); rq->origin = pthread_self(); rq->nitems = nitems; if (sevp) rq->sev = *sevp; else rq->sev.sigev_notify = SIGEV_NONE; memcpy(rq->list, list, sizeof(struct gaicb *)); gaia_lock_reqs(ctx); list_append(&ctx->req_list, &rq->node); gaia_unlock_reqs(ctx); pthread_cond_signal(&ctx->cond); return 0; } static struct GAIAContext *gaia_create_context(void) { struct GAIAContext *ctx; int err; ctx = malloc(sizeof(*ctx)); if (!ctx) return NULL; list_init(&ctx->req_list); err = pthread_cond_init(&ctx->cond, NULL); if (err) goto failed; err = pthread_mutex_init(&ctx->lock, NULL); if (err) goto failed; err = pthread_create(&ctx->thread, NULL, gaia_lookup_thread, ctx); if (err) goto failed; return ctx; failed: free(ctx); errno = err; return NULL; } /* * Final interface */ int getaddrinfo_a(int mode, struct gaicb *list[], int nitems, struct sigevent *sevp) { static struct GAIAContext *ctx; if (nitems <= 0) return 0; if (sevp && sevp->sigev_notify != SIGEV_NONE && sevp->sigev_notify != SIGEV_SIGNAL && sevp->sigev_notify != SIGEV_THREAD) goto einval; if (mode == GAI_WAIT) { gaia_lookup(pthread_self(), list, nitems, sevp); return 0; } else if (mode == GAI_NOWAIT) { if (!ctx) { ctx = gaia_create_context(); if (!ctx) return EAI_MEMORY; } return gaia_post_request(ctx, list, nitems, sevp); } einval: errno = EINVAL; return EAI_SYSTEM; } #else /* without threads not much to do */ int getaddrinfo_a(int mode, struct gaicb *list[], int nitems, struct sigevent *sevp) { errno = ENOSYS; return EAI_SYSTEM; } #endif /* !HAVE_PTHREAD_H */ #endif /* !HAVE_GETADDRINFO_A */ pgbouncer-1.5.4/lib/usual/strpool.h0000644000175000017500000000347411665176410014217 00000000000000/* * Pool for shared strings. * * Copyright (c) 2010 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Storage for shared strings. * * This provides refcounted searchable string pool for cases * where lot of objects reference same strings. */ #ifndef _USUAL_STRPOOL_H_ #define _USUAL_STRPOOL_H_ #include /** Handle for the pool */ struct StrPool; /** Pooled String */ struct PStr { /** Parent pool */ struct StrPool *pool; /** Reference count */ int refcnt; /** String length */ int len; /** Zero-terminated value */ char str[FLEX_ARRAY]; }; /** Create new pool */ struct StrPool *strpool_create(CxMem *ca); /** Release pool */ void strpool_free(struct StrPool *sp); /** Return either existing or new PStr for given value */ struct PStr *strpool_get(struct StrPool *sp, const char *str, int len); /** Increase reference count for existing PStr */ void strpool_incref(struct PStr *str); /** Decrease reference count for existing PStr */ void strpool_decref(struct PStr *str); /** Return count of strings in the pool */ int strpool_total(struct StrPool *sp); #endif pgbouncer-1.5.4/lib/usual/pthread.h0000644000175000017500000000343611665176410014142 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * * Pthreads compat for win32. */ #ifndef _USUAL_PTHREAD_H_ #define _USUAL_PTHREAD_H_ #include #ifdef HAVE_PTHREAD_H #include #else #ifdef WIN32 #define pthread_create(a,b,c,d) compat_pthread_create(a,b,c,d) #define pthread_mutex_init(a,b) compat_pthread_mutex_init(a,b) #define pthread_mutex_destroy(a) compat_pthread_mutex_destroy(a) #define pthread_mutex_lock(a) compat_pthread_mutex_lock(a) #define pthread_mutex_unlock(a) compat_pthread_mutex_unlock(a) #define pthread_join(a,b) compat_pthread_join(a,b) typedef HANDLE pthread_t; typedef HANDLE pthread_mutex_t; typedef int pthread_attr_t; int pthread_create(pthread_t *t, pthread_attr_t *attr, void *(*fn)(void *), void *arg); int pthread_mutex_init(pthread_mutex_t *lock, void *unused); int pthread_mutex_destroy(pthread_mutex_t *lock); int pthread_mutex_lock(pthread_mutex_t *lock); int pthread_mutex_unlock(pthread_mutex_t *lock); int pthread_join(pthread_t *t, void **ret); #endif /* WIN32 */ #endif /* HAVE_PTHREAD_H */ #endif pgbouncer-1.5.4/lib/usual/pgutil_kwlookup.h0000644000175000017500000005374311665176410015760 00000000000000/* ANSI-C code produced by gperf version 3.0.3 */ /* Command-line: gperf -m5 usual/pgutil_kwlookup.g */ /* Computed positions: -k'1-2,6,9,$' */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) /* The character set is not based on ISO-646. */ #error "gperf generated tables don't work with this execution character set. Please report a bug to ." #endif /* maximum key range = 296, duplicates = 0 */ #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static unsigned int pg_keyword_lookup_hash (register const char *str, register unsigned int len) { static const unsigned short asso_values[] = { 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 38, 125, 31, 64, 10, 96, 60, 125, 26, 7, 5, 13, 63, 10, 12, 70, 312, 5, 19, 3, 71, 131, 65, 50, 77, 3, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312 }; register int hval = len; switch (hval) { default: hval += asso_values[(unsigned char)str[8]]; /*FALLTHROUGH*/ case 8: case 7: case 6: hval += asso_values[(unsigned char)str[5]]; /*FALLTHROUGH*/ case 5: case 4: case 3: case 2: hval += asso_values[(unsigned char)str[1]]; /*FALLTHROUGH*/ case 1: hval += asso_values[(unsigned char)str[0]]; break; } return hval + asso_values[(unsigned char)str[len - 1]]; } #ifdef __GNUC__ __inline #ifdef __GNUC_STDC_INLINE__ __attribute__ ((__gnu_inline__)) #endif #endif const char * pg_keyword_lookup_real (register const char *str, register unsigned int len) { enum { TOTAL_KEYWORDS = 148, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 17, MIN_HASH_VALUE = 16, MAX_HASH_VALUE = 311 }; struct pgkw_t { char pgkw_str16[sizeof("treat")]; char pgkw_str22[sizeof("true")]; char pgkw_str24[sizeof("or")]; char pgkw_str27[sizeof("order")]; char pgkw_str28[sizeof("not")]; char pgkw_str29[sizeof("to")]; char pgkw_str30[sizeof("left")]; char pgkw_str31[sizeof("least")]; char pgkw_str32[sizeof("real")]; char pgkw_str33[sizeof("join")]; char pgkw_str34[sizeof("on")]; char pgkw_str36[sizeof("none")]; char pgkw_str37[sizeof("else")]; char pgkw_str39[sizeof("right")]; char pgkw_str41[sizeof("select")]; char pgkw_str42[sizeof("int")]; char pgkw_str43[sizeof("time")]; char pgkw_str44[sizeof("inout")]; char pgkw_str45[sizeof("some")]; char pgkw_str46[sizeof("inner")]; char pgkw_str47[sizeof("limit")]; char pgkw_str48[sizeof("in")]; char pgkw_str51[sizeof("nchar")]; char pgkw_str52[sizeof("into")]; char pgkw_str53[sizeof("like")]; char pgkw_str54[sizeof("ilike")]; char pgkw_str55[sizeof("notnull")]; char pgkw_str56[sizeof("table")]; char pgkw_str57[sizeof("localtime")]; char pgkw_str58[sizeof("integer")]; char pgkw_str60[sizeof("cross")]; char pgkw_str62[sizeof("create")]; char pgkw_str63[sizeof("collate")]; char pgkw_str64[sizeof("references")]; char pgkw_str66[sizeof("is")]; char pgkw_str67[sizeof("all")]; char pgkw_str68[sizeof("analyze")]; char pgkw_str69[sizeof("column")]; char pgkw_str70[sizeof("intersect")]; char pgkw_str71[sizeof("constraint")]; char pgkw_str72[sizeof("except")]; char pgkw_str73[sizeof("grant")]; char pgkw_str75[sizeof("trim")]; char pgkw_str76[sizeof("cast")]; char pgkw_str77[sizeof("isnull")]; char pgkw_str78[sizeof("as")]; char pgkw_str79[sizeof("national")]; char pgkw_str80[sizeof("coalesce")]; char pgkw_str83[sizeof("case")]; char pgkw_str84[sizeof("analyse")]; char pgkw_str85[sizeof("row")]; char pgkw_str86[sizeof("greatest")]; char pgkw_str87[sizeof("end")]; char pgkw_str88[sizeof("new")]; char pgkw_str89[sizeof("out")]; char pgkw_str90[sizeof("do")]; char pgkw_str91[sizeof("asc")]; char pgkw_str92[sizeof("old")]; char pgkw_str93[sizeof("outer")]; char pgkw_str95[sizeof("similar")]; char pgkw_str96[sizeof("union")]; char pgkw_str97[sizeof("default")]; char pgkw_str98[sizeof("null")]; char pgkw_str99[sizeof("user")]; char pgkw_str100[sizeof("leading")]; char pgkw_str101[sizeof("extract")]; char pgkw_str102[sizeof("trailing")]; char pgkw_str103[sizeof("only")]; char pgkw_str104[sizeof("exists")]; char pgkw_str106[sizeof("natural")]; char pgkw_str107[sizeof("unique")]; char pgkw_str108[sizeof("dec")]; char pgkw_str109[sizeof("desc")]; char pgkw_str111[sizeof("distinct")]; char pgkw_str112[sizeof("deferrable")]; char pgkw_str115[sizeof("and")]; char pgkw_str116[sizeof("for")]; char pgkw_str117[sizeof("float")]; char pgkw_str119[sizeof("smallint")]; char pgkw_str120[sizeof("offset")]; char pgkw_str122[sizeof("localtimestamp")]; char pgkw_str123[sizeof("precision")]; char pgkw_str125[sizeof("array")]; char pgkw_str126[sizeof("position")]; char pgkw_str127[sizeof("freeze")]; char pgkw_str128[sizeof("any")]; char pgkw_str129[sizeof("session_user")]; char pgkw_str130[sizeof("setof")]; char pgkw_str132[sizeof("decimal")]; char pgkw_str133[sizeof("xmlforest")]; char pgkw_str134[sizeof("asymmetric")]; char pgkw_str135[sizeof("xmlroot")]; char pgkw_str136[sizeof("xmlparse")]; char pgkw_str137[sizeof("current_time")]; char pgkw_str138[sizeof("xmlconcat")]; char pgkw_str139[sizeof("current_role")]; char pgkw_str140[sizeof("group")]; char pgkw_str142[sizeof("then")]; char pgkw_str144[sizeof("xmlpi")]; char pgkw_str145[sizeof("numeric")]; char pgkw_str146[sizeof("xmlelement")]; char pgkw_str147[sizeof("concurrently")]; char pgkw_str149[sizeof("false")]; char pgkw_str152[sizeof("over")]; char pgkw_str153[sizeof("xmlserialize")]; char pgkw_str154[sizeof("returning")]; char pgkw_str155[sizeof("using")]; char pgkw_str157[sizeof("bit")]; char pgkw_str160[sizeof("placing")]; char pgkw_str162[sizeof("between")]; char pgkw_str163[sizeof("bigint")]; char pgkw_str164[sizeof("primary")]; char pgkw_str165[sizeof("char")]; char pgkw_str166[sizeof("check")]; char pgkw_str168[sizeof("from")]; char pgkw_str170[sizeof("symmetric")]; char pgkw_str175[sizeof("authorization")]; char pgkw_str177[sizeof("verbose")]; char pgkw_str181[sizeof("timestamp")]; char pgkw_str183[sizeof("current_schema")]; char pgkw_str184[sizeof("full")]; char pgkw_str185[sizeof("foreign")]; char pgkw_str186[sizeof("xmlexists")]; char pgkw_str188[sizeof("interval")]; char pgkw_str192[sizeof("boolean")]; char pgkw_str198[sizeof("current_date")]; char pgkw_str200[sizeof("current_user")]; char pgkw_str202[sizeof("current_timestamp")]; char pgkw_str204[sizeof("when")]; char pgkw_str205[sizeof("where")]; char pgkw_str206[sizeof("character")]; char pgkw_str207[sizeof("off")]; char pgkw_str208[sizeof("overlaps")]; char pgkw_str213[sizeof("values")]; char pgkw_str218[sizeof("current_catalog")]; char pgkw_str219[sizeof("varchar")]; char pgkw_str220[sizeof("with")]; char pgkw_str224[sizeof("substring")]; char pgkw_str227[sizeof("window")]; char pgkw_str236[sizeof("fetch")]; char pgkw_str237[sizeof("initially")]; char pgkw_str265[sizeof("overlay")]; char pgkw_str266[sizeof("both")]; char pgkw_str272[sizeof("variadic")]; char pgkw_str273[sizeof("xmlattributes")]; char pgkw_str279[sizeof("nullif")]; char pgkw_str289[sizeof("having")]; char pgkw_str311[sizeof("binary")]; }; static const struct pgkw_t pgkw_contents = { "treat", "true", "or", "order", "not", "to", "left", "least", "real", "join", "on", "none", "else", "right", "select", "int", "time", "inout", "some", "inner", "limit", "in", "nchar", "into", "like", "ilike", "notnull", "table", "localtime", "integer", "cross", "create", "collate", "references", "is", "all", "analyze", "column", "intersect", "constraint", "except", "grant", "trim", "cast", "isnull", "as", "national", "coalesce", "case", "analyse", "row", "greatest", "end", "new", "out", "do", "asc", "old", "outer", "similar", "union", "default", "null", "user", "leading", "extract", "trailing", "only", "exists", "natural", "unique", "dec", "desc", "distinct", "deferrable", "and", "for", "float", "smallint", "offset", "localtimestamp", "precision", "array", "position", "freeze", "any", "session_user", "setof", "decimal", "xmlforest", "asymmetric", "xmlroot", "xmlparse", "current_time", "xmlconcat", "current_role", "group", "then", "xmlpi", "numeric", "xmlelement", "concurrently", "false", "over", "xmlserialize", "returning", "using", "bit", "placing", "between", "bigint", "primary", "char", "check", "from", "symmetric", "authorization", "verbose", "timestamp", "current_schema", "full", "foreign", "xmlexists", "interval", "boolean", "current_date", "current_user", "current_timestamp", "when", "where", "character", "off", "overlaps", "values", "current_catalog", "varchar", "with", "substring", "window", "fetch", "initially", "overlay", "both", "variadic", "xmlattributes", "nullif", "having", "binary" }; #define pgkw ((const char *) &pgkw_contents) static const int wordlist[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str16, -1, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str22, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str24, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str27, (int)(long)&((struct pgkw_t *)0)->pgkw_str28, (int)(long)&((struct pgkw_t *)0)->pgkw_str29, (int)(long)&((struct pgkw_t *)0)->pgkw_str30, (int)(long)&((struct pgkw_t *)0)->pgkw_str31, (int)(long)&((struct pgkw_t *)0)->pgkw_str32, (int)(long)&((struct pgkw_t *)0)->pgkw_str33, (int)(long)&((struct pgkw_t *)0)->pgkw_str34, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str36, (int)(long)&((struct pgkw_t *)0)->pgkw_str37, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str39, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str41, (int)(long)&((struct pgkw_t *)0)->pgkw_str42, (int)(long)&((struct pgkw_t *)0)->pgkw_str43, (int)(long)&((struct pgkw_t *)0)->pgkw_str44, (int)(long)&((struct pgkw_t *)0)->pgkw_str45, (int)(long)&((struct pgkw_t *)0)->pgkw_str46, (int)(long)&((struct pgkw_t *)0)->pgkw_str47, (int)(long)&((struct pgkw_t *)0)->pgkw_str48, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str51, (int)(long)&((struct pgkw_t *)0)->pgkw_str52, (int)(long)&((struct pgkw_t *)0)->pgkw_str53, (int)(long)&((struct pgkw_t *)0)->pgkw_str54, (int)(long)&((struct pgkw_t *)0)->pgkw_str55, (int)(long)&((struct pgkw_t *)0)->pgkw_str56, (int)(long)&((struct pgkw_t *)0)->pgkw_str57, (int)(long)&((struct pgkw_t *)0)->pgkw_str58, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str60, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str62, (int)(long)&((struct pgkw_t *)0)->pgkw_str63, (int)(long)&((struct pgkw_t *)0)->pgkw_str64, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str66, (int)(long)&((struct pgkw_t *)0)->pgkw_str67, (int)(long)&((struct pgkw_t *)0)->pgkw_str68, (int)(long)&((struct pgkw_t *)0)->pgkw_str69, (int)(long)&((struct pgkw_t *)0)->pgkw_str70, (int)(long)&((struct pgkw_t *)0)->pgkw_str71, (int)(long)&((struct pgkw_t *)0)->pgkw_str72, (int)(long)&((struct pgkw_t *)0)->pgkw_str73, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str75, (int)(long)&((struct pgkw_t *)0)->pgkw_str76, (int)(long)&((struct pgkw_t *)0)->pgkw_str77, (int)(long)&((struct pgkw_t *)0)->pgkw_str78, (int)(long)&((struct pgkw_t *)0)->pgkw_str79, (int)(long)&((struct pgkw_t *)0)->pgkw_str80, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str83, (int)(long)&((struct pgkw_t *)0)->pgkw_str84, (int)(long)&((struct pgkw_t *)0)->pgkw_str85, (int)(long)&((struct pgkw_t *)0)->pgkw_str86, (int)(long)&((struct pgkw_t *)0)->pgkw_str87, (int)(long)&((struct pgkw_t *)0)->pgkw_str88, (int)(long)&((struct pgkw_t *)0)->pgkw_str89, (int)(long)&((struct pgkw_t *)0)->pgkw_str90, (int)(long)&((struct pgkw_t *)0)->pgkw_str91, (int)(long)&((struct pgkw_t *)0)->pgkw_str92, (int)(long)&((struct pgkw_t *)0)->pgkw_str93, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str95, (int)(long)&((struct pgkw_t *)0)->pgkw_str96, (int)(long)&((struct pgkw_t *)0)->pgkw_str97, (int)(long)&((struct pgkw_t *)0)->pgkw_str98, (int)(long)&((struct pgkw_t *)0)->pgkw_str99, (int)(long)&((struct pgkw_t *)0)->pgkw_str100, (int)(long)&((struct pgkw_t *)0)->pgkw_str101, (int)(long)&((struct pgkw_t *)0)->pgkw_str102, (int)(long)&((struct pgkw_t *)0)->pgkw_str103, (int)(long)&((struct pgkw_t *)0)->pgkw_str104, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str106, (int)(long)&((struct pgkw_t *)0)->pgkw_str107, (int)(long)&((struct pgkw_t *)0)->pgkw_str108, (int)(long)&((struct pgkw_t *)0)->pgkw_str109, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str111, (int)(long)&((struct pgkw_t *)0)->pgkw_str112, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str115, (int)(long)&((struct pgkw_t *)0)->pgkw_str116, (int)(long)&((struct pgkw_t *)0)->pgkw_str117, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str119, (int)(long)&((struct pgkw_t *)0)->pgkw_str120, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str122, (int)(long)&((struct pgkw_t *)0)->pgkw_str123, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str125, (int)(long)&((struct pgkw_t *)0)->pgkw_str126, (int)(long)&((struct pgkw_t *)0)->pgkw_str127, (int)(long)&((struct pgkw_t *)0)->pgkw_str128, (int)(long)&((struct pgkw_t *)0)->pgkw_str129, (int)(long)&((struct pgkw_t *)0)->pgkw_str130, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str132, (int)(long)&((struct pgkw_t *)0)->pgkw_str133, (int)(long)&((struct pgkw_t *)0)->pgkw_str134, (int)(long)&((struct pgkw_t *)0)->pgkw_str135, (int)(long)&((struct pgkw_t *)0)->pgkw_str136, (int)(long)&((struct pgkw_t *)0)->pgkw_str137, (int)(long)&((struct pgkw_t *)0)->pgkw_str138, (int)(long)&((struct pgkw_t *)0)->pgkw_str139, (int)(long)&((struct pgkw_t *)0)->pgkw_str140, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str142, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str144, (int)(long)&((struct pgkw_t *)0)->pgkw_str145, (int)(long)&((struct pgkw_t *)0)->pgkw_str146, (int)(long)&((struct pgkw_t *)0)->pgkw_str147, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str149, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str152, (int)(long)&((struct pgkw_t *)0)->pgkw_str153, (int)(long)&((struct pgkw_t *)0)->pgkw_str154, (int)(long)&((struct pgkw_t *)0)->pgkw_str155, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str157, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str160, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str162, (int)(long)&((struct pgkw_t *)0)->pgkw_str163, (int)(long)&((struct pgkw_t *)0)->pgkw_str164, (int)(long)&((struct pgkw_t *)0)->pgkw_str165, (int)(long)&((struct pgkw_t *)0)->pgkw_str166, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str168, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str170, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str175, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str177, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str181, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str183, (int)(long)&((struct pgkw_t *)0)->pgkw_str184, (int)(long)&((struct pgkw_t *)0)->pgkw_str185, (int)(long)&((struct pgkw_t *)0)->pgkw_str186, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str188, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str192, -1, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str198, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str200, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str202, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str204, (int)(long)&((struct pgkw_t *)0)->pgkw_str205, (int)(long)&((struct pgkw_t *)0)->pgkw_str206, (int)(long)&((struct pgkw_t *)0)->pgkw_str207, (int)(long)&((struct pgkw_t *)0)->pgkw_str208, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str213, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str218, (int)(long)&((struct pgkw_t *)0)->pgkw_str219, (int)(long)&((struct pgkw_t *)0)->pgkw_str220, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str224, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str227, -1, -1, -1, -1, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str236, (int)(long)&((struct pgkw_t *)0)->pgkw_str237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str265, (int)(long)&((struct pgkw_t *)0)->pgkw_str266, -1, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str272, (int)(long)&((struct pgkw_t *)0)->pgkw_str273, -1, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str279, -1, -1, -1, -1, -1, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str289, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, (int)(long)&((struct pgkw_t *)0)->pgkw_str311 }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { register int key = pg_keyword_lookup_hash (str, len); if (key <= MAX_HASH_VALUE && key >= 0) { register int o = wordlist[key]; if (o >= 0) { register const char *s = o + pgkw; if (*str == *s && !strcmp (str + 1, s + 1)) return s; } } } return 0; } pgbouncer-1.5.4/lib/usual/mbuf.h0000644000175000017500000001726511776051564013456 00000000000000 /** \file * Safe and easy access to memory buffer. */ #ifndef _USUAL_MBUF_H_ #define _USUAL_MBUF_H_ #include #include /** MBuf structure. Allocated by user, can be in stack. */ struct MBuf { uint8_t *data; unsigned read_pos; unsigned write_pos; unsigned alloc_len; bool reader; bool fixed; }; /** Format fragment for *printf() */ #define MBUF_FMT ".*s" /** Argument layout for *printf() */ #define MBUF_ARG(m) ((m) ? mbuf_written(m) : 6), ((m) ? (const char *)mbuf_data(m) : "(null)") /* * Init functions */ /** Initialize R/O buffer to fixed memory area. */ static inline void mbuf_init_fixed_reader(struct MBuf *buf, const void *ptr, unsigned len) { buf->data = (uint8_t *)ptr; buf->read_pos = 0; buf->write_pos = len; buf->alloc_len = len; buf->reader = true; buf->fixed = true; } /** Initialize R/W buffer to fixed memory area. */ static inline void mbuf_init_fixed_writer(struct MBuf *buf, void *ptr, unsigned len) { buf->data = (uint8_t *)ptr; buf->read_pos = 0; buf->write_pos = 0; buf->alloc_len = len; buf->reader = false; buf->fixed = true; } /** Initialize R/W buffer to dynamically allocated memory area. */ static inline void mbuf_init_dynamic(struct MBuf *buf) { buf->data = NULL; buf->read_pos = 0; buf->write_pos = 0; buf->alloc_len = 0; buf->reader = false; buf->fixed = false; } /** Free dynamically allocated area, if exists. */ static inline void mbuf_free(struct MBuf *buf) { if (buf->data) { if (!buf->fixed) free(buf->data); memset(buf, 0, sizeof(*buf)); } } /* * Reset functions. */ /** Move read cursor to start of buffer. */ static inline void mbuf_rewind_reader(struct MBuf *buf) { buf->read_pos = 0; } /** Move both read and write cursor to start of buffer. */ static inline void mbuf_rewind_writer(struct MBuf *buf) { if (!buf->reader) { buf->read_pos = 0; buf->write_pos = 0; } } /* * Info functions. */ /** How many bytes can be read with read cursor. */ static inline unsigned mbuf_avail_for_read(const struct MBuf *buf) { return buf->write_pos - buf->read_pos; } /** How many bytes can be written with write cursor, without realloc. */ static inline unsigned mbuf_avail_for_write(const struct MBuf *buf) { if (!buf->reader && buf->alloc_len > buf->write_pos) return buf->alloc_len - buf->write_pos; return 0; } /** How many data bytes are in buffer. */ static inline unsigned mbuf_written(const struct MBuf *buf) { return buf->write_pos; } /** How many bytes have been read from buffer */ static inline unsigned mbuf_consumed(const struct MBuf *buf) { return buf->read_pos; } /** Return pointer to data area. */ static inline const void *mbuf_data(const struct MBuf *buf) { return buf->data; } /** Do the mbufs contain same data. */ static inline bool mbuf_eq(const struct MBuf *buf1, const struct MBuf *buf2) { if (buf1 == buf2) return true; if (!buf1 || !buf2 || (mbuf_written(buf1) != mbuf_written(buf2))) return false; return memcmp(mbuf_data(buf1), mbuf_data(buf2), mbuf_written(buf1)) == 0; } /** Complare mbuf to asciiz string */ static inline bool mbuf_eq_str(const struct MBuf *buf1, const char *s) { struct MBuf tmp; mbuf_init_fixed_reader(&tmp, s, strlen(s)); return mbuf_eq(buf1, &tmp); } /* * Read functions. */ /** Read a byte from read cursor. */ _MUSTCHECK static inline bool mbuf_get_byte(struct MBuf *buf, uint8_t *dst_p) { if (buf->read_pos + 1 > buf->write_pos) return false; *dst_p = buf->data[buf->read_pos++]; return true; } /** Read big-endian uint16 from read cursor. */ _MUSTCHECK static inline bool mbuf_get_char(struct MBuf *buf, char *dst_p) { if (buf->read_pos + 1 > buf->write_pos) return false; *dst_p = buf->data[buf->read_pos++]; return true; } _MUSTCHECK static inline bool mbuf_get_uint16be(struct MBuf *buf, uint16_t *dst_p) { unsigned a, b; if (buf->read_pos + 2 > buf->write_pos) return false; a = buf->data[buf->read_pos++]; b = buf->data[buf->read_pos++]; *dst_p = (a << 8) | b; return true; } /** Read big-endian uint32 from read cursor. */ _MUSTCHECK static inline bool mbuf_get_uint32be(struct MBuf *buf, uint32_t *dst_p) { unsigned a, b, c, d; if (buf->read_pos + 4 > buf->write_pos) return false; a = buf->data[buf->read_pos++]; b = buf->data[buf->read_pos++]; c = buf->data[buf->read_pos++]; d = buf->data[buf->read_pos++]; *dst_p = (a << 24) | (b << 16) | (c << 8) | d; return true; } /** Get reference to len bytes from read cursor. */ _MUSTCHECK static inline bool mbuf_get_uint64be(struct MBuf *buf, uint64_t *dst_p) { uint32_t a, b; if (!mbuf_get_uint32be(buf, &a) || !mbuf_get_uint32be(buf, &b)) return false; *dst_p = ((uint64_t)a << 32) | b; return true; } _MUSTCHECK static inline bool mbuf_get_bytes(struct MBuf *buf, unsigned len, const uint8_t **dst_p) { if (buf->read_pos + len > buf->write_pos) return false; *dst_p = buf->data + buf->read_pos; buf->read_pos += len; return true; } /** Get reference to asciiz string from read cursor. */ _MUSTCHECK static inline bool mbuf_get_chars(struct MBuf *buf, unsigned len, const char **dst_p) { if (buf->read_pos + len > buf->write_pos) return false; *dst_p = (char *)buf->data + buf->read_pos; buf->read_pos += len; return true; } _MUSTCHECK static inline bool mbuf_get_string(struct MBuf *buf, const char **dst_p) { const char *res = (char *)buf->data + buf->read_pos; const uint8_t *nul = memchr(res, 0, mbuf_avail_for_read(buf)); if (!nul) return false; *dst_p = res; buf->read_pos = nul + 1 - buf->data; return true; } /* * Write functions. */ /** Allocate more room if needed and the mbuf allows. */ _MUSTCHECK bool mbuf_make_room(struct MBuf *buf, unsigned len); /** Write a byte to write cursor. */ _MUSTCHECK static inline bool mbuf_write_byte(struct MBuf *buf, uint8_t val) { if (buf->write_pos + 1 > buf->alloc_len && !mbuf_make_room(buf, 1)) return false; buf->data[buf->write_pos++] = val; return true; } /** Write len bytes to write cursor. */ _MUSTCHECK static inline bool mbuf_write(struct MBuf *buf, const void *ptr, unsigned len) { if (buf->write_pos + len > buf->alloc_len && !mbuf_make_room(buf, len)) return false; memcpy(buf->data + buf->write_pos, ptr, len); buf->write_pos += len; return true; } /** writes full contents of another mbuf, without touching it */ _MUSTCHECK static inline bool mbuf_write_raw_mbuf(struct MBuf *dst, struct MBuf *src) { return mbuf_write(dst, src->data, src->write_pos); } /** writes partial contents of another mbuf, with touching it */ _MUSTCHECK static inline bool mbuf_write_mbuf(struct MBuf *dst, struct MBuf *src, unsigned len) { const uint8_t *data; if (!mbuf_get_bytes(src, len, &data)) return false; if (!mbuf_write(dst, data, len)) { src->read_pos -= len; return false; } return true; } /** Fiil mbuf with byte value */ _MUSTCHECK static inline bool mbuf_fill(struct MBuf *buf, uint8_t byte, unsigned len) { if (buf->write_pos + len > buf->alloc_len && !mbuf_make_room(buf, len)) return false; memset(buf->data + buf->write_pos, byte, len); buf->write_pos += len; return true; } /** remove some data from mbuf */ _MUSTCHECK static inline bool mbuf_cut(struct MBuf *buf, unsigned ofs, unsigned len) { if (buf->reader) return false; if (ofs + len < buf->write_pos) { unsigned endofs = ofs + len; memmove(buf->data + ofs, buf->data + endofs, buf->write_pos - endofs); buf->write_pos -= len; } else if (ofs < buf->write_pos) { buf->write_pos = ofs; } return true; } static inline void mbuf_copy(const struct MBuf *src, struct MBuf *dst) { *dst = *src; } _MUSTCHECK static inline bool mbuf_slice(struct MBuf *src, unsigned len, struct MBuf *dst) { if (len > mbuf_avail_for_read(src)) return false; mbuf_init_fixed_reader(dst, src->data + src->read_pos, len); src->read_pos += len; return true; } #endif pgbouncer-1.5.4/lib/usual/logging.c0000644000175000017500000001457611665176410014143 00000000000000/* * Logging for unix service. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #ifdef HAVE_SYSLOG_H #include #endif #ifdef WIN32 #define LOG_EMERG 0 #define LOG_ALERT 1 #define LOG_CRIT 2 #define LOG_ERR 3 #define LOG_WARNING 4 #define LOG_NOTICE 5 #define LOG_INFO 6 #define LOG_DEBUG 7 #define LOG_PID 0 #define LOG_DAEMON 0 #define openlog(a,b,c) #define syslog win32_eventlog #define closelog() static void win32_eventlog(int level, const char *fmt, ...); #endif int cf_quiet = 0; int cf_verbose = 0; const char *cf_logfile = NULL; int cf_syslog = 0; const char *cf_syslog_ident = NULL; const char *cf_syslog_facility = NULL; enum LogLevel cf_syslog_level = LG_INFO; enum LogLevel cf_logfile_level = LG_NOISE; enum LogLevel cf_stderr_level = LG_NOISE; /* optional function to fill prefix */ logging_prefix_fn_t logging_prefix_cb; static FILE *log_file = NULL; static bool syslog_started = false; struct LevelInfo { const char *tag; int syslog_prio; }; static const struct LevelInfo log_level_list[] = { { "FATAL", LOG_CRIT }, /* LG_FATAL */ { "ERROR", LOG_ERR }, /* LG_ERROR */ { "WARNING", LOG_WARNING },/* LG_WARNING */ { "LOG", LOG_INFO }, /* LG_STATS*/ { "LOG", LOG_INFO }, /* LG_INFO */ { "DEBUG", LOG_DEBUG }, /* LG_DEBUG */ { "NOISE", LOG_DEBUG }, /* LG_NOISE */ }; struct FacName { const char *name; int code; }; static const struct FacName facility_names [] = { #ifndef WIN32 { "auth", LOG_AUTH }, #ifdef LOG_AUTHPRIV { "authpriv", LOG_AUTHPRIV }, #endif { "daemon", LOG_DAEMON }, { "user", LOG_USER }, { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, #endif { NULL }, }; void reset_logging(void) { if (log_file) { fclose(log_file); log_file = NULL; } if (syslog_started) { closelog(); syslog_started = 0; } } static void start_syslog(void) { const struct FacName *f; int fac = LOG_DAEMON; const char *ident = cf_syslog_ident; if (!cf_syslog) return; if (cf_syslog_facility) { for (f = facility_names; f->name; f++) { if (strcmp(f->name, cf_syslog_facility) == 0) { fac = f->code; break; } } } if (!ident) { ident = getprogname(); if (!ident) ident = "unnamed"; } openlog(ident, LOG_PID, fac); syslog_started = 1; } void log_generic(enum LogLevel level, void *ctx, const char *fmt, ...) { char buf[2048], buf2[2048]; char ebuf[256]; char timebuf[64]; const struct LevelInfo *lev = &log_level_list[level]; unsigned pid = getpid(); va_list ap; int pfxlen = 0; int old_errno = errno; char *msg = buf; if (logging_prefix_cb) { pfxlen = logging_prefix_cb(level, ctx, buf, sizeof(buf)); if (pfxlen < 0) goto done; if (pfxlen >= (int)sizeof(buf)) pfxlen = sizeof(buf) - 1; } va_start(ap, fmt); vsnprintf(buf + pfxlen, sizeof(buf) - pfxlen, fmt, ap); va_end(ap); /* replace '\n' in message with '\n\t', strip trailing whitespace */ if (strchr(msg, '\n')) { char *dst = buf2, *end = buf2 + sizeof(buf2) - 2; for (; *msg && dst < end; msg++) { *dst++ = *msg; if (*msg == '\n') *dst++ = '\t'; } while (dst > buf2 && isspace(dst[-1])) dst--; *dst = 0; msg = buf2; } format_time_ms(0, timebuf, sizeof(timebuf)); if (!log_file && cf_logfile && cf_logfile[0]) { log_file = fopen(cf_logfile, "a"); if (log_file) { /* Got the file, disable buffering */ setvbuf(log_file, NULL, _IONBF, 0); } else { /* Unable to open, complain and fail */ fprintf(stderr, "%s %u %s Cannot open logfile: '%s': %s\n", timebuf, pid, log_level_list[0].tag, cf_logfile, strerror_r(errno, ebuf, sizeof(ebuf))); exit(1); } } if (!cf_quiet && level <= cf_stderr_level) fprintf(stderr, "%s %u %s %s\n", timebuf, pid, lev->tag, msg); if (log_file && level <= cf_logfile_level) fprintf(log_file, "%s %u %s %s\n", timebuf, pid, lev->tag, msg); if (cf_syslog && level <= cf_syslog_level) { if (!syslog_started) start_syslog(); syslog(lev->syslog_prio, "%s", msg); } done: if (old_errno != errno) errno = old_errno; } void log_fatal(const char *file, int line, const char *func, bool show_perror, void *ctx, const char *fmt, ...) { char buf[2048], ebuf[256]; const char *estr = NULL; int old_errno = 0; va_list ap; if (show_perror) { old_errno = errno; estr = strerror_r(errno, ebuf, sizeof(ebuf)); } va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (show_perror) { log_generic(LG_FATAL, ctx, "@%s:%d in function %s(): %s: %s [%d]", file, line, func, buf, estr, old_errno); } else { log_generic(LG_FATAL, ctx, "@%s:%d in function %s(): %s", file, line, func, buf); } } #ifdef WIN32 static void win32_eventlog(int level, const char *fmt, ...) { static HANDLE evtHandle = INVALID_HANDLE_VALUE; int elevel; char buf[1024]; const char *strlist[1] = { buf }; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); switch (level) { case LOG_CRIT: case LOG_ERR: elevel = EVENTLOG_ERROR_TYPE; break; case LOG_WARNING: elevel = EVENTLOG_WARNING_TYPE; break; default: elevel = EVENTLOG_INFORMATION_TYPE; } if (evtHandle == INVALID_HANDLE_VALUE) { evtHandle = RegisterEventSource(NULL, cf_syslog_ident); if (evtHandle == NULL || evtHandle == INVALID_HANDLE_VALUE) { evtHandle = INVALID_HANDLE_VALUE; return; } } ReportEvent(evtHandle, elevel, 0, 0, NULL, 1, 0, strlist, NULL); } #endif pgbouncer-1.5.4/lib/usual/event.c0000644000175000017500000004074311665176410013631 00000000000000/* * event.c - libevent compatible event loop. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Small poll()-based async event loop, API-compatible with libevent. * * For sitations where full libevent is not necessary. */ #include #ifndef HAVE_LIBEVENT #include #include #include #include #include #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif /* max number of signals we care about */ #define MAX_SIGNAL 32 /* if tv_sec is larger, it's absolute timeout */ #define MAX_REL_TIMEOUT (30*24*60*60) /* if no nearby timeouts, max time to sleep (usecs) */ #define MAX_SLEEP (5*USEC) /* extra event flag to track if event is added */ #define EV_ACTIVE 0x80 struct event_base { /* pending timeouts */ struct Heap *timeout_heap; /* fd events */ struct StatList fd_list; /* pollfd <-> event mapping */ struct event **pfd_event; struct pollfd *pfd_list; int pfd_size; /* signal handling */ struct List sig_node; unsigned int sig_seen[MAX_SIGNAL]; struct List sig_waiters[MAX_SIGNAL]; int sig_send, sig_recv; struct event sig_ev; /* exit loop ASAP */ bool loop_break; /* finish current loop and exit */ bool loop_exit; /* cache if refreshed after each poll() */ usec_t cached_time; }; /* default event base */ static struct event_base *current_base; /* global signal data */ static volatile unsigned int sig_count[MAX_SIGNAL]; static bool signal_set_up[MAX_SIGNAL]; static struct sigaction old_handler[MAX_SIGNAL]; static LIST(sig_base_list); /* internal signal functions */ static bool sig_init(struct event_base *base, int sig); static void sig_close(struct event_base *base); /* * Debugging. */ #ifdef CASSERT #include #include #include #include static void base_dbg(struct event_base *base, const char *s, ...) { va_list ap; char buf[1024]; va_start(ap, s); vsnprintf(buf, sizeof(buf), s, ap); va_end(ap); log_noise("event base=%p: fdlist=%u timeouts=%d pfds=%d: %s", base, statlist_count(&base->fd_list), heap_size(base->timeout_heap), base->pfd_size, buf); } static void ev_dbg(struct event *ev, const char *s, ...) { va_list ap; char buf[1024], tval[128]; const char *typ = (ev->flags & EV_SIGNAL) ? "sig" : "fd"; va_start(ap, s); vsnprintf(buf, sizeof(buf), s, ap); va_end(ap); log_noise("event %s %d (flags=%s%s%s%s%s) [%s]: %s", typ, ev->fd, (ev->flags & EV_ACTIVE) ? "A" : "", (ev->flags & EV_PERSIST) ? "P" : "", (ev->flags & EV_TIMEOUT) ? "T" : "", (ev->flags & EV_READ) ? "R" : "", (ev->flags & EV_WRITE) ? "W" : "", (ev->flags & EV_TIMEOUT) ? format_time_ms(ev->timeout_val, tval, sizeof(tval)) : "-", buf); } #else #define base_dbg(b, ...) #define ev_dbg(b, ...) #endif /* * Helper functions. */ /* per-base time cache */ static usec_t get_base_time(struct event_base *base) { if (!base->cached_time) base->cached_time = get_time_usec(); return base->cached_time; } /* reset cached time */ static void reset_base_time(struct event_base *base) { base->cached_time = 0; } /* convert user tv to absolute tv */ static usec_t convert_timeout(struct event_base *base, struct timeval *tv) { usec_t val = tv->tv_sec * USEC + tv->tv_usec; if (tv->tv_sec < MAX_REL_TIMEOUT) val += get_base_time(base); return val; } static bool ev_is_better(const void *a, const void *b) { const struct event *ev1 = a, *ev2 = b; return ev1->timeout_val < ev2->timeout_val; } static void ev_save_pos(void *obj, unsigned pos) { struct event *ev = obj; ev->timeout_idx = pos; } /* enlarge pollfd array if needed */ static bool make_room(struct event_base *base, int need) { int total; void *tmp1; void *tmp2; if (need < base->pfd_size) return true; total = base->pfd_size * 2; if (total < 8) total = 8; while (total < need) total *= 2; tmp1 = realloc(base->pfd_list, total * sizeof(struct pollfd)); if (!tmp1) return false; base->pfd_list = tmp1; tmp2 = realloc(base->pfd_event, total * sizeof(struct event *)); if (!tmp2) return false; base->pfd_event = tmp2; base->pfd_size = total; return true; } /* * Single base functions. */ struct event_base *event_init(void) { struct event_base *base = event_base_new(); if (!current_base) current_base = base; return base; } int event_loop(int loop_flags) { return event_base_loop(current_base, loop_flags); } int event_loopbreak(void) { return event_base_loopbreak(current_base); } void event_set(struct event *ev, int fd, short flags, uevent_cb_f cb, void *arg) { event_assign(ev, current_base, fd, flags, cb, arg); } int event_once(int fd, short flags, uevent_cb_f cb_func, void *cb_arg, struct timeval *timeout) { return event_base_once(current_base, fd, flags, cb_func, cb_arg, timeout); } int event_loopexit(struct timeval *timeout) { return event_base_loopexit(current_base, timeout); } /* * Event base initialization. */ struct event_base *event_base_new(void) { struct event_base *base; int i; base = calloc(1, sizeof(*base)); if (!base) return NULL; /* initialize timeout and fd areas */ base->timeout_heap = heap_create(ev_is_better, ev_save_pos, USUAL_ALLOC); if (!base->timeout_heap) { free(base); return NULL; } statlist_init(&base->fd_list, "fd_list"); /* initialize signal areas */ for (i = 0; i < MAX_SIGNAL; i++) list_init(&base->sig_waiters[i]); list_init(&base->sig_node); base->sig_send = base->sig_recv = -1; /* allocate pollfds */ if (!make_room(base, 8)) { event_base_free(base); return NULL; } return base; } void event_base_free(struct event_base *base) { if (!base) { if (!current_base) return; base = current_base; } if (base == current_base) current_base = NULL; heap_destroy(base->timeout_heap); free(base->pfd_event); free(base->pfd_list); sig_close(base); free(base); } /* set flag to exit loop ASAP */ int event_base_loopbreak(struct event_base *base) { base->loop_break = true; return 0; } /* * Multi-base functions. */ /* fill event structure */ void event_assign(struct event *ev, struct event_base *base, int fd, short flags, uevent_cb_f cb, void *arg) { Assert(base); Assert((ev->flags & EV_ACTIVE) == 0); if (base == NULL) base = current_base; ev->fd = fd; ev->base = base; ev->flags = flags; ev->cb_func = cb; ev->cb_arg = arg; ev->ev_idx = -1; list_init(&ev->node); ev_dbg(ev, "event_set"); } /* Change base for a event */ int event_base_set(struct event_base *base, struct event *ev) { if (ev->flags & EV_ACTIVE) { errno = EINVAL; return -1; } ev->base = base; return 0; } /* Check if activated */ int is_event_active(struct event *ev) { return (ev->flags & EV_ACTIVE) ? 1 : 0; } /* de-activate event */ int event_del(struct event *ev) { struct event_base *base = ev->base; /* allow repeated deletions */ if ((ev->flags & EV_ACTIVE) == 0) { ev_dbg(ev, "event_del for inactive event??"); return 0; } ev_dbg(ev, "event_del"); /* remove from fd/signal list */ if (ev->flags & EV_SIGNAL) list_del(&ev->node); else if (ev->flags & (EV_READ | EV_WRITE)) statlist_remove(&base->fd_list, &ev->node); /* remove from timeout tree */ if (ev->flags & EV_TIMEOUT) { heap_remove(ev->base->timeout_heap, ev->timeout_idx); ev->flags &= ~EV_TIMEOUT; } /* clear reference to pollfd area */ if (ev->ev_idx >= 0) { ev->base->pfd_event[ev->ev_idx] = NULL; ev->ev_idx = -1; } /* tag inactive */ ev->flags &= ~EV_ACTIVE; return 0; } /* activate event */ int event_add(struct event *ev, struct timeval *timeout) { struct event_base *base = ev->base; Assert((ev->flags & EV_ACTIVE) == 0); Assert(base); /* sanity check, but dont do anything yet */ if (timeout) { if (ev->flags & EV_PERSIST) goto err_inval; if (!heap_reserve(base->timeout_heap, 1)) return -1; } else { if (ev->flags & EV_TIMEOUT) ev->flags &= ~EV_TIMEOUT; if (!(ev->flags & (EV_SIGNAL | EV_READ | EV_WRITE))) goto err_inval; } /* setup signal/fd */ if (ev->flags & EV_SIGNAL) { if (ev->flags & (EV_READ|EV_WRITE)) goto err_inval; if (!sig_init(base, ev->fd)) return -1; list_append(&base->sig_waiters[ev->fd], &ev->node); } else if (ev->flags & (EV_READ|EV_WRITE)) { statlist_append(&base->fd_list, &ev->node); } /* now act on timeout */ if (timeout) { ev->timeout_val = convert_timeout(base, timeout); ev->flags |= EV_TIMEOUT; heap_push(base->timeout_heap, ev); } ev->ev_idx = -1; ev->flags |= EV_ACTIVE; ev_dbg(ev, "event_add"); return 0; err_inval: errno = EINVAL; return -1; } /* * Event loop functions. */ static void deliver_event(struct event *ev, short flags) { ev_dbg(ev, "deliver_event: %d", flags); /* remove non-persitant event before calling user func */ if ((ev->flags & EV_PERSIST) == 0) event_del(ev); /* now call user func */ ev->cb_func(ev->fd, flags, ev->cb_arg); } static inline struct event *get_smallest_timeout(struct event_base *base) { return heap_top(base->timeout_heap); } /* decide how long poll() should sleep */ static int calc_timeout_ms(struct event_base *base) { struct event *ev; usec_t now; usec_t res; ev = get_smallest_timeout(base); if (!ev) return MAX_SLEEP / 1000; now = get_base_time(base); if (now + MAX_SLEEP < ev->timeout_val) res = MAX_SLEEP; else if (ev->timeout_val < now) res = 0; else res = ev->timeout_val - now; /* round up */ return (res + 999) / 1000; } /* deliver fd events */ static void process_fds(struct event_base *base, int pf_cnt) { int i; for (i = 0; i < pf_cnt; i++) { struct pollfd *pf = &base->pfd_list[i]; struct event *ev = base->pfd_event[i]; if (!ev) continue; base->pfd_event[i] = NULL; ev->ev_idx = -1; if (pf->revents & (POLLIN | POLLOUT | POLLERR | POLLHUP)) { int flags = ev->flags & (EV_READ | EV_WRITE); deliver_event(ev, flags); } if (base->loop_break) break; } } /* handle passed timeouts */ static void process_timeouts(struct event_base *base) { usec_t now; struct event *ev; ev = get_smallest_timeout(base); if (!ev) return; now = get_base_time(base); while (ev) { if (now < ev->timeout_val) break; deliver_event(ev, EV_TIMEOUT); if (base->loop_break) break; ev = get_smallest_timeout(base); } } /* main event loop */ int event_base_loop(struct event_base *base, int loop_flags) { int pf_cnt, res, timeout_ms; struct List *node; /* don't loop if non-block was requested */ if (loop_flags & EVLOOP_NONBLOCK) loop_flags |= EVLOOP_ONCE; base->loop_break = false; base->loop_exit = false; loop: if (!make_room(base, statlist_count(&base->fd_list))) return -1; /* fill pollfds */ pf_cnt = 0; statlist_for_each(node, &base->fd_list) { struct event *ev = container_of(node, struct event, node); struct pollfd *pf; ev->ev_idx = pf_cnt++; base->pfd_event[ev->ev_idx] = ev; pf = &base->pfd_list[ev->ev_idx]; pf->events = 0; pf->revents = 0; pf->fd = ev->fd; if (ev->flags & EV_READ) pf->events |= POLLIN; if (ev->flags & EV_WRITE) pf->events |= POLLOUT; } /* decide sleep time */ if (loop_flags & EVLOOP_NONBLOCK) timeout_ms = 0; else timeout_ms = calc_timeout_ms(base); /* forget cached time */ reset_base_time(base); /* poll for events */ res = poll(base->pfd_list, pf_cnt, timeout_ms); base_dbg(base, "poll(%d, timeout=%d) = res=%d errno=%d", pf_cnt, timeout_ms, res, res < 0 ? errno : 0); if (res == -1 && errno != EINTR) return -1; /* process events */ if (res > 0) { process_fds(base, pf_cnt); if (base->loop_break) return 0; } process_timeouts(base); /* decide whether to continue looping */ if (loop_flags & EVLOOP_ONCE) return 0; if (base->loop_break || base->loop_exit) return 0; goto loop; } /* * Signal handling. */ /* global signal handler registered via sigaction() */ static void uevent_sig_handler(int sig) { struct List *node, *tmp; struct event_base *base; uint8_t byte = sig; int res; if (sig < 0 || sig >= MAX_SIGNAL) return; sig_count[sig]++; list_for_each_safe(node, &sig_base_list, tmp) { base = container_of(node, struct event_base, sig_node); if (base->sig_send >= 0) { loop: res = send(base->sig_send, &byte, 1, MSG_NOSIGNAL); if (res == -1 && (errno == EINTR)) goto loop; } } } /* close signal resources on one base */ static void sig_close(struct event_base *base) { list_del(&base->sig_node); if (base->sig_send >= 0) close(base->sig_send); if (base->sig_recv >= 0) close(base->sig_recv); base->sig_recv = base->sig_send = -1; } /* call all handlers waiting for specific signal */ static void deliver_signal(struct event_base *base, int sig) { struct List *node, *tmp; list_for_each_safe(node, &base->sig_waiters[sig], tmp) { struct event *ev = container_of(node, struct event, node); deliver_event(ev, EV_SIGNAL); } } /* reader from sig socket, calls actual signal handlers */ static void sig_reader(int fd, short flags, void *arg) { struct event_base *base = arg; uint8_t buf[128]; int res, sig; /* drain the socket */ loop: res = recv(fd, buf, sizeof(buf), 0); if (res < 0) { if (errno == EINTR) goto loop; } else if ((res == sizeof(buf)) && (res > 1)) goto loop; /* now check for new signals */ for (sig = 0; sig < MAX_SIGNAL; sig++) { unsigned glob, local; if (list_empty(&base->sig_waiters[sig])) continue; glob = sig_count[sig]; local = base->sig_seen[sig]; if (glob != local) { base->sig_seen[sig] = glob; deliver_signal(base, sig); } } } /* setup signal handling for particular signal */ static bool sig_init(struct event_base *base, int sig) { int spair[2]; if (sig < 0 || sig >= MAX_SIGNAL) { errno = EINVAL; return false; } /* global handler setup */ if (!signal_set_up[sig]) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = uevent_sig_handler; sa.sa_flags = SA_RESTART; sigfillset(&sa.sa_mask); if (sigaction(sig, &sa, &old_handler[sig]) != 0) return false; } /* local handler for base */ if (list_empty(&base->sig_node)) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, spair) != 0) return false; if (!socket_setup(spair[0], true)) goto failed; if (!socket_setup(spair[1], true)) goto failed; event_assign(&base->sig_ev, base, spair[1], EV_READ|EV_PERSIST, sig_reader, base); if (event_add(&base->sig_ev, NULL) != 0) goto failed; base->sig_send = spair[0]; base->sig_recv = spair[1]; list_append(&sig_base_list, &base->sig_node); } /* if first waiter, then ignore previous signals */ if (list_empty(&base->sig_waiters[sig])) base->sig_seen[sig] = sig_count[sig]; return true; failed: close(spair[0]); close(spair[1]); return false; } /* * One-time events. */ struct once_event { struct event ev; uevent_cb_f cb_func; void *cb_arg; }; static void once_handler(int fd, short flags, void *arg) { struct once_event *once = arg; uevent_cb_f cb_func = once->cb_func; void *cb_arg = once->cb_arg; free(once); cb_func(fd, flags, cb_arg); } /* wait for one-time event, provide event struct internally */ int event_base_once(struct event_base *base, int fd, short flags, uevent_cb_f cb_func, void *cb_arg, struct timeval *timeout) { struct once_event *once; if (flags & EV_PERSIST) { errno = EINVAL; return -1; } once = calloc(1, sizeof(*once)); if (!once) return -1; event_assign(&once->ev, base, fd, flags, once_handler, once); if (event_add(&once->ev, timeout) != 0) { free(once); return -1; } return 0; } /* * Stop loop at particular time. */ static void loopexit_handler(int fd, short flags, void *arg) { struct event_base *base = arg; base->loop_exit = true; } int event_base_loopexit(struct event_base *base, struct timeval *timeout) { if (!timeout) { errno = EINVAL; return -1; } return event_base_once(base, -1, 0, loopexit_handler, base, timeout); } /* * Info */ const char *event_get_version(void) { return "usual/event"; } const char *event_get_method(void) { return "poll"; } #endif /* !HAVE_LIBEVENT */ pgbouncer-1.5.4/lib/usual/slab.c0000644000175000017500000001431011665176410013420 00000000000000/* * Primitive slab allocator. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #ifndef USUAL_FAKE_SLAB /* * Store for pre-initialized objects of one type. */ struct Slab { struct List head; struct StatList freelist; struct StatList fraglist; char name[32]; unsigned final_size; unsigned total_count; slab_init_fn init_func; CxMem *cx; }; /* * Header for each slab. */ struct SlabFrag { struct List head; }; /* keep track of all active slabs */ static STATLIST(slab_list); static void slab_list_append(struct Slab *slab) { #ifndef _REENTRANT statlist_append(&slab_list, &slab->head); #endif } static void slab_list_remove(struct Slab *slab) { #ifndef _REENTRANT statlist_remove(&slab_list, &slab->head); #endif } /* fill struct contents */ static void init_slab(struct Slab *slab, const char *name, unsigned obj_size, unsigned align, slab_init_fn init_func, CxMem *cx) { unsigned slen = strlen(name); list_init(&slab->head); statlist_init(&slab->freelist, name); statlist_init(&slab->fraglist, name); slab->total_count = 0; slab->init_func = init_func; slab->cx = cx; if (slen >= sizeof(slab->name)) slen = sizeof(slab->name) - 1; memcpy(slab->name, name, slen); slab->name[slen] = 0; if (align == 0) slab->final_size = ALIGN(obj_size); else slab->final_size = CUSTOM_ALIGN(obj_size, align); slab_list_append(slab); } /* make new slab */ struct Slab *slab_create(const char *name, unsigned obj_size, unsigned align, slab_init_fn init_func, CxMem *cx) { struct Slab *slab; /* new slab object */ slab = cx_alloc0(cx, sizeof(*slab)); if (slab) init_slab(slab, name, obj_size, align, init_func, cx); return slab; } /* free all storage associated by slab */ void slab_destroy(struct Slab *slab) { struct List *item, *tmp; struct SlabFrag *frag; if (!slab) return; slab_list_remove(slab); statlist_for_each_safe(item, &slab->fraglist, tmp) { frag = container_of(item, struct SlabFrag, head); cx_free(slab->cx, frag); } cx_free(slab->cx, slab); } /* add new block of objects to slab */ static void grow(struct Slab *slab) { unsigned count, i, size; char *area; struct SlabFrag *frag; /* calc new slab size */ count = slab->total_count; if (count < 50) count = 16 * 1024 / slab->final_size; if (count < 50) count = 50; size = count * slab->final_size; /* allocate & init */ frag = cx_alloc0(slab->cx, size + sizeof(struct SlabFrag)); if (!frag) return; list_init(&frag->head); area = (char *)frag + sizeof(struct SlabFrag); /* init objects */ for (i = 0; i < count; i++) { void *obj = area + i * slab->final_size; struct List *head = (struct List *)obj; list_init(head); statlist_append(&slab->freelist, head); } /* register to slab */ slab->total_count += count; statlist_append(&slab->fraglist, &frag->head); } /* get free object from slab */ void *slab_alloc(struct Slab *slab) { struct List *item = statlist_pop(&slab->freelist); if (!item) { grow(slab); item = statlist_pop(&slab->freelist); } if (item) { if (slab->init_func) slab->init_func(item); else memset(item, 0, slab->final_size); } return item; } /* put object back to slab */ void slab_free(struct Slab *slab, void *obj) { struct List *item = obj; list_init(item); statlist_prepend(&slab->freelist, item); } /* total number of objects allocated from slab */ int slab_total_count(const struct Slab *slab) { return slab->total_count; } /* free objects in slab */ int slab_free_count(const struct Slab *slab) { return statlist_count(&slab->freelist); } /* number of objects in use */ int slab_active_count(const struct Slab *slab) { return slab_total_count(slab) - slab_free_count(slab); } static void run_slab_stats(struct Slab *slab, slab_stat_fn cb_func, void *cb_arg) { unsigned free = statlist_count(&slab->freelist); cb_func(cb_arg, slab->name, slab->final_size, free, slab->total_count); } /* call a function for all active slabs */ void slab_stats(slab_stat_fn cb_func, void *cb_arg) { struct Slab *slab; struct List *item; statlist_for_each(item, &slab_list) { slab = container_of(item, struct Slab, head); run_slab_stats(slab, cb_func, cb_arg); } } #else struct Slab { int size; struct StatList obj_list; slab_init_fn init_func; CxMem *cx; }; struct Slab *slab_create(const char *name, unsigned obj_size, unsigned align, slab_init_fn init_func, CxMem *cx) { struct Slab *s = cx_alloc(cx, sizeof(*s)); if (s) { s->size = obj_size; s->init_func = init_func; s->cx = cx; statlist_init(&s->obj_list, "obj_list"); } return s; } void slab_destroy(struct Slab *slab) { struct List *el, *tmp; statlist_for_each_safe(el, &slab->obj_list, tmp) { statlist_remove(&slab->obj_list, el); cx_free(slab->cx, el); } cx_free(slab->cx, slab); } void *slab_alloc(struct Slab *slab) { struct List *o; void *res; o = cx_alloc(slab->cx, sizeof(struct List) + slab->size); if (!o) return NULL; list_init(o); statlist_append(&slab->obj_list, o); res = (void *)(o + 1); if (slab->init_func) slab->init_func(res); return res; } void slab_free(struct Slab *slab, void *obj) { if (obj) { struct List *el = obj; statlist_remove(&slab->obj_list, el - 1); cx_free(slab->cx, el - 1); } } int slab_total_count(const struct Slab *slab) { return 0; } int slab_free_count(const struct Slab *slab) { return 0; } int slab_active_count(const struct Slab *slab) { return 0; } void slab_stats(slab_stat_fn cb_func, void *cb_arg) {} #endif pgbouncer-1.5.4/lib/usual/cfparser.c0000644000175000017500000002547012001573466014312 00000000000000/* * Config file parser. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #ifdef HAVE_PWD_H #include #endif #include #include #include #include /* * INI file parser. */ static int count_lines(const char *s, const char *end) { int lineno = 1; for (; s < end; s++) { if (*s == '\n') lineno++; } return lineno; } bool parse_ini_file(const char *fn, cf_handler_f user_handler, void *arg) { char *buf; char *p, *key, *val; int klen, vlen; char o1, o2; bool ok; buf = load_file(fn, NULL); if (buf == NULL) return false; p = buf; while (*p) { /* space at the start of line - including empty lines */ while (*p && isspace(*p)) p++; /* skip comment lines */ if (*p == '#' || *p == ';') { while (*p && *p != '\n') p++; continue; } /* got new section */ if (*p == '[') { key = ++p; while (*p && *p != ']' && *p != '\n') p++; if (*p != ']') goto syntax_error; o1 = *p; *p = 0; log_debug("parse_ini_file: [%s]", key); ok = user_handler(arg, true, key, NULL); *p++ = o1; if (!ok) goto failed; continue; } /* done? */ if (*p == 0) break; /* read key val */ key = p; while (*p && (isalnum(*p) || strchr("_.-*", *p))) p++; klen = p - key; /* expect '=', skip it */ while (*p && (*p == ' ' || *p == '\t')) p++; if (*p != '=') { goto syntax_error; } else p++; while (*p && (*p == ' ' || *p == '\t')) p++; /* now read value */ val = p; while (*p && (*p != '\n')) p++; vlen = p - val; /* eat space at end */ while (vlen > 0 && isspace(val[vlen - 1])) vlen--; /* skip junk */ while (*p && isspace(*p)) p++; /* our buf is r/w, so take it easy */ o1 = key[klen]; o2 = val[vlen]; key[klen] = 0; val[vlen] = 0; log_debug("parse_ini_file: '%s' = '%s'", key, val); ok = user_handler(arg, false, key, val); log_debug("parse_ini_file: '%s' = '%s' ok:%d", key, val, ok); /* restore data, to keep count_lines() working */ key[klen] = o1; val[vlen] = o2; if (!ok) goto failed; } free(buf); return true; syntax_error: log_error("syntax error in configuration (%s:%d), stopping loading", fn, count_lines(buf, p)); failed: free(buf); return false; } /* * Config framework. */ static void *get_dest(void *base, const struct CfKey *k) { char *dst; if (k->flags & CF_VAL_REL) { /* relative address requires base */ if (!base) return NULL; dst = (char *)base + k->key_ofs; } else dst = (char *)k->key_ofs; return dst; } static const struct CfSect *find_sect(const struct CfContext *cf, const char *name) { const struct CfSect *s; for (s = cf->sect_list; s->sect_name; s++) { if (strcmp(s->sect_name, name) == 0) return s; if (strcmp(s->sect_name, "*") == 0) return s; } return NULL; } static const struct CfKey *find_key(const struct CfSect *s, const char *key) { const struct CfKey *k; for (k = s->key_list; k->key_name; k++) { if (strcmp(k->key_name, key) == 0) return k; } return k; } const char *cf_get(const struct CfContext *cf, const char *sect, const char *key, char *buf, int buflen) { const struct CfSect *s; const struct CfKey *k; void *base, *p; struct CfValue cv; /* find section */ s = find_sect(cf, sect); if (!s) return NULL; /* find section base */ base = cf->base; if (s->base_lookup) base = s->base_lookup(base, sect); /* handle dynamic keys */ if (s->set_key) { if (!s->get_key) return NULL; return s->get_key(base, key, buf, buflen); } /* get fixed key */ k = find_key(s, key); if (!k || !k->op.getter) return NULL; p = get_dest(base, k); if (!p) return NULL; cv.key_name = k->key_name; cv.extra = k->op.op_extra; cv.value_p = p; cv.buf = buf; cv.buflen = buflen; return k->op.getter(&cv); } bool cf_set(const struct CfContext *cf, const char *sect, const char *key, const char *val) { const struct CfSect *s; const struct CfKey *k; void *base, *p; struct CfValue cv; /* find section */ s = find_sect(cf, sect); if (!s) { log_error("Unknown section: %s", sect); return false; } /* find section base */ base = cf->base; if (s->base_lookup) base = s->base_lookup(base, sect); /* handle dynamic keys */ if (s->set_key) return s->set_key(base, key, val); /* set fixed key */ k = find_key(s, key); if (!k) { log_error("Unknown parameter: %s/%s", sect, key); return false; } if (!k->op.setter || (k->flags & CF_READONLY)) { /* silently ignore */ return true; } if ((k->flags & CF_NO_RELOAD) && cf->loaded) { /* silently ignore */ return true; } p = get_dest(base, k); if (!p) { log_error("Bug - no base for relative key: %s/%s", sect, key); return false; } cv.key_name = k->key_name; cv.extra = k->op.op_extra; cv.value_p = p; cv.buf = NULL; cv.buflen = 0; return k->op.setter(&cv, val); } /* * File loader */ struct LoaderCtx { const struct CfContext *cf; const char *cur_sect; void *top_base; }; static bool fill_defaults(struct LoaderCtx *ctx) { const struct CfKey *k; const struct CfSect *s; s = find_sect(ctx->cf, ctx->cur_sect); if (!s) goto fail; if (s->section_start) { if (!s->section_start(ctx->top_base, ctx->cur_sect)) return false; } if (s->set_key) return true; for (k = s->key_list; k->key_name; k++) { if (!k->def_value || (k->flags & CF_READONLY)) continue; if ((k->flags & CF_NO_RELOAD) && ctx->cf->loaded) continue; if (!cf_set(ctx->cf, ctx->cur_sect, k->key_name, k->def_value)) goto fail; } return true; fail: log_error("fill_defaults fail"); return false; } static bool load_handler(void *arg, bool is_sect, const char *key, const char *val) { struct LoaderCtx *ctx = arg; if (is_sect) { if (ctx->cur_sect) free(ctx->cur_sect); ctx->cur_sect = strdup(key); if (!ctx->cur_sect) return false; return fill_defaults(ctx); } else if (!ctx->cur_sect) { log_error("load_init_file: value without section: %s", key); return false; } else { return cf_set(ctx->cf, ctx->cur_sect, key, val); } } bool cf_load_file(const struct CfContext *cf, const char *fn) { struct LoaderCtx ctx = { .cf = cf, .cur_sect = NULL, }; bool ok = parse_ini_file(fn, load_handler, &ctx); if (ctx.cur_sect) free(ctx.cur_sect); return ok; } /* * Various value parsers. */ bool cf_set_int(struct CfValue *cv, const char *value) { int *ptr = cv->value_p; char *end; long val; errno = 0; val = strtol(value, &end, 0); if (end == value || *end != 0) { /* reject partial parse */ if (!errno) errno = EINVAL; return false; } *ptr = val; return true; } bool cf_set_uint(struct CfValue *cv, const char *value) { unsigned int *ptr = cv->value_p; char *end; unsigned long val; errno = 0; val = strtoul(value, &end, 0); if (end == value || *end != 0) { /* reject partial parse */ if (!errno) errno = EINVAL; return false; } *ptr = val; return true; } bool cf_set_str(struct CfValue *cv, const char *value) { char **dst_p = cv->value_p; char *tmp = strdup(value); if (!tmp) { log_error("cf_set_str: no mem"); return false; } if (*dst_p) free(*dst_p); *dst_p = tmp; return true; } bool cf_set_filename(struct CfValue *cv, const char *value) { char **dst_p = cv->value_p; char *tmp, *home, *p; int v_len, usr_len, home_len; struct passwd *pw; /* do we need to do tilde expansion */ if (value[0] != '~') return cf_set_str(cv, value); /* find username end */ v_len = strlen(value); if ((p = memchr(value, '/', v_len)) == NULL) usr_len = v_len - 1; else usr_len = (p - value) - 1; if (usr_len) { p = malloc(usr_len + 1); if (!p) return false; memcpy(p, value + 1, usr_len); p[usr_len] = 0; pw = getpwnam(p); free(p); if (!pw) goto fail; home = pw->pw_dir; } else { home = getenv("HOME"); if (!home) { pw = getpwuid(getuid()); if (!pw) goto fail; home = pw->pw_dir; } } if (!home) goto fail; home_len = strlen(home); tmp = malloc(v_len - usr_len + home_len); if (!tmp) return false; memcpy(tmp, home, home_len); memcpy(tmp + home_len, value + usr_len + 1, v_len - usr_len - 1); tmp[v_len - 1 - usr_len + home_len] = 0; log_debug("expanded '%s' -> '%s'", value, tmp); if (*dst_p) free(*dst_p); *dst_p = tmp; return true; fail: log_error("cannot to expand filename: %s", value); return false; } /* parse float with error checking. returns -1 if failed */ static double parse_time(const char *value) { double v; char *endp = NULL; errno = 0; v = strtod(value, &endp); if (errno) return -1; if (*endp || endp == value || v < 0) { errno = EINVAL; return -1; } return v; } bool cf_set_time_usec(struct CfValue *cv, const char *value) { usec_t *ptr = cv->value_p; double v = parse_time(value); if (v < 0) return false; *ptr = USEC * v; return true; } bool cf_set_time_double(struct CfValue *cv, const char *value) { double *ptr = cv->value_p; double v = parse_time(value); if (v < 0) return false; *ptr = v; return true; } /* * Various value formatters. */ const char *cf_get_str(struct CfValue *cv) { char **p = cv->value_p; return *p; } const char *cf_get_int(struct CfValue *cv) { int *p = cv->value_p; snprintf(cv->buf, cv->buflen, "%d", *p); return cv->buf; } const char *cf_get_uint(struct CfValue *cv) { unsigned int *p = cv->value_p; snprintf(cv->buf, cv->buflen, "%u", *p); return cv->buf; } const char *cf_get_time_double(struct CfValue *cv) { double *p = cv->value_p; snprintf(cv->buf, cv->buflen, "%g", *p); return cv->buf; } const char *cf_get_time_usec(struct CfValue *cv) { struct CfValue tmp = *cv; usec_t *p = cv->value_p; double d = (double)(*p) / USEC; tmp.value_p = &d; return cf_get_time_double(&tmp); } /* * str->int mapping */ const char *cf_get_lookup(struct CfValue *cv) { int *p = cv->value_p; const struct CfLookup *lk = cv->extra; for (; lk->name; lk++) { if (lk->value == *p) return lk->name; } return "INVALID"; } bool cf_set_lookup(struct CfValue *cv, const char *value) { int *p = cv->value_p; const struct CfLookup *lk = cv->extra; for (; lk->name; lk++) { if (strcasecmp(lk->name, value) == 0) { *p = lk->value; return true; } } return false; } pgbouncer-1.5.4/lib/usual/endian.h0000644000175000017500000001075611665176410013754 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Endianess conversion macros. */ #ifndef _USUAL_ENDIAN_H_ #define _USUAL_ENDIAN_H_ #include #ifdef HAVE_ENDIAN_H #include #endif #ifdef HAVE_SYS_ENDIAN_H #include #endif #ifdef HAVE_BYTESWAP_H #include #endif #include /** * @name Always swap. * @{ */ #ifndef bswap16 #ifdef bswap_16 #define bswap16(x) bswap_16(x) #else static inline uint16_t bswap16(uint16_t x) { return (x << 8) | (x >> 8); } #endif #endif #ifndef bswap32 #ifdef bswap_32 #define bswap32(x) bswap_32(x) #else static inline uint32_t bswap32(uint32_t x) { #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))) return __builtin_bswap32(x); #else x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF); return (x << 16) | (x >> 16); #endif } #endif #endif #ifndef bswap64 #ifdef bswap_64 #define bswap64(x) bswap_64(x) #else static inline uint64_t bswap64(uint64_t x) { return ((uint64_t)bswap32(x) << 32) | bswap32(x >> 32); } #endif #endif /* @} */ /** * @name Host <-> LE/BE * @{ */ /* Ignore OS defines, as they may define only some subset of functions */ #undef htobe16 #undef htobe32 #undef htobe64 #undef htole16 #undef htole32 #undef htole64 #undef be16toh #undef be32toh #undef be64toh #undef le16toh #undef le32toh #undef le64toh #ifdef WORDS_BIGENDIAN #define htobe16(x) ((uint16_t)(x)) #define htobe32(x) ((uint32_t)(x)) #define htobe64(x) ((uint64_t)(x)) #define htole16(x) bswap16(x) #define htole32(x) bswap32(x) #define htole64(x) bswap64(x) #define be16toh(x) ((uint16_t)(x)) #define be32toh(x) ((uint32_t)(x)) #define be64toh(x) ((uint64_t)(x)) #define le16toh(x) bswap16(x) #define le32toh(x) bswap32(x) #define le64toh(x) bswap64(x) #else #define htobe16(x) bswap16(x) #define htobe32(x) bswap32(x) #define htobe64(x) bswap64(x) #define htole16(x) ((uint16_t)(x)) #define htole32(x) ((uint32_t)(x)) #define htole64(x) ((uint64_t)(x)) #define be16toh(x) bswap16(x) #define be32toh(x) bswap32(x) #define be64toh(x) bswap64(x) #define le16toh(x) ((uint16_t)(x)) #define le32toh(x) ((uint32_t)(x)) #define le64toh(x) ((uint64_t)(x)) #endif /* @} */ #ifndef HAVE_ENCDEC_FUNCS /** * @name Read LE/BE values from memory and convert to host format * @{ */ static inline uint16_t be16dec(const void *p) { uint16_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htobe16(tmp); } static inline uint32_t be32dec(const void *p) { uint32_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htobe32(tmp); } static inline uint64_t be64dec(const void *p) { uint64_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htobe64(tmp); } static inline uint16_t le16dec(const void *p) { uint16_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htole16(tmp); } static inline uint32_t le32dec(const void *p) { uint32_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htole32(tmp); } static inline uint64_t le64dec(const void *p) { uint64_t tmp; memcpy(&tmp, p, sizeof(tmp)); return htole64(tmp); } /* @} */ /** * @name Convert host value to LE/BE and write to memory * @{ */ static inline void be16enc(void *p, uint16_t x) { uint16_t tmp = htobe16(x); memcpy(p, &tmp, sizeof(tmp)); } static inline void be32enc(void *p, uint32_t x) { uint32_t tmp = htobe32(x); memcpy(p, &tmp, sizeof(tmp)); } static inline void be64enc(void *p, uint64_t x) { uint64_t tmp = htobe64(x); memcpy(p, &tmp, sizeof(tmp)); } static inline void le16enc(void *p, uint16_t x) { uint16_t tmp = htole16(x); memcpy(p, &tmp, sizeof(tmp)); } static inline void le32enc(void *p, uint32_t x) { uint32_t tmp = htole32(x); memcpy(p, &tmp, sizeof(tmp)); } static inline void le64enc(void *p, uint64_t x) { uint64_t tmp = htole64(x); memcpy(p, &tmp, sizeof(tmp)); } /* @} */ #endif /* !HAVE_ENCDEC_FUNCS */ #endif /* _USUAL_ENDIAN_H_ */ pgbouncer-1.5.4/lib/usual/socket_pton.c0000644000175000017500000001224011665176410015027 00000000000000/* $OpenBSD: inet_pton.c,v 1.8 2010/05/06 15:47:14 claudio Exp $ */ /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #include #ifndef HAVE_INET_PTON #ifndef INADDRSZ #define INADDRSZ 4 #endif #ifndef IN6ADDRSZ #define IN6ADDRSZ 16 #endif #ifndef INT16SZ #define INT16SZ 2 #endif #define u_char uint8_t #define u_int unsigned int /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static int inet_pton4(const char *src, u_char *dst); static int inet_pton6(const char *src, u_char *dst); /* int * inet_pton(af, src, dst) * convert from presentation format (which usually means ASCII printable) * to network format (which is usually some kind of binary format). * return: * 1 if the address was valid for the specified address family * 0 if the address wasn't valid (`dst' is untouched in this case) * -1 if some other error occurred (`dst' is untouched in this case, too) * author: * Paul Vixie, 1996. */ int inet_pton(int af, const char *src, void *dst) { switch (af) { case AF_INET: return (inet_pton4(src, dst)); case AF_INET6: return (inet_pton6(src, dst)); default: errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ } /* int * inet_pton4(src, dst) * like inet_aton() but without all the hexadecimal and shorthand. * return: * 1 if `src' is a valid dotted quad, else 0. * notice: * does not touch `dst' unless it's returning 1. * author: * Paul Vixie, 1996. */ static int inet_pton4(const char *src, u_char *dst) { static const char digits[] = "0123456789"; int saw_digit, octets, ch; u_char tmp[INADDRSZ], *tp; saw_digit = 0; octets = 0; *(tp = tmp) = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { u_int new = *tp * 10 + (pch - digits); if (new > 255) return (0); if (! saw_digit) { if (++octets > 4) return (0); saw_digit = 1; } *tp = new; } else if (ch == '.' && saw_digit) { if (octets == 4) return (0); *++tp = 0; saw_digit = 0; } else return (0); } if (octets < 4) return (0); memcpy(dst, tmp, INADDRSZ); return (1); } /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * 1 if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * does not touch `dst' unless it's returning 1. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ static int inet_pton6(const char *src, u_char *dst) { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, saw_xdigit, count_xdigit; u_int val; memset((tp = tmp), '\0', IN6ADDRSZ); endp = tp + IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; saw_xdigit = count_xdigit = 0; val = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { if (count_xdigit >= 4) return (0); val <<= 4; val |= (pch - xdigits); if (val > 0xffff) return (0); saw_xdigit = 1; count_xdigit++; continue; } if (ch == ':') { curtok = src; if (!saw_xdigit) { if (colonp) return (0); colonp = tp; continue; } else if (*src == '\0') { return (0); } if (tp + INT16SZ > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; saw_xdigit = 0; count_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) { tp += INADDRSZ; saw_xdigit = 0; count_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } return (0); } if (saw_xdigit) { if (tp + INT16SZ > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = tp - colonp; int i; if (tp == endp) return (0); for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return (0); memcpy(dst, tmp, IN6ADDRSZ); return (1); } #endif pgbouncer-1.5.4/lib/usual/heap.c0000644000175000017500000000736311665176410013426 00000000000000/* * Binary Heap. * * Copyright (c) 2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include struct Heap { void **data; unsigned allocated; unsigned used; heap_is_better_f is_better; heap_save_pos_f save_pos; CxMem *cx; }; /* * Low-level operations. */ static unsigned get_parent(unsigned i) { return (i - 1) / 2; } static unsigned get_child(unsigned i, unsigned child_nr) { return 2*i + 1 + child_nr; } static bool is_better(struct Heap *h, unsigned i1, unsigned i2) { return h->is_better(h->data[i1], h->data[i2]); } static void set(struct Heap *h, unsigned i, void *ptr) { h->data[i] = ptr; if (h->save_pos) h->save_pos(ptr, i); } static void swap(struct Heap *h, unsigned i1, unsigned i2) { void *tmp = h->data[i1]; set(h, i1, h->data[i2]); set(h, i2, tmp); } static void bubble_up(struct Heap *h, unsigned i) { unsigned p; while (i > 0) { p = get_parent(i); if (!is_better(h, i, p)) break; swap(h, i, p); i = p; } } static void bubble_down(struct Heap *h, unsigned i) { unsigned c = get_child(i, 0); while (c < h->used) { if (c + 1 < h->used) { if (is_better(h, c + 1, c)) c = c + 1; } if (!is_better(h, c, i)) break; swap(h, i, c); i = c; c = get_child(i, 0); } } static void rebalance(struct Heap *h, unsigned pos) { if (pos == 0) { bubble_down(h, pos); } else if (pos == h->used - 1) { bubble_up(h, pos); } else if (is_better(h, pos, get_parent(pos))) { bubble_up(h, pos); } else { bubble_down(h, pos); } } /* * Actual API. */ struct Heap *heap_create(heap_is_better_f is_better_cb, heap_save_pos_f save_pos_cb, CxMem *cx) { struct Heap *h; h = cx_alloc0(cx, sizeof(*h)); if (!h) return NULL; h->save_pos = save_pos_cb; h->is_better = is_better_cb; h->cx = cx; return h; } void heap_destroy(struct Heap *h) { cx_free(h->cx, h->data); cx_free(h->cx, h); } bool heap_reserve(struct Heap *h, unsigned extra) { void *tmp; unsigned newalloc; if (h->used + extra < h->allocated) return true; newalloc = h->allocated * 2; if (newalloc < 32) newalloc = 32; if (newalloc < h->used + extra) newalloc = h->used + extra; tmp = cx_realloc(h->cx, h->data, newalloc * sizeof(void *)); if (!tmp) return false; h->data = tmp; h->allocated = newalloc; return true; } void *heap_top(struct Heap *h) { return (h->used > 0) ? h->data[0] : NULL; } bool heap_push(struct Heap *h, void *ptr) { unsigned pos; if (h->used >= h->allocated) { if (!heap_reserve(h, 1)) return false; } pos = h->used++; set(h, pos, ptr); bubble_up(h, pos); return true; } void *heap_remove(struct Heap *h, unsigned pos) { unsigned last; void *obj; if (pos >= h->used) return NULL; obj = h->data[pos]; last = --h->used; if (pos < last) { set(h, pos, h->data[last]); rebalance(h, pos); } h->data[last] = NULL; return obj; } void *heap_pop(struct Heap *h) { return heap_remove(h, 0); } unsigned heap_size(struct Heap *h) { return h->used; } void *heap_get_obj(struct Heap *h, unsigned pos) { if (pos < h->used) return h->data[pos]; return NULL; } pgbouncer-1.5.4/lib/usual/fileutil.c0000644000175000017500000000615211665176410014321 00000000000000/* * File access utils. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #ifdef HAVE_SYS_MMAN_H #include #endif #include #include #include /* * Load text file into C string. */ void *load_file(const char *fn, size_t *len_p) { struct stat st; char *buf = NULL; int res; FILE *f; res = stat(fn, &st); if (res < 0) return NULL; buf = malloc(st.st_size + 1); if (!buf) return NULL; f = fopen(fn, "r"); if (!f) { free(buf); return NULL; } if ((res = fread(buf, 1, st.st_size, f)) < 0) { free(buf); fclose(f); return NULL; } fclose(f); buf[res] = 0; if (len_p) *len_p = res; return buf; } /* * Read file line-by-line, call user func on each. */ bool foreach_line(const char *fn, procline_cb proc_line, void *arg) { char *ln = NULL; size_t len = 0; ssize_t res; FILE *f = fopen(fn, "rb"); bool ok = false; if (!f) return false; while (1) { res = getline(&ln, &len, f); if (res < 0) { if (feof(f)) ok = true; break; } if (!proc_line(arg, ln, res)) break; } fclose(f); free(ln); return ok; } /* * Find file size. */ ssize_t file_size(const char *fn) { struct stat st; if (stat(fn, &st) < 0) return -1; return st.st_size; } /* * Map a file into mem. */ #ifdef HAVE_MMAP int map_file(struct MappedFile *m, const char *fname, int rw) { struct stat st; m->fd = open(fname, rw ? O_RDWR : O_RDONLY); if (m->fd < 0) return -1; if (fstat(m->fd, &st) < 0) { close(m->fd); return -1; } m->len = st.st_size; m->ptr = mmap(NULL, m->len, PROT_READ | (rw ? PROT_WRITE : 0), MAP_SHARED, m->fd, 0); if (m->ptr == MAP_FAILED) { close(m->fd); return -1; } return 0; } void unmap_file(struct MappedFile *m) { munmap(m->ptr, m->len); close(m->fd); m->ptr = NULL; m->fd = 0; } #endif #ifndef HAVE_GETLINE /* * Read line from FILE with dynamic allocation. */ int getline(char **line_p, size_t *size_p, void *_f) { FILE *f = _f; char *p; int len = 0; if (!*line_p || *size_p < 128) { p = realloc(*line_p, 512); if (!p) return -1; *line_p = p; *size_p = 512; } while (1) { p = fgets(*line_p + len, *size_p - len, f); if (!p) return len ? len : -1; len += strlen(p); if ((*line_p)[len - 1] == '\n') return len; p = realloc(*line_p, *size_p * 2); if (!p) return -1; *line_p = p; *size_p *= 2; } } #endif pgbouncer-1.5.4/lib/usual/mempool.h0000644000175000017500000000217111665176410014156 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * Simple memory pool for variable-length allocations. */ #ifndef _USUAL_MEMPOOL_H_ #define _USUAL_MEMPOOL_H_ #include /** Pool Reference */ struct MemPool; /** Allocate from pool */ void *mempool_alloc(struct MemPool **pool, unsigned size) _MALLOC; /** Release all memory in pool */ void mempool_destroy(struct MemPool **pool); #endif pgbouncer-1.5.4/lib/usual/aatree.c0000644000175000017500000001644011665176410013746 00000000000000/* * AA-Tree - Binary tree with embeddable nodes. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Self-balancing binary tree. * * Here is an implementation of AA-tree (Arne Andersson tree) * which is simplification of Red-Black tree. * * Red-black tree has following properties that must be kept: * 1. A node is either red or black. * 2. The root is black. * 3. All leaves (NIL nodes) are black. * 4. Both childen of red node are black. * 5. Every path from root to leaf contains same number of black nodes. * * AA-tree adds additional property: * 6. Red node can exist only as a right node. * * Red-black tree properties quarantee that the longest path is max 2x longer * than shortest path (B-R-B-R-B-R-B vs. B-B-B-B) thus the tree will be roughly * balanced. Also it has good worst-case guarantees for insertion and deletion, * which makes it good tool for real-time applications. * * AA-tree removes most special cases from RB-tree, thus making resulting * code lot simpler. It requires slightly more rotations when inserting * and deleting but also keeps the tree more balanced. */ #include #include /* for NULL */ typedef struct AATree Tree; typedef struct AANode Node; /* * NIL node */ #define NIL ((struct AANode *)&_nil) static const struct AANode _nil = { NIL, NIL, 0 }; /* * Rebalancing. AA-tree needs only 2 operations * to keep the tree balanced. */ /* * Fix red on left. * * X Y * / --> \ * Y X * \ / * a a */ static inline Node * skew(Node *x) { Node *y = x->left; if (x->level == y->level && x != NIL) { x->left = y->right; y->right = x; return y; } return x; } /* * Fix 2 reds on right. * * X Y * \ / \ * Y --> X Z * / \ \ * a Z a */ static inline Node * split(Node *x) { Node *y = x->right; if (x->level == y->right->level && x != NIL) { x->right = y->left; y->left = x; y->level++; return y; } return x; } /* insert is easy */ static Node *rebalance_on_insert(Node *current) { return split(skew(current)); } /* remove is bit more tricky */ static Node *rebalance_on_remove(Node *current) { /* * Removal can create a gap in levels, * fix it by lowering current->level. */ if (current->left->level < current->level - 1 || current->right->level < current->level - 1) { current->level--; /* if ->right is red, change it's level too */ if (current->right->level > current->level) current->right->level = current->level; /* reshape, ask Arne about those */ current = skew(current); current->right = skew(current->right); current->right->right = skew(current->right->right); current = split(current); current->right = split(current->right); } return current; } /* * Recursive insertion */ static Node * insert_sub(Tree *tree, Node *current, uintptr_t value, Node *node) { int cmp; if (current == NIL) { /* * Init node as late as possible, to avoid corrupting * the tree in case it is already added. */ node->left = node->right = NIL; node->level = 1; tree->count++; return node; } /* recursive insert */ cmp = tree->node_cmp(value, current); if (cmp > 0) current->right = insert_sub(tree, current->right, value, node); else if (cmp < 0) current->left = insert_sub(tree, current->left, value, node); else /* already exists? */ return current; return rebalance_on_insert(current); } void aatree_insert(Tree *tree, uintptr_t value, Node *node) { tree->root = insert_sub(tree, tree->root, value, node); } /* * Recursive removal */ /* remove_sub could be used for that, but want to avoid comparisions */ static Node *steal_leftmost(Tree *tree, Node *current, Node **save_p) { if (current->left == NIL) { *save_p = current; return current->right; } current->left = steal_leftmost(tree, current->left, save_p); return rebalance_on_remove(current); } /* drop this node from tree */ static Node *drop_this_node(Tree *tree, Node *old) { Node *new = NIL; if (old->left == NIL) new = old->right; else if (old->right == NIL) new = old->left; else { /* * Picking nearest from right is better than from left, * due to asymmetry of the AA-tree. It will result in * less tree operations in the long run, */ old->right = steal_leftmost(tree, old->right, &new); /* take old node's place */ *new = *old; } /* cleanup for old node */ if (tree->release_cb) tree->release_cb(old, tree); tree->count--; return new; } static Node *remove_sub(Tree *tree, Node *current, uintptr_t value) { int cmp; /* not found? */ if (current == NIL) return current; cmp = tree->node_cmp(value, current); if (cmp > 0) current->right = remove_sub(tree, current->right, value); else if (cmp < 0) current->left = remove_sub(tree, current->left, value); else current = drop_this_node(tree, current); return rebalance_on_remove(current); } void aatree_remove(Tree *tree, uintptr_t value) { tree->root = remove_sub(tree, tree->root, value); } /* * Walking all nodes */ static void walk_sub(Node *current, enum AATreeWalkType wtype, aatree_walker_f walker, void *arg) { if (current == NIL) return; switch (wtype) { case AA_WALK_IN_ORDER: walk_sub(current->left, wtype, walker, arg); walker(current, arg); walk_sub(current->right, wtype, walker, arg); break; case AA_WALK_POST_ORDER: walk_sub(current->left, wtype, walker, arg); walk_sub(current->right, wtype, walker, arg); walker(current, arg); break; case AA_WALK_PRE_ORDER: walker(current, arg); walk_sub(current->left, wtype, walker, arg); walk_sub(current->right, wtype, walker, arg); break; } } /* walk tree in correct order */ void aatree_walk(Tree *tree, enum AATreeWalkType wtype, aatree_walker_f walker, void *arg) { walk_sub(tree->root, wtype, walker, arg); } /* walk tree in bottom-up order, so that walker can destroy the nodes */ void aatree_destroy(Tree *tree) { walk_sub(tree->root, AA_WALK_POST_ORDER, tree->release_cb, tree); /* reset tree */ tree->root = NIL; tree->count = 0; } /* prepare tree */ void aatree_init(Tree *tree, aatree_cmp_f cmpfn, aatree_walker_f release_cb) { tree->root = NIL; tree->count = 0; tree->node_cmp = cmpfn; tree->release_cb = release_cb; } /* * search function */ Node *aatree_search(Tree *tree, uintptr_t value) { Node *current = tree->root; while (current != NIL) { int cmp = tree->node_cmp(value, current); if (cmp > 0) current = current->right; else if (cmp < 0) current = current->left; else return current; } return NULL; } pgbouncer-1.5.4/lib/usual/daemon.c0000644000175000017500000001076311665176410013752 00000000000000/* * Daemonization & pidfile handling. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include /* * pidfile management. */ static char *g_pidfile; static void remove_pidfile(void) { if (!g_pidfile) return; unlink(g_pidfile); free(g_pidfile); g_pidfile = NULL; } /* * Reads pid from pidfile and sends a signal to it. * * true - signaling was successful. * false - ENOENT / ESRCH * * fatal() otherwise. */ bool signal_pidfile(const char *pidfile, int sig) { char buf[128 + 1]; struct stat st; pid_t pid = 0; int fd, res; if (!pidfile || !pidfile[0]) return false; intr_loop: /* check if pidfile exists */ if (stat(pidfile, &st) < 0) goto fail; /* read old pid */ fd = open(pidfile, O_RDONLY); if (fd < 0) goto fail; res = read(fd, buf, sizeof(buf) - 1); close(fd); if (res <= 0) goto fail; /* parse pid */ buf[res] = 0; errno = 0; pid = strtoul(buf, NULL, 10); if (errno) { /* should we panic, or say no such process exists? */ if (0) errno = ESRCH; goto fail; } /* send the signal */ res = kill(pid, sig); if (res == 0) return true; fail: /* decide error seriousness */ if (errno == EINTR) goto intr_loop; if (errno == ENOENT || errno == ESRCH) return false; fatal_perror("signal_pidfile: Unexpected error"); } static void check_pidfile(const char *pidfile) { if (signal_pidfile(pidfile, 0)) fatal("pidfile exists, another instance running?"); if (errno == ESRCH) { log_info("Stale pidfile, removing"); unlink(pidfile); } } static void write_pidfile(const char *pidfile, bool first_write) { char buf[64]; pid_t pid; int res, fd, len; static int atexit_hook = 0; int flags = O_WRONLY | O_CREAT; if (!pidfile || !pidfile[0]) return; if (g_pidfile) free(g_pidfile); g_pidfile = strdup(pidfile); if (!g_pidfile) fatal_perror("cannot alloc pidfile"); pid = getpid(); snprintf(buf, sizeof(buf), "%u\n", (unsigned)pid); /* don't allow overwrite on first write */ if (first_write) flags |= O_EXCL; fd = open(pidfile, flags, 0644); if (fd < 0) fatal_perror("Cannot write pidfile: '%s'", pidfile); len = strlen(buf); loop: res = write(fd, buf, len); if (res < 0) { if (errno == EINTR) goto loop; fatal_perror("Write to pidfile failed: '%s'", pidfile); } else if (res < len) { len -= res; goto loop; } close(fd); if (!atexit_hook) { /* only remove when we have it actually written */ atexit(remove_pidfile); atexit_hook = 1; } } /* * Function: daemonize * * Handle pidfile and daemonization. * * If pidfile is given, check if old process is running. * * If going background is required, require non-empty pidfile * and logfile. Then fork to background and write pidfile. */ void daemonize(const char *pidfile, bool go_background) { int pid, fd; if (pidfile && pidfile[0]) { check_pidfile(pidfile); /* write pidfile twice, to be able to show problems to user */ write_pidfile(pidfile, true); } else if (go_background) fatal("daemon needs pidfile configured"); if (!go_background) return; if ((!cf_logfile || !cf_logfile[0]) && !cf_syslog) fatal("daemon needs logging configured"); /* send stdin, stdout, stderr to /dev/null */ fd = open("/dev/null", O_RDWR); if (fd < 0) fatal_perror("/dev/null"); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); if (fd > 2) close(fd); /* fork new process */ pid = fork(); if (pid < 0) fatal_perror("fork"); if (pid > 0) _exit(0); /* create new session */ pid = setsid(); if (pid < 0) fatal_perror("setsid"); /* fork again to avoid being session leader */ pid = fork(); if (pid < 0) fatal_perror("fork"); if (pid > 0) _exit(0); write_pidfile(pidfile, false); } pgbouncer-1.5.4/lib/usual/cxalloc.h0000644000175000017500000000656211665176410014143 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Context-based Memory Allocator. * * The idea is that each data structure is given a context to allocate from, * and it can create subcontext for that which can be specific allocation * pattern that matches the data structure. * * It is slightly more work to use than palloc (PostgreSQL) or talloc (Samba), * but it avoids the need to have big fully-featured framework that does * everything at once. * * Instead you have small task-specific allocators, and you can always fall * back to raw malloc if you want to valgrind the code. * * Potential variants: * - fully-featured pooled * - randomly failing * - logging * - locking * - guard signatures * - palloc / talloc like API */ #ifndef _USUAL_CXALLOC_H_ #define _USUAL_CXALLOC_H_ #include /** * Ops for allocator that takes context. * * NB! - they are not equivalent to cx_* API. The cx_* * functions do additional sanitizing. */ struct CxOps { /** * Allocate memory. * len will not be 0. */ void *(*c_alloc)(void *ctx, size_t len); /** * Resize existing allocation. * Both p and len will not be 0 */ void *(*c_realloc)(void *ctx, void *p, size_t len); /** * Free existing allocation. * p will not be 0 */ void (*c_free)(void *ctx, const void *p); /** * Release all memory in context. * This is not supported by all allocators. */ void (*c_destroy)(void *ctx); }; /** * Memory allocation context. */ struct CxMem { const struct CxOps *ops; void *ctx; }; /** Shortcut to const CxMem */ typedef const struct CxMem CxMem; /* * Basic operations on allocation context. */ /** * Allocate memory from context. * * Returns NULL if no memory or len == 0. */ void *cx_alloc(CxMem *cx, size_t len) _MALLOC; /** * Change existing allocation. * * If ptr is NULL it creates new allocation. * If len is 0 it frees the memory. */ void *cx_realloc(CxMem *cx, void *ptr, size_t len); /** * Free existing allocation. * * Does nothing if ptr is NULL. */ void cx_free(CxMem *cx, const void *ptr); /** * Release all memory allocated in context. * * Should be called only on contexts that support it. */ void cx_destroy(CxMem *cx); /** Allocate and zero-fill memory */ void *cx_alloc0(CxMem *cx, size_t len) _MALLOC; /** Allocate and copy */ void *cx_memdup(CxMem *cx, const void *src, size_t len) _MALLOC; /** Allocate and copy string */ void *cx_strdup(CxMem *cx, const char *str) _MALLOC; /** Allocator that uses libc malloc/realloc/free */ extern CxMem cx_libc_allocator; /** Default allocator */ #ifndef USUAL_ALLOC #define USUAL_ALLOC (&cx_libc_allocator) #endif #endif pgbouncer-1.5.4/lib/usual/md5.c0000644000175000017500000001234311665176410013170 00000000000000/* * MD5 implementation based on RFC1321. * * Copyright (c) 2008 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include /* * Support functions. */ #define bufpos(ctx) ((ctx)->nbytes & (MD5_BLOCK_LENGTH - 1)) static inline void swap_words(uint32_t *w, int n) { #ifdef WORDS_BIGENDIAN for (; n > 0; w++, n--) *w = le32toh(*w); #endif } /* * MD5 core. */ #define F(X,Y,Z) ((X & Y) | ((~X) & Z)) #define G(X,Y,Z) ((X & Z) | (Y & (~Z))) #define H(X,Y,Z) (X ^ Y ^ Z) #define I(X,Y,Z) (Y ^ (X | (~Z))) #define OP(fn, a, b, c, d, k, s, T_i) \ a = b + rol32(a + fn(b, c, d) + X[k] + T_i, s) static void md5_mix(struct md5_ctx *ctx, const uint32_t *X) { uint32_t a, b, c, d; a = ctx->a; b = ctx->b; c = ctx->c; d = ctx->d; /* Round 1. */ OP(F, a, b, c, d, 0, 7, 0xd76aa478); OP(F, d, a, b, c, 1, 12, 0xe8c7b756); OP(F, c, d, a, b, 2, 17, 0x242070db); OP(F, b, c, d, a, 3, 22, 0xc1bdceee); OP(F, a, b, c, d, 4, 7, 0xf57c0faf); OP(F, d, a, b, c, 5, 12, 0x4787c62a); OP(F, c, d, a, b, 6, 17, 0xa8304613); OP(F, b, c, d, a, 7, 22, 0xfd469501); OP(F, a, b, c, d, 8, 7, 0x698098d8); OP(F, d, a, b, c, 9, 12, 0x8b44f7af); OP(F, c, d, a, b, 10, 17, 0xffff5bb1); OP(F, b, c, d, a, 11, 22, 0x895cd7be); OP(F, a, b, c, d, 12, 7, 0x6b901122); OP(F, d, a, b, c, 13, 12, 0xfd987193); OP(F, c, d, a, b, 14, 17, 0xa679438e); OP(F, b, c, d, a, 15, 22, 0x49b40821); /* Round 2. */ OP(G, a, b, c, d, 1, 5, 0xf61e2562); OP(G, d, a, b, c, 6, 9, 0xc040b340); OP(G, c, d, a, b, 11, 14, 0x265e5a51); OP(G, b, c, d, a, 0, 20, 0xe9b6c7aa); OP(G, a, b, c, d, 5, 5, 0xd62f105d); OP(G, d, a, b, c, 10, 9, 0x02441453); OP(G, c, d, a, b, 15, 14, 0xd8a1e681); OP(G, b, c, d, a, 4, 20, 0xe7d3fbc8); OP(G, a, b, c, d, 9, 5, 0x21e1cde6); OP(G, d, a, b, c, 14, 9, 0xc33707d6); OP(G, c, d, a, b, 3, 14, 0xf4d50d87); OP(G, b, c, d, a, 8, 20, 0x455a14ed); OP(G, a, b, c, d, 13, 5, 0xa9e3e905); OP(G, d, a, b, c, 2, 9, 0xfcefa3f8); OP(G, c, d, a, b, 7, 14, 0x676f02d9); OP(G, b, c, d, a, 12, 20, 0x8d2a4c8a); /* Round 3. */ OP(H, a, b, c, d, 5, 4, 0xfffa3942); OP(H, d, a, b, c, 8, 11, 0x8771f681); OP(H, c, d, a, b, 11, 16, 0x6d9d6122); OP(H, b, c, d, a, 14, 23, 0xfde5380c); OP(H, a, b, c, d, 1, 4, 0xa4beea44); OP(H, d, a, b, c, 4, 11, 0x4bdecfa9); OP(H, c, d, a, b, 7, 16, 0xf6bb4b60); OP(H, b, c, d, a, 10, 23, 0xbebfbc70); OP(H, a, b, c, d, 13, 4, 0x289b7ec6); OP(H, d, a, b, c, 0, 11, 0xeaa127fa); OP(H, c, d, a, b, 3, 16, 0xd4ef3085); OP(H, b, c, d, a, 6, 23, 0x04881d05); OP(H, a, b, c, d, 9, 4, 0xd9d4d039); OP(H, d, a, b, c, 12, 11, 0xe6db99e5); OP(H, c, d, a, b, 15, 16, 0x1fa27cf8); OP(H, b, c, d, a, 2, 23, 0xc4ac5665); /* Round 4. */ OP(I, a, b, c, d, 0, 6, 0xf4292244); OP(I, d, a, b, c, 7, 10, 0x432aff97); OP(I, c, d, a, b, 14, 15, 0xab9423a7); OP(I, b, c, d, a, 5, 21, 0xfc93a039); OP(I, a, b, c, d, 12, 6, 0x655b59c3); OP(I, d, a, b, c, 3, 10, 0x8f0ccc92); OP(I, c, d, a, b, 10, 15, 0xffeff47d); OP(I, b, c, d, a, 1, 21, 0x85845dd1); OP(I, a, b, c, d, 8, 6, 0x6fa87e4f); OP(I, d, a, b, c, 15, 10, 0xfe2ce6e0); OP(I, c, d, a, b, 6, 15, 0xa3014314); OP(I, b, c, d, a, 13, 21, 0x4e0811a1); OP(I, a, b, c, d, 4, 6, 0xf7537e82); OP(I, d, a, b, c, 11, 10, 0xbd3af235); OP(I, c, d, a, b, 2, 15, 0x2ad7d2bb); OP(I, b, c, d, a, 9, 21, 0xeb86d391); ctx->a += a; ctx->b += b; ctx->c += c; ctx->d += d; } /* * Public API. */ void md5_reset(struct md5_ctx *ctx) { ctx->nbytes = 0; ctx->a = 0x67452301; ctx->b = 0xefcdab89; ctx->c = 0x98badcfe; ctx->d = 0x10325476; } void md5_update(struct md5_ctx *ctx, const void *data, unsigned int len) { unsigned int n; const uint8_t *ptr = data; uint8_t *buf = (uint8_t *)ctx->buf; while (len > 0) { n = MD5_BLOCK_LENGTH - bufpos(ctx); if (n > len) n = len; memcpy(buf + bufpos(ctx), ptr, n); ptr += n; len -= n; ctx->nbytes += n; if (bufpos(ctx) == 0) { swap_words(ctx->buf, 16); md5_mix(ctx, ctx->buf); } } } void md5_final(uint8_t *dst, struct md5_ctx *ctx) { static const uint8_t padding[MD5_BLOCK_LENGTH] = { 0x80 }; uint64_t final_len = ctx->nbytes * 8; int pad_len, pos = bufpos(ctx); /* add padding */ pad_len = MD5_BLOCK_LENGTH - 8 - pos; if (pad_len <= 0) pad_len += MD5_BLOCK_LENGTH; md5_update(ctx, padding, pad_len); /* add length directly */ swap_words(ctx->buf, 14); ctx->buf[14] = final_len; ctx->buf[15] = final_len >> 32; /* final result */ md5_mix(ctx, ctx->buf); le32enc(dst + 0, ctx->a); le32enc(dst + 4, ctx->b); le32enc(dst + 8, ctx->c); le32enc(dst + 12, ctx->d); } pgbouncer-1.5.4/lib/usual/statlist.h0000644000175000017500000001007511665176410014357 00000000000000/* * Wrapper for list.h that keeps track of number of items. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Circular list that keep track of stats about the list. * * Currenly only count of abjects currently in list * is kept track of. The plan was to track more, * like max, but it was not useful enough. */ #ifndef _USUAL_STATLIST_H_ #define _USUAL_STATLIST_H_ #include /** * Header structure for StatList. */ struct StatList { /** Actual list head */ struct List head; /** Count of objects currently in list */ int cur_count; #ifdef LIST_DEBUG /** List name */ const char *name; #endif }; /** Define and initialize StatList head */ #ifdef LIST_DEBUG #define STATLIST(var) struct StatList var = { {&var.head, &var.head}, 0, #var } #else #define STATLIST(var) struct StatList var = { {&var.head, &var.head}, 0 } #endif /** Add to the start of the list */ static inline void statlist_prepend(struct StatList *list, struct List *item) { list_prepend(&list->head, item); list->cur_count++; } /** Add to the end of the list */ static inline void statlist_append(struct StatList *list, struct List *item) { list_append(&list->head, item); list->cur_count++; } /** Remove element from the list */ static inline void statlist_remove(struct StatList *list, struct List *item) { list_del(item); list->cur_count--; //Assert(list->cur_count >= 0); } /** Initialize StatList head */ static inline void statlist_init(struct StatList *list, const char *name) { list_init(&list->head); list->cur_count = 0; #ifdef LIST_DEBUG list->name = name; #endif } /** return number of elements currently in list */ static inline int statlist_count(const struct StatList *list) { //Assert(list->cur_count > 0 || list_empty(&list->head)); return list->cur_count; } /** remove and return first element */ static inline struct List *statlist_pop(struct StatList *list) { struct List *item = list_pop(&list->head); if (item) list->cur_count--; //Assert(list->cur_count >= 0); return item; } /** Return first element */ static inline struct List *statlist_first(const struct StatList *list) { return list_first(&list->head); } /** Return last element */ static inline struct List *statlist_last(const struct StatList *list) { return list_last(&list->head); } /** Is list empty */ static inline bool statlist_empty(const struct StatList *list) { return list_empty(&list->head); } /** Loop over list */ #define statlist_for_each(item, list) list_for_each(item, &((list)->head)) /** Loop over list backwards */ #define statlist_for_each_reverse(item, list) list_for_each_reverse(item, &((list)->head)) /** Loop over list safely, so that elements can be removed during */ #define statlist_for_each_safe(item, list, tmp) list_for_each_safe(item, &((list)->head), tmp) /** Loop over list backwards safely, so that elements can be removed during */ #define statlist_for_each_reverse_safe(item, list, tmp) list_for_each_reverse_safe(item, &((list)->head), tmp) /** Put intem before another */ static inline void statlist_put_before(struct StatList *list, struct List *item, struct List *pos) { list_append(pos, item); list->cur_count++; } /** Put item after another */ static inline void statlist_put_after(struct StatList *list, struct List *item, struct List *pos) { list_prepend(pos, item); list->cur_count++; } #endif /* __LIST_H_ */ pgbouncer-1.5.4/lib/usual/utf8.c0000644000175000017500000000651211665176410013372 00000000000000/* * Low-level UTF8 handling. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #define u8head(c, mask) (((c) & (mask | (mask >> 1))) == mask) #define u8tail(c) u8head(c, 0x80) /* * conservative utf8 decoder * * if invalid char, advance src pointer by one and return * negative byte value. this can be ignored or replaced. */ int utf8_get_char(const char **src_p, const char *_srcend) { uint32_t c; const uint8_t *srcend = (uint8_t *)_srcend; const uint8_t *p = (uint8_t *)(*src_p); /* * 0xxx xxxx -> len=1 * 10xx xxxx -> tail byte * 110x xxxx -> len=2 * 1110 xxxx -> len=3 * 1111 0xxx -> len=4 */ if (p[0] < 0x80) { c = *p++; } else if (u8head(p[0], 0xC0)) { if (p + 2 > srcend) goto eos; if (!u8tail(p[1])) goto bad_enc; c = ((p[0] & 0x1F) << 6) | (p[1] & 0x3F); if (c < 0x80) goto bad_enc; p += 2; } else if (u8head(p[0], 0xE0)) { if (p + 3 > srcend) goto eos; if (!u8tail(p[1]) || !u8tail(p[2])) goto bad_enc; c = ((p[0] & 0x0F) << 12) | ((p[1] & 0x3F) << 6) | (p[2] & 0x3F); if ((c < 0x800) || ((c & 0xF800) == 0xD800)) goto bad_enc; p += 3; } else if (u8head(p[0], 0xF0)) { if (p + 4 > srcend) goto eos; if (!u8tail(p[1]) || !u8tail(p[2]) || !u8tail(p[3])) goto bad_enc; c = ((p[0] & 0x07) << 18) | ((p[1] & 0x3F) << 12) | ((p[2] & 0x3F) << 6) | (p[3] & 0x3F); if (c < 0x10000 || c > 0x10FFFF) goto bad_enc; p += 4; } else { goto bad_enc; } *src_p = (char *)p; return c; bad_enc: eos: c = p[0]; *src_p = (char *)p + 1; return -(int)c; } /* encode one char - skip invalid ones */ bool utf8_put_char(unsigned int c, char **dst_p, const char *dstend) { char *dst = *dst_p; if (c < 0x80) { if (dst + 1 > dstend) goto no_room; *dst++ = c; } else if (c < 0x800) { if (dst + 2 > dstend) goto no_room; *dst++ = 0xC0 | (c >> 6); *dst++ = 0x80 | (c & 0x3F); } else if (c < 0x10000) { if (dst + 3 > dstend) goto no_room; if (c < 0xD800 || c > 0xDFFF) { *dst++ = 0xE0 | (c >> 12); *dst++ = 0x80 | ((c >> 6) & 0x3F); *dst++ = 0x80 | (c & 0x3F); } } else if (c <= 0x10FFFF) { if (dst + 4 > dstend) goto no_room; *dst++ = 0xF0 | (c >> 18); *dst++ = 0x80 | ((c >> 12) & 0x3F); *dst++ = 0x80 | ((c >> 6) & 0x3F); *dst++ = 0x80 | (c & 0x3F); } *dst_p = dst; return true; no_room: return false; } int utf8_char_size(unsigned int c) { if (c < 0x80) return 1; if (c < 0x800) return 2; if (c < 0x10000) return 3; return 4; } int utf8_seq_size(unsigned char b) { if (b < 0x80) return 1; if (b < 0xC2) return 0; if (b < 0xE0) return 2; if (b < 0xF0) return 3; if (b < 0xF5) return 4; return 0; } pgbouncer-1.5.4/lib/usual/logging.h0000644000175000017500000001201611665176410014133 00000000000000/* * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * Logging framework for unix services. * * * Supported outputs: * - syslog * - log file * - stderr * * @section logging_prefix Logging context * * It is possible to pass context info to all logging calls * and later add details to log lines or to filter based on it. * * Each call references 2 macros: * - LOG_CONTEXT_DEF - which can define/call any variables * - LOG_CONTEXT - which should return a pointer variable. * * Later, global callback function \ref logging_prefix_cb * will get this pointer with destination buffer and can either * add more info for log line or tell to skip logging this message. */ #ifndef _USUAL_LOGGING_H_ #define _USUAL_LOGGING_H_ #include /* internal log levels */ enum LogLevel { LG_FATAL = 0, LG_ERROR = 1, LG_WARNING = 2, LG_STATS = 3, LG_INFO = 4, LG_DEBUG = 5, LG_NOISE = 6, }; #ifndef LOG_CONTEXT_DEF /** Example: Prepare dummy context pointer */ #define LOG_CONTEXT_DEF void *_log_ctx = NULL #endif #ifndef LOG_CONTEXT /** Example: Reference dummy context pointer */ #define LOG_CONTEXT _log_ctx #endif /** * Signature for logging_prefix_cb. Return value is either added string length in dst * or negative value to skip logging. */ typedef int (*logging_prefix_fn_t)(enum LogLevel lev, void *ctx, char *dst, unsigned int dstlen); /** * Optional global callback for each log line. * * It can either add info to log message or skip logging it. */ extern logging_prefix_fn_t logging_prefix_cb; /** * Global verbosity level. * * 0 - show only info level msgs (default) * 1 - show debug msgs (log_debug) * 2 - show noise msgs (log_noise) */ extern int cf_verbose; /** * Toggle logging to stderr. Default: 1. * daemon.c turns this off if goes to background */ extern int cf_quiet; /** * Logfile location, default NULL */ extern const char *cf_logfile; /** Syslog on/off */ extern int cf_syslog; /** ident for syslog, if NULL syslog is disabled (default) */ extern const char *cf_syslog_ident; /** Facility name */ extern const char *cf_syslog_facility; /** Max log level for syslog writer */ extern enum LogLevel cf_syslog_level; /** Max log level for logfile writer */ extern enum LogLevel cf_logfile_level; /** Max log level for stderr writer */ extern enum LogLevel cf_stderr_level; /* * Internal API. */ /* non-fatal logging */ void log_generic(enum LogLevel level, void *ctx, const char *s, ...) _PRINTF(3, 4); /* this is also defined in base.h for Assert() */ void log_fatal(const char *file, int line, const char *func, bool show_perror, void *ctx, const char *s, ...) _PRINTF(6, 7); /* * Public API */ /** Log error message */ #define log_error(fmt, args...) do { LOG_CONTEXT_DEF; \ log_generic(LG_ERROR, LOG_CONTEXT, fmt, ## args); \ } while (0) /** Log warning message */ #define log_warning(fmt, args...) do { LOG_CONTEXT_DEF; \ log_generic(LG_WARNING, LOG_CONTEXT, fmt, ## args); \ } while (0) /** Log stats (liveness) message */ #define log_stats(fmt, args...) do { LOG_CONTEXT_DEF; \ log_generic(LG_STATS, LOG_CONTEXT, fmt, ## args); \ } while (0) /** Log info message */ #define log_info(fmt, args...) do { LOG_CONTEXT_DEF; \ log_generic(LG_INFO, LOG_CONTEXT, fmt, ## args); \ } while (0) /** Log debug message */ #define log_debug(fmt, args...) do { LOG_CONTEXT_DEF; \ if (unlikely(cf_verbose > 0)) \ log_generic(LG_DEBUG, LOG_CONTEXT, fmt, ## args); \ } while (0) /** Log debug noise */ #define log_noise(fmt, args...) do { LOG_CONTEXT_DEF; \ if (unlikely(cf_verbose > 1)) \ log_generic(LG_NOISE, LOG_CONTEXT, fmt, ## args); \ } while (0) /** Log and die. It also logs source location */ #define fatal(fmt, args...) do { LOG_CONTEXT_DEF; \ log_fatal(__FILE__, __LINE__, __func__, false, LOG_CONTEXT, fmt, ## args); \ exit(1); } while (0) /** Log strerror and die. Error message also includes strerror(errno) */ #define fatal_perror(fmt, args...) do { LOG_CONTEXT_DEF; \ log_fatal(__FILE__, __LINE__, __func__, true, LOG_CONTEXT, fmt, ## args); \ exit(1); } while (0) /** Less verbose fatal() */ #define die(fmt, args...) do { LOG_CONTEXT_DEF; \ log_generic(LG_FATAL, LOG_CONTEXT, fmt, ## args); \ exit(1); } while (0) /** * Close open logfiles and syslog. * * Useful when rotating log files. */ void reset_logging(void); #endif pgbouncer-1.5.4/lib/usual/mempool.c0000644000175000017500000000346311665176410014156 00000000000000/* * Simple memory pool for variable-length allocations. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include /* * Allows allocation of several variable-sized objects, * freeing them all together. * * ToDo: make it more 'obstack'-like (???) * - free_last * - resize_last * - append */ struct MemPool { struct MemPool *prev; unsigned size; unsigned used; }; void *mempool_alloc(struct MemPool **pool, unsigned size) { struct MemPool *cur = *pool; void *ptr; unsigned nsize; size = ALIGN(size); if (cur && cur->used + size <= cur->size) { ptr = (char *)(cur + 1) + cur->used; cur->used += size; return ptr; } else { nsize = cur ? (2 * cur->size) : 512; while (nsize < size) nsize *= 2; cur = calloc(1, sizeof(*cur) + nsize); if (cur == NULL) return NULL; cur->used = size; cur->size = nsize; cur->prev = *pool; *pool = cur; return (char *)(cur + 1); } } void mempool_destroy(struct MemPool **pool) { struct MemPool *cur, *tmp; if (!pool) return; for (cur = *pool, *pool = NULL; cur; ) { tmp = cur->prev; free(cur); cur = tmp; } } pgbouncer-1.5.4/lib/usual/lookup3.c0000644000175000017500000000267611665176410014107 00000000000000/* * The contents of this file are public domain. * * Based on: lookup3.c, by Bob Jenkins, May 2006, Public Domain. */ /* * Compact version of Bob Jenkins' lookup3.c hash. */ #include #include #define rot(x, k) (((x)<<(k)) | ((x)>>(32-(k)))) #define mix(a, b, c) do { \ a -= c; a ^= rot(c, 4); c += b; \ b -= a; b ^= rot(a, 6); a += c; \ c -= b; c ^= rot(b, 8); b += a; \ a -= c; a ^= rot(c,16); c += b; \ b -= a; b ^= rot(a,19); a += c; \ c -= b; c ^= rot(b, 4); b += a; \ } while (0) #define final(a, b, c) do { \ c ^= b; c -= rot(b,14); \ a ^= c; a -= rot(c,11); \ b ^= a; b -= rot(a,25); \ c ^= b; c -= rot(b,16); \ a ^= c; a -= rot(c, 4); \ b ^= a; b -= rot(a,14); \ c ^= b; c -= rot(b,24); \ } while (0) /* variable length copy of ~6 bytes, avoid call to libc */ static inline void simple_memcpy(void *dst_, const void *src_, size_t len) { const uint8_t *src = src_; uint8_t *dst = dst_; while (len--) *dst++ = *src++; } uint64_t hash_lookup3(const void *data, size_t len) { uint32_t a, b, c; uint32_t buf[3]; const uint8_t *p = data; a = b = c = 0xdeadbeef + len; if (len == 0) goto done; while (len > 12) { memcpy(buf, p, 12); a += buf[0]; b += buf[1]; c += buf[2]; mix(a, b, c); p += 12; len -= 12; } buf[0] = buf[1] = buf[2] = 0; simple_memcpy(buf, p, len); a += buf[0]; b += buf[1]; c += buf[2]; final(a, b, c); done: return ((uint64_t)b << 32) | c; } pgbouncer-1.5.4/lib/usual/regex.c0000644000175000017500000006743511724760261013630 00000000000000/* * Small POSIX-only regex engine. * * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Simple recursive matcher, only features are small size * and POSIX compatibility. * * ERE syntax: . * ^ $ [] [[:cname:]] () {} | + ? * BRE syntax: . * ^ $ [] [[:cname:]] \(\) \{\} \1-9 * * With REG_RELAXED_SYNTAX, following common escapes will be available: * \b\B\d\D\s\S\w\W BRE: \| ERE: \1-9 * * With REG_RELAXED_MATCHING it returns the first match found after applying * leftmost-longest to all elements. It skips the combinatorics to turn it * into guaranteed-longest match. * * Skipped POSIX features: * - collation classes: [[. .]] * - equivalence classes: [[= =]] * - char ranges by locale order: [a-z] (byte order will be used) * - multi-byte chars: UTF-8 */ #include #ifndef USE_SYSTEM_REGEX #include #include #include #include #undef STRICT /* either dynamic or static decision */ #define STRICT (ctx->strict) /* how many regmatch_t can be reported */ #define MAX_GROUPS 128 /* max count we want to store, means 'infinite' for simple atoms */ #define MAX_COUNT 0x7fff /* max count for simple atoms: char, any or class */ #define SIMPLE_MAXCNT(op) (((op)->maxcnt == MAX_COUNT) ? 0x7FFFFFFF : (op)->maxcnt) #define is_word(c) (isalnum(c) || (c) == '_') #ifndef isblank #define isblank usual_isblank static int isblank(int c) { return ((c) == ' ' || (c) == '\t'); } #endif struct Op; struct ExecCtx; struct GMatch; /* Operation type */ enum OpType { /* ops that take count */ OP_CHAR, OP_ANY, OP_CLASS, OP_GROUP, OP_BREF, /* ops that dont take count */ OP_BOL, OP_EOL, OP_WCHANGE, OP_NWCHANGE, OP_GMATCH, OP_FULLMATCH, }; #define NONCOUNT_OPS_START OP_BOL /* regex_t->internal */ struct RegexInt { struct Op *root; struct Op *glist; struct MemPool *pool; int flags; }; /* match function and its setter */ typedef int (*matcher_f)(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm); static void set_op_type(struct Op *op, enum OpType op_type); /* List of tokens to be AND-ed together */ struct AndList { struct AndList *next; struct Op *op_list; }; /* extra data for group Op */ struct GroupData { struct Op *parent; /* parent group or NULL for first group */ struct AndList *or_list;/* alternative AndLists */ struct Op *glist_prev; /* prev group Op */ bool has_refs; /* if bref references it */ }; /* char class data */ struct ClassData { uint32_t bitmap[256 / 32]; }; /* operation data */ struct Op { struct Op *next; matcher_f matcher; uint16_t mincnt; uint16_t maxcnt; uint8_t type; union { uint8_t grp_no; /* OP_GROUP: group nr, 0-toplevel */ char lit; /* OP_CHAR */ uint8_t bref; /* OP_BREF */ }; union { struct ClassData cdata; struct GroupData gdata; }; }; #define OP_BASE (offsetof(struct Op, cdata)) /* * Operations on ClassData */ static bool class_isset(const struct ClassData *cd, unsigned char c) { return cd->bitmap[c / 32] & (1 << (c % 32)); } static void class_set(struct ClassData *cd, unsigned char c) { cd->bitmap[c / 32] |= (1 << (c % 32)); } static void class_negate(struct ClassData *cd) { int i; class_set(cd, 0); for (i = 0; i < 256/32; i++) cd->bitmap[i] ^= -1; } /* * Parsing code */ /* top-level context */ struct ParseCtx { regex_t *rx; struct RegexInt *rxi; struct Op *last_group; struct AndList *last_andlist; struct Op *last_elem; /* last op in current OR branch */ bool gotcnt; /* count was attached to last op */ bool strict; /* strict syntax */ }; static struct AndList *new_andlist(struct ParseCtx *ctx, struct Op *g) { struct AndList *al = mempool_alloc(&ctx->rxi->pool, sizeof(*al)); if (!al) return NULL; if (ctx->last_andlist) { ctx->last_andlist->next = al; } else { g->gdata.or_list = al; } ctx->last_andlist = al; return al; } static struct Op *new_op(struct ParseCtx *ctx, enum OpType t, int extra) { struct Op *op = mempool_alloc(&ctx->rxi->pool, OP_BASE + extra); if (!op) return NULL; set_op_type(op, t); op->mincnt = op->maxcnt = 1; ctx->gotcnt = false; /* append */ if (ctx->last_elem) { ctx->last_elem->next = op; } else if (ctx->last_andlist) { ctx->last_andlist->op_list = op; } else if (ctx->last_group) { struct AndList *alist; alist = new_andlist(ctx, ctx->last_group); if (!alist) return NULL; alist->op_list = op; } ctx->last_elem = op; if (t == OP_GROUP) { struct Op *parent = ctx->last_group; int gno = ++ctx->rx->re_nsub; op->grp_no = gno; op->gdata.parent = parent; op->gdata.glist_prev = ctx->rxi->glist; ctx->rxi->glist = op; ctx->last_group = op; ctx->last_andlist = NULL; ctx->last_elem = NULL; if (!ctx->rxi->root) ctx->rxi->root = op; } return op; } static int op_char(struct ParseCtx *ctx, unsigned c) { struct Op *op = new_op(ctx, OP_CHAR, 0); if (!op) return REG_ESPACE; op->lit = c; if ((ctx->rxi->flags & REG_ICASE) && isalpha(c)) op->lit = tolower(c); return 0; } static int op_bref(struct ParseCtx *ctx, unsigned c) { struct Op *g, *op; op = new_op(ctx, OP_BREF, 0); if (!op) return REG_ESPACE; op->bref = c - '0'; /* check if valid ref */ for (g = ctx->last_group; g; g = g->gdata.parent) { if (g->grp_no == op->bref) return REG_ESUBREG; } /* tag the group as referenced */ for (g = ctx->rxi->glist; g; g = g->gdata.glist_prev) { if (g->grp_no == op->bref) { g->gdata.has_refs = true; return 0; } } return REG_ESUBREG; } static int op_simple(struct ParseCtx *ctx, enum OpType t) { struct Op *op = new_op(ctx, t, 0); if (!op) return REG_ESPACE; return 0; } static int op_count_simple(struct ParseCtx *ctx, int min, int max) { struct Op *op = ctx->last_elem; if (!op || ctx->gotcnt) return REG_BADRPT; if (op->type >= NONCOUNT_OPS_START) return REG_BADRPT; ctx->gotcnt = true; op->mincnt = min; op->maxcnt = max; return 0; } static int op_count_full(struct ParseCtx *ctx, const char **re) { unsigned a, b; char *end = (char *)*re; bool ext = ctx->rxi->flags & REG_EXTENDED; int err; /* apply sanity check */ err = op_count_simple(ctx, 1, 1); if (err) return err; /* parse */ a = b = strtoul(*re, &end, 10); if (end == *re) return REG_EBRACE; if (*end == ',') { *re = end + 1; end = (char*)*re; b = strtoul(*re, &end, 10); if (end == *re) b = MAX_COUNT; } if (a > b || b > MAX_COUNT || a >= MAX_COUNT) return REG_BADBR; /* check for correct termination */ if (ext && end[0] == '}') { *re = end + 1; goto done; } else if (!ext && end[0] == '\\' && end[1] == '}') { *re = end + 2; goto done; } /* bad fmt, decide between error codes */ for (a = 0; end[a] && a < 5; a++) { if (end[a] == '}') return REG_BADBR; } return REG_EBRACE; done: ctx->last_elem->mincnt = a; ctx->last_elem->maxcnt = b; return 0; } static int op_gstart(struct ParseCtx *ctx) { struct Op *op; op = new_op(ctx, OP_GROUP, sizeof(struct GroupData)); if (!op) return REG_ESPACE; if (op->grp_no >= MAX_GROUPS) return REG_BADPAT; return 0; } static int finish_branch(struct ParseCtx *ctx) { int err; /* disallow empty OR fragments, but not empty groups */ if (!ctx->last_elem && ctx->last_andlist && STRICT) return REG_BADPAT; if (ctx->last_group->gdata.parent) err = op_simple(ctx, OP_GMATCH); else err = op_simple(ctx, OP_FULLMATCH); if (err) return err; ctx->last_elem = NULL; return 0; } static int op_gend(struct ParseCtx *ctx) { struct Op *op = ctx->last_group; struct AndList *alist; int err; if (!op) return REG_EPAREN; err = finish_branch(ctx); if (err) return err; ctx->last_group = op->gdata.parent; ctx->last_elem = op; /* recover previous andlist... */ alist = ctx->last_group->gdata.or_list; while (alist && alist->next) alist = alist->next; ctx->last_andlist = alist; return 0; } static int op_or(struct ParseCtx *ctx) { struct Op *gop = ctx->last_group; struct AndList *alist; int err; /* disallow empty OR branches */ if (!ctx->last_elem && STRICT) return REG_BADPAT; /* start new branch */ err = finish_branch(ctx); if (err) return err; alist = new_andlist(ctx, gop); if (!alist) return REG_ESPACE; ctx->last_andlist = alist; ctx->last_elem = NULL; return 0; } /* * Parse bracketed classes. */ static void add_char(struct ClassData *cd, unsigned char c, bool icase) { if (icase && isalpha(c)) { class_set(cd, tolower(c)); class_set(cd, toupper(c)); } else { class_set(cd, c); } } struct NamedClass { const char name[7]; unsigned char name_len; int (*check_func)(int c); }; static const struct NamedClass ctype_list[] = { { "alnum", 5, isalnum }, { "alpha", 5, isalpha }, { "blank", 5, isblank }, { "cntrl", 5, iscntrl }, { "digit", 5, isdigit }, { "graph", 5, isgraph }, { "lower", 5, islower }, { "print", 5, isprint }, { "punct", 5, ispunct }, { "space", 5, isspace }, { "upper", 5, isupper }, { "xdigit", 6, isxdigit }, }; static int fill_class(struct ClassData *cd, const char *name, const char **s_p, bool icase) { unsigned c; const struct NamedClass *cc = ctype_list; for (c = 0; c < ARRAY_NELEM(ctype_list); c++) { cc = ctype_list + c; if (strncmp(name, cc->name, cc->name_len) != 0) continue; name += cc->name_len; if (name[0] == ':' && name[1] == ']') goto found; break; } return *name ? REG_ECTYPE : REG_EBRACK; found: /* fill map */ for (c = 1; c < 256; c++) { if (cc->check_func(c)) add_char(cd, c, icase); } *s_p = name + 2; return 0; } #define MAP_RANGE 0x7FFF0001 #define MAP_END 0x7FFF0002 #define MAP_OTHER 0x7FFF0003 static int get_map_token(struct ParseCtx *ctx, const char **s_p, unsigned *dst_p, bool start, struct ClassData *cd, bool icase) { const char *s = *s_p; unsigned res; if (*s == '-') { if (start || s[1] == ']') res = '-'; else res = MAP_RANGE; s += 1; } else if (*s == ']' && !start) { res = MAP_END; s++; } else if (*s == '[' && (s[1] == '.' || s[1] == ':' || s[1] == '=')) { if (s[1] == ':') { s += 2; *dst_p = MAP_OTHER; return fill_class(cd, s, s_p, icase); } return REG_BADPAT; } else { res = (unsigned char)*s++; } *dst_p = res; *s_p = s; return 0; } static int op_class(struct ParseCtx *ctx, const char **re) { const char *s = *re; struct ClassData *cd; struct Op *op; bool not = false, icase = ctx->rxi->flags & REG_ICASE; const char *start; unsigned tk, c, prevtk = 0; bool is_range = false; int err; if (*s == '^') { s++; not = true; } start = s; op = new_op(ctx, OP_CLASS, sizeof(struct ClassData)); if (!op) return REG_ESPACE; cd = &op->cdata; if (not && (ctx->rxi->flags & REG_NEWLINE)) class_set(cd, '\n'); while (*s) { err = get_map_token(ctx, &s, &tk, s == start, cd, icase); if (err) return err; if (tk == MAP_END) { if (prevtk) add_char(cd, prevtk, icase); goto done; } else if (tk == MAP_OTHER) { if (is_range) return REG_ERANGE; if (prevtk) add_char(cd, prevtk, icase); prevtk = 0; } else if (tk == MAP_RANGE) { if (!prevtk) return REG_ERANGE; is_range = true; } else if (is_range) { if (tk < prevtk) return REG_ERANGE; for (c = prevtk; c <= tk; c++) add_char(cd, c, icase); is_range = false; prevtk = 0; } else { if (prevtk) add_char(cd, prevtk, icase); prevtk = tk; } } return REG_EBRACK; done: *re = s; if (not) class_negate(cd); return 0; } static int op_class_const(struct ParseCtx *ctx, const char *def) { const char *p = def + 1; return op_class(ctx, &p); } /* * Top-level syntax */ static int parse_relaxed_escapes(struct ParseCtx *ctx, char c) { if (STRICT) return REG_BADPAT; switch (c) { case 'b': return op_simple(ctx, OP_WCHANGE); case 'B': return op_simple(ctx, OP_NWCHANGE); case 'w': return op_class_const(ctx, "[_[:alnum:]]"); case 'W': return op_class_const(ctx, "[^_[:alnum:]]"); case 'd': return op_class_const(ctx, "[[:digit:]]"); case 'D': return op_class_const(ctx, "[^[:digit:]]"); case 's': return op_class_const(ctx, "[[:space:]]"); case 'S': return op_class_const(ctx, "[^[:space:]]"); } return REG_BADPAT; } static int parse_posix_ext(struct ParseCtx *ctx, const char *re) { int err = 0; unsigned c; int glevel = 0; loop: if (err) return err; c = *re++; switch (c) { case 0: return (glevel == 0) ? 0 : REG_EPAREN; case '(': glevel++; err = op_gstart(ctx); break; case ')': if (glevel > 0) { glevel--; err = op_gend(ctx); } else { err = op_char(ctx, c); /* POSIX bug */ } break; case '|': err = op_or(ctx); break; case '*': err = op_count_simple(ctx, 0, MAX_COUNT); break; case '?': err = op_count_simple(ctx, 0, 1); break; case '+': err = op_count_simple(ctx, 1, MAX_COUNT); break; case '[': err = op_class(ctx, &re); break; case '{': err = op_count_full(ctx, &re); break; case '.': err = op_simple(ctx, OP_ANY); break; case '^': err = op_simple(ctx, OP_BOL); break; case '$': err = op_simple(ctx, OP_EOL); break; case '\\': goto escaped; default: err = op_char(ctx, c); } goto loop; escaped: c = *re++; if (c == 0) err = REG_EESCAPE; else if (c >= '0' && c <= '9') err = STRICT ? REG_BADPAT : op_bref(ctx, c); else if (isalpha(c)) err = parse_relaxed_escapes(ctx, c); else err = op_char(ctx, c); goto loop; } static int parse_posix_basic(struct ParseCtx *ctx, const char *re) { int err = 0; unsigned c; int glevel = 0; loop: if (err) return err; c = *re++; switch (c) { case 0: return (glevel == 0) ? 0 : REG_EPAREN; case '*': if (ctx->last_elem && ctx->last_elem->type != OP_BOL) err = op_count_simple(ctx, 0, MAX_COUNT); else err = op_char(ctx, '*'); break; case '.': err = op_simple(ctx, OP_ANY); break; case '[': err = op_class(ctx, &re); break; case '^': if (!ctx->last_elem) err = op_simple(ctx, OP_BOL); else err = op_char(ctx, c); break; case '$': if (!*re || (re[0] == '\\' && re[1] == ')')) err = op_simple(ctx, OP_EOL); else err = op_char(ctx, c); break; case '\\': goto escaped; default: err = op_char(ctx, c); } goto loop; escaped: c = *re++; switch (c) { case 0: return REG_EESCAPE; case '(': glevel++; err = op_gstart(ctx); break; case ')': glevel--; if (glevel < 0) return REG_EPAREN; err = op_gend(ctx); break; case '{': err = op_count_full(ctx, &re); break; case '.': case '^': case '$': case '*': case '[': case ']': case '\\': err = op_char(ctx, c); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': err = op_bref(ctx, c); break; case '|': err = STRICT ? REG_BADPAT : op_or(ctx); break; default: err = parse_relaxed_escapes(ctx, c); } goto loop; } /* * Public compiling API. */ int regcomp(regex_t *rx, const char *re, int flags) { struct ParseCtx ctx; struct RegexInt *rxi; int err; struct MemPool *pool = NULL; /* do it first, to allow regfree() */ memset(rx, 0, sizeof(*rx)); if (flags & ~(REG_EXTENDED | REG_ICASE | REG_NOSUB | REG_NEWLINE | REG_RELAXED)) return REG_BADPAT; if (!*re) return REG_BADPAT; rxi = mempool_alloc(&pool, sizeof(*rxi)); if (!rxi) return REG_ESPACE; rx->internal = rxi; rxi->pool = pool; /* initialize rx and local context */ memset(&ctx, 0, sizeof(ctx)); ctx.rx = rx; ctx.rxi = rxi; ctx.strict = !(flags & REG_RELAXED_SYNTAX); rxi->flags = flags; /* setup group #0 */ rx->re_nsub = -1; err = op_gstart(&ctx); if (err) goto failed; /* launch proper parser */ if (flags & REG_EXTENDED) err = parse_posix_ext(&ctx, re); else err = parse_posix_basic(&ctx, re); /* finalize group #0 */ if (!err) err = finish_branch(&ctx); /* relax if details are not needed */ if (flags & REG_NOSUB) { rxi->flags |= REG_RELAXED_MATCHING; rx->re_nsub = 0; } failed: /* clean up if problems */ if (err) regfree(rx); return err; } /* * Matching code */ /* historical best match */ struct HMatch { const char *hist_start; const char *hist_end; int rep_len; /* if repeated seq, full len thus far */ }; /* per-group-match context */ struct GMatch { struct GMatch *parent; /* parent group */ const struct Op *owner; /* Op for this group */ const char *start; /* match start */ const char *end; /* match end, NULL if no match */ struct GMatch *prevgm; /* older stack entry */ struct HMatch hm_next; /* best match for following stack entry */ int count; /* match nr in repeated seq */ }; /* top context */ struct ExecCtx { const regex_t *rx; const struct RegexInt *rxi; const char *str_start; regmatch_t *pmatch; int nmatch; int flags; bool strict; const char *last_endpos; struct HMatch hm_first[MAX_GROUPS]; struct GMatch *gm_stack[MAX_GROUPS]; struct GMatch *gm_cache[MAX_GROUPS]; }; static void push_gm(struct ExecCtx *ctx, struct GMatch *gm) { int gno = gm->owner->grp_no; gm->prevgm = ctx->gm_stack[gno]; ctx->gm_stack[gno] = gm; } static void pop_gm(struct ExecCtx *ctx, struct GMatch *gm) { int gno = gm->owner->grp_no; ctx->gm_stack[gno] = gm->prevgm; } static inline int do_match(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm) { return op->matcher(ctx, op, str, gm); } static int scan_next(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm, int curcnt, int alen) { int err = REG_NOMATCH; bool gotmatch = false; if (curcnt == op->mincnt) return do_match(ctx, op->next, str, gm); for (; curcnt >= op->mincnt; curcnt--) { err = do_match(ctx, op->next, str, gm); if (STRICT && err == 0) gotmatch = true; else if (err != REG_NOMATCH) break; str -= alen; } if (err == REG_NOMATCH && gotmatch) err = 0; return err; } static int match_char(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm) { bool icase = (ctx->flags & REG_ICASE); int c, i, maxcnt = SIMPLE_MAXCNT(op); for (i = 0; (i < maxcnt) && str[i]; i++) { c = icase ? tolower((unsigned char)str[i]) : str[i]; if (c != op->lit) break; } return scan_next(ctx, op, str + i, gm, i, 1); } static int match_any(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm) { bool nl = (ctx->flags & REG_NEWLINE); int i, maxcnt = SIMPLE_MAXCNT(op); for (i = 0; (i < maxcnt) && str[i]; i++) { if (nl && str[i] == '\n') break; } return scan_next(ctx, op, str + i, gm, i, 1); } static int match_class(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm) { int i, maxcnt = SIMPLE_MAXCNT(op); for (i = 0; (i < maxcnt); i++) { if (!class_isset(&op->cdata, str[i])) break; } return scan_next(ctx, op, str + i, gm, i, 1); } static int match_bol(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm) { if (str == ctx->str_start && !(ctx->flags & REG_NOTBOL)) return do_match(ctx, op->next, str, gm); else if (str != ctx->str_start && str[-1] == '\n' && (ctx->flags & REG_NEWLINE)) return do_match(ctx, op->next, str, gm); return REG_NOMATCH; } static int match_eol(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm) { if (*str == '\n' && (ctx->flags & REG_NEWLINE)) return do_match(ctx, op->next, str, gm); else if (*str == 0 && !(ctx->flags & REG_NOTEOL)) return do_match(ctx, op->next, str, gm); return REG_NOMATCH; } static int match_wchange(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm) { bool prevw = (str == ctx->str_start) ? false : is_word(str[-1]); bool curw = is_word(str[0]); bool ischange = prevw ^ curw; if ((op->type == OP_WCHANGE) ? ischange : !ischange) return do_match(ctx, op->next, str, gm); return REG_NOMATCH; } static int match_bref(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm) { bool icase = ctx->flags & REG_ICASE; int i; struct GMatch *bgm = ctx->gm_stack[op->bref]; int blen = (bgm && bgm->end) ? (bgm->end - bgm->start) : -1; /* handle no-match, zero-len, zero-count */ if (blen < 0 && op->mincnt > 0) return REG_NOMATCH; if (blen <= 0 || op->maxcnt == 0) return do_match(ctx, op->next, str, gm); /* find max matches */ for (i = 0; (i < op->maxcnt) && *str; i++) { if (icase && strncasecmp(str, bgm->start, blen) != 0) break; else if (!icase && strncmp(str, bgm->start, blen) != 0) break; str += blen; } return scan_next(ctx, op, str, gm, i, blen); } static int match_group(struct ExecCtx *ctx, const struct Op *op, const char *str, struct GMatch *gm) { int err = REG_NOMATCH; bool gotmatch = false; struct GMatch gthis; /* per-group-match context */ memset(>his, 0, sizeof(gthis)); gthis.owner = op; gthis.start = str; gthis.parent = gm; if (gm && gm->owner == op) { gthis.parent = gm->parent; gthis.count = gm->count + 1; } gm = >his; push_gm(ctx, gm); if (op->maxcnt > 0) { struct AndList *alist = op->gdata.or_list; /* check all branches, unless relaxed matching */ while (alist) { err = do_match(ctx, alist->op_list, str, gm); if (err == 0 && STRICT) { gm->end = NULL; gotmatch = true; } else if (err != REG_NOMATCH) break; alist = alist->next; } } /* is no-match allowed? */ if ((op->mincnt == 0) && (gm->count == 0) && (err == REG_NOMATCH || (err == 0 && STRICT))) { gm->end = NULL; err = do_match(ctx, op->next, str, gm->parent); } pop_gm(ctx, gm); return gotmatch ? 0 : err; } static int match_gend(struct ExecCtx *ctx, const struct Op *f_op, const char *str, struct GMatch *gm) { int err = REG_NOMATCH; const struct Op *op = gm->owner; bool zeromatch = (str == gm->start); bool gotmatch = false; /* ignore follow-up empty matches, unless it has backrefs */ if (zeromatch && gm->count > 0 && gm->count >= op->mincnt && !gm->owner->gdata.has_refs) return REG_NOMATCH; /* tag as matched */ gm->end = str; /* try more repeats, stop if count full or last match was zero-length */ if (gm->count + 1 < op->maxcnt && !zeromatch) { err = match_group(ctx, op, str, gm); if (err == 0 && STRICT) gotmatch = true; else if (err != REG_NOMATCH) return err; } /* fail if not enough repeats */ if (!zeromatch && gm->count + 1 < op->mincnt) return err; /* continue with parent branch */ err = do_match(ctx, op->next, str, gm->parent); if (err == REG_NOMATCH && gotmatch) err = 0; return err; } /* * The juice of POSIX - match weighting. */ static int gmatch_hist_cmp(struct ExecCtx *ctx, int gno, struct GMatch *gm, int replen) { struct HMatch *hm = (gm->prevgm) ? &gm->prevgm->hm_next : &ctx->hm_first[gno]; int gmlen = (gm->end) ? (gm->end - gm->start) : -1; int hmlen = (hm->hist_end) ? (hm->hist_end - hm->hist_start) : -1; int gmreplen = (gmlen >= 0) ? (gmlen + replen) : replen; int hmreplen = ((hmlen >= 0) ? hmlen : 0) + hm->rep_len; int gmofs = (gm->end) ? (gm->start - ctx->str_start) : -1; int hmofs = (hm->hist_start) ? (hm->hist_start - ctx->str_start) : -1; /* prefer rightmost match, to allow preceding elements match more */ int res = (gmofs - hmofs); /* prefer longer repeated match */ if (res == 0 && gm->count == 0) res = (gmreplen - hmreplen); /* prefer longer single match */ if (res == 0) res = (gmlen - hmlen); return res; } static int cmp_gmatches(struct ExecCtx *ctx, int gno, struct GMatch *gm, int replen) { int cmp = 0, gmlen; if (gm) { /* need to compare preceding groups first */ gmlen = gm->end ? gm->end - gm->start : 0; cmp = cmp_gmatches(ctx, gno, gm->prevgm, (gm->count == 0) ? 0 : (replen + gmlen)); /* actual comparision */ if (!cmp) cmp = gmatch_hist_cmp(ctx, gno, gm, replen); } return cmp; } static int gm_resolve_tie(struct ExecCtx *ctx, int gno) { struct GMatch *gm = ctx->gm_stack[gno]; if (!gm) /* 0-count match is better than no match */ return ctx->hm_first[gno].hist_start ? -1 : 0; return cmp_gmatches(ctx, gno, gm, 0); } static void fill_history(struct ExecCtx *ctx, int gno) { struct HMatch *hm; int gmlen, rep_len = 0; struct GMatch *gm = ctx->gm_stack[gno]; while (STRICT && gm) { hm = (gm->prevgm) ? &gm->prevgm->hm_next : &ctx->hm_first[gno]; hm->hist_start = gm->start; hm->hist_end = gm->end; hm->rep_len = rep_len; gmlen = gm->end ? (gm->end - gm->start) : 0; rep_len += gmlen; if (gm->count == 0) rep_len = 0; gm = gm->prevgm; } } static void publish_gm(struct ExecCtx *ctx, int gno) { struct GMatch *gm = ctx->gm_stack[gno]; regmatch_t *rm = ctx->pmatch + gno; /* ignore non-matches */ while (gm && !gm->end) gm = gm->prevgm; /* require it to be inside reported parent */ if (gm && gm->parent) { int pno = gm->parent->owner->grp_no; if (gm->parent != ctx->gm_cache[pno]) gm = NULL; } ctx->gm_cache[gno] = gm; /* publish new match */ if (gm) { rm->rm_so = gm->start - ctx->str_start; rm->rm_eo = gm->end - ctx->str_start; } else { rm->rm_so = -1; rm->rm_eo = -1; } } /* compare and publish */ static int got_full_match(struct ExecCtx *ctx, const struct Op *f_op, const char *str, struct GMatch *gm) { int gno, cmp; /* tag group as matched */ gm->end = str; /* ignore shorter matches */ if (ctx->last_endpos && str < ctx->last_endpos) return 0; /* longer or equal length */ if (str > ctx->last_endpos) { ctx->last_endpos = str; goto better_match; } else if (STRICT && ctx->nmatch > 1) { for (gno = 0; gno < ctx->nmatch; gno++) { cmp = gm_resolve_tie(ctx, gno); if (cmp < 0) break; if (cmp > 0) goto better_match; } } return 0; better_match: for (gno = 0; gno < ctx->nmatch; gno++) { publish_gm(ctx, gno); fill_history(ctx, gno); } return 0; } /* fill in proper matcher */ static void set_op_type(struct Op *op, enum OpType op_type) { static const matcher_f mlist[] = { match_char, match_any, match_class, match_group, match_bref, match_bol, match_eol, match_wchange, match_wchange, match_gend, got_full_match }; op->matcher = mlist[op_type]; op->type = op_type; } /* * Public matching API */ int regexec(const regex_t *rx, const char *str, size_t nmatch, regmatch_t pmatch[], int eflags) { int err; struct ExecCtx ctx; if (eflags & ~(REG_NOTBOL | REG_NOTEOL)) return REG_BADPAT; /* init local context */ memset(&ctx, 0, sizeof(ctx)); ctx.pmatch = pmatch; ctx.nmatch = nmatch; ctx.str_start = str; ctx.rx = rx; ctx.rxi = rx->internal; ctx.flags = ctx.rxi->flags | eflags; /* reset pmatch area */ if (!(ctx.flags & REG_NOSUB)) memset(pmatch, -1, nmatch * sizeof(regmatch_t)); /* decide pmatch area that will be used */ if (!pmatch || (ctx.flags & REG_NOSUB)) ctx.nmatch = 0; else if (nmatch > (size_t)rx->re_nsub + 1) ctx.nmatch = rx->re_nsub + 1; ctx.strict = !(ctx.flags & REG_RELAXED_MATCHING) && (ctx.nmatch > 0); /* execute search */ str--; do { str++; err = do_match(&ctx, ctx.rxi->root, str, NULL); } while ((err == REG_NOMATCH) && *str); return err; } /* * Free parse tree */ void regfree(regex_t *rx) { struct RegexInt *rxi; if (rx) { rxi = rx->internal; if (rxi) mempool_destroy(&rxi->pool); memset(rx, 0, sizeof(*rx)); } } /* * Error strings */ size_t regerror(int err, const regex_t *rx, char *dst, size_t dstlen) { static const char errlist[][9] = { "NOERROR", /* 0 */ "NOMATCH", /* 1 */ "BADBR", /* 2 */ "BADPAT", /* 3 */ "BADRPT", /* 4 */ "EBRACE", /* 5 */ "EBRACK", /* 6 */ "ECOLLATE", /* 7 */ "ECTYPE", /* 8 */ "EESCAPE", /* 9 */ "EPAREN", /* 10 */ "ERANGE", /* 11 */ "ESPACE", /* 12 */ "ESUBREG", /* 13 */ }; const char *s = "EUNKNOWN"; if ((size_t)err < ARRAY_NELEM(errlist)) s = errlist[err]; return snprintf(dst, dstlen, "%s", s); } #endif /* !USE_SYSTEM_REGEX */ pgbouncer-1.5.4/lib/usual/signal.h0000644000175000017500000000503411724760261013763 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * Signals compat. * * general * - sigaction() -> signal() * * win32: * - SIGALRM, alarm(), signal(SIGALRM), sigaction(SIGALRM) * - kill(pid, 0) */ #ifndef _USUAL_SIGNAL_H_ #define _USUAL_SIGNAL_H_ #include #include /* * Compat sigval, detect based on siginfo_t.si_code. */ #if !defined(SI_QUEUE) && !defined(HAVE_SIGQUEUE) union sigval { int sival_int; void *sival_ptr; }; #endif /* * Compat sigevent */ #ifndef SIGEV_NONE #define SIGEV_NONE 0 #define SIGEV_SIGNAL 1 #define SIGEV_THREAD 2 struct sigevent { int sigev_notify; int sigev_signo; union sigval sigev_value; void (*sigev_notify_function)(union sigval); }; #endif /* * Compat sigaction() */ #ifndef HAVE_SIGACTION #define SA_SIGINFO 1 #define SA_RESTART 2 typedef struct siginfo_t siginfo_t; struct sigaction { union { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); }; int sa_flags; int sa_mask; }; #define sigemptyset(s) #define sigfillset(s) #define sigaddset(s, sig) #define sigdelset(s, sig) #define sigaction(a,b,c) compat_sigaction(a,b,c) int sigaction(int sig, const struct sigaction *sa, struct sigaction *old); #endif /* * win32 compat: * kill(), alarm, SIGALRM */ #ifdef WIN32 #define SIGALRM 1023 #define SIGBUS 1022 unsigned alarm(unsigned); int kill(int pid, int sig); typedef void (*_sighandler_t)(int); static inline _sighandler_t wrap_signal(int sig, _sighandler_t func) { /* sigaction has custom handling for SIGALRM */ if (sig == SIGALRM) { struct sigaction sa, oldsa; sa.sa_handler = func; sa.sa_flags = sa.sa_mask = 0; sigaction(SIGALRM, &sa, &oldsa); return oldsa.sa_handler; } else if (sig == SIGBUS) { return NULL; } return signal(sig, func); } #define signal(a,b) wrap_signal(a,b) #endif #endif pgbouncer-1.5.4/lib/usual/pgutil.c0000644000175000017500000001141711665176410014010 00000000000000/* * Some utility functions for Postgres. * * - Literal & ident quoting. * - Array parsing */ #include #include /* str -> E'str' */ bool pg_quote_literal(char *_dst, const char *_src, int dstlen) { char *dst = _dst; char *end = _dst + dstlen - 2; const char *src = _src; bool stdquote = true; if (dstlen < 3) return false; if (_src == NULL) { if (dstlen < 5) return false; memcpy(_dst, "NULL", 5); return true; } retry: *dst++ = '\''; while (*src && dst < end) { if (*src == '\'') *dst++ = '\''; else if (*src == '\\') { if (stdquote) goto retry_ext; *dst++ = '\\'; } *dst++ = *src++; } if (*src || dst > end) return false; *dst++ = '\''; *dst = 0; return true; retry_ext: /* string contains '\\', retry as E'' string */ dst = _dst; src = _src; *dst++ = 'E'; stdquote = false; goto retry; } static inline bool id_start(unsigned char c) { return (c >= 'a' && c <= 'z') || c == '_'; } static inline bool id_body(unsigned char c) { return id_start(c) || (c >= '0' && c <= '9'); } /* ident -> "ident" */ bool pg_quote_ident(char *_dst, const char *_src, int dstlen) { char *dst = _dst; char *end = _dst + dstlen - 1; const char *src = _src; if (dstlen < 1) return false; if (!id_start(*src)) goto needs_quoting; while (*src && dst < end) { if (!id_body(*src)) goto needs_quoting; *dst++ = *src++; } if (*src) return false; *dst = 0; if (!pg_is_reserved_word(_dst)) return true; needs_quoting: dst = _dst; src = _src; end = _dst + dstlen - 2; if (dstlen < 3) return false; *dst++ = '"'; while (*src && dst < end) { if (*src == '"') *dst++ = *src; *dst++ = *src++; } if (*src) return false; *dst++ = '"'; *dst = 0; return true; } /* schema.name -> "schema"."name" */ bool pg_quote_fqident(char *_dst, const char *_src, int dstlen) { const char *dot = strchr(_src, '.'); char scmbuf[128]; const char *scm; int scmlen; if (dot) { scmlen = dot - _src; if (scmlen >= (int)sizeof(scmbuf)) return false; memcpy(scmbuf, _src, scmlen); scmbuf[scmlen] = 0; scm = scmbuf; _src = dot + 1; } else { scm = "public"; } if (!pg_quote_ident(_dst, scm, dstlen)) return false; scmlen = strlen(_dst); _dst[scmlen] = '.'; _dst += scmlen + 1; dstlen -= scmlen + 1; if (!pg_quote_ident(_dst, _src, dstlen)) return false; return true; } /* * pgarray parsing */ static bool parse_value(struct StrList *arr, const char *val, const char *vend, CxMem *cx) { int len; const char *s; char *str, *p; unsigned c; while (val < vend && isspace(*val)) val++; while (vend > val && isspace(vend[-1])) vend--; if (val == vend) return false; s = val; len = vend - val; if (len == 4 && !strncasecmp(val, "null", len)) { return strlist_append_ref(arr, NULL); } p = str = cx_alloc(cx, len + 1); if (!str) return false; /* unquote & copy */ while (s < vend) { c = *s++; if (c == '"') { while (1) { c = *s++; if (c == '"') break; else if (c == '\\') *p++ = *s++; else *p++ = c; } } else if (c == '\\') { *p++ = *s++; } else *p++ = c; } *p++ = 0; if (!strlist_append_ref(arr, str)) { cx_free(cx, str); return false; } return true; } struct StrList *pg_parse_array(const char *pgarr, CxMem *cx) { const char *s = pgarr; struct StrList *lst; const char *val = NULL; unsigned c; /* skip dimension def "[x,y]={..}" */ if (*s == '[') { s = strchr(s, ']'); if (!s || s[1] != '=') return NULL; s += 2; } if (*s++ != '{') return NULL; lst = strlist_new(cx); if (!lst) return NULL; while (*s) { /* array end */ if (s[0] == '}') { if (s[1] != 0) { goto failed; } if (val) { if (!parse_value(lst, val, s, cx)) goto failed; } return lst; } /* cannot init earlier to support empty arrays */ if (!val) val = s; /* val done? */ if (*s == ',') { if (!parse_value(lst, val, s, cx)) goto failed; val = ++s; continue; } /* scan value */ c = *s++; if (c == '"') { while (1) { c = *s++; if (c == '"') break; else if (c == '\\') { if (!*s) goto failed; s++; } else if (!*s) goto failed; } } else if (c == '\\') { if (!*s) goto failed; s++; } } if (s[-1] != '}') goto failed; return lst; failed: strlist_free(lst); return NULL; } /* * Postgres keyword lookup. */ /* gperf tries ot inline a non-static function. */ #undef inline #undef __inline #undef __attribute__ #define inline #define __inline #define __attribute__(x) #define long uintptr_t /* include gperf code */ const char *pg_keyword_lookup_real(const char *str, unsigned int len); #include bool pg_is_reserved_word(const char *str) { const char *kw = pg_keyword_lookup_real(str, strlen(str)); return kw != NULL; } pgbouncer-1.5.4/lib/usual/time.c0000644000175000017500000001020211665176410013431 00000000000000/* * Common time functions. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include char *format_time_ms(usec_t time, char *dst, unsigned dstlen) { struct tm *tm, tmbuf; struct timeval tv; time_t sec; if (!time) { gettimeofday(&tv, NULL); } else { tv.tv_sec = time / USEC; tv.tv_usec = time % USEC; } sec = tv.tv_sec; tm = localtime_r(&sec, &tmbuf); snprintf(dst, dstlen, "%04d-%02d-%02d %02d:%02d:%02d.%03d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000)); return dst; } char *format_time_s(usec_t time, char *dst, unsigned dstlen) { time_t s; struct tm tbuf, *tm; if (!time) { struct timeval tv; gettimeofday(&tv, NULL); s = tv.tv_sec; } else { s = time / USEC; } tm = localtime_r(&s, &tbuf); snprintf(dst, dstlen, "%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return dst; } /* read current time */ usec_t get_time_usec(void) { struct timeval tv; gettimeofday(&tv, NULL); return (usec_t)tv.tv_sec * USEC + tv.tv_usec; } static usec_t _time_cache; /* read cached time */ usec_t get_cached_time(void) { if (!_time_cache) _time_cache = get_time_usec(); return _time_cache; } /* forget cached time, let next read fill it */ void reset_time_cache(void) { _time_cache = 0; } /* * win32 compat */ #ifdef WIN32 /* unix epoch (1970) in seconds from windows epoch (1601) */ #define UNIX_EPOCH 11644473600LL /* 1 sec in 100 nsec units */ #define FT_SEC 10000000LL static void ft2tv(FILETIME *src, struct timeval *dst, bool use_epoch) { ULARGE_INTEGER tmp; tmp.LowPart = src->dwLowDateTime; tmp.HighPart = src->dwHighDateTime; dst->tv_sec = (tmp.QuadPart / FT_SEC) - (use_epoch ? UNIX_EPOCH : 0); dst->tv_usec = (tmp.QuadPart % FT_SEC) / 10; } #ifndef HAVE_GETTIMEOFDAY int gettimeofday(struct timeval * tp, void * tzp) { FILETIME file_time; SYSTEMTIME system_time; /* read UTC timestamp */ GetSystemTime(&system_time); SystemTimeToFileTime(&system_time, &file_time); /* convert to timeval */ ft2tv(&file_time, tp, true); return 0; } #endif /* !HAVE_GETTIMEOFDAY */ #ifndef HAVE_LOCALTIME_R struct tm *localtime_r(const time_t *tp, struct tm *dst) { ULARGE_INTEGER utc; FILETIME ft_utc; SYSTEMTIME st_utc, st_local; /* convert time_t to FILETIME */ utc.QuadPart = (*tp + UNIX_EPOCH) * FT_SEC; ft_utc.dwLowDateTime = utc.LowPart; ft_utc.dwHighDateTime = utc.HighPart; /* split to parts and get local time */ if (!FileTimeToSystemTime(&ft_utc, &st_utc)) return NULL; if (!SystemTimeToTzSpecificLocalTime(NULL, &st_utc, &st_local)) return NULL; /* fill struct tm */ dst->tm_sec = st_local.wSecond; dst->tm_min = st_local.wMinute; dst->tm_hour = st_local.wHour; dst->tm_mday = st_local.wDay; dst->tm_mon = st_local.wMonth - 1; dst->tm_year = st_local.wYear - 1900; dst->tm_wday = st_local.wDayOfWeek; dst->tm_yday = 0; dst->tm_isdst = -1; return dst; } #endif /* !HAVE_LOCALTIME_R */ #ifndef HAVE_GETRUSAGE int getrusage(int who, struct rusage *dst) { FILETIME tcreate, texit, tkern, tuser; if (who != RUSAGE_SELF) { errno = EINVAL; return -1; } if (!GetProcessTimes(GetCurrentProcess(), &tcreate, &texit, &tkern, &tuser)) return -1; ft2tv(&tuser, &dst->ru_utime, false); ft2tv(&tkern, &dst->ru_stime, false); return 0; } #endif /* !HAVE_GETRUSAGE */ #endif /* WIN32 */ pgbouncer-1.5.4/lib/usual/misc.h0000644000175000017500000000307711665176410013447 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * Random stuff that does not fit elsewhere. */ #ifndef _USUAL_MISC_H_ #define _USUAL_MISC_H_ #include #ifdef WORDS_BIGENDIAN #define FOURCC(a,b,c,d) \ ( ((unsigned int)(unsigned char)(a) << 24) \ | ((unsigned int)(unsigned char)(b) << 16) \ | ((unsigned int)(unsigned char)(c) << 8) \ | ((unsigned int)(unsigned char)(d))) #else /** Four-byte identifier as integer */ #define FOURCC(a,b,c,d) \ ( ((unsigned int)(unsigned char)(a)) \ | ((unsigned int)(unsigned char)(b) << 8) \ | ((unsigned int)(unsigned char)(c) << 16) \ | ((unsigned int)(unsigned char)(d) << 24)) #endif #if defined(__i386__) || defined(__x86_64__) #define mb() asm volatile("mfence":::"memory") #define rmb() asm volatile("lfence":::"memory") #define wmb() asm volatile("sfence":::"memory") #endif #endif pgbouncer-1.5.4/lib/usual/socket.c0000644000175000017500000002270211665176410013773 00000000000000/* * Socket helpers and compat. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #ifdef HAVE_UCRED_H #include #endif #ifdef HAVE_SYS_UCRED_H #include #endif /* toggle non-blocking flag */ bool socket_set_nonblocking(int fd, bool non_block) { int flags; /* get old flags */ flags = fcntl(fd, F_GETFL, 0); if (flags < 0) return false; /* flip O_NONBLOCK */ if (non_block) flags |= O_NONBLOCK; else flags &= ~O_NONBLOCK; /* set new flags */ if (fcntl(fd, F_SETFL, flags) < 0) return false; return true; } /* initial socket setup */ bool socket_setup(int sock, bool non_block) { int res; #ifdef SO_NOSIGPIPE /* disallow SIGPIPE, if possible */ int val = 1; res = setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)); if (res < 0) return false; #endif /* close fd on exec */ res = fcntl(sock, F_SETFD, FD_CLOEXEC); if (res < 0) return false; /* when no data available, return EAGAIN instead blocking */ if (!socket_set_nonblocking(sock, non_block)) return false; return true; } bool socket_set_keepalive(int fd, int onoff, int keepidle, int keepintvl, int keepcnt) { int val, res; if (!onoff) { /* turn keepalive off */ val = 0; res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); return (res == 0); } /* turn keepalive on */ val = 1; res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); if (res < 0) return false; /* Darwin */ #ifdef TCP_KEEPALIVE if (keepidle) { val = keepidle; res = setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)); if (res < 0 && errno != ENOPROTOOPT) return false; } #endif /* Linux, NetBSD */ #ifdef TCP_KEEPIDLE if (keepidle) { val = keepidle; res = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)); if (res < 0 && errno != ENOPROTOOPT) return false; } #endif #ifdef TCP_KEEPINTVL if (keepintvl) { val = keepintvl; res = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)); if (res < 0 && errno != ENOPROTOOPT) return false; } #endif #ifdef TCP_KEEPCNT if (keepcnt > 0) { val = keepcnt; res = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)); if (res < 0 && errno != ENOPROTOOPT) return false; } #endif /* Windows */ #ifdef SIO_KEEPALIVE_VALS if (keepidle || keepintvl) { struct tcp_keepalive vals; DWORD outlen = 0; if (!keepidle) keepidle = 5 * 60; if (!keepintvl) keepintvl = 15; vals.onoff = 1; vals.keepalivetime = keepidle * 1000; vals.keepaliveinterval = keepintvl * 1000; res = WSAIoctl(fd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals), NULL, 0, &outlen, NULL, NULL); if (res != 0) return false; } #endif return true; } /* * Convert sockaddr to string. Supports ipv4, ipv6 and unix sockets. */ const char *sa2str(const struct sockaddr *sa, char *dst, int dstlen) { const struct sockaddr_in *in; const struct sockaddr_in6 *in6; const struct sockaddr_un *un; const char *tmp; char buf[128]; switch (sa->sa_family) { case AF_INET: in = (struct sockaddr_in *)sa; tmp = inet_ntop(AF_INET, &in->sin_addr, buf, sizeof(buf)); if (!tmp) return NULL; snprintf(dst, dstlen, "%s:%d", tmp, ntohs(in->sin_port)); break; case AF_INET6: in6 = (struct sockaddr_in6 *)sa; tmp = inet_ntop(AF_INET6, &in6->sin6_addr, buf, sizeof(buf)); if (!tmp) return NULL; snprintf(dst, dstlen, "%s/%d", tmp, ntohs(in6->sin6_port)); break; case AF_UNIX: un = (struct sockaddr_un *)sa; snprintf(dst, dstlen, "unix:%s", un->sun_path); break; default: snprintf(dst, dstlen, "sa2str(%d): unknown proto", sa->sa_family); break; } return dst; } #ifndef HAVE_GETPEEREID /* * Get other side's uid for UNIX socket. * * Standardise on getpeereid() from BSDs. */ int getpeereid(int fd, uid_t *uid_p, gid_t *gid_p) { #ifdef SO_PEERCRED struct ucred cred; socklen_t len = sizeof(cred); if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) >= 0) { *uid_p = cred.uid; *gid_p = cred.gid; return 0; } #else /* !SO_PEERCRED */ #ifdef HAVE_GETPEERUCRED ucred_t *cred = NULL; if (getpeerucred(fd, &cred) >= 0) { *uid_p = ucred_geteuid(cred); *gid_p = ucred_getegid(cred); ucred_free(cred); if ((int)*uid_p == -1 || (int)*gid_p == -1) return -1; return 0; } #else errno = ENOSYS; #endif /* HAVE_GETPEERUCRED */ #endif /* !SO_PEERCRED */ return -1; } #endif #ifndef HAVE_POLL /* * Emulate poll() with select() */ #ifdef HAVE_SYS_SELECT_H #include #endif /* * dynamic buffer for fd_set to avoid depending on FD_SETSIZE */ struct fd_buf { fd_set *set; int alloc_bytes; }; static void fdbuf_zero(struct fd_buf *buf) { if (buf->set) memset(buf->set, 0, buf->alloc_bytes); } static bool fdbuf_resize(struct fd_buf *buf, int fd) { int need_bytes; unsigned char *ptr; /* default allocation */ int alloc = sizeof(fd_set); #ifdef WIN32 int cnt = buf->set ? buf->set->fd_count : 0; /* win32 fd_set is array of handles, +8 for count&padding */ need_bytes = (cnt + 1) * sizeof(buf->set->fd_array[0]) + 8; #else /* otherwise, fd_set is bitmap, +8 for int/long alignment */ need_bytes = fd / 8 + 8; #endif if (buf->alloc_bytes < need_bytes) { while (alloc < need_bytes) alloc *= 2; if (!buf->set) ptr = malloc(alloc); else ptr = realloc(buf->set, alloc); if (!ptr) return false; /* clean new area */ memset(ptr + buf->alloc_bytes, 0, alloc - buf->alloc_bytes); buf->set = (fd_set *)ptr; buf->alloc_bytes = alloc; } return true; } /* win32: make macros ignore FD_SETSIZE */ #undef FD_SETSIZE #define FD_SETSIZE (1 << 30) int poll(struct pollfd *fds, nfds_t nfds, int timeout_ms) { static struct fd_buf readfds = { NULL, 0 }; static struct fd_buf writefds = { NULL, 0 }; struct pollfd *pf; int res, fd_max = 0; struct timeval *tv = NULL; struct timeval tvreal; unsigned i; /* convert timeout_ms to timeval */ if (timeout_ms >= 0) { tvreal.tv_sec = timeout_ms / 1000; tvreal.tv_usec = (timeout_ms % 1000) * 1000; tv = &tvreal; } else if (timeout_ms < -1) goto err_inval; /* * Convert pollfds to fd sets. */ fdbuf_zero(&readfds); fdbuf_zero(&writefds); for (i = 0; i < nfds; i++) { pf = fds + i; if (pf->fd < 0) goto err_badf; /* sets must be equal size */ if (!fdbuf_resize(&readfds, pf->fd)) goto err_nomem; if (!fdbuf_resize(&writefds, pf->fd)) goto err_nomem; if (pf->events & POLLIN) FD_SET((unsigned)pf->fd, readfds.set); if (pf->events & POLLOUT) FD_SET((unsigned)pf->fd, writefds.set); if (pf->fd > fd_max) fd_max = pf->fd; } res = select(fd_max + 1, readfds.set, writefds.set, NULL, tv); if (res <= 0) return res; /* * select() and poll() count fd-s differently, * need to recount them here. */ res = 0; for (i = 0; i < nfds; i++) { pf = fds + i; pf->revents = 0; if ((pf->events & POLLIN) && FD_ISSET(pf->fd, readfds.set)) pf->revents |= POLLIN; if ((pf->events & POLLOUT) && FD_ISSET(pf->fd, writefds.set)) pf->revents |= POLLOUT; if (pf->revents) res += 1; } return res; err_nomem: errno = ENOMEM; return -1; err_badf: errno = EBADF; return -1; err_inval: errno = EINVAL; return -1; } #endif /* PLPROXY_POLL_COMPAT */ #ifdef WIN32 /* create local TCP socket, idea from libevent/Tor */ int win32_socketpair(int d, int typ, int proto, int sv[2]) { int list = -1, s1 = -1, s2 = -1; struct sockaddr_in sa1, sa2; socklen_t slen = sizeof(sa1); int res; if (d != AF_INET && d != AF_UNIX) goto err_inval; if (proto || !sv) goto err_inval; /* prepare sockaddr for bind */ memset(&sa1, 0, sizeof(sa1)); sa1.sin_family = AF_INET; sa1.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sa1.sin_port = htons(0); /* create listen socket */ list = socket(AF_INET, typ, 0); if (list == -1) return -1; res = bind(list, (struct sockaddr *)&sa1, sizeof(sa1)); if (res == -1) goto failed; res = listen(list, 1); if (res == -1) goto failed; /* read listen port */ res = getsockname(list, (struct sockaddr *)&sa1, &slen); if (res == -1 || slen != sizeof(sa1)) goto failed; /* connect to it */ s1 = socket(AF_INET, typ, 0); if (s1 == -1) goto failed; res = connect(s1, (struct sockaddr *)&sa1, sizeof(sa1)); if (res == -1) goto failed; /* and accept from other end */ s2 = accept(list, (struct sockaddr *)&sa2, &slen); if (s2 == -1 || slen != sizeof(sa2)) goto failed; /* sanity check */ res = getsockname(s1, (struct sockaddr *)&sa1, &slen); if (res == -1 || slen != sizeof(sa1)) goto failed; if (sa1.sin_port != sa2.sin_port) goto failed; closesocket(list); sv[0] = s1; sv[1] = s2; return 0; failed: errno = (res == -1) ? WSAGetLastError() : EFAULT; if (list != -1) closesocket(list); if (s1 != -1) closesocket(s1); if (s2 != -1) closesocket(s2); return -1; err_inval: errno = EINVAL; return -1; } #endif pgbouncer-1.5.4/lib/usual/cbtree.h0000644000175000017500000000442211665176410013753 00000000000000/* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * * Crit-bit tree / binary radix tree. */ #ifndef _USUAL_CBTREE_H_ #define _USUAL_CBTREE_H_ #include /** returns length of the key */ typedef unsigned int (*cbtree_getkey_func)(void *ctx, void *obj, const void **dst_p); /** walk over tree */ typedef bool (*cbtree_walker_func)(void *ctx, void *obj); /** Handle to tree */ struct CBTree; /** * Create new tree. * * @param obj_key_cb callback to get the key for a object * @param obj_free_cb callback to free the object when tree node is freed (optional) * @param cb_ctx extra pointer passed to callbacks * @param cx memory context where from allocate */ struct CBTree *cbtree_create(cbtree_getkey_func obj_key_cb, cbtree_walker_func obj_free_cb, void *cb_ctx, CxMem *cx); /** * frees all resources allocated. * If obj_free_cb is non-NULL, it will be called per each object. */ void cbtree_destroy(struct CBTree *tree); /** Inserts new node to tree */ bool cbtree_insert(struct CBTree *tree, void *obj) _MUSTCHECK; /** Removed node from tree. * If obj_free_cb is non-NULL, it will be called for the object. * * @returns true if key was found, false otherwise. */ bool cbtree_delete(struct CBTree *tree, const void *key, unsigned klen); /** * Lookup a key. * * @returns object pointer if found, NULL ohterwise */ void *cbtree_lookup(struct CBTree *tree, const void *key, unsigned klen); /** Walk over tree */ bool cbtree_walk(struct CBTree *tree, cbtree_walker_func cb_func, void *cb_arg); #endif pgbouncer-1.5.4/lib/usual/pthread.c0000644000175000017500000000377411665176410014142 00000000000000/* * Pthreads compat. * * Copyright (c) 2007-2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #ifdef WIN32 /* * basic pthreads for win32. */ struct _w32thread { void *(*fn)(void *); void *arg; }; static DWORD WINAPI w32launcher(LPVOID arg) { struct _w32thread *info = arg; info->fn(info->arg); free(info); return 0; } int pthread_create(pthread_t *t, pthread_attr_t *attr, void *(*fn)(void *), void *arg) { struct _w32thread *info = calloc(1, sizeof(*info)); if (!info) return -1; info->fn = fn; info->arg = arg; *t = CreateThread(NULL, 0, w32launcher, info, 0, NULL); if (*t == NULL) return -1; return 0; } int pthread_join(pthread_t *t, void **ret) { if (WaitForSingleObject(*t, INFINITE) != WAIT_OBJECT_0) return -1; CloseHandle(*t); return 0; } int pthread_mutex_init(pthread_mutex_t *lock, void *unused) { *lock = CreateMutex(NULL, FALSE, NULL); if (*lock == NULL) return -1; return 0; } int pthread_mutex_destroy(pthread_mutex_t *lock) { if (*lock) { CloseHandle(*lock); *lock = NULL; } return 0; } int pthread_mutex_lock(pthread_mutex_t *lock) { if (WaitForSingleObject(*lock, INFINITE) != WAIT_OBJECT_0) return -1; return 0; } int pthread_mutex_unlock(pthread_mutex_t *lock) { if (!ReleaseMutex(*lock)) return -1; return 0; } #endif /* win32 */ pgbouncer-1.5.4/lib/usual/heap.h0000644000175000017500000000542311665176410013426 00000000000000/* * Binary Heap. * * Copyright (c) 2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** @file * Binary heap. * * Binary heap is sort of binary tree held inside array, * with following 2 properties: * - heap property: each node is "better" than it's childs. * - shape property: binary tree is complete, meaning all levels * except the last one are fully filled. * * Instead of "min"- or "max"-heap, this is "best"-heap, * as it operates with user-defined heap_is_better() functions, * which is used to bubble elements on top. */ #ifndef _USUAL_HEAP_H_ #define _USUAL_HEAP_H_ #include /** * Object comparision function. * * Should return true if a needs to reach top before b, * false if not or equal. */ typedef bool (*heap_is_better_f)(const void *a, const void *b); /** * Heap position storage. * * If user wants to delete elements from the middle of heap, * this function should be used to keep track where the element * is located. */ typedef void (*heap_save_pos_f)(void *a, unsigned pos); /** * Heap object. */ struct Heap; /** * Create new heap object. * * @param is_better_cb Callback to decide priority. * @param save_pos_cb Callback to store current index. * @param cx Allocation context. */ struct Heap *heap_create( heap_is_better_f is_better_cb, heap_save_pos_f save_pos_cb, CxMem *cx); /** Release memory allocated by heap */ void heap_destroy(struct Heap *h); /** Put new object into heap */ bool heap_push(struct Heap *h, void *ptr); /** Remove and return topmost object from heap */ void *heap_pop(struct Heap *h); /** Return topmost object in heap */ void *heap_top(struct Heap *h); /** Remove and return any object from heap by index */ void *heap_remove(struct Heap *h, unsigned pos); /** * Reserve room for more elements. * * Returns false if allocation failed. */ bool heap_reserve(struct Heap *h, unsigned extra); /** Return number of objects in heap */ unsigned heap_size(struct Heap *h); /* Return object by index, for testing */ void *heap_get_obj(struct Heap *h, unsigned pos); #endif pgbouncer-1.5.4/lib/usual/cxalloc.c0000644000175000017500000000437211665176410014133 00000000000000/* * libusual - Utility library for C * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include /* * Utility routines for cx_* API. */ void *cx_alloc(CxMem *cx, size_t len) { if (!len) return NULL; return cx->ops->c_alloc(cx->ctx, len); } void *cx_realloc(CxMem *cx, void *ptr, size_t len) { if (!ptr) return cx_alloc(cx, len); if (!len) { cx_free(cx, ptr); return NULL; } return cx->ops->c_realloc(cx->ctx, ptr, len); } void cx_free(CxMem *cx, const void *ptr) { if (ptr) cx->ops->c_free(cx->ctx, ptr); } void cx_destroy(CxMem *cx) { if (!cx) return; if (!cx->ops->c_destroy) abort(); cx->ops->c_destroy(cx->ctx); } void *cx_alloc0(CxMem *cx, size_t len) { void *p = cx_alloc(cx, len); if (p) memset(p, 0, len); return p; } void *cx_memdup(CxMem *cx, const void *src, size_t len) { void *p = cx_alloc(cx, len); if (p) memcpy(p, src, len); return p; } void *cx_strdup(CxMem *cx, const char *s) { return cx_memdup(cx, s, strlen(s) + 1); } /* * Base allocator that uses libc routines. */ static void *libc_alloc(void *ctx, size_t len) { return malloc(len); } static void *libc_realloc(void *ctx, void *ptr, size_t len) { return realloc(ptr, len); } static void libc_free(void *ctx, const void *ptr) { free(ptr); } static const struct CxOps libc_alloc_ops = { .c_alloc = libc_alloc, .c_realloc = libc_realloc, .c_free = libc_free, }; const struct CxMem cx_libc_allocator = { .ops = &libc_alloc_ops, .ctx = NULL, }; pgbouncer-1.5.4/lib/usual/utf8.h0000644000175000017500000000345611665176410013403 00000000000000/** @file * Low-level UTF8 handling. */ /* * Copyright (c) 2009 Marko Kreen * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _USUAL_UTF8_H_ #define _USUAL_UTF8_H_ #include /** * Parse Unicode codepoint from UTF8 stream. * * On invalid UTF8 sequence returns negative byte value and * inreases src_p by one. * * @param src_p Location of data pointer. Will be incremented in-place. * @param srcend Pointer to end of data. * @return UNOCODE codepoint or negative byte value on error. */ int utf8_get_char(const char **src_p, const char *srcend); /** * Write Unicode codepoint as UTF8 sequence. * * Skips invalid Unicode values without error. * * @param c Unicode codepoint. * @param dst_p Location of dest pointer, will be increased in-place. * @param dstend Pointer to end of buffer. * @return false if not room, true otherwise. */ bool utf8_put_char(unsigned int c, char **dst_p, const char *dstend); /** Return UTF8 seq length based on unicode codepoint */ int utf8_char_size(unsigned int c); /** Return UTF8 seq length based on first byte */ int utf8_seq_size(unsigned char c); #endif pgbouncer-1.5.4/lib/usual/getopt.h0000644000175000017500000000670011665176410014012 00000000000000/* * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @file * getopt compat. * * This module provides getopt() and getopt_long(). */ #ifndef _USUAL_GETOPT_H_ #define _USUAL_GETOPT_H_ #include #ifndef NEED_USUAL_GETOPT #if !defined(HAVE_GETOPT_H) || !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_LONG) #define NEED_USUAL_GETOPT #endif #endif #ifndef NEED_USUAL_GETOPT /* Use system getopt */ #include #else /* NEED_USUAL_GETOPT */ /* avoid name collision */ #define optarg usual_optarg #define opterr usual_opterr #define optind usual_optind #define optopt usual_optopt #define getopt(a,b,c) usual_getopt(a,b,c) #define getopt_long(a,b,c,d,e) usual_getopt_long(a,b,c,d,e) /** argument to current option, or NULL if it has none */ extern char *optarg; /** Current position in arg string. Starts from 1. Setting to 0 resets state. */ extern int optind; /** whether getopt() should print error messages on problems. Default: 1. */ extern int opterr; /** Option char which caused error */ extern int optopt; /** long option takes no argument */ #define no_argument 0 /** long option requires argument */ #define required_argument 1 /** long option has optional argument */ #define optional_argument 2 /** Long option description */ struct option { /** name of long option */ const char *name; /** * whether option takes an argument. * One of no_argument, required_argument, and optional_argument. */ int has_arg; /** if not NULL, set *flag to val when option found */ int *flag; /** if flag not NULL, value to set *flag to; else return value */ int val; }; /** Compat: getopt */ int getopt(int argc, char *argv[], const char *options); /** Compat: getopt_long */ int getopt_long(int argc, char *argv[], const char *options, const struct option *longopts, int *longindex); /** Compat: getopt_long_only */ int getopt_long_only(int nargc, char *argv[], const char *options, const struct option *long_options, int *idx); #endif /* NEED_USUAL_GETOPT */ #endif /* !_USUAL_GETOPT_H_ */ pgbouncer-1.5.4/lib/README0000644000175000017500000000011211665176410012055 00000000000000= libusual = Collection of various code useful for writing server code. pgbouncer-1.5.4/lib/COPYRIGHT0000644000175000017500000000151211665176410012475 00000000000000/* * libusual - Utility library for C * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ pgbouncer-1.5.4/src/0000755000175000017500000000000012055406737011306 500000000000000pgbouncer-1.5.4/src/objects.c0000644000175000017500000010533312023063534013015 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Herding objects between lists happens here. */ #include "bouncer.h" /* those items will be allocated as needed, never freed */ STATLIST(user_list); STATLIST(database_list); STATLIST(pool_list); struct AATree user_tree; /* * client and server objects will be pre-allocated * they are always in either active or free lists * in addition to others. */ STATLIST(login_client_list); struct Slab *server_cache; struct Slab *client_cache; struct Slab *db_cache; struct Slab *pool_cache; struct Slab *user_cache; struct Slab *iobuf_cache; /* * libevent may still report events when event_del() * is called from somewhere else. So hide just freed * PgSockets for one loop. */ static STATLIST(justfree_client_list); static STATLIST(justfree_server_list); /* init autodb idle list */ STATLIST(autodatabase_idle_list); /* fast way to get number of active clients */ int get_active_client_count(void) { return slab_active_count(client_cache); } /* fast way to get number of active servers */ int get_active_server_count(void) { return slab_active_count(server_cache); } static void construct_client(void *obj) { PgSocket *client = obj; memset(client, 0, sizeof(PgSocket)); list_init(&client->head); sbuf_init(&client->sbuf, client_proto); client->state = CL_FREE; } static void construct_server(void *obj) { PgSocket *server = obj; memset(server, 0, sizeof(PgSocket)); list_init(&server->head); sbuf_init(&server->sbuf, server_proto); server->state = SV_FREE; } /* compare string with PgUser->name, for usage with btree */ static int user_node_cmp(uintptr_t userptr, struct AANode *node) { const char *name = (const char *)userptr; PgUser *user = container_of(node, PgUser, tree_node); return strcmp(name, user->name); } /* initialization before config loading */ void init_objects(void) { aatree_init(&user_tree, user_node_cmp, NULL); user_cache = slab_create("user_cache", sizeof(PgUser), 0, NULL, USUAL_ALLOC); db_cache = slab_create("db_cache", sizeof(PgDatabase), 0, NULL, USUAL_ALLOC); pool_cache = slab_create("pool_cache", sizeof(PgPool), 0, NULL, USUAL_ALLOC); if (!user_cache || !db_cache || !pool_cache) fatal("cannot create initial caches"); } static void do_iobuf_reset(void *arg) { IOBuf *io = arg; iobuf_reset(io); } /* initialization after config loading */ void init_caches(void) { server_cache = slab_create("server_cache", sizeof(PgSocket), 0, construct_server, USUAL_ALLOC); client_cache = slab_create("client_cache", sizeof(PgSocket), 0, construct_client, USUAL_ALLOC); iobuf_cache = slab_create("iobuf_cache", IOBUF_SIZE, 0, do_iobuf_reset, USUAL_ALLOC); } /* state change means moving between lists */ void change_client_state(PgSocket *client, SocketState newstate) { PgPool *pool = client->pool; /* remove from old location */ switch (client->state) { case CL_FREE: break; case CL_JUSTFREE: statlist_remove(&justfree_client_list, &client->head); break; case CL_LOGIN: statlist_remove(&login_client_list, &client->head); break; case CL_WAITING: statlist_remove(&pool->waiting_client_list, &client->head); break; case CL_ACTIVE: statlist_remove(&pool->active_client_list, &client->head); break; case CL_CANCEL: statlist_remove(&pool->cancel_req_list, &client->head); break; default: fatal("bad cur client state: %d", client->state); } client->state = newstate; /* put to new location */ switch (client->state) { case CL_FREE: varcache_clean(&client->vars); slab_free(client_cache, client); break; case CL_JUSTFREE: statlist_append(&justfree_client_list, &client->head); break; case CL_LOGIN: statlist_append(&login_client_list, &client->head); break; case CL_WAITING: statlist_append(&pool->waiting_client_list, &client->head); break; case CL_ACTIVE: statlist_append(&pool->active_client_list, &client->head); break; case CL_CANCEL: statlist_append(&pool->cancel_req_list, &client->head); break; default: fatal("bad new client state: %d", client->state); } } /* state change means moving between lists */ void change_server_state(PgSocket *server, SocketState newstate) { PgPool *pool = server->pool; /* remove from old location */ switch (server->state) { case SV_FREE: break; case SV_JUSTFREE: statlist_remove(&justfree_server_list, &server->head); break; case SV_LOGIN: statlist_remove(&pool->new_server_list, &server->head); break; case SV_USED: statlist_remove(&pool->used_server_list, &server->head); break; case SV_TESTED: statlist_remove(&pool->tested_server_list, &server->head); break; case SV_IDLE: statlist_remove(&pool->idle_server_list, &server->head); break; case SV_ACTIVE: statlist_remove(&pool->active_server_list, &server->head); break; default: fatal("change_server_state: bad old server state: %d", server->state); } server->state = newstate; /* put to new location */ switch (server->state) { case SV_FREE: varcache_clean(&server->vars); slab_free(server_cache, server); break; case SV_JUSTFREE: statlist_append(&justfree_server_list, &server->head); break; case SV_LOGIN: statlist_append(&pool->new_server_list, &server->head); break; case SV_USED: /* use LIFO */ statlist_prepend(&pool->used_server_list, &server->head); break; case SV_TESTED: statlist_append(&pool->tested_server_list, &server->head); break; case SV_IDLE: if (server->close_needed || cf_server_round_robin) /* try to avoid immediate usage then */ statlist_append(&pool->idle_server_list, &server->head); else /* otherwise use LIFO */ statlist_prepend(&pool->idle_server_list, &server->head); break; case SV_ACTIVE: statlist_append(&pool->active_server_list, &server->head); break; default: fatal("bad server state"); } } /* compare pool names, for use with put_in_order */ static int cmp_pool(struct List *i1, struct List *i2) { PgPool *p1 = container_of(i1, PgPool, head); PgPool *p2 = container_of(i2, PgPool, head); if (p1->db != p2->db) return strcmp(p1->db->name, p2->db->name); if (p1->user != p2->user) return strcmp(p1->user->name, p2->user->name); return 0; } /* compare user names, for use with put_in_order */ static int cmp_user(struct List *i1, struct List *i2) { PgUser *u1 = container_of(i1, PgUser, head); PgUser *u2 = container_of(i2, PgUser, head); return strcmp(u1->name, u2->name); } /* compare db names, for use with put_in_order */ static int cmp_database(struct List *i1, struct List *i2) { PgDatabase *db1 = container_of(i1, PgDatabase, head); PgDatabase *db2 = container_of(i2, PgDatabase, head); return strcmp(db1->name, db2->name); } /* put elem into list in correct pos */ static void put_in_order(struct List *newitem, struct StatList *list, int (*cmpfn)(struct List *, struct List *)) { int res; struct List *item; statlist_for_each(item, list) { res = cmpfn(item, newitem); if (res == 0) fatal("put_in_order: found existing elem"); else if (res > 0) { statlist_put_before(list, newitem, item); return; } } statlist_append(list, newitem); } /* create new object if new, then return it */ PgDatabase *add_database(const char *name) { PgDatabase *db = find_database(name); /* create new object if needed */ if (db == NULL) { db = slab_alloc(db_cache); if (!db) return NULL; list_init(&db->head); if (strlcpy(db->name, name, sizeof(db->name)) >= sizeof(db->name)) { log_warning("Too long db name: %s", name); slab_free(db_cache, db); return NULL; } put_in_order(&db->head, &database_list, cmp_database); } return db; } /* register new auto database */ PgDatabase *register_auto_database(const char *name) { PgDatabase *db; int len; char *cs; if (!cf_autodb_connstr) return NULL; len = strlen(cf_autodb_connstr); cs = malloc(len + 1); if (!cs) return NULL; memcpy(cs, cf_autodb_connstr, len + 1); parse_database(NULL, (char*)name, cs); free(cs); db = find_database(name); if (db) { db->db_auto = 1; /* do not forget to check pool_size like in config_postprocess */ if (db->pool_size < 0) db->pool_size = cf_default_pool_size; if (db->res_pool_size < 0) db->res_pool_size = cf_res_pool_size; } return db; } /* add or update client users */ PgUser *add_user(const char *name, const char *passwd) { PgUser *user = find_user(name); if (user == NULL) { user = slab_alloc(user_cache); if (!user) return NULL; list_init(&user->head); list_init(&user->pool_list); safe_strcpy(user->name, name, sizeof(user->name)); put_in_order(&user->head, &user_list, cmp_user); aatree_insert(&user_tree, (uintptr_t)user->name, &user->tree_node); } safe_strcpy(user->passwd, passwd, sizeof(user->passwd)); return user; } /* create separate user object for storing server user info */ PgUser *force_user(PgDatabase *db, const char *name, const char *passwd) { PgUser *user = db->forced_user; if (!user) { user = slab_alloc(user_cache); if (!user) return NULL; list_init(&user->head); list_init(&user->pool_list); } safe_strcpy(user->name, name, sizeof(user->name)); safe_strcpy(user->passwd, passwd, sizeof(user->passwd)); db->forced_user = user; return user; } /* find an existing database */ PgDatabase *find_database(const char *name) { struct List *item, *tmp; PgDatabase *db; statlist_for_each(item, &database_list) { db = container_of(item, PgDatabase, head); if (strcmp(db->name, name) == 0) return db; } /* also trying to find in idle autodatabases list */ statlist_for_each_safe(item, &autodatabase_idle_list, tmp) { db = container_of(item, PgDatabase, head); if (strcmp(db->name, name) == 0) { db->inactive_time = 0; statlist_remove(&autodatabase_idle_list, &db->head); put_in_order(&db->head, &database_list, cmp_database); return db; } } return NULL; } /* find existing user */ PgUser *find_user(const char *name) { PgUser *user = NULL; struct AANode *node; node = aatree_search(&user_tree, (uintptr_t)name); user = node ? container_of(node, PgUser, tree_node) : NULL; return user; } /* create new pool object */ static PgPool *new_pool(PgDatabase *db, PgUser *user) { PgPool *pool; pool = slab_alloc(pool_cache); if (!pool) return NULL; list_init(&pool->head); list_init(&pool->map_head); pool->user = user; pool->db = db; statlist_init(&pool->active_client_list, "active_client_list"); statlist_init(&pool->waiting_client_list, "waiting_client_list"); statlist_init(&pool->active_server_list, "active_server_list"); statlist_init(&pool->idle_server_list, "idle_server_list"); statlist_init(&pool->tested_server_list, "tested_server_list"); statlist_init(&pool->used_server_list, "used_server_list"); statlist_init(&pool->new_server_list, "new_server_list"); statlist_init(&pool->cancel_req_list, "cancel_req_list"); list_append(&user->pool_list, &pool->map_head); /* keep pools in db/user order to make stats faster */ put_in_order(&pool->head, &pool_list, cmp_pool); return pool; } /* find pool object, create if needed */ PgPool *get_pool(PgDatabase *db, PgUser *user) { struct List *item; PgPool *pool; if (!db || !user) return NULL; list_for_each(item, &user->pool_list) { pool = container_of(item, PgPool, map_head); if (pool->db == db) return pool; } return new_pool(db, user); } /* deactivate socket and put into wait queue */ static void pause_client(PgSocket *client) { Assert(client->state == CL_ACTIVE); slog_debug(client, "pause_client"); change_client_state(client, CL_WAITING); if (!sbuf_pause(&client->sbuf)) disconnect_client(client, true, "pause failed"); } /* wake client from wait */ void activate_client(PgSocket *client) { Assert(client->state == CL_WAITING); slog_debug(client, "activate_client"); change_client_state(client, CL_ACTIVE); sbuf_continue(&client->sbuf); } /* * Don't let clients queue at all, if there is no working server connection. * * It must still allow following cases: * - empty pool on startup * - idle pool where all servers are removed * * Current assumptions: * - old server connections will be dropped by query_timeout * - new server connections fail due to server_connect_timeout, or other failure * * So here we drop client if all server connections have been dropped * and new one's fail. */ bool check_fast_fail(PgSocket *client) { int cnt; PgPool *pool = client->pool; /* reject if no servers and last connect failed */ if (!pool->last_connect_failed) return true; cnt = pool_server_count(pool) - statlist_count(&pool->new_server_list); if (cnt) return true; disconnect_client(client, true, "pgbouncer cannot connect to server"); /* usual relaunch wont work, as there are no waiting clients */ launch_new_connection(pool); return false; } /* link if found, otherwise put into wait queue */ bool find_server(PgSocket *client) { PgPool *pool = client->pool; PgSocket *server; bool res; bool varchange = false; Assert(client->state == CL_ACTIVE); if (client->link) return true; /* try to get idle server, if allowed */ if (cf_pause_mode == P_PAUSE) { server = NULL; } else { while (1) { server = first_socket(&pool->idle_server_list); if (!server) break; else if (server->close_needed) disconnect_server(server, true, "obsolete connection"); else if (!server->ready) disconnect_server(server, true, "idle server got dirty"); else break; } if (!server && !check_fast_fail(client)) return false; } Assert(!server || server->state == SV_IDLE); /* send var changes */ if (server) { res = varcache_apply(server, client, &varchange); if (!res) { disconnect_server(server, true, "var change failed"); server = NULL; } } /* link or send to waiters list */ if (server) { client->link = server; server->link = client; change_server_state(server, SV_ACTIVE); if (varchange) { server->setting_vars = 1; server->ready = 0; res = false; /* don't process client data yet */ if (!sbuf_pause(&client->sbuf)) disconnect_client(client, true, "pause failed"); } else res = true; } else { pause_client(client); res = false; } return res; } /* pick waiting client */ static bool reuse_on_release(PgSocket *server) { bool res = true; PgPool *pool = server->pool; PgSocket *client = first_socket(&pool->waiting_client_list); if (client) { activate_client(client); /* * As the activate_client() does full read loop, * then it may happen that linked client close * couses server close. Report it. */ if (server->state == SV_FREE || server->state == SV_JUSTFREE) res = false; } return res; } /* send reset query */ static bool reset_on_release(PgSocket *server) { bool res; Assert(server->state == SV_TESTED); slog_debug(server, "Resetting: %s", cf_server_reset_query); SEND_generic(res, server, 'Q', "s", cf_server_reset_query); if (!res) disconnect_server(server, false, "reset query failed"); return res; } static bool life_over(PgSocket *server) { PgPool *pool = server->pool; usec_t lifetime_kill_gap = 0; usec_t now = get_cached_time(); usec_t age = now - server->connect_time; usec_t last_kill = now - pool->last_lifetime_disconnect; if (age < cf_server_lifetime) return false; if (pool->db->pool_size > 0) lifetime_kill_gap = cf_server_lifetime / pool->db->pool_size; if (last_kill >= lifetime_kill_gap) return true; return false; } /* connecting/active -> idle, unlink if needed */ bool release_server(PgSocket *server) { PgPool *pool = server->pool; SocketState newstate = SV_IDLE; Assert(server->ready); /* remove from old list */ switch (server->state) { case SV_ACTIVE: server->link->link = NULL; server->link = NULL; if (*cf_server_reset_query) /* notify reset is required */ newstate = SV_TESTED; else if (cf_server_check_delay == 0 && *cf_server_check_query) /* * deprecated: before reset_query, the check_delay = 0 * was used to get same effect. This if() can be removed * after couple of releases. */ newstate = SV_USED; case SV_USED: case SV_TESTED: break; case SV_LOGIN: pool->last_connect_failed = 0; break; default: fatal("bad server state in release_server (%d)", server->state); } /* enforce lifetime immediately on release */ if (server->state != SV_LOGIN && life_over(server)) { disconnect_server(server, true, "server_lifetime"); pool->last_lifetime_disconnect = get_cached_time(); return false; } /* enforce close request */ if (server->close_needed) { disconnect_server(server, true, "close_needed"); return false; } Assert(server->link == NULL); slog_noise(server, "release_server: new state=%d", newstate); change_server_state(server, newstate); if (newstate == SV_IDLE) /* immediately process waiters, to give fair chance */ return reuse_on_release(server); else if (newstate == SV_TESTED) return reset_on_release(server); return true; } /* drop server connection */ void disconnect_server(PgSocket *server, bool notify, const char *reason, ...) { PgPool *pool = server->pool; PgSocket *client; static const uint8_t pkt_term[] = {'X', 0,0,0,4}; int send_term = 1; usec_t now = get_cached_time(); char buf[128]; va_list ap; va_start(ap, reason); vsnprintf(buf, sizeof(buf), reason, ap); va_end(ap); reason = buf; if (cf_log_disconnections) slog_info(server, "closing because: %s (age=%" PRIu64 ")", reason, (now - server->connect_time) / USEC); switch (server->state) { case SV_ACTIVE: client = server->link; if (client) { client->link = NULL; server->link = NULL; disconnect_client(client, true, "%s", reason); } break; case SV_TESTED: case SV_USED: case SV_IDLE: break; case SV_LOGIN: /* * usually disconnect means problems in startup phase, * except when sending cancel packet */ if (!server->ready) pool->last_connect_failed = 1; else send_term = 0; break; default: fatal("disconnect_server: bad server state (%d)", server->state); } Assert(server->link == NULL); /* notify server and close connection */ if (send_term && notify) { if (!sbuf_answer(&server->sbuf, pkt_term, sizeof(pkt_term))) /* ignore result */ notify = false; } if (server->dns_token) { adns_cancel(adns, server->dns_token); server->dns_token = NULL; } change_server_state(server, SV_JUSTFREE); if (!sbuf_close(&server->sbuf)) log_noise("sbuf_close failed, retry later"); } /* drop client connection */ void disconnect_client(PgSocket *client, bool notify, const char *reason, ...) { char buf[128]; va_list ap; usec_t now = get_cached_time(); va_start(ap, reason); vsnprintf(buf, sizeof(buf), reason, ap); va_end(ap); reason = buf; if (cf_log_disconnections) slog_info(client, "closing because: %s (age=%" PRIu64 ")", reason, (now - client->connect_time) / USEC); switch (client->state) { case CL_ACTIVE: if (client->link) { PgSocket *server = client->link; /* ->ready may be set before all is sent */ if (server->ready && sbuf_is_empty(&server->sbuf)) { /* retval does not matter here */ release_server(server); } else { server->link = NULL; client->link = NULL; disconnect_server(server, true, "unclean server"); } } case CL_LOGIN: case CL_WAITING: case CL_CANCEL: break; default: fatal("bad client state in disconnect_client: %d", client->state); } /* send reason to client */ if (notify && reason && client->state != CL_CANCEL) { /* * don't send Ready pkt here, or client won't notice * closed connection */ send_pooler_error(client, false, reason); } change_client_state(client, CL_JUSTFREE); if (!sbuf_close(&client->sbuf)) log_noise("sbuf_close failed, retry later"); } /* * Connection creation utilities */ static void connect_server(struct PgSocket *server, const struct sockaddr *sa, int salen) { bool res; /* fill remote_addr */ memset(&server->remote_addr, 0, sizeof(server->remote_addr)); if (sa->sa_family == AF_UNIX) { pga_set(&server->remote_addr, AF_UNIX, server->pool->db->port); } else { pga_copy(&server->remote_addr, sa); } if (cf_log_connections) slog_info(server, "new connection to server"); /* start connecting */ res = sbuf_connect(&server->sbuf, sa, salen, cf_server_connect_timeout / USEC); if (!res) log_noise("failed to launch new connection"); } static void dns_callback(void *arg, const struct sockaddr *sa, int salen) { struct PgSocket *server = arg; struct PgDatabase *db = server->pool->db; struct sockaddr_in sa_in; struct sockaddr_in6 sa_in6; server->dns_token = NULL; if (!sa) { disconnect_server(server, true, "server dns lookup failed"); return; } else if (sa->sa_family == AF_INET) { char buf[64]; memcpy(&sa_in, sa, sizeof(sa_in)); sa_in.sin_port = htons(db->port); sa = (struct sockaddr *)&sa_in; salen = sizeof(sa_in); slog_debug(server, "dns_callback: inet4: %s", sa2str(sa, buf, sizeof(buf))); } else if (sa->sa_family == AF_INET6) { char buf[64]; memcpy(&sa_in6, sa, sizeof(sa_in6)); sa_in6.sin6_port = htons(db->port); sa = (struct sockaddr *)&sa_in6; salen = sizeof(sa_in6); slog_debug(server, "dns_callback: inet6: %s", sa2str(sa, buf, sizeof(buf))); } else { disconnect_server(server, true, "unknown address family: %d", sa->sa_family); return; } connect_server(server, sa, salen); } static void dns_connect(struct PgSocket *server) { struct sockaddr_un sa_un; struct sockaddr_in sa_in; struct sockaddr_in6 sa_in6; struct sockaddr *sa; struct PgDatabase *db = server->pool->db; const char *host = db->host; const char *unix_dir; int sa_len; if (!host || host[0] == '/') { slog_noise(server, "unix socket: %s", sa_un.sun_path); memset(&sa_un, 0, sizeof(sa_un)); sa_un.sun_family = AF_UNIX; unix_dir = host ? host : cf_unix_socket_dir; if (!unix_dir || !*unix_dir) { log_error("Unix socket dir not configured: %s", db->name); disconnect_server(server, false, "cannot connect"); return; } snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s/.s.PGSQL.%d", unix_dir, db->port); sa = (struct sockaddr *)&sa_un; sa_len = sizeof(sa_un); } else if (strchr(host, ':')) { // assume IPv6 address on any : in addr slog_noise(server, "inet6 socket: %s", db->host); memset(&sa_in6, 0, sizeof(sa_in6)); sa_in6.sin6_family = AF_INET6; inet_pton(AF_INET6, db->host, (void *) sa_in6.sin6_addr.s6_addr); sa_in6.sin6_port = htons(db->port); sa = (struct sockaddr *)&sa_in6; sa_len = sizeof(sa_in6); } else if (host[0] >= '0' && host[0] <= '9') { // else try IPv4 slog_noise(server, "inet socket: %s", db->host); memset(&sa_in, 0, sizeof(sa_in)); sa_in.sin_family = AF_INET; sa_in.sin_addr.s_addr = inet_addr(db->host); sa_in.sin_port = htons(db->port); sa = (struct sockaddr *)&sa_in; sa_len = sizeof(sa_in); } else { struct DNSToken *tk; slog_noise(server, "dns socket: %s", db->host); /* launch dns lookup */ tk = adns_resolve(adns, db->host, dns_callback, server); if (tk) server->dns_token = tk; return; } connect_server(server, sa, sa_len); } /* the pool needs new connection, if possible */ void launch_new_connection(PgPool *pool) { PgSocket *server; int total; /* allow only small number of connection attempts at a time */ if (!statlist_empty(&pool->new_server_list)) { log_debug("launch_new_connection: already progress"); return; } /* if server bounces, don't retry too fast */ if (pool->last_connect_failed) { usec_t now = get_cached_time(); if (now - pool->last_connect_time < cf_server_login_retry) { log_debug("launch_new_connection: last failed, wait"); return; } } /* is it allowed to add servers? */ total = pool_server_count(pool); if (total >= pool->db->pool_size && pool->welcome_msg_ready) { /* should we use reserve pool? */ if (cf_res_pool_timeout && pool->db->res_pool_size) { usec_t now = get_cached_time(); PgSocket *c = first_socket(&pool->waiting_client_list); if (c && (now - c->request_time) >= cf_res_pool_timeout) { if (total < pool->db->pool_size + pool->db->res_pool_size) { slog_warning(c, "Taking connection from reserve_pool"); goto allow_new; } } } log_debug("launch_new_connection: pool full (%d >= %d)", total, pool->db->pool_size); return; } allow_new: /* get free conn object */ server = slab_alloc(server_cache); if (!server) { log_debug("launch_new_connection: no memory"); return; } /* initialize it */ server->pool = pool; server->auth_user = server->pool->user; server->connect_time = get_cached_time(); pool->last_connect_time = get_cached_time(); change_server_state(server, SV_LOGIN); dns_connect(server); } /* new client connection attempt */ PgSocket *accept_client(int sock, bool is_unix) { bool res; PgSocket *client; /* get free PgSocket */ client = slab_alloc(client_cache); if (!client) { log_warning("cannot allocate client struct"); safe_close(sock); return NULL; } client->connect_time = client->request_time = get_cached_time(); client->query_start = 0; /* FIXME: take local and remote address from pool_accept() */ fill_remote_addr(client, sock, is_unix); fill_local_addr(client, sock, is_unix); change_client_state(client, CL_LOGIN); res = sbuf_accept(&client->sbuf, sock, is_unix); if (!res) { if (cf_log_connections) slog_debug(client, "failed connection attempt"); return NULL; } return client; } /* send cached parameters to client to pretend being server */ /* client managed to authenticate, send welcome msg and accept queries */ bool finish_client_login(PgSocket *client) { switch (client->state) { case CL_LOGIN: change_client_state(client, CL_ACTIVE); case CL_ACTIVE: break; default: fatal("bad client state"); } /* check if we know server signature */ if (!client->pool->welcome_msg_ready) { log_debug("finish_client_login: no welcome message, pause"); client->wait_for_welcome = 1; pause_client(client); if (cf_pause_mode == P_NONE) launch_new_connection(client->pool); return false; } client->wait_for_welcome = 0; /* send the message */ if (!welcome_client(client)) return false; slog_debug(client, "logged in"); return true; } /* client->cancel_key has requested client key */ void accept_cancel_request(PgSocket *req) { struct List *pitem, *citem; PgPool *pool = NULL; PgSocket *server = NULL, *client, *main_client = NULL; Assert(req->state == CL_LOGIN); /* find real client this is for */ statlist_for_each(pitem, &pool_list) { pool = container_of(pitem, PgPool, head); statlist_for_each(citem, &pool->active_client_list) { client = container_of(citem, PgSocket, head); if (memcmp(client->cancel_key, req->cancel_key, 8) == 0) { main_client = client; goto found; } } } found: /* wrong key */ if (!main_client) { disconnect_client(req, false, "failed cancel request"); return; } /* not linked client, just drop it then */ if (!main_client->link) { bool res; /* let administrative cancel be handled elsewhere */ if (main_client->pool->db->admin) { disconnect_client(req, false, "cancel request for console client"); admin_handle_cancel(main_client); return; } disconnect_client(req, false, "cancel request for idle client"); /* notify readiness */ SEND_ReadyForQuery(res, main_client); if (!res) disconnect_client(main_client, true, "ReadyForQuery for main_client failed"); return; } /* drop the connection, if fails, retry later in justfree list */ if (!sbuf_close(&req->sbuf)) log_noise("sbuf_close failed, retry later"); /* remember server key */ server = main_client->link; memcpy(req->cancel_key, server->cancel_key, 8); /* attach to target pool */ req->pool = pool; change_client_state(req, CL_CANCEL); /* need fresh connection */ launch_new_connection(pool); } void forward_cancel_request(PgSocket *server) { bool res; PgSocket *req = first_socket(&server->pool->cancel_req_list); Assert(req != NULL && req->state == CL_CANCEL); Assert(server->state == SV_LOGIN); SEND_CancelRequest(res, server, req->cancel_key); change_client_state(req, CL_JUSTFREE); } bool use_client_socket(int fd, PgAddr *addr, const char *dbname, const char *username, uint64_t ckey, int oldfd, int linkfd, const char *client_enc, const char *std_string, const char *datestyle, const char *timezone) { PgSocket *client; PktBuf tmp; client = accept_client(fd, pga_is_unix(addr)); if (client == NULL) return false; client->suspended = 1; if (!set_pool(client, dbname, username)) return false; change_client_state(client, CL_ACTIVE); /* store old cancel key */ pktbuf_static(&tmp, client->cancel_key, 8); pktbuf_put_uint64(&tmp, ckey); /* store old fds */ client->tmp_sk_oldfd = oldfd; client->tmp_sk_linkfd = linkfd; varcache_set(&client->vars, "client_encoding", client_enc); varcache_set(&client->vars, "standard_conforming_strings", std_string); varcache_set(&client->vars, "datestyle", datestyle); varcache_set(&client->vars, "timezone", timezone); return true; } bool use_server_socket(int fd, PgAddr *addr, const char *dbname, const char *username, uint64_t ckey, int oldfd, int linkfd, const char *client_enc, const char *std_string, const char *datestyle, const char *timezone) { PgDatabase *db = find_database(dbname); PgUser *user; PgPool *pool; PgSocket *server; PktBuf tmp; bool res; /* if the database not found, it's an auto database -> registering... */ if (!db) { db = register_auto_database(dbname); if (!db) return true; } if (db->forced_user) user = db->forced_user; else user = find_user(username); pool = get_pool(db, user); if (!pool) return false; server = slab_alloc(server_cache); if (!server) return false; res = sbuf_accept(&server->sbuf, fd, pga_is_unix(addr)); if (!res) return false; server->suspended = 1; server->pool = pool; server->auth_user = user; server->connect_time = server->request_time = get_cached_time(); server->query_start = 0; fill_remote_addr(server, fd, pga_is_unix(addr)); fill_local_addr(server, fd, pga_is_unix(addr)); if (linkfd) { server->ready = 0; change_server_state(server, SV_ACTIVE); } else { server->ready = 1; change_server_state(server, SV_IDLE); } /* store old cancel key */ pktbuf_static(&tmp, server->cancel_key, 8); pktbuf_put_uint64(&tmp, ckey); /* store old fds */ server->tmp_sk_oldfd = oldfd; server->tmp_sk_linkfd = linkfd; varcache_set(&server->vars, "client_encoding", client_enc); varcache_set(&server->vars, "standard_conforming_strings", std_string); varcache_set(&server->vars, "datestyle", datestyle); varcache_set(&server->vars, "timezone", timezone); return true; } void for_each_server(PgPool *pool, void (*func)(PgSocket *sk)) { struct List *item; statlist_for_each(item, &pool->idle_server_list) func(container_of(item, PgSocket, head)); statlist_for_each(item, &pool->used_server_list) func(container_of(item, PgSocket, head)); statlist_for_each(item, &pool->tested_server_list) func(container_of(item, PgSocket, head)); statlist_for_each(item, &pool->active_server_list) func(container_of(item, PgSocket, head)); statlist_for_each(item, &pool->new_server_list) func(container_of(item, PgSocket, head)); } static void for_each_server_filtered(PgPool *pool, void (*func)(PgSocket *sk), bool (*filter)(PgSocket *sk, void *arg), void *filter_arg) { struct List *item; PgSocket *sk; statlist_for_each(item, &pool->idle_server_list) { sk = container_of(item, PgSocket, head); if (filter(sk, filter_arg)) func(sk); } statlist_for_each(item, &pool->used_server_list) { sk = container_of(item, PgSocket, head); if (filter(sk, filter_arg)) func(sk); } statlist_for_each(item, &pool->tested_server_list) { sk = container_of(item, PgSocket, head); if (filter(sk, filter_arg)) func(sk); } statlist_for_each(item, &pool->active_server_list) { sk = container_of(item, PgSocket, head); if (filter(sk, filter_arg)) func(sk); } statlist_for_each(item, &pool->new_server_list) { sk = container_of(item, PgSocket, head); if (filter(sk, filter_arg)) func(sk); } } static void tag_dirty(PgSocket *sk) { sk->close_needed = 1; } static void tag_pool_dirty(PgPool *pool) { struct List *item, *tmp; struct PgSocket *server; /* reset welcome msg */ if (pool->welcome_msg) { pktbuf_free(pool->welcome_msg); pool->welcome_msg = NULL; } pool->welcome_msg_ready = 0; /* drop all existing servers ASAP */ for_each_server(pool, tag_dirty); /* drop servers login phase immediately */ statlist_for_each_safe(item, &pool->new_server_list, tmp) { server = container_of(item, PgSocket, head); disconnect_server(server, true, "connect string changed"); } } void tag_database_dirty(PgDatabase *db) { struct List *item; PgPool *pool; statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); if (pool->db == db) tag_pool_dirty(pool); } } void tag_autodb_dirty(void) { struct List *item; PgPool *pool; statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); if (pool->db->db_auto) tag_pool_dirty(pool); } } static bool server_remote_addr_filter(PgSocket *sk, void *arg) { PgAddr *addr = arg; return (pga_cmp_addr(&sk->remote_addr, addr) == 0); } void tag_host_addr_dirty(const char *host, const struct sockaddr *sa) { struct List *item; PgPool *pool; PgAddr addr; memset(&addr, 0, sizeof(addr)); pga_copy(&addr, sa); statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); if (pool->db->host && strcmp(host, pool->db->host) == 0) { for_each_server_filtered(pool, tag_dirty, server_remote_addr_filter, &addr); } } } /* move objects from justfree_* to free_* lists */ void reuse_just_freed_objects(void) { struct List *tmp, *item; PgSocket *sk; bool close_works = true; /* * event_del() may fail because of ENOMEM for event handlers * that need only changes sent to kernel on each loop. * * Keep open sbufs in justfree lists until successful. */ statlist_for_each_safe(item, &justfree_client_list, tmp) { sk = container_of(item, PgSocket, head); if (sbuf_is_closed(&sk->sbuf)) change_client_state(sk, CL_FREE); else if (close_works) close_works = sbuf_close(&sk->sbuf); } statlist_for_each_safe(item, &justfree_server_list, tmp) { sk = container_of(item, PgSocket, head); if (sbuf_is_closed(&sk->sbuf)) change_server_state(sk, SV_FREE); else if (close_works) close_works = sbuf_close(&sk->sbuf); } } pgbouncer-1.5.4/src/util.c0000644000175000017500000002311712005217606012341 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Random small utility functions */ #include "bouncer.h" #define MD5_COMPAT #include int log_socket_prefix(enum LogLevel lev, void *ctx, char *dst, unsigned int dstlen) { const struct PgSocket *sock = ctx; const char *user, *db, *host; char host6[PGADDR_BUF]; int port; /* no prefix */ if (!sock) return 0; /* format prefix */ db = sock->pool ? sock->pool->db->name : "(nodb)"; user = sock->auth_user ? sock->auth_user->name : "(nouser)"; if (pga_is_unix(&sock->remote_addr)) { host = "unix"; } else { host = pga_ntop(&sock->remote_addr, host6, sizeof(host6)); } port = pga_port(&sock->remote_addr); return snprintf(dst, dstlen, "%c-%p: %s/%s@%s:%d ", is_server_socket(sock) ? 'S' : 'C', sock, db, user, host, port); } const char *bin2hex(const uint8_t *src, unsigned srclen, char *dst, unsigned dstlen) { unsigned int i, j; static const char hextbl [] = "0123456789abcdef"; if (!dstlen) return ""; if (srclen*2+1 > dstlen) srclen = (dstlen - 1) / 2; for (i = j = 0; i < srclen; i++) { dst[j++] = hextbl[src[i] >> 4]; dst[j++] = hextbl[src[i] & 15]; } dst[j] = 0; return dst; } /* * PostgreSQL MD5 hashing. */ static void hash2hex(const uint8_t *hash, char *dst) { bin2hex(hash, MD5_DIGEST_LENGTH, dst, 16*2+1); } void pg_md5_encrypt(const char *part1, const char *part2, size_t part2len, char *dest) { MD5_CTX ctx; uint8_t hash[MD5_DIGEST_LENGTH]; MD5_Init(&ctx); MD5_Update(&ctx, part1, strlen(part1)); MD5_Update(&ctx, part2, part2len); MD5_Final(hash, &ctx); memcpy(dest, "md5", 3); hash2hex(hash, dest + 3); } /* wrapped for getting random bytes */ void get_random_bytes(uint8_t *dest, int len) { int i; for (i = 0; i < len; i++) dest[i] = random() & 255; } /* set needed socket options */ bool tune_socket(int sock, bool is_unix) { int res; int val; /* close fd on exec */ res = fcntl(sock, F_SETFD, FD_CLOEXEC); if (res < 0) goto fail; /* when no data available, return EAGAIN instead blocking */ socket_set_nonblocking(sock, 1); #ifdef SO_NOSIGPIPE /* disallow SIGPIPE, if possible */ val = 1; res = setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)); if (res < 0) goto fail; #endif /* * Following options are for network sockets */ if (is_unix) return true; /* the keepalive stuff needs some poking before enbling */ if (cf_tcp_keepalive) { /* turn on socket keepalive */ val = 1; res = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); if (res < 0) goto fail; #ifdef __linux__ /* set count of keepalive packets */ if (cf_tcp_keepcnt > 0) { val = cf_tcp_keepcnt; res = setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)); if (res < 0) goto fail; } /* how long the connection can stay idle before sending keepalive pkts */ if (cf_tcp_keepidle) { val = cf_tcp_keepidle; res = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)); if (res < 0) goto fail; } /* time between packets */ if (cf_tcp_keepintvl) { val = cf_tcp_keepintvl; res = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)); if (res < 0) goto fail; } #else #ifdef TCP_KEEPALIVE if (cf_tcp_keepidle) { val = cf_tcp_keepidle; res = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)); if (res < 0) goto fail; } #endif #endif } /* set in-kernel socket buffer size */ if (cf_tcp_socket_buffer) { val = cf_tcp_socket_buffer; res = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); if (res < 0) goto fail; val = cf_tcp_socket_buffer; res = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)); if (res < 0) goto fail; } /* * Turn off kernel buffering, each send() will be one packet. */ val = 1; res = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); if (res < 0) goto fail; return true; fail: log_warning("tune_socket(%d) failed: %s", sock, strerror(errno)); return false; } /* * Find a string in comma-separated list. * * It does not support space inside tokens. */ bool strlist_contains(const char *liststr, const char *str) { int c, len = strlen(str); const char *p, *listpos = liststr; loop: /* find string fragment, later check if actual token */ p = strstr(listpos, str); if (p == NULL) return false; /* move listpos further */ listpos = p + len; /* survive len=0 and avoid unneccesary compare */ if (*listpos) listpos++; /* check previous symbol */ if (p > liststr) { c = *(p - 1); if (!isspace(c) && c != ',') goto loop; } /* check following symbol */ c = p[len]; if (c != 0 && !isspace(c) && c != ',') goto loop; return true; } void fill_remote_addr(PgSocket *sk, int fd, bool is_unix) { PgAddr *dst = &sk->remote_addr; socklen_t len = sizeof(PgAddr); int err; if (is_unix) { pga_set(dst, AF_UNIX, cf_listen_port); } else { err = getpeername(fd, (struct sockaddr *)dst, &len); if (err < 0) { log_error("fill_remote_addr: getpeername(%d) = %s", fd, strerror(errno)); } } } void fill_local_addr(PgSocket *sk, int fd, bool is_unix) { PgAddr *dst = &sk->local_addr; socklen_t len = sizeof(PgAddr); int err; if (is_unix) { pga_set(dst, AF_UNIX, cf_listen_port); } else { err = getsockname(fd, (struct sockaddr *)dst, &len); if (err < 0) { log_error("fill_local_addr: getsockname(%d) = %s", fd, strerror(errno)); } } } /* * Error handling around evtimer_add() is nasty as the code * may not be called again. As there is fixed number of timers * in pgbouncer, provider safe_evtimer_add() that stores args of * failed calls in static array and retries later. */ #define TIMER_BACKUP_SLOTS 10 struct timer_slot { struct event *ev; struct timeval tv; }; static struct timer_slot timer_backup_list[TIMER_BACKUP_SLOTS]; static int timer_backup_used = 0; void safe_evtimer_add(struct event *ev, struct timeval *tv) { int res; struct timer_slot *ts; res = evtimer_add(ev, tv); if (res >= 0) return; if (timer_backup_used >= TIMER_BACKUP_SLOTS) fatal_perror("TIMER_BACKUP_SLOTS full"); ts = &timer_backup_list[timer_backup_used++]; ts->ev = ev; ts->tv = *tv; } void rescue_timers(void) { struct timer_slot *ts; while (timer_backup_used) { ts = &timer_backup_list[timer_backup_used - 1]; if (evtimer_add(ts->ev, &ts->tv) < 0) break; timer_backup_used--; } } /* * PgAddr operations */ int pga_port(const PgAddr *a) { if (a->sa.sa_family == AF_INET6) { return ntohs(a->sin6.sin6_port); } else { return ntohs(a->sin.sin_port); } } /* set family and port */ void pga_set(PgAddr *a, int af, int port) { memset(a, 0, sizeof(*a)); if (af == AF_INET6) { a->sin6.sin6_family = af; a->sin6.sin6_port = htons(port); } else { a->sin.sin_family = af; a->sin.sin_port = htons(port); } } /* copy sockaddr_in/in6 to PgAddr */ void pga_copy(PgAddr *a, const struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: memcpy(&a->sin, sa, sizeof(a->sin)); break; case AF_INET6: memcpy(&a->sin6, sa, sizeof(a->sin6)); break; case AF_UNIX: log_error("pga_copy: AF_UNIX copy not supported"); } } static inline unsigned pga_family(const PgAddr *a) { return a->sa.sa_family; } int pga_cmp_addr(const PgAddr *a, const PgAddr *b) { if (pga_family(a) != pga_family(b)) return pga_family(a) - pga_family(b); switch (pga_family(a)) { case AF_INET: return memcmp(&a->sin.sin_addr, &b->sin.sin_addr, sizeof(a->sin.sin_addr)); break; case AF_INET6: return memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr, sizeof(a->sin6.sin6_addr)); break; default: log_error("pga_cmp_addr: unsupported family"); return 0; } } /* convert pgaddr to string */ const char *pga_ntop(const PgAddr *a, char *dst, int dstlen) { const char *res = NULL; char buf[PGADDR_BUF]; memset(buf, 0, sizeof(buf)); switch (pga_family(a)) { case AF_UNIX: res = "unix"; break; case AF_INET: res = inet_ntop(AF_INET, &a->sin.sin_addr, buf, sizeof(buf)); break; case AF_INET6: res = inet_ntop(AF_INET6, &a->sin6.sin6_addr, buf, sizeof(buf)); break; default: res = "(bad-af)"; } if (res == NULL) res = "(err-ntop)"; strlcpy(dst, res, dstlen); return dst; } /* parse address from string */ bool pga_pton(PgAddr *a, const char *s, int port) { int res = 1; if (strcmp(s, "unix") == 0) { pga_set(a, AF_UNIX, port); } else if (strcmp(s, "*") == 0) { pga_set(a, AF_INET, port); a->sin.sin_addr.s_addr = htonl(INADDR_ANY); } else if (strchr(s, ':')) { pga_set(a, AF_INET6, port); res = inet_pton(AF_INET6, s, &a->sin6.sin6_addr); } else { pga_set(a, AF_INET, port); res = inet_pton(AF_INET, s, &a->sin.sin_addr); } if (res == 0) errno = EINVAL; return res > 0; } const char *pga_str(const PgAddr *a, char *dst, int dstlen) { char buf[PGADDR_BUF]; pga_ntop(a, buf, sizeof(buf)); snprintf(dst, dstlen, "%s@%d", buf, pga_port(a)); return dst; } pgbouncer-1.5.4/src/stats.c0000644000175000017500000001263711765176015012541 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "bouncer.h" static struct event ev_stats; static usec_t old_stamp, new_stamp; static void reset_stats(PgStats *stat) { stat->server_bytes = 0; stat->client_bytes = 0; stat->request_count = 0; stat->query_time = 0; } static void stat_add(PgStats *total, PgStats *stat) { total->server_bytes += stat->server_bytes; total->client_bytes += stat->client_bytes; total->request_count += stat->request_count; total->query_time += stat->query_time; } static void calc_average(PgStats *avg, PgStats *cur, PgStats *old) { uint64_t qcount; usec_t dur = get_cached_time() - old_stamp; reset_stats(avg); if (dur <= 0) return; avg->request_count = USEC * (cur->request_count - old->request_count) / dur; avg->client_bytes = USEC * (cur->client_bytes - old->client_bytes) / dur; avg->server_bytes = USEC * (cur->server_bytes - old->server_bytes) / dur; qcount = cur->request_count - old->request_count; if (qcount > 0) avg->query_time = (cur->query_time - old->query_time) / qcount; } static void write_stats(PktBuf *buf, PgStats *stat, PgStats *old, char *dbname) { PgStats avg; calc_average(&avg, stat, old); pktbuf_write_DataRow(buf, "sqqqqqqqq", dbname, stat->request_count, stat->client_bytes, stat->server_bytes, stat->query_time, avg.request_count, avg.client_bytes, avg.server_bytes, avg.query_time); } bool admin_database_stats(PgSocket *client, struct StatList *pool_list) { PgPool *pool; struct List *item; PgDatabase *cur_db = NULL; PgStats st_total, st_db, old_db, old_total; int rows = 0; PktBuf *buf; reset_stats(&st_total); reset_stats(&st_db); reset_stats(&old_db); reset_stats(&old_total); buf = pktbuf_dynamic(512); if (!buf) { admin_error(client, "no mem"); return true; } pktbuf_write_RowDescription(buf, "sqqqqqqqq", "database", "total_requests", "total_received", "total_sent", "total_query_time", "avg_req", "avg_recv", "avg_sent", "avg_query"); statlist_for_each(item, pool_list) { pool = container_of(item, PgPool, head); if (!cur_db) cur_db = pool->db; if (pool->db != cur_db) { write_stats(buf, &st_db, &old_db, cur_db->name); rows ++; cur_db = pool->db; stat_add(&st_total, &st_db); stat_add(&old_total, &old_db); reset_stats(&st_db); reset_stats(&old_db); } stat_add(&st_db, &pool->stats); stat_add(&old_db, &pool->older_stats); } if (cur_db) { write_stats(buf, &st_db, &old_db, cur_db->name); stat_add(&st_total, &st_db); stat_add(&old_total, &old_db); rows ++; } admin_flush(client, buf, "SHOW"); return true; } bool show_stat_totals(PgSocket *client, struct StatList *pool_list) { PgPool *pool; struct List *item; PgStats st_total, old_total, avg; PktBuf *buf; reset_stats(&st_total); reset_stats(&old_total); buf = pktbuf_dynamic(512); if (!buf) { admin_error(client, "no mem"); return true; } statlist_for_each(item, pool_list) { pool = container_of(item, PgPool, head); stat_add(&st_total, &pool->stats); stat_add(&old_total, &pool->older_stats); } calc_average(&avg, &st_total, &old_total); pktbuf_write_RowDescription(buf, "sq", "name", "value"); #define WTOTAL(name) pktbuf_write_DataRow(buf, "sq", "total_" #name, st_total.name) #define WAVG(name) pktbuf_write_DataRow(buf, "sq", "avg_" #name, avg.name) WTOTAL(request_count); WTOTAL(client_bytes); WTOTAL(server_bytes); WTOTAL(query_time); WAVG(request_count); WAVG(client_bytes); WAVG(server_bytes); WAVG(query_time); admin_flush(client, buf, "SHOW"); return true; } static void refresh_stats(int s, short flags, void *arg) { struct List *item; PgPool *pool; struct timeval period = { cf_stats_period, 0 }; PgStats old_total, cur_total, avg; reset_stats(&old_total); reset_stats(&cur_total); old_stamp = new_stamp; new_stamp = get_cached_time(); statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); pool->older_stats = pool->newer_stats; pool->newer_stats = pool->stats; stat_add(&cur_total, &pool->stats); stat_add(&old_total, &pool->older_stats); } calc_average(&avg, &cur_total, &old_total); /* send totals to logfile */ log_info("Stats: %" PRIu64 " req/s," " in %" PRIu64 " b/s," " out %" PRIu64 " b/s," "query %" PRIu64 " us", avg.request_count, avg.client_bytes, avg.server_bytes, avg.query_time); safe_evtimer_add(&ev_stats, &period); } void stats_setup(void) { struct timeval period = { cf_stats_period, 0 }; new_stamp = get_cached_time(); old_stamp = new_stamp - USEC; /* launch stats */ evtimer_set(&ev_stats, refresh_stats, NULL); safe_evtimer_add(&ev_stats, &period); } pgbouncer-1.5.4/src/server.c0000644000175000017500000002640112013151606012665 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Handling of server connections */ #include "bouncer.h" static bool load_parameter(PgSocket *server, PktHdr *pkt, bool startup) { const char *key, *val; PgSocket *client = server->link; /* * Want to see complete packet. That means SMALL_PKT * in sbuf.c must be larger than max param pkt. */ if (incomplete_pkt(pkt)) return false; if (!mbuf_get_string(&pkt->data, &key)) goto failed; if (!mbuf_get_string(&pkt->data, &val)) goto failed; slog_debug(server, "S: param: %s = %s", key, val); varcache_set(&server->vars, key, val); if (client) { slog_debug(client, "setting client var: %s='%s'", key, val); varcache_set(&client->vars, key, val); } if (startup) { if (!add_welcome_parameter(server->pool, key, val)) goto failed_store; } return true; failed: disconnect_server(server, true, "broken ParameterStatus packet"); return false; failed_store: disconnect_server(server, true, "failed to store ParameterStatus"); return false; } /* we cannot log in at all, notify clients */ static void kill_pool_logins(PgPool *pool, PktHdr *errpkt) { struct List *item, *tmp; PgSocket *client; const char *level, *msg; parse_server_error(errpkt, &level, &msg); log_warning("server login failed: %s %s", level, msg); statlist_for_each_safe(item, &pool->waiting_client_list, tmp) { client = container_of(item, PgSocket, head); if (!client->wait_for_welcome) continue; disconnect_client(client, true, "%s", msg); } } /* process packets on server auth phase */ static bool handle_server_startup(PgSocket *server, PktHdr *pkt) { SBuf *sbuf = &server->sbuf; bool res = false; const uint8_t *ckey; if (incomplete_pkt(pkt)) { disconnect_server(server, true, "partial pkt in login phase"); return false; } /* ignore most that happens during connect_query */ if (server->exec_on_connect) { switch (pkt->type) { case 'Z': case 'S': /* handle them below */ break; case 'E': /* log & ignore errors */ log_server_error("S: error while executing exec_on_query", pkt); default: /* ignore rest */ sbuf_prepare_skip(sbuf, pkt->len); return true; } } switch (pkt->type) { default: slog_error(server, "unknown pkt from server: '%c'", pkt_desc(pkt)); disconnect_server(server, true, "unknown pkt from server"); break; case 'E': /* ErrorResponse */ if (!server->pool->welcome_msg_ready) kill_pool_logins(server->pool, pkt); else log_server_error("S: login failed", pkt); disconnect_server(server, true, "login failed"); break; /* packets that need closer look */ case 'R': /* AuthenticationXXX */ slog_debug(server, "calling login_answer"); res = answer_authreq(server, pkt); if (!res) disconnect_server(server, false, "failed to answer authreq"); break; case 'S': /* ParameterStatus */ res = load_parameter(server, pkt, true); break; case 'Z': /* ReadyForQuery */ if (server->exec_on_connect) { server->exec_on_connect = 0; /* deliberately ignore transaction status */ } else if (server->pool->db->connect_query) { server->exec_on_connect = 1; slog_debug(server, "server conect ok, send exec_on_connect"); SEND_generic(res, server, 'Q', "s", server->pool->db->connect_query); if (!res) disconnect_server(server, false, "exec_on_connect query failed"); break; } /* login ok */ slog_debug(server, "server login ok, start accepting queries"); server->ready = 1; /* got all params */ finish_welcome_msg(server); /* need to notify sbuf if server was closed */ res = release_server(server); /* let the takeover process handle it */ if (res && server->pool->db->admin) res = takeover_login(server); break; /* ignorable packets */ case 'K': /* BackendKeyData */ if (!mbuf_get_bytes(&pkt->data, BACKENDKEY_LEN, &ckey)) { disconnect_server(server, true, "bad cancel key"); return false; } memcpy(server->cancel_key, ckey, BACKENDKEY_LEN); res = true; break; case 'N': /* NoticeResponse */ slog_noise(server, "skipping pkt: %c", pkt_desc(pkt)); res = true; break; } if (res) sbuf_prepare_skip(sbuf, pkt->len); return res; } /* process packets on logged in connection */ static bool handle_server_work(PgSocket *server, PktHdr *pkt) { bool ready = false; bool idle_tx = false; char state; SBuf *sbuf = &server->sbuf; PgSocket *client = server->link; Assert(!server->pool->db->admin); switch (pkt->type) { default: slog_error(server, "unknown pkt: '%c'", pkt_desc(pkt)); disconnect_server(server, true, "unknown pkt"); return false; /* pooling decisions will be based on this packet */ case 'Z': /* ReadyForQuery */ /* if partial pkt, wait */ if (!mbuf_get_char(&pkt->data, &state)) return false; /* set ready only if no tx */ if (state == 'I') { ready = true; } else if (cf_pool_mode == POOL_STMT) { disconnect_server(server, true, "Long transactions not allowed"); return false; } else if (state == 'T' || state == 'E') { idle_tx = true; } break; case 'S': /* ParameterStatus */ if (!load_parameter(server, pkt, false)) return false; break; /* * 'E' and 'N' packets currently set ->ready to 0. Correct would * be to leave ->ready as-is, because overal TX state stays same. * It matters for connections in IDLE or USED state which get dirty * suddenly but should not as they are still usable. * * But the 'E' or 'N' packet between transactions signifies probably * dying backend. This its better to tag server as dirty and drop * it later. */ case 'E': /* ErrorResponse */ if (server->setting_vars) { /* * the SET and user query will be different TX * so we cannot report SET error to user. */ log_server_error("varcache_apply failed", pkt); /* * client probably gave invalid values in startup pkt. * * no reason to keep such guys. */ disconnect_server(server, true, "invalid server parameter"); return false; } case 'N': /* NoticeResponse */ break; /* reply to LISTEN, don't change connection state */ case 'A': /* NotificationResponse */ idle_tx = server->idle_tx; ready = server->ready; break; /* chat packets */ case '2': /* BindComplete */ case '3': /* CloseComplete */ case 'c': /* CopyDone(F/B) */ case 'f': /* CopyFail(F/B) */ case 'I': /* EmptyQueryResponse == CommandComplete */ case 'V': /* FunctionCallResponse */ case 'n': /* NoData */ case 'G': /* CopyInResponse */ case 'H': /* CopyOutResponse */ case '1': /* ParseComplete */ case 's': /* PortalSuspended */ case 'C': /* CommandComplete */ /* data packets, there will be more coming */ case 'd': /* CopyData(F/B) */ case 'D': /* DataRow */ case 't': /* ParameterDescription */ case 'T': /* RowDescription */ break; } server->idle_tx = idle_tx; server->ready = ready; server->pool->stats.server_bytes += pkt->len; if (server->setting_vars) { Assert(client); sbuf_prepare_skip(sbuf, pkt->len); } else if (client) { sbuf_prepare_send(sbuf, &client->sbuf, pkt->len); if (ready && client->query_start) { usec_t total; total = get_cached_time() - client->query_start; client->query_start = 0; server->pool->stats.query_time += total; slog_debug(client, "query time: %d us", (int)total); } else if (ready) { slog_warning(client, "FIXME: query end, but query_start == 0"); } } else { if (server->state != SV_TESTED) slog_warning(server, "got packet '%c' from server when not linked", pkt_desc(pkt)); sbuf_prepare_skip(sbuf, pkt->len); } return true; } /* got connection, decide what to do */ static bool handle_connect(PgSocket *server) { bool res = false; PgPool *pool = server->pool; fill_local_addr(server, sbuf_socket(&server->sbuf), pga_is_unix(&server->remote_addr)); if (!statlist_empty(&pool->cancel_req_list)) { slog_debug(server, "use it for pending cancel req"); /* if pending cancel req, send it */ forward_cancel_request(server); /* notify disconnect_server() that connect did not fail */ server->ready = 1; disconnect_server(server, false, "sent cancel req"); } else { /* proceed with login */ res = send_startup_packet(server); if (!res) disconnect_server(server, false, "startup pkt failed"); } return res; } /* callback from SBuf */ bool server_proto(SBuf *sbuf, SBufEvent evtype, struct MBuf *data) { bool res = false; PgSocket *server = container_of(sbuf, PgSocket, sbuf); PgPool *pool = server->pool; PktHdr pkt; Assert(is_server_socket(server)); Assert(server->state != SV_FREE); /* may happen if close failed */ if (server->state == SV_JUSTFREE) return false; switch (evtype) { case SBUF_EV_RECV_FAILED: disconnect_server(server, false, "server conn crashed?"); break; case SBUF_EV_SEND_FAILED: disconnect_client(server->link, false, "unexpected eof"); break; case SBUF_EV_READ: if (mbuf_avail_for_read(data) < NEW_HEADER_LEN) { slog_noise(server, "S: got partial header, trying to wait a bit"); break; } /* parse pkt header */ if (!get_header(data, &pkt)) { disconnect_server(server, true, "bad pkt header"); break; } slog_noise(server, "S: pkt '%c', len=%d", pkt_desc(&pkt), pkt.len); server->request_time = get_cached_time(); switch (server->state) { case SV_LOGIN: res = handle_server_startup(server, &pkt); break; case SV_TESTED: case SV_USED: case SV_ACTIVE: case SV_IDLE: res = handle_server_work(server, &pkt); break; default: fatal("server_proto: server in bad state: %d", server->state); } break; case SBUF_EV_CONNECT_FAILED: Assert(server->state == SV_LOGIN); disconnect_server(server, false, "connect failed"); break; case SBUF_EV_CONNECT_OK: slog_debug(server, "S: connect ok"); Assert(server->state == SV_LOGIN); server->request_time = get_cached_time(); res = handle_connect(server); break; case SBUF_EV_FLUSH: res = true; if (!server->ready) break; if (server->setting_vars) { PgSocket *client = server->link; Assert(client); server->setting_vars = 0; sbuf_continue(&client->sbuf); break; } if (cf_pool_mode != POOL_SESSION || server->state == SV_TESTED) { switch (server->state) { case SV_ACTIVE: case SV_TESTED: /* retval does not matter here */ release_server(server); break; default: slog_warning(server, "EV_FLUSH with state=%d", server->state); case SV_IDLE: break; } } break; case SBUF_EV_PKT_CALLBACK: slog_warning(server, "SBUF_EV_PKT_CALLBACK with state=%d", server->state); break; } if (!res && pool->db->admin) takeover_login_failed(); return res; } pgbouncer-1.5.4/src/takeover.c0000644000175000017500000002134111765176015013213 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Connect to running bouncer process, load fds from it, shut it down * and continue with them. * * Each row from SHOW FDS will have corresponding fd in ancillary message. * * Manpages: unix, sendmsg, recvmsg, cmsg, readv */ #include "bouncer.h" /* * Takeover done, old process shut down, * kick this one running. */ static PgSocket *old_bouncer = NULL; void takeover_finish(void) { uint8_t buf[512]; int fd = sbuf_socket(&old_bouncer->sbuf); bool res; int got; log_info("sending SHUTDOWN;"); socket_set_nonblocking(fd, 0); SEND_generic(res, old_bouncer, 'Q', "s", "SHUTDOWN;"); if (!res) fatal("failed to send SHUTDOWN;"); while (1) { got = safe_recv(fd, buf, sizeof(buf), 0); if (got == 0) break; if (got < 0) fatal_perror("sky is falling - error while waiting result from SHUTDOWN"); } disconnect_server(old_bouncer, false, "disko over"); old_bouncer = NULL; log_info("old process killed, resuming work"); resume_all(); } static void takeover_finish_part1(PgSocket *bouncer) { Assert(old_bouncer == NULL); /* unregister bouncer from libevent */ if (!sbuf_pause(&bouncer->sbuf)) fatal_perror("sbuf_pause failed"); old_bouncer = bouncer; cf_reboot = 0; log_info("disko over, going background"); } /* parse msg for fd and info */ static void takeover_load_fd(struct MBuf *pkt, const struct cmsghdr *cmsg) { int fd; char *task, *saddr, *user, *db; char *client_enc, *std_string, *datestyle, *timezone; int oldfd, port, linkfd; int got; uint64_t ckey; PgAddr addr; bool res = false; memset(&addr, 0, sizeof(addr)); if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS && cmsg->cmsg_len >= CMSG_LEN(sizeof(int))) { /* get the fd */ memcpy(&fd, CMSG_DATA(cmsg), sizeof(int)); log_debug("got fd: %d", fd); } else fatal("broken fd packet"); /* parse row contents */ got = scan_text_result(pkt, "issssiqissss", &oldfd, &task, &user, &db, &saddr, &port, &ckey, &linkfd, &client_enc, &std_string, &datestyle, &timezone); if (got < 0 || task == NULL || saddr == NULL) fatal("NULL data from old process"); log_debug("FD row: fd=%d(%d) linkfd=%d task=%s user=%s db=%s enc=%s", oldfd, fd, linkfd, task, user ? user : "NULL", db ? db : "NULL", client_enc ? client_enc : "NULL"); /* fill address */ if (strcmp(saddr, "unix") == 0) { pga_set(&addr, AF_UNIX, cf_listen_port); } else { if (!pga_pton(&addr, saddr, port)) fatal("failed to convert address: %s", saddr); } /* decide what to do with it */ if (strcmp(task, "client") == 0) res = use_client_socket(fd, &addr, db, user, ckey, oldfd, linkfd, client_enc, std_string, datestyle, timezone); else if (strcmp(task, "server") == 0) res = use_server_socket(fd, &addr, db, user, ckey, oldfd, linkfd, client_enc, std_string, datestyle, timezone); else if (strcmp(task, "pooler") == 0) res = use_pooler_socket(fd, pga_is_unix(&addr)); else fatal("unknown task: %s", task); if (!res) fatal("socket takeover failed - no mem?"); } static void takeover_create_link(PgPool *pool, PgSocket *client) { struct List *item; PgSocket *server; statlist_for_each(item, &pool->active_server_list) { server = container_of(item, PgSocket, head); if (server->tmp_sk_oldfd == client->tmp_sk_linkfd) { server->link = client; client->link = server; return; } } fatal("takeover_create_link: failed to find pair"); } /* clean the inappropriate places the old fds got stored in */ static void takeover_clean_socket_list(struct StatList *list) { struct List *item; PgSocket *sk; statlist_for_each(item, list) { sk = container_of(item, PgSocket, head); if (sk->suspended) { sk->tmp_sk_oldfd = get_cached_time(); sk->tmp_sk_linkfd = get_cached_time(); } } } /* all fds loaded, create links */ static void takeover_postprocess_fds(void) { struct List *item, *item2; PgSocket *client; PgPool *pool; statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); if (pool->db->admin) continue; statlist_for_each(item2, &pool->active_client_list) { client = container_of(item2, PgSocket, head); if (client->suspended && client->tmp_sk_linkfd) takeover_create_link(pool, client); } } statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); takeover_clean_socket_list(&pool->active_client_list); takeover_clean_socket_list(&pool->active_server_list); takeover_clean_socket_list(&pool->idle_server_list); } } static void next_command(PgSocket *bouncer, struct MBuf *pkt) { bool res = true; const char *cmd; if (!mbuf_get_string(pkt, &cmd)) fatal("bad result pkt"); log_debug("takeover_recv_fds: 'C' body: %s", cmd); if (strcmp(cmd, "SUSPEND") == 0) { log_info("SUSPEND finished, sending SHOW FDS"); SEND_generic(res, bouncer, 'Q', "s", "SHOW FDS;"); } else if (strncmp(cmd, "SHOW", 4) == 0) { /* all fds loaded, review them */ takeover_postprocess_fds(); log_info("SHOW FDS finished"); takeover_finish_part1(bouncer); } else fatal("got bad CMD from old bouncer: %s", cmd); if (!res) fatal("command send failed"); } static void takeover_parse_data(PgSocket *bouncer, struct msghdr *msg, struct MBuf *data) { struct cmsghdr *cmsg; PktHdr pkt; cmsg = msg->msg_controllen ? CMSG_FIRSTHDR(msg) : NULL; while (mbuf_avail_for_read(data) > 0) { if (!get_header(data, &pkt)) fatal("cannot parse packet"); /* * There should not be partial reads from UNIX socket. */ if (incomplete_pkt(&pkt)) fatal("unexpected partial packet"); switch (pkt.type) { case 'T': /* RowDescription */ log_debug("takeover_parse_data: 'T'"); break; case 'D': /* DataRow */ log_debug("takeover_parse_data: 'D'"); if (cmsg) { takeover_load_fd(&pkt.data, cmsg); cmsg = CMSG_NXTHDR(msg, cmsg); } else fatal("got row without fd info"); break; case 'Z': /* ReadyForQuery */ log_debug("takeover_parse_data: 'Z'"); break; case 'C': /* CommandComplete */ log_debug("takeover_parse_data: 'C'"); next_command(bouncer, &pkt.data); break; case 'E': /* ErrorMessage */ log_server_error("old bouncer sent", &pkt); fatal("something failed"); default: fatal("takeover_parse_data: unexpected pkt: '%c'", pkt_desc(&pkt)); } } } /* * listen for data from old bouncer. * * use always recvmsg, to keep code simpler */ static void takeover_recv_cb(int sock, short flags, void *arg) { PgSocket *bouncer = container_of(arg, PgSocket, sbuf); uint8_t data_buf[STARTUP_BUF * 2]; uint8_t cnt_buf[128]; struct msghdr msg; struct iovec io; int res; struct MBuf data; memset(&msg, 0, sizeof(msg)); io.iov_base = data_buf; io.iov_len = sizeof(data_buf); msg.msg_iov = &io; msg.msg_iovlen = 1; msg.msg_control = cnt_buf; msg.msg_controllen = sizeof(cnt_buf); res = safe_recvmsg(sock, &msg, 0); if (res > 0) { mbuf_init_fixed_reader(&data, data_buf, res); takeover_parse_data(bouncer, &msg, &data); } else if (res == 0) { fatal("unexpected EOF"); } else { if (errno == EAGAIN) return; fatal_perror("safe_recvmsg"); } } /* * login finished, send first command, * replace recv callback with custom recvmsg() based one. */ bool takeover_login(PgSocket *bouncer) { bool res; slog_info(bouncer, "Login OK, sending SUSPEND"); SEND_generic(res, bouncer, 'Q', "s", "SUSPEND;"); if (res) { /* use own callback */ if (!sbuf_pause(&bouncer->sbuf)) fatal("sbuf_pause failed"); res = sbuf_continue_with_callback(&bouncer->sbuf, takeover_recv_cb); if (!res) fatal("takeover_login: sbuf_continue_with_callback failed"); } else { fatal("takeover_login: failed to send command"); } return res; } /* launch connection to running process */ void takeover_init(void) { PgDatabase *db = find_database("pgbouncer"); PgPool *pool = get_pool(db, db->forced_user); if (!pool) fatal("no admin pool?"); log_info("takeover_init: launching connection"); launch_new_connection(pool); } void takeover_login_failed(void) { fatal("login failed"); } pgbouncer-1.5.4/src/system.c0000644000175000017500000000564711765176015012732 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Compat functions for OSes where libc does not provide them. */ #include "bouncer.h" #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_UCRED_H #include #endif #ifdef HAVE_SYS_UCRED_H #include #endif #ifdef HAVE_PWD_H #include #endif #ifdef HAVE_GRP_H #include #endif void change_user(const char *user) { const struct passwd *pw; gid_t gset[1]; /* check for a valid username */ pw = getpwnam(user); if (pw == NULL) fatal("could not find user '%s' to switch to", user); gset[0] = pw->pw_gid; if (getuid() == 0) { if (setgroups(1, gset) < 0) fatal_perror("failed to reset groups"); } if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) fatal_perror("failed to assume identity of user '%s'", user); if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) fatal("setuid() failed to work"); } /* set permissions & mode for file */ void change_file_mode(const char *fn, mode_t mode, const char *user_name, const char *group_name) { int res; uid_t uid = -1; gid_t gid = -1; unsigned long val; char *end; /* user lookup */ if (user_name && user_name[0]) { const struct passwd *pw; val = strtoul(user_name, &end, 0); if (*end == 0) { uid = val; } else { /* check for a valid username */ pw = getpwnam(user_name); if (!pw) fatal("could not find user '%s': %s", user_name, strerror(errno)); uid = pw->pw_uid; } } /* group lookup */ if (group_name && group_name[0]) { struct group *gr; val = strtoul(group_name, &end, 0); if (*end == 0) { gid = val; } else { gr = getgrnam(group_name); if (!gr) fatal("cound not find group '%s': %s", group_name, strerror(errno)); gid = gr->gr_gid; } } /* change user/group */ if (uid != (uid_t)-1 || gid != (gid_t)-1) { res = chown(fn, uid, gid); if (res != 0) fatal("chown(%s, %d, %d) failed: %s", fn, uid, gid, strerror(errno)); } /* change mode */ res = chmod(fn, mode); if (res != 0) fatal("Failure to chmod(%s, 0%o): %s", fn, mode, strerror(errno)); } pgbouncer-1.5.4/src/client.c0000644000175000017500000002646312013151606012645 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Client connection handling */ #include "bouncer.h" static const char *hdr2hex(const struct MBuf *data, char *buf, unsigned buflen) { const uint8_t *bin = data->data + data->read_pos; unsigned int dlen; dlen = mbuf_avail_for_read(data); return bin2hex(bin, dlen, buf, buflen); } static bool check_client_passwd(PgSocket *client, const char *passwd) { char md5[MD5_PASSWD_LEN + 1]; const char *correct; PgUser *user = client->auth_user; /* disallow empty passwords */ if (!*passwd || !*user->passwd) return false; switch (cf_auth_type) { case AUTH_PLAIN: return strcmp(user->passwd, passwd) == 0; case AUTH_CRYPT: correct = crypt(user->passwd, (char *)client->tmp_login_salt); return correct && strcmp(correct, passwd) == 0; case AUTH_MD5: if (strlen(passwd) != MD5_PASSWD_LEN) return false; if (!isMD5(user->passwd)) pg_md5_encrypt(user->passwd, user->name, strlen(user->name), user->passwd); pg_md5_encrypt(user->passwd + 3, (char *)client->tmp_login_salt, 4, md5); return strcmp(md5, passwd) == 0; } return false; } bool set_pool(PgSocket *client, const char *dbname, const char *username) { PgDatabase *db; PgUser *user; /* find database */ db = find_database(dbname); if (!db) { db = register_auto_database(dbname); if (!db) { disconnect_client(client, true, "No such database: %s", dbname); return false; } else { slog_info(client, "registered new auto-database: db = %s", dbname ); } } /* find user */ if (cf_auth_type == AUTH_ANY) { /* ignore requested user */ user = NULL; if (db->forced_user == NULL) { slog_error(client, "auth_type=any requires forced user"); disconnect_client(client, true, "bouncer config error"); return false; } client->auth_user = db->forced_user; } else { /* the user clients wants to log in as */ user = find_user(username); if (!user) { disconnect_client(client, true, "No such user: %s", username); return false; } client->auth_user = user; } /* pool user may be forced */ if (db->forced_user) user = db->forced_user; client->pool = get_pool(db, user); if (!client->pool) { disconnect_client(client, true, "no memory for pool"); return false; } return check_fast_fail(client); } static bool decide_startup_pool(PgSocket *client, PktHdr *pkt) { const char *username = NULL, *dbname = NULL; const char *key, *val; bool ok; while (1) { ok = mbuf_get_string(&pkt->data, &key); if (!ok || *key == 0) break; ok = mbuf_get_string(&pkt->data, &val); if (!ok) break; if (strcmp(key, "database") == 0) { slog_debug(client, "got var: %s=%s", key, val); dbname = val; } else if (strcmp(key, "user") == 0) { slog_debug(client, "got var: %s=%s", key, val); username = val; } else if (varcache_set(&client->vars, key, val)) { slog_debug(client, "got var: %s=%s", key, val); } else if (strlist_contains(cf_ignore_startup_params, key)) { slog_debug(client, "ignoring startup parameter: %s=%s", key, val); } else { slog_warning(client, "unsupported startup parameter: %s=%s", key, val); disconnect_client(client, true, "Unsupported startup parameter: %s", key); return false; } } if (!username || !username[0]) { disconnect_client(client, true, "No username supplied"); return false; } /* if missing dbname, default to username */ if (!dbname || !dbname[0]) dbname = username; /* check if limit allows, dont limit admin db nb: new incoming conn will be attached to PgSocket, thus get_active_client_count() counts it */ if (get_active_client_count() > cf_max_client_conn) { if (strcmp(dbname, "pgbouncer") != 0) { disconnect_client(client, true, "no more connections allowed (max_client_conn)"); return false; } } /* find pool and log about it */ if (set_pool(client, dbname, username)) { if (cf_log_connections) slog_info(client, "login attempt: db=%s user=%s", dbname, username); return true; } else { if (cf_log_connections) slog_info(client, "login failed: db=%s user=%s", dbname, username); return false; } } /* mask to get offset into valid_crypt_salt[] */ #define SALT_MASK 0x3F static const char valid_crypt_salt[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static bool send_client_authreq(PgSocket *client) { uint8_t saltlen = 0; int res; int auth = cf_auth_type; uint8_t randbuf[2]; if (auth == AUTH_CRYPT) { saltlen = 2; get_random_bytes(randbuf, saltlen); client->tmp_login_salt[0] = valid_crypt_salt[randbuf[0] & SALT_MASK]; client->tmp_login_salt[1] = valid_crypt_salt[randbuf[1] & SALT_MASK]; client->tmp_login_salt[2] = 0; } else if (cf_auth_type == AUTH_MD5) { saltlen = 4; get_random_bytes((void*)client->tmp_login_salt, saltlen); } else if (auth == AUTH_ANY) auth = AUTH_TRUST; SEND_generic(res, client, 'R', "ib", auth, client->tmp_login_salt, saltlen); return res; } /* decide on packets of client in login phase */ static bool handle_client_startup(PgSocket *client, PktHdr *pkt) { const char *passwd; const uint8_t *key; bool ok; SBuf *sbuf = &client->sbuf; /* don't tolerate partial packets */ if (incomplete_pkt(pkt)) { disconnect_client(client, true, "client sent partial pkt in startup phase"); return false; } if (client->wait_for_welcome) { if (finish_client_login(client)) { /* the packet was already parsed */ sbuf_prepare_skip(sbuf, pkt->len); return true; } else return false; } switch (pkt->type) { case PKT_SSLREQ: slog_noise(client, "C: req SSL"); slog_noise(client, "P: nak"); /* reject SSL attempt */ if (!sbuf_answer(&client->sbuf, "N", 1)) { disconnect_client(client, false, "failed to nak SSL"); return false; } break; case PKT_STARTUP_V2: disconnect_client(client, true, "Old V2 protocol not supported"); return false; case PKT_STARTUP: if (client->pool) { disconnect_client(client, true, "client re-sent startup pkt"); return false; } if (!decide_startup_pool(client, pkt)) return false; if (client->pool->db->admin) { if (!admin_pre_login(client)) return false; } if (cf_auth_type <= AUTH_TRUST || client->own_user) { if (!finish_client_login(client)) return false; } else { if (!send_client_authreq(client)) { disconnect_client(client, false, "failed to send auth req"); return false; } } break; case 'p': /* PasswordMessage */ /* haven't requested it */ if (cf_auth_type <= AUTH_TRUST) { disconnect_client(client, true, "unrequested passwd pkt"); return false; } ok = mbuf_get_string(&pkt->data, &passwd); if (ok && check_client_passwd(client, passwd)) { if (!finish_client_login(client)) return false; } else { disconnect_client(client, true, "Auth failed"); return false; } break; case PKT_CANCEL: if (mbuf_avail_for_read(&pkt->data) == BACKENDKEY_LEN && mbuf_get_bytes(&pkt->data, BACKENDKEY_LEN, &key)) { memcpy(client->cancel_key, key, BACKENDKEY_LEN); accept_cancel_request(client); } else disconnect_client(client, false, "bad cancel request"); return false; default: disconnect_client(client, false, "bad packet"); return false; } sbuf_prepare_skip(sbuf, pkt->len); client->request_time = get_cached_time(); return true; } /* decide on packets of logged-in client */ static bool handle_client_work(PgSocket *client, PktHdr *pkt) { SBuf *sbuf = &client->sbuf; switch (pkt->type) { /* one-packet queries */ case 'Q': /* Query */ if (cf_disable_pqexec) { slog_error(client, "Client used 'Q' packet type."); disconnect_client(client, true, "PQexec disallowed"); return false; } case 'F': /* FunctionCall */ /* request immediate response from server */ case 'H': /* Flush */ case 'S': /* Sync */ /* copy end markers */ case 'c': /* CopyDone(F/B) */ case 'f': /* CopyFail(F/B) */ /* * extended protocol allows server (and thus pooler) * to buffer packets until sync or flush is sent by client */ case 'P': /* Parse */ case 'E': /* Execute */ case 'C': /* Close */ case 'B': /* Bind */ case 'D': /* Describe */ case 'd': /* CopyData(F/B) */ /* update stats */ if (!client->query_start) { client->pool->stats.request_count++; client->query_start = get_cached_time(); } if (client->pool->db->admin) return admin_handle_client(client, pkt); /* aquire server */ if (!find_server(client)) return false; client->pool->stats.client_bytes += pkt->len; /* tag the server as dirty */ client->link->ready = false; client->link->idle_tx = false; /* forward the packet */ sbuf_prepare_send(sbuf, &client->link->sbuf, pkt->len); break; /* client wants to go away */ default: slog_error(client, "unknown pkt from client: %d/0x%x", pkt->type, pkt->type); disconnect_client(client, true, "unknown pkt"); return false; case 'X': /* Terminate */ disconnect_client(client, false, "client close request"); return false; } return true; } /* callback from SBuf */ bool client_proto(SBuf *sbuf, SBufEvent evtype, struct MBuf *data) { bool res = false; PgSocket *client = container_of(sbuf, PgSocket, sbuf); PktHdr pkt; Assert(!is_server_socket(client)); Assert(client->sbuf.sock); Assert(client->state != CL_FREE); /* may happen if close failed */ if (client->state == CL_JUSTFREE) return false; switch (evtype) { case SBUF_EV_CONNECT_OK: case SBUF_EV_CONNECT_FAILED: /* ^ those should not happen */ case SBUF_EV_RECV_FAILED: disconnect_client(client, false, "client unexpected eof"); break; case SBUF_EV_SEND_FAILED: disconnect_server(client->link, false, "Server connection closed"); break; case SBUF_EV_READ: if (mbuf_avail_for_read(data) < NEW_HEADER_LEN && client->state != CL_LOGIN) { slog_noise(client, "C: got partial header, trying to wait a bit"); return false; } if (!get_header(data, &pkt)) { char hex[8*2 + 1]; disconnect_client(client, true, "bad packet header: '%s'", hdr2hex(data, hex, sizeof(hex))); return false; } slog_noise(client, "pkt='%c' len=%d", pkt_desc(&pkt), pkt.len); client->request_time = get_cached_time(); switch (client->state) { case CL_LOGIN: res = handle_client_startup(client, &pkt); break; case CL_ACTIVE: if (client->wait_for_welcome) res = handle_client_startup(client, &pkt); else res = handle_client_work(client, &pkt); break; case CL_WAITING: fatal("why waiting client in client_proto()"); default: fatal("bad client state: %d", client->state); } break; case SBUF_EV_FLUSH: /* client is not interested in it */ break; case SBUF_EV_PKT_CALLBACK: /* unused ATM */ break; } return res; } pgbouncer-1.5.4/src/varcache.c0000644000175000017500000001031111765176015013142 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Operations with server config parameters. */ #include "bouncer.h" #include struct var_lookup { const char *name; enum VarCacheIdx idx; }; static const struct var_lookup lookup [] = { {"client_encoding", VClientEncoding }, {"DateStyle", VDateStyle }, {"TimeZone", VTimeZone }, {"standard_conforming_strings", VStdStr }, {"application_name", VAppName }, {NULL}, }; static struct StrPool *vpool; static inline struct PStr *get_value(VarCache *cache, const struct var_lookup *lk) { return cache->var_list[lk->idx]; } bool varcache_set(VarCache *cache, const char *key, const char *value) { const struct var_lookup *lk; struct PStr *pstr = NULL; if (!vpool) { vpool = strpool_create(USUAL_ALLOC); if (!vpool) return false; } for (lk = lookup; lk->name; lk++) { if (strcasecmp(lk->name, key) == 0) goto set_value; } return false; set_value: /* drop old value */ strpool_decref(cache->var_list[lk->idx]); cache->var_list[lk->idx] = NULL; /* NULL value? */ if (!value) return false; /* set new value */ pstr = strpool_get(vpool, value, strlen(value)); if (!pstr) return false; cache->var_list[lk->idx] = pstr; return true; } static int apply_var(PktBuf *pkt, const char *key, const struct PStr *cval, const struct PStr *sval) { char buf[128]; char qbuf[128]; unsigned len; /* if unset, skip */ if (!cval || !sval || !*cval->str) return 0; /* if equal, skip */ if (cval == sval) return 0; /* ignore case difference */ if (strcasecmp(cval->str, sval->str) == 0) return 0; /* the string may have been taken from startup pkt */ if (!pg_quote_literal(qbuf, cval->str, sizeof(qbuf))) return 0; /* add SET statement to packet */ len = snprintf(buf, sizeof(buf), "SET %s=%s;", key, qbuf); if (len < sizeof(buf)) { pktbuf_put_bytes(pkt, buf, len); return 1; } else { log_warning("got too long value, skipping"); return 0; } } bool varcache_apply(PgSocket *server, PgSocket *client, bool *changes_p) { int changes = 0; struct PStr *cval, *sval; const struct var_lookup *lk; int sql_ofs; struct PktBuf *pkt = pktbuf_temp(); pktbuf_start_packet(pkt, 'Q'); /* grab quory position inside pkt */ sql_ofs = pktbuf_written(pkt); for (lk = lookup; lk->name; lk++) { sval = get_value(&server->vars, lk); cval = get_value(&client->vars, lk); changes += apply_var(pkt, lk->name, cval, sval); } *changes_p = changes > 0; if (!changes) return true; pktbuf_put_char(pkt, 0); pktbuf_finish_packet(pkt); slog_debug(server, "varcache_apply: %s", pkt->buf + sql_ofs); return pktbuf_send_immediate(pkt, server); } void varcache_fill_unset(VarCache *src, PgSocket *dst) { struct PStr *srcval, *dstval; const struct var_lookup *lk; for (lk = lookup; lk->name; lk++) { srcval = src->var_list[lk->idx]; dstval = dst->vars.var_list[lk->idx]; if (!dstval) { strpool_incref(srcval); dst->vars.var_list[lk->idx] = srcval; } } } void varcache_clean(VarCache *cache) { int i; for (i = 0; i < NumVars; i++) { strpool_decref(cache->var_list[i]); cache->var_list[i] = NULL; } } void varcache_add_params(PktBuf *pkt, VarCache *vars) { struct PStr *val; const struct var_lookup *lk; for (lk = lookup; lk->name; lk++) { val = vars->var_list[lk->idx]; if (val) pktbuf_write_ParameterStatus(pkt, lk->name, val->str); } } pgbouncer-1.5.4/src/admin.c0000644000175000017500000010520012013151606012442 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Admin console commands. */ #include "bouncer.h" #include #include /* regex elements */ #define WS0 "[ \t\n\r]*" #define WS1 "[ \t\n\r]+" #define WORD "(\"([^\"]+|\"\")*\"|[0-9a-z_]+)" #define STRING "('([^']|'')*')" /* possible max + 1 */ #define MAX_GROUPS 10 /* group numbers */ #define CMD_NAME 1 #define CMD_ARG 4 #define SET_KEY 1 #define SET_VAL 4 typedef bool (*cmd_func_t)(PgSocket *admin, const char *arg); struct cmd_lookup { const char *word; cmd_func_t func; }; /* CMD [arg]; */ static const char cmd_normal_rx[] = "^" WS0 WORD "(" WS1 WORD ")?" WS0 "(;" WS0 ")?$"; /* SET with simple value */ static const char cmd_set_word_rx[] = "^" WS0 "set" WS1 WORD WS0 "(=|to)" WS0 WORD WS0 "(;" WS0 ")?$"; /* SET with quoted value */ static const char cmd_set_str_rx[] = "^" WS0 "set" WS1 WORD WS0 "(=|to)" WS0 STRING WS0 "(;" WS0 ")?$"; /* compiled regexes */ static regex_t rc_cmd; static regex_t rc_set_word; static regex_t rc_set_str; static PgPool *admin_pool; /* only valid during processing */ static const char *current_query; static bool syntax_error(PgSocket *admin) { return admin_error(admin, "invalid command '%s', use SHOW HELP;", current_query ? current_query : ""); } static bool exec_cmd(struct cmd_lookup *lookup, PgSocket *admin, const char *cmd, const char *arg) { for (; lookup->word; lookup++) { if (strcasecmp(lookup->word, cmd) == 0) return lookup->func(admin, arg); } return syntax_error(admin); } bool admin_error(PgSocket *admin, const char *fmt, ...) { char str[1024]; va_list ap; bool res = true; va_start(ap, fmt); vsnprintf(str, sizeof(str), fmt, ap); va_end(ap); log_error("%s", str); if (admin) res = send_pooler_error(admin, true, str); return res; } static int count_paused_databases(void) { struct List *item; PgDatabase *db; int cnt = 0; statlist_for_each(item, &database_list) { db = container_of(item, PgDatabase, head); cnt += db->db_paused; } return cnt; } static int count_db_active(PgDatabase *db) { struct List *item; PgPool *pool; int cnt = 0; statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); if (pool->db != db) continue; cnt += pool_server_count(pool); } return cnt; } bool admin_flush(PgSocket *admin, PktBuf *buf, const char *desc) { pktbuf_write_CommandComplete(buf, desc); pktbuf_write_ReadyForQuery(buf); return pktbuf_send_queued(buf, admin); } bool admin_ready(PgSocket *admin, const char *desc) { PktBuf buf; uint8_t tmp[512]; pktbuf_static(&buf, tmp, sizeof(tmp)); pktbuf_write_CommandComplete(&buf, desc); pktbuf_write_ReadyForQuery(&buf); return pktbuf_send_immediate(&buf, admin); } /* * some silly clients start actively messing with server parameters * without checking if thats necessary. Fake some env for them. */ struct FakeParam { const char *name; const char *value; }; static const struct FakeParam fake_param_list[] = { { "client_encoding", "UTF-8" }, { "default_transaction_isolation", "read committed" }, { "standard_conforming_strings", "on" }, { "datestyle", "ISO" }, { "timezone", "GMT" }, { NULL }, }; /* fake result send, returns if handled */ static bool fake_show(PgSocket *admin, const char *name) { PktBuf *buf; const struct FakeParam *p; bool got = false; for (p = fake_param_list; p->name; p++) { if (strcasecmp(name, p->name) == 0) { got = true; break; } } if (got) { buf = pktbuf_dynamic(256); if (buf) { pktbuf_write_RowDescription(buf, "s", p->name); pktbuf_write_DataRow(buf, "s", p->value); admin_flush(admin, buf, "SHOW"); } else admin_error(admin, "no mem"); } return got; } static bool fake_set(PgSocket *admin, const char *key, const char *val) { PktBuf *buf; const struct FakeParam *p; bool got = false; for (p = fake_param_list; p->name; p++) { if (strcasecmp(key, p->name) == 0) { got = true; break; } } if (got) { buf = pktbuf_dynamic(256); if (buf) { pktbuf_write_Notice(buf, "SET ignored"); admin_flush(admin, buf, "SET"); } else admin_error(admin, "no mem"); } return got; } /* Command: SET key = val; */ static bool admin_set(PgSocket *admin, const char *key, const char *val) { char tmp[512]; bool ok; if (fake_set(admin, key, val)) return true; if (admin->admin_user) { ok = set_config_param(key, val); if (ok) { snprintf(tmp, sizeof(tmp), "SET %s=%s", key, val); return admin_ready(admin, tmp); } else { return admin_error(admin, "SET failed"); } } else return admin_error(admin, "admin access needed"); } /* send a row with sendmsg, optionally attaching a fd */ static bool send_one_fd(PgSocket *admin, int fd, const char *task, const char *user, const char *db, const char *addr, int port, uint64_t ckey, int link, const char *client_enc, const char *std_strings, const char *datestyle, const char *timezone) { struct msghdr msg; struct cmsghdr *cmsg; struct iovec iovec; int res; uint8_t cntbuf[CMSG_SPACE(sizeof(int))]; struct PktBuf *pkt = pktbuf_temp(); pktbuf_write_DataRow(pkt, "issssiqissss", fd, task, user, db, addr, port, ckey, link, client_enc, std_strings, datestyle, timezone); if (pkt->failed) return false; iovec.iov_base = pkt->buf; iovec.iov_len = pktbuf_written(pkt); /* sending fds */ memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iovec; msg.msg_iovlen = 1; /* attach a fd */ if (pga_is_unix(&admin->remote_addr) && admin->own_user) { msg.msg_control = cntbuf; msg.msg_controllen = sizeof(cntbuf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; } slog_debug(admin, "sending socket list: fd=%d, len=%d", fd, (int)msg.msg_controllen); res = safe_sendmsg(sbuf_socket(&admin->sbuf), &msg, 0); if (res < 0) { log_error("send_one_fd: sendmsg error: %s", strerror(errno)); return false; } else if ((size_t)res != iovec.iov_len) { log_error("send_one_fd: partial sendmsg"); return false; } return true; } /* send a row with sendmsg, optionally attaching a fd */ static bool show_one_fd(PgSocket *admin, PgSocket *sk) { PgAddr *addr = &sk->remote_addr; struct MBuf tmp; VarCache *v = &sk->vars; uint64_t ckey; const struct PStr *client_encoding = v->var_list[VClientEncoding]; const struct PStr *std_strings = v->var_list[VStdStr]; const struct PStr *datestyle = v->var_list[VDateStyle]; const struct PStr *timezone = v->var_list[VTimeZone]; char addrbuf[PGADDR_BUF]; mbuf_init_fixed_reader(&tmp, sk->cancel_key, 8); if (!mbuf_get_uint64be(&tmp, &ckey)) return false; return send_one_fd(admin, sbuf_socket(&sk->sbuf), is_server_socket(sk) ? "server" : "client", sk->auth_user ? sk->auth_user->name : NULL, sk->pool ? sk->pool->db->name : NULL, pga_ntop(addr, addrbuf, sizeof(addrbuf)), pga_port(addr), ckey, sk->link ? sbuf_socket(&sk->link->sbuf) : 0, client_encoding ? client_encoding->str : NULL, std_strings ? std_strings->str : NULL, datestyle ? datestyle->str : NULL, timezone ? timezone->str : NULL); } static bool show_pooler_cb(void *arg, int fd, const PgAddr *a) { char buf[PGADDR_BUF]; return send_one_fd(arg, fd, "pooler", NULL, NULL, pga_ntop(a, buf, sizeof(buf)), pga_port(a), 0, 0, NULL, NULL, NULL, NULL); } /* send a row with sendmsg, optionally attaching a fd */ static bool show_pooler_fds(PgSocket *admin) { return for_each_pooler_fd(show_pooler_cb, admin); } static bool show_fds_from_list(PgSocket *admin, struct StatList *list) { struct List *item; PgSocket *sk; bool res = true; statlist_for_each(item, list) { sk = container_of(item, PgSocket, head); res = show_one_fd(admin, sk); if (!res) break; } return res; } /* * Command: SHOW FDS * * If privileged connection, send also actual fds */ static bool admin_show_fds(PgSocket *admin, const char *arg) { struct List *item; PgPool *pool; bool res; /* * Dangerous to show to everybody: * - can lock pooler as code flips async option * - show cancel keys for all users */ if (!admin->admin_user) return admin_error(admin, "admin access needed"); /* * It's very hard to send it reliably over in async manner, * so turn async off for this resultset. */ socket_set_nonblocking(sbuf_socket(&admin->sbuf), 0); /* * send resultset */ SEND_RowDescription(res, admin, "issssiqissss", "fd", "task", "user", "database", "addr", "port", "cancel", "link", "client_encoding", "std_strings", "datestyle", "timezone"); if (res) res = show_pooler_fds(admin); if (res) res = show_fds_from_list(admin, &login_client_list); statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); if (pool->db->admin) continue; res = res && show_fds_from_list(admin, &pool->active_client_list); res = res && show_fds_from_list(admin, &pool->waiting_client_list); res = res && show_fds_from_list(admin, &pool->active_server_list); res = res && show_fds_from_list(admin, &pool->idle_server_list); res = res && show_fds_from_list(admin, &pool->used_server_list); res = res && show_fds_from_list(admin, &pool->tested_server_list); res = res && show_fds_from_list(admin, &pool->new_server_list); if (!res) break; } if (res) res = admin_ready(admin, "SHOW"); /* turn async back on */ socket_set_nonblocking(sbuf_socket(&admin->sbuf), 1); return res; } /* Command: SHOW DATABASES */ static bool admin_show_databases(PgSocket *admin, const char *arg) { PgDatabase *db; struct List *item; const char *f_user; PktBuf *buf; buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } pktbuf_write_RowDescription(buf, "ssissii", "name", "host", "port", "database", "force_user", "pool_size", "reserve_pool"); statlist_for_each(item, &database_list) { db = container_of(item, PgDatabase, head); f_user = db->forced_user ? db->forced_user->name : NULL; pktbuf_write_DataRow(buf, "ssissii", db->name, db->host, db->port, db->dbname, f_user, db->pool_size, db->res_pool_size); } admin_flush(admin, buf, "SHOW"); return true; } /* Command: SHOW LISTS */ static bool admin_show_lists(PgSocket *admin, const char *arg) { PktBuf *buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } pktbuf_write_RowDescription(buf, "si", "list", "items"); #define SENDLIST(name, size) pktbuf_write_DataRow(buf, "si", (name), (size)) SENDLIST("databases", statlist_count(&database_list)); SENDLIST("users", statlist_count(&user_list)); SENDLIST("pools", statlist_count(&pool_list)); SENDLIST("free_clients", slab_free_count(client_cache)); SENDLIST("used_clients", slab_active_count(client_cache)); SENDLIST("login_clients", statlist_count(&login_client_list)); SENDLIST("free_servers", slab_free_count(server_cache)); SENDLIST("used_servers", slab_active_count(server_cache)); { int names, zones, qry, pend; adns_info(adns, &names, &zones, &qry, &pend); SENDLIST("dns_names", names); SENDLIST("dns_zones", zones); SENDLIST("dns_queries", qry); SENDLIST("dns_pending", pend); } admin_flush(admin, buf, "SHOW"); return true; } /* Command: SHOW USERS */ static bool admin_show_users(PgSocket *admin, const char *arg) { PgUser *user; struct List *item; PktBuf *buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } pktbuf_write_RowDescription(buf, "s", "name"); statlist_for_each(item, &user_list) { user = container_of(item, PgUser, head); pktbuf_write_DataRow(buf, "s", user->name); } admin_flush(admin, buf, "SHOW"); return true; } #define SKF_STD "sssssisiTTss" #define SKF_DBG "sssssisiTTssiiiiiii" static void socket_header(PktBuf *buf, bool debug) { pktbuf_write_RowDescription(buf, debug ? SKF_DBG : SKF_STD, "type", "user", "database", "state", "addr", "port", "local_addr", "local_port", "connect_time", "request_time", "ptr", "link", "recv_pos", "pkt_pos", "pkt_remain", "send_pos", "send_remain", "pkt_avail", "send_avail"); } static void adr2txt(const PgAddr *adr, char *dst, unsigned dstlen) { pga_ntop(adr, dst, dstlen); } static void socket_row(PktBuf *buf, PgSocket *sk, const char *state, bool debug) { int pkt_avail = 0, send_avail = 0; char ptrbuf[128], linkbuf[128]; char l_addr[PGADDR_BUF], r_addr[PGADDR_BUF]; IOBuf *io = sk->sbuf.io; if (io) { pkt_avail = iobuf_amount_parse(sk->sbuf.io); send_avail = iobuf_amount_pending(sk->sbuf.io); } adr2txt(&sk->remote_addr, r_addr, sizeof(r_addr)); adr2txt(&sk->local_addr, l_addr, sizeof(l_addr)); snprintf(ptrbuf, sizeof(ptrbuf), "%p", sk); if (sk->link) snprintf(linkbuf, sizeof(linkbuf), "%p", sk->link); else linkbuf[0] = 0; pktbuf_write_DataRow(buf, debug ? SKF_DBG : SKF_STD, is_server_socket(sk) ? "S" :"C", sk->auth_user ? sk->auth_user->name : "(nouser)", sk->pool ? sk->pool->db->name : "(nodb)", state, r_addr, pga_port(&sk->remote_addr), l_addr, pga_port(&sk->local_addr), sk->connect_time, sk->request_time, ptrbuf, linkbuf, io ? io->recv_pos : 0, io ? io->parse_pos : 0, sk->sbuf.pkt_remain, io ? io->done_pos : 0, 0, pkt_avail, send_avail); } /* Helper for SHOW CLIENTS */ static void show_socket_list(PktBuf *buf, struct StatList *list, const char *state, bool debug) { struct List *item; PgSocket *sk; statlist_for_each(item, list) { sk = container_of(item, PgSocket, head); socket_row(buf, sk, state, debug); } } /* Command: SHOW CLIENTS */ static bool admin_show_clients(PgSocket *admin, const char *arg) { struct List *item; PgPool *pool; PktBuf *buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } socket_header(buf, false); statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); show_socket_list(buf, &pool->active_client_list, "active", false); show_socket_list(buf, &pool->waiting_client_list, "waiting", false); } admin_flush(admin, buf, "SHOW"); return true; } /* Command: SHOW SERVERS */ static bool admin_show_servers(PgSocket *admin, const char *arg) { struct List *item; PgPool *pool; PktBuf *buf; buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } socket_header(buf, false); statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); show_socket_list(buf, &pool->active_server_list, "active", false); show_socket_list(buf, &pool->idle_server_list, "idle", false); show_socket_list(buf, &pool->used_server_list, "used", false); show_socket_list(buf, &pool->tested_server_list, "tested", false); show_socket_list(buf, &pool->new_server_list, "new", false); } admin_flush(admin, buf, "SHOW"); return true; } /* Command: SHOW SOCKETS */ static bool admin_show_sockets(PgSocket *admin, const char *arg) { struct List *item; PgPool *pool; PktBuf *buf; buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } socket_header(buf, true); statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); show_socket_list(buf, &pool->active_client_list, "cl_active", true); show_socket_list(buf, &pool->waiting_client_list, "cl_waiting", true); show_socket_list(buf, &pool->active_server_list, "sv_active", true); show_socket_list(buf, &pool->idle_server_list, "sv_idle", true); show_socket_list(buf, &pool->used_server_list, "sv_used", true); show_socket_list(buf, &pool->tested_server_list, "sv_tested", true); show_socket_list(buf, &pool->new_server_list, "sv_login", true); } show_socket_list(buf, &login_client_list, "cl_login", true); admin_flush(admin, buf, "SHOW"); return true; } static void show_active_socket_list(PktBuf *buf, struct StatList *list, const char *state) { struct List *item; statlist_for_each(item, list) { PgSocket *sk = container_of(item, PgSocket, head); if (!sbuf_is_empty(&sk->sbuf)) socket_row(buf, sk, state, true); } } /* Command: SHOW ACTIVE_SOCKETS */ static bool admin_show_active_sockets(PgSocket *admin, const char *arg) { struct List *item; PgPool *pool; PktBuf *buf; buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } socket_header(buf, true); statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); show_active_socket_list(buf, &pool->active_client_list, "cl_active"); show_active_socket_list(buf, &pool->waiting_client_list, "cl_waiting"); show_active_socket_list(buf, &pool->active_server_list, "sv_active"); show_active_socket_list(buf, &pool->idle_server_list, "sv_idle"); show_active_socket_list(buf, &pool->used_server_list, "sv_used"); show_active_socket_list(buf, &pool->tested_server_list, "sv_tested"); show_active_socket_list(buf, &pool->new_server_list, "sv_login"); } show_active_socket_list(buf, &login_client_list, "cl_login"); admin_flush(admin, buf, "SHOW"); return true; } /* Command: SHOW POOLS */ static bool admin_show_pools(PgSocket *admin, const char *arg) { struct List *item; PgPool *pool; PktBuf *buf; PgSocket *waiter; usec_t now = get_cached_time(); buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } pktbuf_write_RowDescription(buf, "ssiiiiiiii", "database", "user", "cl_active", "cl_waiting", "sv_active", "sv_idle", "sv_used", "sv_tested", "sv_login", "maxwait"); statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); waiter = first_socket(&pool->waiting_client_list); pktbuf_write_DataRow(buf, "ssiiiiiiii", pool->db->name, pool->user->name, statlist_count(&pool->active_client_list), statlist_count(&pool->waiting_client_list), statlist_count(&pool->active_server_list), statlist_count(&pool->idle_server_list), statlist_count(&pool->used_server_list), statlist_count(&pool->tested_server_list), statlist_count(&pool->new_server_list), /* how long is the oldest client waited */ (waiter && waiter->query_start) ? (int)((now - waiter->query_start) / USEC) : 0); } admin_flush(admin, buf, "SHOW"); return true; } static void slab_stat_cb(void *arg, const char *slab_name, unsigned size, unsigned free, unsigned total) { PktBuf *buf = arg; unsigned alloc = total * size; pktbuf_write_DataRow(buf, "siiii", slab_name, size, total - free, free, alloc); } /* Command: SHOW MEM */ static bool admin_show_mem(PgSocket *admin, const char *arg) { PktBuf *buf; buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } pktbuf_write_RowDescription(buf, "siiii", "name", "size", "used", "free", "memtotal"); slab_stats(slab_stat_cb, buf); admin_flush(admin, buf, "SHOW"); return true; } /* Command: SHOW DNS_HOSTS */ static void dns_name_cb(void *arg, const char *name, const struct addrinfo *ai, usec_t ttl) { PktBuf *buf = arg; char *s, *end; char adrs[1024]; usec_t now = get_cached_time(); end = adrs + sizeof(adrs) - 2; for (s = adrs; ai && s < end; ai = ai->ai_next) { if (s != adrs) *s++ = ','; sa2str(ai->ai_addr, s, end - s); s += strlen(s); } *s = 0; pktbuf_write_DataRow(buf, "sqs", name, (ttl - now) / USEC, adrs); } static bool admin_show_dns_hosts(PgSocket *admin, const char *arg) { PktBuf *buf; buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } pktbuf_write_RowDescription(buf, "sqs", "hostname", "ttl", "addrs"); adns_walk_names(adns, dns_name_cb, buf); admin_flush(admin, buf, "SHOW"); return true; } /* Command: SHOW DNS_ZONES */ static void dns_zone_cb(void *arg, const char *name, uint32_t serial, int nhosts) { PktBuf *buf = arg; pktbuf_write_DataRow(buf, "sqi", name, (uint64_t)serial, nhosts); } static bool admin_show_dns_zones(PgSocket *admin, const char *arg) { PktBuf *buf; buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } pktbuf_write_RowDescription(buf, "sqi", "zonename", "serial", "count"); adns_walk_zones(adns, dns_zone_cb, buf); admin_flush(admin, buf, "SHOW"); return true; } /* Command: SHOW CONFIG */ static void show_one_param(void *arg, const char *name, const char *val, bool reloadable) { PktBuf *buf = arg; pktbuf_write_DataRow(buf, "sss", name, val, reloadable ? "yes" : "no"); } static bool admin_show_config(PgSocket *admin, const char *arg) { PktBuf *buf; buf = pktbuf_dynamic(256); if (!buf) { admin_error(admin, "no mem"); return true; } pktbuf_write_RowDescription(buf, "sss", "key", "value", "changeable"); config_for_each(show_one_param, buf); admin_flush(admin, buf, "SHOW"); return true; } /* Command: RELOAD */ static bool admin_cmd_reload(PgSocket *admin, const char *arg) { if (arg && *arg) return syntax_error(admin); if (!admin->admin_user) return admin_error(admin, "admin access needed"); log_info("RELOAD command issued"); load_config(); return admin_ready(admin, "RELOAD"); } /* Command: SHUTDOWN */ static bool admin_cmd_shutdown(PgSocket *admin, const char *arg) { if (arg && *arg) return syntax_error(admin); if (!admin->admin_user) return admin_error(admin, "admin access needed"); /* * note: new pooler expects unix socket file gone when it gets * event from fd. currently atexit() cleanup should be called * before closing open sockets. */ log_info("SHUTDOWN command issued"); cf_shutdown = 2; event_loopbreak(); return true; } static void full_resume(void) { int tmp_mode = cf_pause_mode; cf_pause_mode = P_NONE; if (tmp_mode == P_SUSPEND) resume_all(); /* avoid surprise later if cf_shutdown stays set */ if (cf_shutdown) { log_info("canceling shutdown"); cf_shutdown = 0; } } /* Command: RESUME */ static bool admin_cmd_resume(PgSocket *admin, const char *arg) { if (!admin->admin_user) return admin_error(admin, "admin access needed"); if (!arg[0]) { log_info("RESUME command issued"); if (cf_pause_mode != P_NONE) full_resume(); else return admin_error(admin, "Pooler is not paused/suspended"); } else { PgDatabase *db = find_database(arg); log_info("RESUME '%s' command issued", arg); if (db == NULL) return admin_error(admin, "no such database: %s", arg); if (!db->db_paused) return admin_error(admin, "database %s is not paused", arg); db->db_paused = 0; } return admin_ready(admin, "RESUME"); } /* Command: SUSPEND */ static bool admin_cmd_suspend(PgSocket *admin, const char *arg) { if (arg && *arg) return syntax_error(admin); if (!admin->admin_user) return admin_error(admin, "admin access needed"); if (cf_pause_mode) return admin_error(admin, "already suspended/paused"); /* suspend needs to be able to flush buffers */ if (count_paused_databases() > 0) return admin_error(admin, "cannot suspend with paused databases"); log_info("SUSPEND command issued"); cf_pause_mode = P_SUSPEND; admin->wait_for_response = 1; suspend_pooler(); g_suspend_start = get_cached_time(); return true; } /* Command: PAUSE */ static bool admin_cmd_pause(PgSocket *admin, const char *arg) { if (!admin->admin_user) return admin_error(admin, "admin access needed"); if (cf_pause_mode) return admin_error(admin, "already suspended/paused"); if (!arg[0]) { log_info("PAUSE command issued"); cf_pause_mode = P_PAUSE; admin->wait_for_response = 1; } else { PgDatabase *db; log_info("PAUSE '%s' command issued", arg); db = find_database(arg); if (db == NULL) { db = register_auto_database(arg); if (db == NULL) { return admin_error(admin, "no such database: %s", arg); } else { slog_info(admin, "registered new auto-database for PAUSE: %s", arg); } } if (db == admin->pool->db) return admin_error(admin, "cannot pause admin db: %s", arg); db->db_paused = 1; if (count_db_active(db) > 0) admin->wait_for_response = 1; else return admin_ready(admin, "PAUSE"); } return true; } /* Command: KILL */ static bool admin_cmd_kill(PgSocket *admin, const char *arg) { struct List *item, *tmp; PgDatabase *db; PgPool *pool; if (!admin->admin_user) return admin_error(admin, "admin access needed"); if (cf_pause_mode) return admin_error(admin, "already suspended/paused"); if (!arg[0]) return admin_error(admin, "a database is required"); log_info("KILL '%s' command issued", arg); db = find_database(arg); if (db == NULL) { db = register_auto_database(arg); if (db == NULL) { return admin_error(admin, "no such database: %s", arg); } else { slog_info(admin, "registered new auto-database for KILL: %s", arg); } } if (db == admin->pool->db) return admin_error(admin, "cannot kill admin db: %s", arg); db->db_paused = 1; statlist_for_each_safe(item, &pool_list, tmp) { pool = container_of(item, PgPool, head); if (pool->db == db) kill_pool(pool); } return admin_ready(admin, "KILL"); } /* extract substring from regex group */ static bool copy_arg(const char *src, regmatch_t *glist, int gnum, char *dst, unsigned dstmax, char qchar) { regmatch_t *g = &glist[gnum]; unsigned len; const char *s; char *d = dst; unsigned i; /* no match, if regex allows, it must be fine */ if (g->rm_so < 0 || g->rm_eo < 0) { dst[0] = 0; return true; } len = g->rm_eo - g->rm_so; s = src + g->rm_so; /* too big value */ if (len >= dstmax) { dst[0] = 0; return false; } /* copy and unquote */ if (*s == qchar) { for (i = 1; i < len - 1; i++) { if (s[i] == qchar && s[i+1] == qchar) i++; *d++ = s[i]; } len = d - dst; } else { memcpy(dst, s, len); } dst[len] = 0; return true; } static bool admin_show_help(PgSocket *admin, const char *arg) { bool res; SEND_generic(res, admin, 'N', "sssss", "SNOTICE", "C00000", "MConsole usage", "D\n\tSHOW HELP|CONFIG|DATABASES" "|POOLS|CLIENTS|SERVERS|VERSION\n" "\tSHOW STATS|FDS|SOCKETS|ACTIVE_SOCKETS|LISTS|MEM\n" "\tSHOW DNS_HOSTS|DNS_ZONES\n" "\tSET key = arg\n" "\tRELOAD\n" "\tPAUSE []\n" "\tRESUME []\n" "\tKILL \n" "\tSUSPEND\n" "\tSHUTDOWN", ""); if (res) res = admin_ready(admin, "SHOW"); return res; } static bool admin_show_version(PgSocket *admin, const char *arg) { bool res; SEND_generic(res, admin, 'N', "ssss", "SNOTICE", "C00000", "M" FULLVER, ""); if (res) res = admin_ready(admin, "SHOW"); return res; } static bool admin_show_stats(PgSocket *admin, const char *arg) { return admin_database_stats(admin, &pool_list); } static bool admin_show_totals(PgSocket *admin, const char *arg) { return show_stat_totals(admin, &pool_list); } static struct cmd_lookup show_map [] = { {"clients", admin_show_clients}, {"config", admin_show_config}, {"databases", admin_show_databases}, {"fds", admin_show_fds}, {"help", admin_show_help}, {"lists", admin_show_lists}, {"pools", admin_show_pools}, {"servers", admin_show_servers}, {"sockets", admin_show_sockets}, {"active_sockets", admin_show_active_sockets}, {"stats", admin_show_stats}, {"users", admin_show_users}, {"version", admin_show_version}, {"totals", admin_show_totals}, {"mem", admin_show_mem}, {"dns_hosts", admin_show_dns_hosts}, {"dns_zones", admin_show_dns_zones}, {NULL, NULL} }; static bool admin_cmd_show(PgSocket *admin, const char *arg) { if (fake_show(admin, arg)) return true; return exec_cmd(show_map, admin, arg, NULL); } static struct cmd_lookup cmd_list [] = { {"kill", admin_cmd_kill}, {"pause", admin_cmd_pause}, {"reload", admin_cmd_reload}, {"resume", admin_cmd_resume}, {"select", admin_cmd_show}, {"show", admin_cmd_show}, {"shutdown", admin_cmd_shutdown}, {"suspend", admin_cmd_suspend}, {NULL, NULL} }; /* handle user query */ static bool admin_parse_query(PgSocket *admin, const char *q) { regmatch_t grp[MAX_GROUPS]; char cmd[16]; char arg[64]; char val[256]; bool res; bool ok; current_query = q; if (regexec(&rc_cmd, q, MAX_GROUPS, grp, 0) == 0) { ok = copy_arg(q, grp, CMD_NAME, cmd, sizeof(cmd), '"'); if (!ok) goto failed; ok = copy_arg(q, grp, CMD_ARG, arg, sizeof(arg), '"'); if (!ok) goto failed; res = exec_cmd(cmd_list, admin, cmd, arg); } else if (regexec(&rc_set_str, q, MAX_GROUPS, grp, 0) == 0) { ok = copy_arg(q, grp, SET_KEY, arg, sizeof(arg), '"'); if (!ok || !arg[0]) goto failed; ok = copy_arg(q, grp, SET_VAL, val, sizeof(val), '\''); if (!ok) goto failed; res = admin_set(admin, arg, val); } else if (regexec(&rc_set_word, q, MAX_GROUPS, grp, 0) == 0) { ok = copy_arg(q, grp, SET_KEY, arg, sizeof(arg), '"'); if (!ok || !arg[0]) goto failed; ok = copy_arg(q, grp, SET_VAL, val, sizeof(val), '"'); if (!ok) goto failed; res = admin_set(admin, arg, val); } else res = syntax_error(admin); done: current_query = NULL; if (!res) disconnect_client(admin, true, "failure"); return res; failed: res = admin_error(admin, "bad arguments"); goto done; } /* handle packets */ bool admin_handle_client(PgSocket *admin, PktHdr *pkt) { const char *q; bool res; /* dont tolerate partial packets */ if (incomplete_pkt(pkt)) { disconnect_client(admin, true, "incomplete pkt"); return false; } switch (pkt->type) { case 'Q': if (!mbuf_get_string(&pkt->data, &q)) { disconnect_client(admin, true, "incomplete query"); return false; } log_debug("got admin query: %s", q); res = admin_parse_query(admin, q); if (res) sbuf_prepare_skip(&admin->sbuf, pkt->len); return res; case 'X': disconnect_client(admin, false, "close req"); break; default: admin_error(admin, "unsupported pkt type: %d", pkt_desc(pkt)); disconnect_client(admin, true, "bad pkt"); break; } return false; } /** * Client is unauthenticated, look if it wants to connect * to special "pgbouncer" user. */ bool admin_pre_login(PgSocket *client) { uid_t peer_uid = -1; gid_t peer_gid = -1; int res; const char *username = client->auth_user->name; client->admin_user = 0; client->own_user = 0; /* tag same uid as special */ if (pga_is_unix(&client->remote_addr)) { res = getpeereid(sbuf_socket(&client->sbuf), &peer_uid, &peer_gid); if (res >= 0 && peer_uid == getuid() && strcmp("pgbouncer", username) == 0) { client->own_user = 1; client->admin_user = 1; slog_info(client, "pgbouncer access from unix socket"); return true; } } /* * auth_mode=any does not keep original username around, * so username based checks do not work. */ if (cf_auth_type == AUTH_ANY) { if (cf_log_connections) slog_info(client, "auth_mode=any: allowing anybody in as admin"); client->admin_user = 1; return true; } if (strlist_contains(cf_admin_users, username)) { client->admin_user = 1; return true; } else if (strlist_contains(cf_stats_users, username)) { return true; } disconnect_client(client, true, "not allowed"); return false; } /* init special database and query parsing */ void admin_setup(void) { PgDatabase *db; PgPool *pool; PgUser *user; PktBuf *msg; int res; /* fake database */ db = add_database("pgbouncer"); if (!db) fatal("no memory for admin database"); db->port = cf_listen_port; db->pool_size = 2; db->admin = 1; if (!force_user(db, "pgbouncer", "")) fatal("no mem on startup - cannot alloc pgbouncer user"); /* fake pool */ pool = get_pool(db, db->forced_user); if (!pool) fatal("cannot create admin pool?"); admin_pool = pool; /* fake user, with disabled psw */ user = add_user("pgbouncer", ""); if (!user) fatal("cannot create admin user?"); /* prepare welcome */ msg = pktbuf_dynamic(128); if (!msg) fatal("cannot create admin welcome"); pktbuf_write_AuthenticationOk(msg); pktbuf_write_ParameterStatus(msg, "server_version", PACKAGE_VERSION "/bouncer"); pktbuf_write_ParameterStatus(msg, "client_encoding", "UNICODE"); pktbuf_write_ParameterStatus(msg, "server_encoding", "SQL_ASCII"); pktbuf_write_ParameterStatus(msg, "DateStyle", "ISO"); pktbuf_write_ParameterStatus(msg, "TimeZone", "GMT"); pktbuf_write_ParameterStatus(msg, "standard_conforming_strings", "on"); pktbuf_write_ParameterStatus(msg, "is_superuser", "on"); if (msg->failed) fatal("admin welcome failed"); pool->welcome_msg = msg; pool->welcome_msg_ready = 1; msg = pktbuf_dynamic(128); if (!msg) fatal("cannot create admin startup pkt"); db->startup_params = msg; pktbuf_put_string(msg, "database"); db->dbname = "pgbouncer"; pktbuf_put_string(msg, db->dbname); /* initialize regexes */ res = regcomp(&rc_cmd, cmd_normal_rx, REG_EXTENDED | REG_ICASE); if (res != 0) fatal("cmd regex compilation error"); res = regcomp(&rc_set_word, cmd_set_word_rx, REG_EXTENDED | REG_ICASE); if (res != 0) fatal("set/word regex compilation error"); res = regcomp(&rc_set_str, cmd_set_str_rx, REG_EXTENDED | REG_ICASE); if (res != 0) fatal("set/str regex compilation error"); } void admin_pause_done(void) { struct List *item, *tmp; PgSocket *admin; bool res; statlist_for_each_safe(item, &admin_pool->active_client_list, tmp) { admin = container_of(item, PgSocket, head); if (!admin->wait_for_response) continue; res = false; switch (cf_pause_mode) { case P_PAUSE: res = admin_ready(admin, "PAUSE"); break; case P_SUSPEND: res = admin_ready(admin, "SUSPEND"); break; default: if (count_paused_databases() > 0) res = admin_ready(admin, "PAUSE"); else /* fixme */ fatal("admin_pause_done: bad state"); } if (!res) disconnect_client(admin, false, "dead admin"); else admin->wait_for_response = 0; } if (statlist_empty(&admin_pool->active_client_list) && cf_pause_mode == P_SUSPEND) { log_info("Admin disappeared when suspended, doing RESUME"); cf_pause_mode = P_NONE; resume_all(); } } /* admin on console has pressed ^C */ void admin_handle_cancel(PgSocket *admin) { bool res; /* weird, but no reason to fail */ if (!admin->wait_for_response) slog_warning(admin, "admin cancel request for non-waiting client?"); if (cf_pause_mode != P_NONE) full_resume(); /* notify readiness */ SEND_ReadyForQuery(res, admin); if (!res) disconnect_client(admin, false, "readiness send failed"); } pgbouncer-1.5.4/src/proto.c0000644000175000017500000002322512005217606012527 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Pieces that need to have detailed info about protocol. */ #include "bouncer.h" /* * parse protocol header from struct MBuf */ /* parses pkt header from buffer, returns false if failed */ bool get_header(struct MBuf *data, PktHdr *pkt) { unsigned type; uint32_t len; unsigned got; unsigned avail; uint16_t len16; uint8_t type8; uint32_t code; struct MBuf hdr; const uint8_t *ptr; mbuf_copy(data, &hdr); if (mbuf_avail_for_read(&hdr) < NEW_HEADER_LEN) { log_noise("get_header: less then 5 bytes available"); return false; } if (!mbuf_get_byte(&hdr, &type8)) return false; type = type8; if (type != 0) { /* wire length does not include type byte */ if (!mbuf_get_uint32be(&hdr, &len)) return false; len++; got = NEW_HEADER_LEN; } else { if (!mbuf_get_byte(&hdr, &type8)) return false; if (type8 != 0) { log_noise("get_header: unknown special pkt"); return false; } /* dont tolerate partial pkt */ if (mbuf_avail_for_read(&hdr) < OLD_HEADER_LEN - 2) { log_noise("get_header: less than 8 bytes for special pkt"); return false; } if (!mbuf_get_uint16be(&hdr, &len16)) return false; len = len16; if (!mbuf_get_uint32be(&hdr, &code)) return false; if (code == PKT_CANCEL) type = PKT_CANCEL; else if (code == PKT_SSLREQ) type = PKT_SSLREQ; else if ((code >> 16) == 3 && (code & 0xFFFF) < 2) type = PKT_STARTUP; else if (code == PKT_STARTUP_V2) type = PKT_STARTUP_V2; else { log_noise("get_header: unknown special pkt: len=%u code=%u", len, code); return false; } got = OLD_HEADER_LEN; } /* don't believe nonsense */ if (len < got || len > cf_max_packet_size) return false; /* store pkt info */ pkt->type = type; pkt->len = len; /* fill pkt with only data for this packet */ if (len > mbuf_avail_for_read(data)) avail = mbuf_avail_for_read(data); else avail = len; if (!mbuf_slice(data, avail, &pkt->data)) return false; /* tag header as read */ return mbuf_get_bytes(&pkt->data, got, &ptr); } /* * Send error message packet to client. */ bool send_pooler_error(PgSocket *client, bool send_ready, const char *msg) { uint8_t tmpbuf[512]; PktBuf buf; if (cf_log_pooler_errors) slog_warning(client, "Pooler Error: %s", msg); pktbuf_static(&buf, tmpbuf, sizeof(tmpbuf)); pktbuf_write_generic(&buf, 'E', "cscscsc", 'S', "ERROR", 'C', "08P01", 'M', msg, 0); if (send_ready) pktbuf_write_ReadyForQuery(&buf); return pktbuf_send_immediate(&buf, client); } /* * Parse server error message and log it. */ void parse_server_error(PktHdr *pkt, const char **level_p, const char **msg_p) { const char *level = NULL, *msg = NULL, *val; uint8_t type; while (mbuf_avail_for_read(&pkt->data)) { if (!mbuf_get_byte(&pkt->data, &type)) break; if (type == 0) break; if (!mbuf_get_string(&pkt->data, &val)) break; if (type == 'S') level = val; else if (type == 'M') msg = val; } *level_p = level; *msg_p = msg; } void log_server_error(const char *note, PktHdr *pkt) { const char *level = NULL, *msg = NULL; parse_server_error(pkt, &level, &msg); if (!msg || !level) log_error("%s: partial error message, cannot log", note); else log_error("%s: %s: %s", note, level, msg); } /* * Preparation of welcome message for client connection. */ /* add another server parameter packet to cache */ bool add_welcome_parameter(PgPool *pool, const char *key, const char *val) { PktBuf *msg = pool->welcome_msg; if (pool->welcome_msg_ready) return true; if (!msg) { msg = pktbuf_dynamic(128); if (!msg) return false; pool->welcome_msg = msg; } /* first packet must be AuthOk */ if (msg->write_pos == 0) pktbuf_write_AuthenticationOk(msg); /* if not stored in ->orig_vars, write full packet */ if (!varcache_set(&pool->orig_vars, key, val)) pktbuf_write_ParameterStatus(msg, key, val); return !msg->failed; } /* all parameters processed */ void finish_welcome_msg(PgSocket *server) { PgPool *pool = server->pool; if (pool->welcome_msg_ready) return; pool->welcome_msg_ready = 1; } bool welcome_client(PgSocket *client) { int res; PgPool *pool = client->pool; const PktBuf *pmsg = pool->welcome_msg; PktBuf *msg; slog_noise(client, "P: welcome_client"); /* copy prepared stuff around */ msg = pktbuf_temp(); pktbuf_put_bytes(msg, pmsg->buf, pmsg->write_pos); /* fill vars */ varcache_fill_unset(&pool->orig_vars, client); varcache_add_params(msg, &client->vars); /* give each client its own cancel key */ get_random_bytes(client->cancel_key, 8); pktbuf_write_BackendKeyData(msg, client->cancel_key); /* finish */ pktbuf_write_ReadyForQuery(msg); if (msg->failed) { disconnect_client(client, true, "failed to prepare welcome message"); return false; } /* send all together */ res = pktbuf_send_immediate(msg, client); if (!res) { disconnect_client(client, true, "failed to send welcome message"); return false; } return true; } /* * Password authentication for server */ static PgUser *get_srv_psw(PgSocket *server) { PgDatabase *db = server->pool->db; PgUser *user = server->pool->user; /* if forced user without password, use userlist psw */ if (!user->passwd[0] && db->forced_user) { PgUser *u2 = find_user(user->name); if (u2) return u2; } return user; } /* actual packet send */ static bool send_password(PgSocket *server, const char *enc_psw) { bool res; SEND_PasswordMessage(res, server, enc_psw); return res; } static bool login_clear_psw(PgSocket *server) { PgUser *user = get_srv_psw(server); slog_debug(server, "P: send clear password"); return send_password(server, user->passwd); } static bool login_crypt_psw(PgSocket *server, const uint8_t *salt) { char saltbuf[3]; const char *enc; PgUser *user = get_srv_psw(server); slog_debug(server, "P: send crypt password"); memcpy(saltbuf, salt, 2); saltbuf[2] = 0; enc = crypt(user->passwd, saltbuf); if (!enc) { slog_warning(server, "crypt failed"); return false; } return send_password(server, enc); } static bool login_md5_psw(PgSocket *server, const uint8_t *salt) { char txt[MD5_PASSWD_LEN + 1], *src; PgUser *user = get_srv_psw(server); slog_debug(server, "P: send md5 password"); if (!isMD5(user->passwd)) { pg_md5_encrypt(user->passwd, user->name, strlen(user->name), txt); src = txt + 3; } else src = user->passwd + 3; pg_md5_encrypt(src, (char *)salt, 4, txt); return send_password(server, txt); } /* answer server authentication request */ bool answer_authreq(PgSocket *server, PktHdr *pkt) { uint32_t cmd; const uint8_t *salt; bool res = false; /* authreq body must contain 32bit cmd */ if (mbuf_avail_for_read(&pkt->data) < 4) return false; if (!mbuf_get_uint32be(&pkt->data, &cmd)) return false; switch (cmd) { case 0: slog_debug(server, "S: auth ok"); res = true; break; case 3: slog_debug(server, "S: req cleartext password"); res = login_clear_psw(server); break; case 4: slog_debug(server, "S: req crypt psw"); if (!mbuf_get_bytes(&pkt->data, 2, &salt)) return false; res = login_crypt_psw(server, salt); break; case 5: slog_debug(server, "S: req md5-crypted psw"); if (!mbuf_get_bytes(&pkt->data, 4, &salt)) return false; res = login_md5_psw(server, salt); break; case 2: /* kerberos */ case 6: /* deprecated usage of SCM_RIGHTS */ slog_error(server, "unsupported auth method: %d", cmd); res = false; break; default: slog_error(server, "unknown auth method: %d", cmd); res = false; break; } return res; } bool send_startup_packet(PgSocket *server) { PgDatabase *db = server->pool->db; const char *username = server->pool->user->name; PktBuf *pkt; pkt = pktbuf_temp(); pktbuf_write_StartupMessage(pkt, username, db->startup_params->buf, db->startup_params->write_pos); return pktbuf_send_immediate(pkt, server); } int scan_text_result(struct MBuf *pkt, const char *tupdesc, ...) { const char *val = NULL; uint32_t len; uint16_t ncol; unsigned i, asked; va_list ap; int *int_p; uint64_t *long_p; const char **str_p; asked = strlen(tupdesc); if (!mbuf_get_uint16be(pkt, &ncol)) return -1; va_start(ap, tupdesc); for (i = 0; i < asked; i++) { if (i < ncol) { if (!mbuf_get_uint32be(pkt, &len)) return -1; if ((int32_t)len < 0) { val = NULL; } else { if (!mbuf_get_chars(pkt, len, &val)) return -1; } /* hack to zero-terminate the result */ if (val) { char *xval = (char *)val - 1; memmove(xval, val, len); xval[len] = 0; val = xval; } } else /* tuple was shorter than requested */ val = NULL; switch (tupdesc[i]) { case 'i': int_p = va_arg(ap, int *); *int_p = val ? atoi(val) : 0; break; case 'q': long_p = va_arg(ap, uint64_t *); *long_p = val ? atoll(val) : 0; break; case 's': str_p = va_arg(ap, const char **); *str_p = val; break; default: fatal("bad tupdesc: %s", tupdesc); } } va_end(ap); return ncol; } pgbouncer-1.5.4/src/pktbuf.c0000644000175000017500000002122212006550770012655 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Packet writing and sending. */ #include "bouncer.h" void pktbuf_free(PktBuf *buf) { if (!buf || buf->fixed_buf) return; log_debug("pktbuf_free(%p)", buf); if (buf->buf) free(buf->buf); if (buf->ev) free(buf->ev); free(buf); } PktBuf *pktbuf_dynamic(int start_len) { PktBuf *buf = zmalloc(sizeof(PktBuf)); log_debug("pktbuf_dynamic(%d): %p", start_len, buf); if (!buf) return NULL; buf->ev = zmalloc(sizeof(*buf->ev)); if (!buf->ev) { pktbuf_free(buf); return NULL; } buf->buf = malloc(start_len); if (!buf->buf) { pktbuf_free(buf); return NULL; } buf->buf_len = start_len; return buf; } void pktbuf_reset(struct PktBuf *pkt) { pkt->failed = 0; pkt->write_pos = 0; pkt->pktlen_pos = 0; pkt->send_pos = 0; pkt->sending = 0; } void pktbuf_static(PktBuf *buf, uint8_t *data, int len) { memset(buf, 0, sizeof(*buf)); buf->buf = data; buf->buf_len = len; buf->fixed_buf = 1; } struct PktBuf *pktbuf_temp(void) { static PktBuf *temp_pktbuf; if (!temp_pktbuf) temp_pktbuf = pktbuf_dynamic(512); if (!temp_pktbuf) fatal("failed to create temp pktbuf"); pktbuf_reset(temp_pktbuf); return temp_pktbuf; } bool pktbuf_send_immediate(PktBuf *buf, PgSocket *sk) { int fd = sbuf_socket(&sk->sbuf); uint8_t *pos = buf->buf + buf->send_pos; int amount = buf->write_pos - buf->send_pos; int res; if (buf->failed) return false; res = safe_send(fd, pos, amount, 0); if (res < 0) { log_debug("pktbuf_send_immediate: %s", strerror(errno)); } return res == amount; } static void pktbuf_send_func(int fd, short flags, void *arg) { PktBuf *buf = arg; int amount, res; log_debug("pktbuf_send_func(%d, %d, %p)", fd, (int)flags, buf); if (buf->failed) return; amount = buf->write_pos - buf->send_pos; res = safe_send(fd, buf->buf + buf->send_pos, amount, 0); if (res < 0) { if (res == EAGAIN) { res = 0; } else { log_error("pktbuf_send_func: %s", strerror(errno)); pktbuf_free(buf); return; } } buf->send_pos += res; if (buf->send_pos < buf->write_pos) { event_set(buf->ev, fd, EV_WRITE, pktbuf_send_func, buf); res = event_add(buf->ev, NULL); if (res < 0) { log_error("pktbuf_send_func: %s", strerror(errno)); pktbuf_free(buf); } } else pktbuf_free(buf); } bool pktbuf_send_queued(PktBuf *buf, PgSocket *sk) { int fd = sbuf_socket(&sk->sbuf); Assert(!buf->sending); Assert(!buf->fixed_buf); if (buf->failed) { pktbuf_free(buf); return send_pooler_error(sk, true, "result prepare failed"); } else { buf->sending = 1; pktbuf_send_func(fd, EV_WRITE, buf); return true; } } static void make_room(PktBuf *buf, int len) { int newlen = buf->buf_len; int need = buf->write_pos + len; void *ptr; if (newlen >= need) return; if (buf->failed) return; if (buf->fixed_buf) { buf->failed = 1; return; } while (newlen < need) newlen = newlen * 2; log_debug("make_room(%p, %d): realloc newlen=%d", buf, len, newlen); ptr = realloc(buf->buf, newlen); if (!ptr) { buf->failed = 1; } else { buf->buf = ptr; buf->buf_len = newlen; } } void pktbuf_put_char(PktBuf *buf, char val) { make_room(buf, 1); if (buf->failed) return; buf->buf[buf->write_pos++] = val; } void pktbuf_put_uint16(PktBuf *buf, uint16_t val) { make_room(buf, 4); if (buf->failed) return; buf->buf[buf->write_pos++] = (val >> 8) & 255; buf->buf[buf->write_pos++] = val & 255; } void pktbuf_put_uint32(PktBuf *buf, uint32_t val) { uint8_t *pos; make_room(buf, 4); if (buf->failed) return; pos = buf->buf + buf->write_pos; pos[0] = (val >> 24) & 255; pos[1] = (val >> 16) & 255; pos[2] = (val >> 8) & 255; pos[3] = val & 255; buf->write_pos += 4; } void pktbuf_put_uint64(PktBuf *buf, uint64_t val) { pktbuf_put_uint32(buf, val >> 32); pktbuf_put_uint32(buf, (uint32_t)val); } void pktbuf_put_bytes(PktBuf *buf, const void *data, int len) { make_room(buf, len); if (buf->failed) return; memcpy(buf->buf + buf->write_pos, data, len); buf->write_pos += len; } void pktbuf_put_string(PktBuf *buf, const char *str) { int len = strlen(str); pktbuf_put_bytes(buf, str, len + 1); } /* * write header, remember pos to write length later. */ void pktbuf_start_packet(PktBuf *buf, int type) { if (buf->failed) return; if (type < 256) { /* new-style packet */ pktbuf_put_char(buf, type); buf->pktlen_pos = buf->write_pos; pktbuf_put_uint32(buf, 0); } else { /* old-style packet */ buf->pktlen_pos = buf->write_pos; pktbuf_put_uint32(buf, 0); pktbuf_put_uint32(buf, type); } } void pktbuf_finish_packet(PktBuf *buf) { uint8_t *pos; unsigned len; if (buf->failed) return; len = buf->write_pos - buf->pktlen_pos; pos = buf->buf + buf->pktlen_pos; buf->pktlen_pos = 0; *pos++ = (len >> 24) & 255; *pos++ = (len >> 16) & 255; *pos++ = (len >> 8) & 255; *pos++ = len & 255; } /* types: * c - char/byte * h - uint16 * i - uint32 * q - uint64 * s - Cstring * b - bytes */ void pktbuf_write_generic(PktBuf *buf, int type, const char *pktdesc, ...) { va_list ap; int len; const char *adesc = pktdesc; uint8_t *bin; pktbuf_start_packet(buf, type); va_start(ap, pktdesc); while (*adesc) { switch (*adesc) { case 'c': pktbuf_put_char(buf, va_arg(ap, int)); break; case 'h': pktbuf_put_uint16(buf, va_arg(ap, int)); break; case 'i': pktbuf_put_uint32(buf, va_arg(ap, int)); break; case 'q': pktbuf_put_uint64(buf, va_arg(ap, uint64_t)); break; case 's': pktbuf_put_string(buf, va_arg(ap, char *)); break; case 'b': bin = va_arg(ap, uint8_t *); len = va_arg(ap, int); pktbuf_put_bytes(buf, bin, len); break; default: fatal("bad pktdesc: %s", pktdesc); } adesc++; } va_end(ap); /* set correct length */ pktbuf_finish_packet(buf); } /* send resultset column info * tupdesc keys: * 'i' - int4 * 'q' - int8 * 's' - string * 'T' - usec_t to date */ void pktbuf_write_RowDescription(PktBuf *buf, const char *tupdesc, ...) { va_list ap; char *name; int i, ncol = strlen(tupdesc); log_noise("write RowDescription"); pktbuf_start_packet(buf, 'T'); pktbuf_put_uint16(buf, ncol); va_start(ap, tupdesc); for (i = 0; i < ncol; i++) { name = va_arg(ap, char *); /* Fields: name, reloid, colnr, oid, typsize, typmod, fmt */ pktbuf_put_string(buf, name); pktbuf_put_uint32(buf, 0); pktbuf_put_uint16(buf, 0); if (tupdesc[i] == 's') { pktbuf_put_uint32(buf, TEXTOID); pktbuf_put_uint16(buf, -1); } else if (tupdesc[i] == 'i') { pktbuf_put_uint32(buf, INT4OID); pktbuf_put_uint16(buf, 4); } else if (tupdesc[i] == 'q') { pktbuf_put_uint32(buf, INT8OID); pktbuf_put_uint16(buf, 8); } else if (tupdesc[i] == 'T') { pktbuf_put_uint32(buf, TEXTOID); pktbuf_put_uint16(buf, -1); } else fatal("bad tupdesc"); pktbuf_put_uint32(buf, 0); pktbuf_put_uint16(buf, 0); } va_end(ap); /* set correct length */ pktbuf_finish_packet(buf); } /* * send DataRow. * * tupdesc keys: * 'i' - int4 * 'q' - int8 * 's' - string * 'T' - usec_t to date */ void pktbuf_write_DataRow(PktBuf *buf, const char *tupdesc, ...) { char tmp[32]; const char *val = NULL; int i, len, ncol = strlen(tupdesc); va_list ap; pktbuf_start_packet(buf, 'D'); pktbuf_put_uint16(buf, ncol); va_start(ap, tupdesc); for (i = 0; i < ncol; i++) { if (tupdesc[i] == 'i') { snprintf(tmp, sizeof(tmp), "%d", va_arg(ap, int)); val = tmp; } else if (tupdesc[i] == 'q') { snprintf(tmp, sizeof(tmp), "%" PRIu64, va_arg(ap, uint64_t)); val = tmp; } else if (tupdesc[i] == 's') { val = va_arg(ap, char *); } else if (tupdesc[i] == 'T') { usec_t time = va_arg(ap, usec_t); val = format_time_s(time, tmp, sizeof(tmp)); } else fatal("bad tupdesc: %s", tupdesc); if (val) { len = strlen(val); pktbuf_put_uint32(buf, len); pktbuf_put_bytes(buf, val, len); } else { /* NULL */ pktbuf_put_uint32(buf, -1); } } va_end(ap); pktbuf_finish_packet(buf); } pgbouncer-1.5.4/src/loader.c0000644000175000017500000002502312013151606012624 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Config and pg_auth file reading. */ #include "bouncer.h" #ifdef HAVE_NETDB_H #include #endif #include /* * ConnString parsing */ /* just skip whitespace */ static char *cstr_skip_ws(char *p) { while (*p && *p == ' ') p++; return p; } /* parse paramenter name before '=' */ static char *cstr_get_key(char *p, char **dst_p) { char *end; p = cstr_skip_ws(p); *dst_p = p; while (*p && *p != '=' && *p != ' ') p++; end = p; p = cstr_skip_ws(p); /* fail if no '=' or empty name */ if (*p != '=' || *dst_p == end) return NULL; *end = 0; return p + 1; } /* unquote the quoted value after first quote */ static char *cstr_unquote_value(char *p) { char *s = p; while (1) { if (!*p) return NULL; if (p[0] == '\'') { if (p[1] == '\'') p++; else break; } *s++ = *p++; } /* terminate actual value */ *s = 0; /* return position after quote */ return p + 1; } /* parse value, possibly quoted */ static char *cstr_get_value(char *p, char **dst_p) { p = cstr_skip_ws(p); if (*p == '\'') { *dst_p = ++p; p = cstr_unquote_value(p); if (!p) return NULL; } else { *dst_p = p; while (*p && *p != ' ') p++; } if (*p) { /* if not EOL, cut value */ *p = 0; p++; } /* disallow empty values */ if (*dst_p[0] == 0) return NULL; return p; } /* * Get key=val pair from connstring. returns position it stopped * or NULL on error. EOF is signaled by *key = 0. */ static char * cstr_get_pair(char *p, char **key_p, char **val_p) { p = cstr_skip_ws(p); *key_p = *val_p = p; if (*p == 0) return p; /* read key */ p = cstr_get_key(p, key_p); if (!p) return NULL; /* read value */ p = cstr_get_value(p, val_p); if (!p) return NULL; log_noise("cstr_get_pair: \"%s\"=\"%s\"", *key_p, *val_p); return cstr_skip_ws(p); } static void set_connect_query(PgDatabase *db, const char *new) { const char *old = db->connect_query; char *val = NULL; if (old && new) { if (strcmp(old, new) == 0) return; val = strdup(new); if (val) { free((void *)old); db->connect_query = val; } } else if (new) { val = strdup(new); db->connect_query = val; } else { free((void *)db->connect_query); db->connect_query = NULL; } if (new && !val) log_error("no memory, cannot assign connect_query for %s", db->name); } static void set_autodb(const char *connstr) { char *tmp = strdup(connstr); if (!tmp) { log_warning("no mem to change autodb_connstr"); return; } if (cf_autodb_connstr) { if (strcmp(connstr, cf_autodb_connstr) != 0) tag_autodb_dirty(); free(cf_autodb_connstr); } cf_autodb_connstr = tmp; } /* fill PgDatabase from connstr */ bool parse_database(void *base, const char *name, const char *connstr) { char *p, *key, *val; PktBuf *msg; PgDatabase *db; int pool_size = -1; int res_pool_size = -1; int dbname_ofs; char *tmp_connstr; const char *dbname = name; char *host = NULL; char *port = "5432"; char *username = NULL; char *password = ""; char *client_encoding = NULL; char *datestyle = NULL; char *timezone = NULL; char *connect_query = NULL; char *appname = NULL; int v_port; if (strcmp(name, "*") == 0) { set_autodb(connstr); return true; } tmp_connstr = strdup(connstr); if (!tmp_connstr) return false; p = tmp_connstr; while (*p) { p = cstr_get_pair(p, &key, &val); if (p == NULL) { log_error("%s: syntax error in connstring", name); goto fail; } else if (!key[0]) break; if (strcmp("dbname", key) == 0) dbname = val; else if (strcmp("host", key) == 0) host = val; else if (strcmp("port", key) == 0) port = val; else if (strcmp("user", key) == 0) username = val; else if (strcmp("password", key) == 0) password = val; else if (strcmp("client_encoding", key) == 0) client_encoding = val; else if (strcmp("datestyle", key) == 0) datestyle = val; else if (strcmp("timezone", key) == 0) timezone = val; else if (strcmp("pool_size", key) == 0) pool_size = atoi(val); else if (strcmp("reserve_pool", key) == 0) res_pool_size = atoi(val); else if (strcmp("connect_query", key) == 0) connect_query = val; else if (strcmp("application_name", key) == 0) appname = val; else { log_error("skipping database %s because" " of unknown parameter in connstring: %s", name, key); goto fail; } } /* port= */ v_port = atoi(port); if (v_port == 0) { log_error("skipping database %s because" " of bad port: %s", name, port); goto fail; } db = add_database(name); if (!db) { log_error("cannot create database, no memory?"); goto fail; } /* host= */ if (host) { host = strdup(host); if (!host) { log_error("failed to allocate host="); goto fail; } } /* tag the db as alive */ db->db_dead = 0; /* assuming not an autodb */ db->db_auto = 0; db->inactive_time = 0; /* if updating old db, check if anything changed */ if (db->dbname) { bool changed = false; if (strcmp(db->dbname, dbname) != 0) changed = true; else if (!!host != !!db->host) changed = true; else if (host && strcmp(host, db->host) != 0) changed = true; else if (v_port != db->port) changed = true; else if (username && !db->forced_user) changed = true; else if (username && strcmp(username, db->forced_user->name) != 0) changed = true; else if (!username && db->forced_user) changed = true; else if ((db->connect_query && !connect_query) || (!db->connect_query && connect_query) || (connect_query && strcmp(connect_query, db->connect_query) != 0)) changed = true; if (changed) tag_database_dirty(db); } /* if pool_size < 0 it will be set later */ db->pool_size = pool_size; db->res_pool_size = res_pool_size; if (db->host) free(db->host); db->host = host; db->port = v_port; /* assign connect_query */ set_connect_query(db, connect_query); if (db->startup_params) { msg = db->startup_params; pktbuf_reset(msg); } else { msg = pktbuf_dynamic(128); if (!msg) fatal("cannot allocate startup buf"); db->startup_params = msg; } pktbuf_put_string(msg, "database"); dbname_ofs = msg->write_pos; pktbuf_put_string(msg, dbname); if (client_encoding) { pktbuf_put_string(msg, "client_encoding"); pktbuf_put_string(msg, client_encoding); } if (datestyle) { pktbuf_put_string(msg, "datestyle"); pktbuf_put_string(msg, datestyle); } if (timezone) { pktbuf_put_string(msg, "timezone"); pktbuf_put_string(msg, timezone); } if (appname) { pktbuf_put_string(msg, "application_name"); pktbuf_put_string(msg, appname); } /* if user is forces, create fake object for it */ if (username != NULL) { if (!force_user(db, username, password)) log_warning("db setup failed, trying to continue"); } else if (db->forced_user) log_warning("losing forced user not supported," " keeping old setting"); /* remember dbname */ db->dbname = (char *)msg->buf + dbname_ofs; free(tmp_connstr); return true; fail: free(tmp_connstr); return true; } /* * User file parsing */ /* find next " in string, skipping escaped ones */ static char *find_quote(char *p, bool start) { loop: while (*p && *p != '"') p++; if (p[0] == '"' && p[1] == '"' && !start) { p += 2; goto loop; } return p; } /* string is unquoted while copying */ static void copy_quoted(char *dst, const char *src, int len) { char *end = dst + len - 1; while (*src && dst < end) { if (*src == '"') src++; *dst++ = *src++; } *dst = 0; } static void unquote_add_user(const char *username, const char *password) { char real_user[MAX_USERNAME]; char real_passwd[MAX_PASSWORD]; PgUser *user; copy_quoted(real_user, username, sizeof(real_user)); copy_quoted(real_passwd, password, sizeof(real_passwd)); user = add_user(real_user, real_passwd); if (!user) log_warning("cannot create user, no memory"); } static bool auth_loaded(const char *fn) { static struct stat cache; struct stat cur; /* hack for resetting */ if (fn == NULL) { memset(&cache, 0, sizeof(cache)); return false; } if (stat(fn, &cur) < 0) return false; if (cache.st_dev == cur.st_dev && cache.st_ino == cur.st_ino && cache.st_mode == cur.st_mode && cache.st_uid == cur.st_uid && cache.st_gid == cur.st_gid && cache.st_mtime == cur.st_mtime && cache.st_size == cur.st_size) return true; cache = cur; return false; } bool loader_users_check(void) { if (auth_loaded(cf_auth_file)) return true; return load_auth_file(cf_auth_file); } static void disable_users(void) { PgUser *user; struct List *item; statlist_for_each(item, &user_list) { user = container_of(item, PgUser, head); user->passwd[0] = 0; } } /* load list of users from pg_auth/pg_psw file */ bool load_auth_file(const char *fn) { char *user, *password, *buf, *p; buf = load_file(fn, NULL); if (buf == NULL) { /* reset file info */ auth_loaded(NULL); return false; } disable_users(); p = buf; while (*p) { /* skip whitespace and empty lines */ while (*p && isspace(*p)) p++; if (!*p) break; /* start of line */ if (*p != '"') { log_error("broken auth file"); break; } user = ++p; p = find_quote(p, false); if (*p != '"') { log_error("broken auth file"); break; } if (p - user >= MAX_USERNAME) { log_error("username too long"); break; } *p++ = 0; /* tag username end */ /* get password */ p = find_quote(p, true); if (*p != '"') { log_error("broken auth file"); break; } password = ++p; p = find_quote(p, false); if (*p != '"') { log_error("broken auth file"); break; } if (p - password >= MAX_PASSWORD) { log_error("too long password"); break; } *p++ = 0; /* tag password end */ /* send them away */ unquote_add_user(user, password); /* skip rest of the line */ while (*p && *p != '\n') p++; } free(buf); return true; } pgbouncer-1.5.4/src/main.c0000644000175000017500000004604012013151606012304 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Launcer for all the rest. */ #include "bouncer.h" #include #include #include #include #ifdef HAVE_SYS_RESOURCE_H #include #endif static const char usage_str[] = "Usage: %s [OPTION]... config.ini\n" " -d, --daemon Run in background (as a daemon)\n" " -R, --restart Do a online restart\n" " -q, --quiet Run quietly\n" " -v, --verbose Increase verbosity\n" " -u, --user= Assume identity of \n" " -V, --version Show version\n" " -h, --help Show this help screen and exit\n"; static void usage(int err, char *exe) { printf(usage_str, basename(exe)); exit(err); } /* async dns handler */ struct DNSContext *adns; /* * configuration storage */ int cf_daemon; int cf_pause_mode = P_NONE; int cf_shutdown; /* 1 - wait for queries to finish, 2 - shutdown immediately */ int cf_reboot; static char *cf_username; char *cf_config_file; char *cf_listen_addr; int cf_listen_port; int cf_listen_backlog; char *cf_unix_socket_dir; int cf_unix_socket_mode; char *cf_unix_socket_group; int cf_pool_mode = POOL_SESSION; /* sbuf config */ int cf_sbuf_len; int cf_sbuf_loopcnt; int cf_tcp_socket_buffer; #if defined(TCP_DEFER_ACCEPT) || defined(SO_ACCEPTFILTER) int cf_tcp_defer_accept = 1; #else int cf_tcp_defer_accept = 0; #endif int cf_tcp_keepalive; int cf_tcp_keepcnt; int cf_tcp_keepidle; int cf_tcp_keepintvl; int cf_auth_type = AUTH_MD5; char *cf_auth_file; int cf_max_client_conn; int cf_default_pool_size; int cf_min_pool_size; int cf_res_pool_size; usec_t cf_res_pool_timeout; char *cf_server_reset_query; char *cf_server_check_query; usec_t cf_server_check_delay; int cf_server_round_robin; int cf_disable_pqexec; usec_t cf_dns_max_ttl; usec_t cf_dns_zone_check_period; unsigned int cf_max_packet_size; char *cf_ignore_startup_params; char *cf_autodb_connstr; /* here is "" different from NULL */ usec_t cf_autodb_idle_timeout; usec_t cf_server_lifetime; usec_t cf_server_idle_timeout; usec_t cf_server_connect_timeout; usec_t cf_server_login_retry; usec_t cf_query_timeout; usec_t cf_query_wait_timeout; usec_t cf_client_idle_timeout; usec_t cf_client_login_timeout; usec_t cf_idle_transaction_timeout; usec_t cf_suspend_timeout; usec_t g_suspend_start; char *cf_pidfile; char *cf_jobname; char *cf_admin_users; char *cf_stats_users; int cf_stats_period; int cf_log_connections; int cf_log_disconnections; int cf_log_pooler_errors; /* * config file description */ static bool set_defer_accept(struct CfValue *cv, const char *val); #define DEFER_OPS {set_defer_accept, cf_get_int} static const struct CfLookup auth_type_map[] = { { "any", AUTH_ANY }, { "trust", AUTH_TRUST }, { "plain", AUTH_PLAIN }, #ifdef HAVE_CRYPT { "crypt", AUTH_CRYPT }, #endif { "md5", AUTH_MD5 }, { NULL } }; static const struct CfLookup pool_mode_map[] = { { "session", POOL_SESSION }, { "transaction", POOL_TX }, { "statement", POOL_STMT }, { NULL } }; static const struct CfKey bouncer_params [] = { CF_ABS("job_name", CF_STR, cf_jobname, CF_NO_RELOAD, "pgbouncer"), #ifdef WIN32 CF_ABS("service_name", CF_STR, cf_jobname, CF_NO_RELOAD, NULL), /* alias for job_name */ #endif CF_ABS("conffile", CF_STR, cf_config_file, 0, NULL), CF_ABS("logfile", CF_STR, cf_logfile, 0, ""), CF_ABS("pidfile", CF_STR, cf_pidfile, CF_NO_RELOAD, ""), CF_ABS("listen_addr", CF_STR, cf_listen_addr, CF_NO_RELOAD, ""), CF_ABS("listen_port", CF_INT, cf_listen_port, CF_NO_RELOAD, "6432"), CF_ABS("listen_backlog", CF_INT, cf_listen_backlog, CF_NO_RELOAD, "128"), #ifndef WIN32 CF_ABS("unix_socket_dir", CF_STR, cf_unix_socket_dir, CF_NO_RELOAD, "/tmp"), CF_ABS("unix_socket_mode", CF_INT, cf_unix_socket_mode, CF_NO_RELOAD, "0777"), CF_ABS("unix_socket_group", CF_STR, cf_unix_socket_group, CF_NO_RELOAD, ""), #endif CF_ABS("auth_type", CF_LOOKUP(auth_type_map), cf_auth_type, 0, "md5"), CF_ABS("auth_file", CF_STR, cf_auth_file, 0, "unconfigured_file"), CF_ABS("pool_mode", CF_LOOKUP(pool_mode_map), cf_pool_mode, 0, "session"), CF_ABS("max_client_conn", CF_INT, cf_max_client_conn, 0, "100"), CF_ABS("default_pool_size", CF_INT, cf_default_pool_size, 0, "20"), CF_ABS("min_pool_size", CF_INT, cf_min_pool_size, 0, "0"), CF_ABS("reserve_pool_size", CF_INT, cf_res_pool_size, 0, "0"), CF_ABS("reserve_pool_timeout", CF_TIME_USEC, cf_res_pool_timeout, 0, "5"), CF_ABS("syslog", CF_INT, cf_syslog, 0, "0"), CF_ABS("syslog_facility", CF_STR, cf_syslog_facility, 0, "daemon"), CF_ABS("syslog_ident", CF_STR, cf_syslog_ident, 0, "pgbouncer"), #ifndef WIN32 CF_ABS("user", CF_STR, cf_username, CF_NO_RELOAD, NULL), #endif CF_ABS("autodb_idle_timeout", CF_TIME_USEC, cf_autodb_idle_timeout, 0, "3600"), CF_ABS("server_reset_query", CF_STR, cf_server_reset_query, 0, "DISCARD ALL"), CF_ABS("server_check_query", CF_STR, cf_server_check_query, 0, "select 1"), CF_ABS("server_check_delay", CF_TIME_USEC, cf_server_check_delay, 0, "30"), CF_ABS("query_timeout", CF_TIME_USEC, cf_query_timeout, 0, "0"), CF_ABS("query_wait_timeout", CF_TIME_USEC, cf_query_wait_timeout, 0, "0"), CF_ABS("client_idle_timeout", CF_TIME_USEC, cf_client_idle_timeout, 0, "0"), CF_ABS("client_login_timeout", CF_TIME_USEC, cf_client_login_timeout, 0, "60"), CF_ABS("idle_transaction_timeout", CF_TIME_USEC, cf_idle_transaction_timeout, 0, "0"), CF_ABS("server_lifetime", CF_TIME_USEC, cf_server_lifetime, 0, "3600"), CF_ABS("server_idle_timeout", CF_TIME_USEC, cf_server_idle_timeout, 0, "600"), CF_ABS("server_connect_timeout", CF_TIME_USEC, cf_server_connect_timeout, 0, "15"), CF_ABS("server_login_retry", CF_TIME_USEC, cf_server_login_retry, 0, "15"), CF_ABS("server_round_robin", CF_INT, cf_server_round_robin, 0, "0"), CF_ABS("suspend_timeout", CF_TIME_USEC, cf_suspend_timeout, 0, "10"), CF_ABS("ignore_startup_parameters", CF_STR, cf_ignore_startup_params, 0, ""), CF_ABS("disable_pqexec", CF_INT, cf_disable_pqexec, CF_NO_RELOAD, "0"), CF_ABS("dns_max_ttl", CF_TIME_USEC, cf_dns_max_ttl, 0, "15"), CF_ABS("dns_zone_check_period", CF_TIME_USEC, cf_dns_zone_check_period, 0, "0"), CF_ABS("max_packet_size", CF_UINT, cf_max_packet_size, 0, "2147483647"), CF_ABS("pkt_buf", CF_INT, cf_sbuf_len, CF_NO_RELOAD, "2048"), CF_ABS("sbuf_loopcnt", CF_INT, cf_sbuf_loopcnt, 0, "5"), CF_ABS("tcp_defer_accept", DEFER_OPS, cf_tcp_defer_accept, 0, NULL), CF_ABS("tcp_socket_buffer", CF_INT, cf_tcp_socket_buffer, 0, "0"), CF_ABS("tcp_keepalive", CF_INT, cf_tcp_keepalive, 0, "1"), CF_ABS("tcp_keepcnt", CF_INT, cf_tcp_keepcnt, 0, "0"), CF_ABS("tcp_keepidle", CF_INT, cf_tcp_keepidle, 0, "0"), CF_ABS("tcp_keepintvl", CF_INT, cf_tcp_keepintvl, 0, "0"), CF_ABS("verbose", CF_INT, cf_verbose, 0, NULL), CF_ABS("admin_users", CF_STR, cf_admin_users, 0, ""), CF_ABS("stats_users", CF_STR, cf_stats_users, 0, ""), CF_ABS("stats_period", CF_INT, cf_stats_period, 0, "60"), CF_ABS("log_connections", CF_INT, cf_log_connections, 0, "1"), CF_ABS("log_disconnections", CF_INT, cf_log_disconnections, 0, "1"), CF_ABS("log_pooler_errors", CF_INT, cf_log_pooler_errors, 0, "1"), {NULL} }; static const struct CfSect config_sects [] = { { .sect_name = "pgbouncer", .key_list = bouncer_params, }, { .sect_name = "databases", .set_key = parse_database, }, { .sect_name = NULL, } }; static struct CfContext main_config = { config_sects, }; bool set_config_param(const char *key, const char *val) { return cf_set(&main_config, "pgbouncer", key, val); } void config_for_each(void (*param_cb)(void *arg, const char *name, const char *val, bool reloadable), void *arg) { const struct CfKey *k = bouncer_params; char buf[256]; bool reloadable; const char *val; int ro = CF_NO_RELOAD | CF_READONLY; for (; k->key_name; k++) { val = cf_get(&main_config, "pgbouncer", k->key_name, buf, sizeof(buf)); reloadable = (k->flags & ro) == 0; param_cb(arg, k->key_name, val, reloadable); } } static bool set_defer_accept(struct CfValue *cv, const char *val) { int *p = cv->value_p; bool ok; int oldval = *p; ok = cf_set_int(cv, val); if (ok && !!oldval != !!*p) pooler_tune_accept(*p); return ok; } static void set_dbs_dead(bool flag) { struct List *item; PgDatabase *db; statlist_for_each(item, &database_list) { db = container_of(item, PgDatabase, head); if (db->admin) continue; if (db->db_auto) continue; db->db_dead = flag; } } /* config loading, tries to be tolerant to errors */ void load_config(void) { static bool loaded = false; bool ok; set_dbs_dead(true); /* actual loading */ ok = cf_load_file(&main_config, cf_config_file); if (ok) { /* load users if needed */ if (cf_auth_type >= AUTH_TRUST) load_auth_file(cf_auth_file); loaded = true; } else if (!loaded) { die("Cannot load config file"); } else { log_warning("Config file loading failed"); /* if ini file missing, dont kill anybody */ set_dbs_dead(false); } /* reset pool_size, kill dbs */ config_postprocess(); /* reopen logfile */ if (main_config.loaded) reset_logging(); } /* * signal handling. * * handle_* functions are not actual signal handlers but called from * event_loop() so they have no restrictions what they can do. */ static struct event ev_sigterm; static struct event ev_sigint; static void handle_sigterm(int sock, short flags, void *arg) { log_info("Got SIGTERM, fast exit"); /* pidfile cleanup happens via atexit() */ exit(1); } static void handle_sigint(int sock, short flags, void *arg) { log_info("Got SIGINT, shutting down"); if (cf_reboot) fatal("Takeover was in progress, going down immediately"); if (cf_pause_mode == P_SUSPEND) fatal("Suspend was in progress, going down immediately"); cf_pause_mode = P_PAUSE; cf_shutdown = 1; } #ifndef WIN32 static struct event ev_sigusr1; static struct event ev_sigusr2; static struct event ev_sighup; static void handle_sigusr1(int sock, short flags, void *arg) { if (cf_pause_mode == P_NONE) { log_info("Got SIGUSR1, pausing all activity"); cf_pause_mode = P_PAUSE; } else { log_info("Got SIGUSR1, but already paused/suspended"); } } static void handle_sigusr2(int sock, short flags, void *arg) { switch (cf_pause_mode) { case P_SUSPEND: log_info("Got SIGUSR2, continuing from SUSPEND"); resume_all(); cf_pause_mode = P_NONE; break; case P_PAUSE: log_info("Got SIGUSR2, continuing from PAUSE"); cf_pause_mode = P_NONE; break; case P_NONE: log_info("Got SIGUSR1, but not paused/suspended"); } /* avoid surprise later if cf_shutdown stays set */ if (cf_shutdown) { log_info("Canceling shutdown"); cf_shutdown = 0; } } static void handle_sighup(int sock, short flags, void *arg) { log_info("Got SIGHUP re-reading config"); load_config(); } #endif static void signal_setup(void) { int err; #ifndef WIN32 sigset_t set; /* block SIGPIPE */ sigemptyset(&set); sigaddset(&set, SIGPIPE); err = sigprocmask(SIG_BLOCK, &set, NULL); if (err < 0) fatal_perror("sigprocmask"); /* install handlers */ signal_set(&ev_sigusr1, SIGUSR1, handle_sigusr1, NULL); err = signal_add(&ev_sigusr1, NULL); if (err < 0) fatal_perror("signal_add"); signal_set(&ev_sigusr2, SIGUSR2, handle_sigusr2, NULL); err = signal_add(&ev_sigusr2, NULL); if (err < 0) fatal_perror("signal_add"); signal_set(&ev_sighup, SIGHUP, handle_sighup, NULL); err = signal_add(&ev_sighup, NULL); if (err < 0) fatal_perror("signal_add"); #endif signal_set(&ev_sigterm, SIGTERM, handle_sigterm, NULL); err = signal_add(&ev_sigterm, NULL); if (err < 0) fatal_perror("signal_add"); signal_set(&ev_sigint, SIGINT, handle_sigint, NULL); err = signal_add(&ev_sigint, NULL); if (err < 0) fatal_perror("signal_add"); } /* * daemon mode */ static void go_daemon(void) { int pid, fd; if (!cf_pidfile[0]) fatal("daemon needs pidfile configured"); /* dont log to stdout anymore */ cf_quiet = 1; /* send stdin, stdout, stderr to /dev/null */ fd = open("/dev/null", O_RDWR); if (fd < 0) fatal_perror("/dev/null"); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); if (fd > 2) close(fd); /* fork new process */ pid = fork(); if (pid < 0) fatal_perror("fork"); if (pid > 0) _exit(0); /* create new session */ pid = setsid(); if (pid < 0) fatal_perror("setsid"); /* fork again to avoid being session leader */ pid = fork(); if (pid < 0) fatal_perror("fork"); if (pid > 0) _exit(0); } /* * pidfile management. */ static void remove_pidfile(void) { if (!cf_pidfile[0]) return; unlink(cf_pidfile); } static void check_pidfile(void) { char buf[128 + 1]; struct stat st; pid_t pid = 0; int fd, res; if (!cf_pidfile[0]) return; /* check if pidfile exists */ if (stat(cf_pidfile, &st) < 0) { if (errno != ENOENT) fatal_perror("stat"); return; } /* read old pid */ fd = open(cf_pidfile, O_RDONLY); if (fd < 0) goto locked_pidfile; res = read(fd, buf, sizeof(buf) - 1); close(fd); if (res <= 0) goto locked_pidfile; /* parse pid */ buf[res] = 0; pid = atol(buf); if (pid <= 0) goto locked_pidfile; /* check if running */ if (kill(pid, 0) >= 0) goto locked_pidfile; if (errno != ESRCH) goto locked_pidfile; /* seems the pidfile is not in use */ log_info("Stale pidfile, removing"); remove_pidfile(); return; locked_pidfile: fatal("pidfile exists, another instance running?"); } static void write_pidfile(void) { char buf[64]; pid_t pid; int res, fd; if (!cf_pidfile[0]) return; pid = getpid(); snprintf(buf, sizeof(buf), "%u", (unsigned)pid); fd = open(cf_pidfile, O_WRONLY | O_CREAT | O_EXCL, 0644); if (fd < 0) fatal_perror("%s", cf_pidfile); res = safe_write(fd, buf, strlen(buf)); if (res < 0) fatal_perror("%s", cf_pidfile); close(fd); /* only remove when we have it actually written */ atexit(remove_pidfile); } /* just print out max files, in the future may warn if something is off */ static void check_limits(void) { struct rlimit lim; int total_users = statlist_count(&user_list); int fd_count; int err; struct List *item; PgDatabase *db; log_noise("event: %d, SBuf: %d, PgSocket: %d, IOBuf: %d", (int)sizeof(struct event), (int)sizeof(SBuf), (int)sizeof(PgSocket), (int)IOBUF_SIZE); /* load limits */ err = getrlimit(RLIMIT_NOFILE, &lim); if (err < 0) { log_error("could not get RLIMIT_NOFILE: %s", strerror(errno)); return; } /* calculate theoretical max, +10 is just in case */ fd_count = cf_max_client_conn + 10; statlist_for_each(item, &database_list) { db = container_of(item, PgDatabase, head); if (db->forced_user) fd_count += db->pool_size; else fd_count += db->pool_size * total_users; } log_info("File descriptor limit: %d (H:%d), max_client_conn: %d, max fds possible: %d", (int)lim.rlim_cur, (int)lim.rlim_max, cf_max_client_conn, fd_count); } static bool check_old_process_unix(void) { struct sockaddr_un sa_un; socklen_t len = sizeof(sa_un); int domain = AF_UNIX; int res, fd; if (!cf_unix_socket_dir || !*cf_unix_socket_dir) return false; memset(&sa_un, 0, len); sa_un.sun_family = domain; snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s/.s.PGSQL.%d", cf_unix_socket_dir, cf_listen_port); fd = socket(domain, SOCK_STREAM, 0); if (fd < 0) fatal_perror("cannot create socket"); res = safe_connect(fd, (struct sockaddr *)&sa_un, len); safe_close(fd); if (res < 0) return false; return true; } static void main_loop_once(void) { int err; reset_time_cache(); err = event_loop(EVLOOP_ONCE); if (err < 0) { if (errno != EINTR) log_warning("event_loop failed: %s", strerror(errno)); } per_loop_maint(); reuse_just_freed_objects(); rescue_timers(); per_loop_pooler_maint(); } static void takeover_part1(void) { /* use temporary libevent base */ void *evtmp = event_init(); if (!cf_unix_socket_dir || !*cf_unix_socket_dir) fatal("cannot reboot if unix dir not configured"); takeover_init(); while (cf_reboot) main_loop_once(); event_base_free(evtmp); } static void dns_setup(void) { if (adns) return; adns = adns_create_context(); if (!adns) fatal_perror("dns setup failed"); } /* boot everything */ int main(int argc, char *argv[]) { int c; bool did_takeover = false; char *arg_username = NULL; int long_idx; static const struct option long_options[] = { {"quiet", no_argument, NULL, 'q'}, {"verbose", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {"daemon", no_argument, NULL, 'd'}, {"version", no_argument, NULL, 'V'}, {"reboot", no_argument, NULL, 'R'}, {"user", required_argument, NULL, 'u'}, {NULL, 0, NULL, 0} }; setprogname(basename(argv[0])); /* parse cmdline */ while ((c = getopt_long(argc, argv, "qvhdVRu:", long_options, &long_idx)) != -1) { switch (c) { case 'R': cf_reboot = 1; break; case 'v': cf_verbose++; break; case 'V': printf("%s\n", FULLVER); return 0; case 'd': cf_daemon = 1; break; case 'q': cf_quiet = 1; break; case 'u': arg_username = optarg; break; case 'h': usage(0, argv[0]); default: usage(1, argv[0]); } } if (optind + 1 != argc) { fprintf(stderr, "Need config file. See pgbouncer -h for usage.\n"); exit(1); } cf_config_file = xstrdup(argv[optind]); init_objects(); load_config(); main_config.loaded = true; init_caches(); logging_prefix_cb = log_socket_prefix; /* prefer cmdline over config for username */ if (arg_username) { if (cf_username) free(cf_username); cf_username = xstrdup(arg_username); } /* switch user is needed */ if (cf_username && *cf_username) change_user(cf_username); /* disallow running as root */ if (getuid() == 0) fatal("PgBouncer should not run as root"); /* need to do that after loading config */ check_limits(); admin_setup(); if (cf_reboot) { if (check_old_process_unix()) { takeover_part1(); did_takeover = true; } else { log_info("old process not found, try to continue normally"); cf_reboot = 0; check_pidfile(); } } else { if (check_old_process_unix()) fatal("unix socket is in use, cannot continue"); check_pidfile(); } if (cf_daemon) go_daemon(); /* initialize subsystems, order important */ srandom(time(NULL) ^ getpid()); if (!event_init()) fatal("event_init() failed"); dns_setup(); signal_setup(); janitor_setup(); stats_setup(); if (did_takeover) takeover_finish(); else pooler_setup(); write_pidfile(); log_info("process up: %s, libevent %s (%s), adns: %s", PACKAGE_STRING, event_get_version(), event_get_method(), adns_get_backend()); /* main loop */ while (cf_shutdown < 2) main_loop_once(); return 0; } pgbouncer-1.5.4/src/sbuf.c0000644000175000017500000004155412006550770012333 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Stream buffer * * The task is to copy data from one socket to another * efficiently, while allowing callbacks to look * at packet headers. */ #include "bouncer.h" /* sbuf_main_loop() skip_recv values */ #define DO_RECV false #define SKIP_RECV true #define ACT_UNSET 0 #define ACT_SEND 1 #define ACT_SKIP 2 #define ACT_CALL 3 enum WaitType { W_NONE = 0, W_CONNECT, W_RECV, W_SEND, }; #define AssertSanity(sbuf) do { \ Assert(iobuf_sane((sbuf)->io)); \ } while (0) #define AssertActive(sbuf) do { \ Assert((sbuf)->sock > 0); \ AssertSanity(sbuf); \ } while (0) /* declare static stuff */ static bool sbuf_queue_send(SBuf *sbuf) _MUSTCHECK; static bool sbuf_send_pending(SBuf *sbuf) _MUSTCHECK; static bool sbuf_process_pending(SBuf *sbuf) _MUSTCHECK; static void sbuf_connect_cb(int sock, short flags, void *arg); static void sbuf_recv_cb(int sock, short flags, void *arg); static void sbuf_send_cb(int sock, short flags, void *arg); static void sbuf_try_resync(SBuf *sbuf, bool release); static bool sbuf_wait_for_data(SBuf *sbuf) _MUSTCHECK; static void sbuf_main_loop(SBuf *sbuf, bool skip_recv); static bool sbuf_call_proto(SBuf *sbuf, int event) /* _MUSTCHECK */; static bool sbuf_actual_recv(SBuf *sbuf, unsigned len) _MUSTCHECK; static bool sbuf_after_connect_check(SBuf *sbuf) _MUSTCHECK; static inline IOBuf *get_iobuf(SBuf *sbuf) { return sbuf->io; } /********************************* * Public functions *********************************/ /* initialize SBuf with proto handler */ void sbuf_init(SBuf *sbuf, sbuf_cb_t proto_fn) { memset(sbuf, 0, sizeof(SBuf)); sbuf->proto_cb = proto_fn; } /* got new socket from accept() */ bool sbuf_accept(SBuf *sbuf, int sock, bool is_unix) { bool res; Assert(iobuf_empty(sbuf->io) && sbuf->sock == 0); AssertSanity(sbuf); sbuf->sock = sock; if (!tune_socket(sock, is_unix)) goto failed; if (!cf_reboot) { res = sbuf_wait_for_data(sbuf); if (!res) goto failed; /* socket should already have some data (linux only) */ if (cf_tcp_defer_accept && !is_unix) { sbuf_main_loop(sbuf, DO_RECV); if (!sbuf->sock) return false; } } return true; failed: sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED); return false; } /* need to connect() to get a socket */ bool sbuf_connect(SBuf *sbuf, const struct sockaddr *sa, int sa_len, int timeout_sec) { int res, sock; struct timeval timeout; bool is_unix = sa->sa_family == AF_UNIX; Assert(iobuf_empty(sbuf->io) && sbuf->sock == 0); AssertSanity(sbuf); /* * common stuff */ sock = socket(sa->sa_family, SOCK_STREAM, 0); if (sock < 0) /* probably fd limit */ goto failed; if (!tune_socket(sock, is_unix)) goto failed; sbuf->sock = sock; timeout.tv_sec = timeout_sec; timeout.tv_usec = 0; /* launch connection */ res = safe_connect(sock, sa, sa_len); if (res == 0) { /* unix socket gives connection immediately */ sbuf_connect_cb(sock, EV_WRITE, sbuf); return true; } else if (errno == EINPROGRESS) { /* tcp socket needs waiting */ event_set(&sbuf->ev, sock, EV_WRITE, sbuf_connect_cb, sbuf); res = event_add(&sbuf->ev, &timeout); if (res >= 0) { sbuf->wait_type = W_CONNECT; return true; } } failed: log_warning("sbuf_connect failed: %s", strerror(errno)); if (sock >= 0) safe_close(sock); sbuf->sock = 0; sbuf_call_proto(sbuf, SBUF_EV_CONNECT_FAILED); return false; } /* don't wait for data on this socket */ bool sbuf_pause(SBuf *sbuf) { AssertActive(sbuf); Assert(sbuf->wait_type == W_RECV); if (event_del(&sbuf->ev) < 0) { log_warning("event_del: %s", strerror(errno)); return false; } sbuf->wait_type = W_NONE; return true; } /* resume from pause, start waiting for data */ void sbuf_continue(SBuf *sbuf) { bool do_recv = DO_RECV; bool res; AssertActive(sbuf); res = sbuf_wait_for_data(sbuf); if (!res) { /* drop if problems */ sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED); return; } /* * It's tempting to try to avoid the recv() but that would * only work if no code wants to see full packet. * * This is not true in ServerParameter case. */ /* * if (sbuf->recv_pos - sbuf->pkt_pos >= SBUF_SMALL_PKT) * do_recv = false; */ sbuf_main_loop(sbuf, do_recv); } /* * Resume from pause and give socket over to external * callback function. * * The callback will be called with arg given to sbuf_init. */ bool sbuf_continue_with_callback(SBuf *sbuf, sbuf_libevent_cb user_cb) { int err; AssertActive(sbuf); event_set(&sbuf->ev, sbuf->sock, EV_READ | EV_PERSIST, user_cb, sbuf); err = event_add(&sbuf->ev, NULL); if (err < 0) { log_warning("sbuf_continue_with_callback: %s", strerror(errno)); return false; } sbuf->wait_type = W_RECV; return true; } /* socket cleanup & close: keeps .handler and .arg values */ bool sbuf_close(SBuf *sbuf) { if (sbuf->wait_type) { Assert(sbuf->sock); /* event_del() acts funny occasionally, debug it */ errno = 0; if (event_del(&sbuf->ev) < 0) { if (errno) log_warning("event_del: %s", strerror(errno)); else log_warning("event_del: libevent error"); /* we can retry whole sbuf_close() if needed */ /* if (errno == ENOMEM) return false; */ } } if (sbuf->sock > 0) safe_close(sbuf->sock); sbuf->dst = NULL; sbuf->sock = 0; sbuf->pkt_remain = 0; sbuf->pkt_action = sbuf->wait_type = 0; if (sbuf->io) { slab_free(iobuf_cache, sbuf->io); sbuf->io = NULL; } return true; } /* proto_fn tells to send some bytes to socket */ void sbuf_prepare_send(SBuf *sbuf, SBuf *dst, unsigned amount) { AssertActive(sbuf); Assert(sbuf->pkt_remain == 0); //Assert(sbuf->pkt_action == ACT_UNSET || sbuf->pkt_action == ACT_SEND || iobuf_amount_pending(&sbuf->io)); Assert(amount > 0); sbuf->pkt_action = ACT_SEND; sbuf->pkt_remain = amount; sbuf->dst = dst; } /* proto_fn tells to skip some amount of bytes */ void sbuf_prepare_skip(SBuf *sbuf, unsigned amount) { AssertActive(sbuf); Assert(sbuf->pkt_remain == 0); //Assert(sbuf->pkt_action == ACT_UNSET || iobuf_send_pending_avail(&sbuf->io)); Assert(amount > 0); sbuf->pkt_action = ACT_SKIP; sbuf->pkt_remain = amount; } /* proto_fn tells to skip some amount of bytes */ void sbuf_prepare_fetch(SBuf *sbuf, unsigned amount) { AssertActive(sbuf); Assert(sbuf->pkt_remain == 0); //Assert(sbuf->pkt_action == ACT_UNSET || iobuf_send_pending_avail(&sbuf->io)); Assert(amount > 0); sbuf->pkt_action = ACT_CALL; sbuf->pkt_remain = amount; /* sbuf->dst = NULL; // fixme ?? */ } /************************* * Internal functions *************************/ /* * Call proto callback with proper struct MBuf. * * If callback returns true it used one of sbuf_prepare_* on sbuf, * and processing can continue. * * If it returned false it used sbuf_pause(), sbuf_close() or simply * wants to wait for next event loop (e.g. too few data available). * Callee should not touch sbuf in that case and just return to libevent. */ static bool sbuf_call_proto(SBuf *sbuf, int event) { struct MBuf mbuf; IOBuf *io = sbuf->io; bool res; AssertSanity(sbuf); Assert(event != SBUF_EV_READ || iobuf_amount_parse(io) > 0); /* if pkt callback, limit only with current packet */ if (event == SBUF_EV_PKT_CALLBACK) iobuf_parse_limit(io, &mbuf, sbuf->pkt_remain); else if (event == SBUF_EV_READ) iobuf_parse_all(io, &mbuf); else memset(&mbuf, 0, sizeof(mbuf)); res = sbuf->proto_cb(sbuf, event, &mbuf); AssertSanity(sbuf); Assert(event != SBUF_EV_READ || !res || sbuf->sock > 0); return res; } /* let's wait for new data */ static bool sbuf_wait_for_data(SBuf *sbuf) { int err; event_set(&sbuf->ev, sbuf->sock, EV_READ | EV_PERSIST, sbuf_recv_cb, sbuf); err = event_add(&sbuf->ev, NULL); if (err < 0) { log_warning("sbuf_wait_for_data: event_add: %s", strerror(errno)); return false; } sbuf->wait_type = W_RECV; return true; } /* libevent EV_WRITE: called when dest socket is writable again */ static void sbuf_send_cb(int sock, short flags, void *arg) { SBuf *sbuf = arg; bool res; /* sbuf was closed before in this loop */ if (!sbuf->sock) return; AssertSanity(sbuf); Assert(sbuf->wait_type == W_SEND); sbuf->wait_type = W_NONE; /* prepare normal situation for sbuf_main_loop */ res = sbuf_wait_for_data(sbuf); if (res) { /* here we should certainly skip recv() */ sbuf_main_loop(sbuf, SKIP_RECV); } else /* drop if problems */ sbuf_call_proto(sbuf, SBUF_EV_SEND_FAILED); } /* socket is full, wait until it's writable again */ static bool sbuf_queue_send(SBuf *sbuf) { int err; AssertActive(sbuf); Assert(sbuf->wait_type == W_RECV); /* if false is returned, the socket will be closed later */ /* stop waiting for read events */ err = event_del(&sbuf->ev); sbuf->wait_type = W_NONE; /* make sure its called only once */ if (err < 0) { log_warning("sbuf_queue_send: event_del failed: %s", strerror(errno)); return false; } /* instead wait for EV_WRITE on destination socket */ event_set(&sbuf->ev, sbuf->dst->sock, EV_WRITE, sbuf_send_cb, sbuf); err = event_add(&sbuf->ev, NULL); if (err < 0) { log_warning("sbuf_queue_send: event_add failed: %s", strerror(errno)); return false; } sbuf->wait_type = W_SEND; return true; } /* * There's data in buffer to be sent. Returns bool if processing can continue. * * Does not look at pkt_pos/remain fields, expects them to be merged to send_* */ static bool sbuf_send_pending(SBuf *sbuf) { int res, avail; IOBuf *io = sbuf->io; AssertActive(sbuf); Assert(sbuf->dst || iobuf_amount_pending(io) == 0); try_more: /* how much data is available for sending */ avail = iobuf_amount_pending(io); if (avail == 0) return true; if (sbuf->dst->sock == 0) { log_error("sbuf_send_pending: no dst sock?"); return false; } /* actually send it */ res = iobuf_send_pending(io, sbuf->dst->sock); if (res < 0) { if (errno == EAGAIN) { if (!sbuf_queue_send(sbuf)) /* drop if queue failed */ sbuf_call_proto(sbuf, SBUF_EV_SEND_FAILED); } else sbuf_call_proto(sbuf, SBUF_EV_SEND_FAILED); return false; } AssertActive(sbuf); /* * Should do sbuf_queue_send() immediately? * * To be sure, let's run into EAGAIN. */ goto try_more; } /* process as much data as possible */ static bool sbuf_process_pending(SBuf *sbuf) { unsigned avail; IOBuf *io = sbuf->io; bool full = iobuf_amount_recv(io) <= 0; bool res; while (1) { AssertActive(sbuf); /* * Enough for now? * * The (avail <= SBUF_SMALL_PKT) check is to avoid partial pkts. * As SBuf should not assume knowledge about packets, * the check is not done in !full case. Packet handler can * then still notify about partial packet by returning false. */ avail = iobuf_amount_parse(io); if (avail == 0 || (full && avail <= SBUF_SMALL_PKT)) break; /* * If start of packet, process packet header. */ if (sbuf->pkt_remain == 0) { res = sbuf_call_proto(sbuf, SBUF_EV_READ); if (!res) return false; Assert(sbuf->pkt_remain > 0); } if (sbuf->pkt_action == ACT_SKIP || sbuf->pkt_action == ACT_CALL) { /* send any pending data before skipping */ if (iobuf_amount_pending(io) > 0) { res = sbuf_send_pending(sbuf); if (!res) return res; } } if (avail > sbuf->pkt_remain) avail = sbuf->pkt_remain; switch (sbuf->pkt_action) { case ACT_SEND: iobuf_tag_send(io, avail); break; case ACT_CALL: res = sbuf_call_proto(sbuf, SBUF_EV_PKT_CALLBACK); if (!res) return false; /* after callback, skip pkt */ case ACT_SKIP: iobuf_tag_skip(io, avail); break; } sbuf->pkt_remain -= avail; } return sbuf_send_pending(sbuf); } /* reposition at buffer start again */ static void sbuf_try_resync(SBuf *sbuf, bool release) { IOBuf *io = sbuf->io; if (io) log_noise("resync: done=%d, parse=%d, recv=%d", io->done_pos, io->parse_pos, io->recv_pos); AssertActive(sbuf); if (!io) return; if (release && iobuf_empty(io)) { slab_free(iobuf_cache, io); sbuf->io = NULL; } else iobuf_try_resync(io, SBUF_SMALL_PKT); } /* actually ask kernel for more data */ static bool sbuf_actual_recv(SBuf *sbuf, unsigned len) { int got; IOBuf *io = sbuf->io; AssertActive(sbuf); Assert(len > 0); Assert(iobuf_amount_recv(io) >= len); got = iobuf_recv_limit(io, sbuf->sock, len); if (got == 0) { /* eof from socket */ sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED); return false; } else if (got < 0 && errno != EAGAIN) { /* some error occured */ sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED); return false; } return true; } /* callback for libevent EV_READ */ static void sbuf_recv_cb(int sock, short flags, void *arg) { SBuf *sbuf = arg; sbuf_main_loop(sbuf, DO_RECV); } static bool allocate_iobuf(SBuf *sbuf) { if (sbuf->io == NULL) { sbuf->io = slab_alloc(iobuf_cache); if (sbuf->io == NULL) { sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED); return false; } iobuf_reset(sbuf->io); } return true; } /* * Main recv-parse-send-repeat loop. * * Reason for skip_recv is to avoid extra recv(). The problem with it * is EOF from socket. Currently that means that the pending data is * dropped. Fortunately server sockets are not paused and dropping * data from client is no problem. So only place where skip_recv is * important is sbuf_send_cb(). */ static void sbuf_main_loop(SBuf *sbuf, bool skip_recv) { unsigned free, ok; int loopcnt = 0; /* sbuf was closed before in this event loop */ if (!sbuf->sock) return; /* reading should be disabled when waiting */ Assert(sbuf->wait_type == W_RECV); AssertSanity(sbuf); if (!allocate_iobuf(sbuf)) return; /* avoid recv() if asked */ if (skip_recv) goto skip_recv; try_more: /* make room in buffer */ sbuf_try_resync(sbuf, false); /* avoid spending too much time on single socket */ if (cf_sbuf_loopcnt > 0 && loopcnt >= cf_sbuf_loopcnt) { log_debug("loopcnt full"); /* * sbuf_process_pending() avoids some data if buffer is full, * but as we exit processing loop here, we need to retry * after resync to process all data. (result is ignored) */ ok = sbuf_process_pending(sbuf); return; } loopcnt++; /* * here used to be if (free > SBUF_SMALL_PKT) check * but with skip_recv switch its should not be needed anymore. */ free = iobuf_amount_recv(sbuf->io); if (free > 0) { /* * When suspending, try to hit packet boundary ASAP. */ if (cf_pause_mode == P_SUSPEND && sbuf->pkt_remain > 0 && sbuf->pkt_remain < free) { free = sbuf->pkt_remain; } /* now fetch the data */ ok = sbuf_actual_recv(sbuf, free); if (!ok) return; } skip_recv: /* now handle it */ ok = sbuf_process_pending(sbuf); if (!ok) return; /* if the buffer is full, there can be more data available */ if (iobuf_amount_recv(sbuf->io) <= 0) goto try_more; /* clean buffer */ sbuf_try_resync(sbuf, true); /* notify proto that all is sent */ if (sbuf_is_empty(sbuf)) sbuf_call_proto(sbuf, SBUF_EV_FLUSH); } /* check if there is any error pending on socket */ static bool sbuf_after_connect_check(SBuf *sbuf) { int optval = 0, err; socklen_t optlen = sizeof(optval); err = getsockopt(sbuf->sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optlen); if (err < 0) { log_debug("sbuf_after_connect_check: getsockopt: %s", strerror(errno)); return false; } if (optval != 0) { log_debug("sbuf_after_connect_check: pending error: %s", strerror(optval)); return false; } return true; } /* callback for libevent EV_WRITE when connecting */ static void sbuf_connect_cb(int sock, short flags, void *arg) { SBuf *sbuf = arg; Assert(sbuf->wait_type == W_CONNECT || sbuf->wait_type == W_NONE); sbuf->wait_type = W_NONE; if (flags & EV_WRITE) { if (!sbuf_after_connect_check(sbuf)) goto failed; if (!sbuf_call_proto(sbuf, SBUF_EV_CONNECT_OK)) return; if (!sbuf_wait_for_data(sbuf)) goto failed; return; } failed: sbuf_call_proto(sbuf, SBUF_EV_CONNECT_FAILED); } /* send some data to listening socket */ bool sbuf_answer(SBuf *sbuf, const void *buf, unsigned len) { int res; if (sbuf->sock <= 0) return false; res = safe_send(sbuf->sock, buf, len, 0); if (res < 0) { log_debug("sbuf_answer: error sending: %s", strerror(errno)); } else if ((unsigned)res != len) log_debug("sbuf_answer: partial send: len=%d sent=%d", len, res); return (unsigned)res == len; } pgbouncer-1.5.4/src/janitor.c0000644000175000017500000004271212013151606013030 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Periodic maintenance. */ #include "bouncer.h" /* do full maintenance 3x per second */ static struct timeval full_maint_period = {0, USEC / 3}; static struct event full_maint_ev; /* close all sockets in server list */ static void close_server_list(struct StatList *sk_list, const char *reason) { struct List *item, *tmp; PgSocket *server; statlist_for_each_safe(item, sk_list, tmp) { server = container_of(item, PgSocket, head); disconnect_server(server, true, "%s", reason); } } static void close_client_list(struct StatList *sk_list, const char *reason) { struct List *item, *tmp; PgSocket *client; statlist_for_each_safe(item, sk_list, tmp) { client = container_of(item, PgSocket, head); disconnect_client(client, true, "%s", reason); } } bool suspend_socket(PgSocket *sk, bool force_suspend) { if (sk->suspended) return true; if (sbuf_is_empty(&sk->sbuf)) { if (sbuf_pause(&sk->sbuf)) sk->suspended = 1; } if (sk->suspended || !force_suspend) return sk->suspended; if (is_server_socket(sk)) disconnect_server(sk, true, "suspend_timeout"); else disconnect_client(sk, true, "suspend_timeout"); return true; } /* suspend all sockets in socket list */ static int suspend_socket_list(struct StatList *list, bool force_suspend) { struct List *item, *tmp; PgSocket *sk; int active = 0; statlist_for_each_safe(item, list, tmp) { sk = container_of(item, PgSocket, head); if (!suspend_socket(sk, force_suspend)) active++; } return active; } /* resume all suspended sockets in socket list */ static void resume_socket_list(struct StatList *list) { struct List *item, *tmp; PgSocket *sk; statlist_for_each_safe(item, list, tmp) { sk = container_of(item, PgSocket, head); if (sk->suspended) { sk->suspended = 0; sbuf_continue(&sk->sbuf); } } } /* resume all suspended sockets in all pools */ static void resume_sockets(void) { struct List *item; PgPool *pool; statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); if (pool->db->admin) continue; resume_socket_list(&pool->active_client_list); resume_socket_list(&pool->active_server_list); resume_socket_list(&pool->idle_server_list); resume_socket_list(&pool->used_server_list); } } /* resume pools and listen sockets */ void resume_all(void) { resume_sockets(); resume_pooler(); } /* * send test/reset query to server if needed */ static void launch_recheck(PgPool *pool) { const char *q = cf_server_check_query; bool need_check = true; PgSocket *server; bool res = true; /* find clean server */ while (1) { server = first_socket(&pool->used_server_list); if (!server) return; if (server->ready) break; disconnect_server(server, true, "idle server got dirty"); } /* is the check needed? */ if (q == NULL || q[0] == 0) need_check = false; else if (cf_server_check_delay > 0) { usec_t now = get_cached_time(); if (now - server->request_time < cf_server_check_delay) need_check = false; } if (need_check) { /* send test query, wait for result */ slog_debug(server, "P: Checking: %s", q); change_server_state(server, SV_TESTED); SEND_generic(res, server, 'Q', "s", q); if (!res) disconnect_server(server, false, "test query failed"); } else /* make immediately available */ release_server(server); } /* * make servers available */ static void per_loop_activate(PgPool *pool) { struct List *item, *tmp; PgSocket *client; /* see if any server have been freed */ statlist_for_each_safe(item, &pool->waiting_client_list, tmp) { client = container_of(item, PgSocket, head); if (!statlist_empty(&pool->idle_server_list)) { /* db not fully initialized after reboot */ if (client->wait_for_welcome && !pool->welcome_msg_ready) { launch_new_connection(pool); continue; } /* there is a ready server already */ activate_client(client); } else if (!statlist_empty(&pool->tested_server_list)) { /* some connections are in testing process */ break; } else if (!statlist_empty(&pool->used_server_list)) { /* ask for more connections to be tested */ launch_recheck(pool); break; } else { /* not enough connections */ launch_new_connection(pool); break; } } } /* * pause active clients */ static int per_loop_pause(PgPool *pool) { int active = 0; if (pool->db->admin) return 0; close_server_list(&pool->idle_server_list, "pause mode"); close_server_list(&pool->used_server_list, "pause mode"); close_server_list(&pool->new_server_list, "pause mode"); active += statlist_count(&pool->active_server_list); active += statlist_count(&pool->tested_server_list); return active; } /* * suspend active clients and servers */ static int per_loop_suspend(PgPool *pool, bool force_suspend) { int active = 0; if (pool->db->admin) return 0; active += suspend_socket_list(&pool->active_client_list, force_suspend); /* this list is unsuspendable, but still need force_suspend and counting */ active += suspend_socket_list(&pool->waiting_client_list, force_suspend); if (active) per_loop_activate(pool); if (!active) { active += suspend_socket_list(&pool->active_server_list, force_suspend); active += suspend_socket_list(&pool->idle_server_list, force_suspend); /* as all clients are done, no need for them */ close_server_list(&pool->tested_server_list, "close unsafe file descriptors on suspend"); close_server_list(&pool->used_server_list, "close unsafe file descriptors on suspend"); } return active; } /* * this function is called for each event loop. */ void per_loop_maint(void) { struct List *item; PgPool *pool; int active = 0; int partial_pause = 0; bool force_suspend = false; if (cf_pause_mode == P_SUSPEND && cf_suspend_timeout > 0) { usec_t stime = get_cached_time() - g_suspend_start; if (stime >= cf_suspend_timeout) force_suspend = true; } statlist_for_each(item, &pool_list) { pool = container_of(item, PgPool, head); if (pool->db->admin) continue; switch (cf_pause_mode) { case P_NONE: if (pool->db->db_paused) { partial_pause = 1; active += per_loop_pause(pool); } else per_loop_activate(pool); break; case P_PAUSE: active += per_loop_pause(pool); break; case P_SUSPEND: active += per_loop_suspend(pool, force_suspend); break; } } switch (cf_pause_mode) { case P_SUSPEND: if (force_suspend) { close_client_list(&login_client_list, "suspend_timeout"); } else active += statlist_count(&login_client_list); case P_PAUSE: if (!active) admin_pause_done(); break; case P_NONE: if (partial_pause && !active) admin_pause_done(); break; } } /* maintaining clients in pool */ static void pool_client_maint(PgPool *pool) { struct List *item, *tmp; usec_t now = get_cached_time(); PgSocket *client; usec_t age; /* force client_idle_timeout */ if (cf_client_idle_timeout > 0) { statlist_for_each_safe(item, &pool->active_client_list, tmp) { client = container_of(item, PgSocket, head); Assert(client->state == CL_ACTIVE); if (client->link) continue; if (now - client->request_time > cf_client_idle_timeout) disconnect_client(client, true, "client_idle_timeout"); } } /* force timeouts for waiting queries */ if (cf_query_timeout > 0 || cf_query_wait_timeout > 0) { statlist_for_each_safe(item, &pool->waiting_client_list, tmp) { client = container_of(item, PgSocket, head); Assert(client->state == CL_WAITING); if (client->query_start == 0) { age = now - client->request_time; //log_warning("query_start==0"); } else age = now - client->query_start; if (cf_query_timeout > 0 && age > cf_query_timeout) disconnect_client(client, true, "query_timeout"); else if (cf_query_wait_timeout > 0 && age > cf_query_wait_timeout) disconnect_client(client, true, "query_wait_timeout"); } } /* apply client_login_timeout to clients waiting for welcome pkt */ if (cf_client_login_timeout > 0 && !pool->welcome_msg_ready) { statlist_for_each_safe(item, &pool->waiting_client_list, tmp) { client = container_of(item, PgSocket, head); if (!client->wait_for_welcome) continue; age = now - client->connect_time; if (age > cf_client_login_timeout) disconnect_client(client, true, "client_login_timeout (server down)"); } } } static void check_unused_servers(PgPool *pool, struct StatList *slist, bool idle_test) { usec_t now = get_cached_time(); struct List *item, *tmp; usec_t idle, age; PgSocket *server; usec_t lifetime_kill_gap = 0; /* * Calculate the time that disconnects because of server_lifetime * must be separated. This avoids the need to re-launch lot * of connections together. */ if (pool->db->pool_size > 0) lifetime_kill_gap = cf_server_lifetime / pool->db->pool_size; /* disconnect idle servers if needed */ statlist_for_each_safe(item, slist, tmp) { server = container_of(item, PgSocket, head); age = now - server->connect_time; idle = now - server->request_time; if (server->close_needed) { disconnect_server(server, true, "database configuration changed"); } else if (server->state == SV_IDLE && !server->ready) { disconnect_server(server, true, "SV_IDLE server got dirty"); } else if (server->state == SV_USED && !server->ready) { disconnect_server(server, true, "SV_USED server got dirty"); } else if (cf_server_idle_timeout > 0 && idle > cf_server_idle_timeout) { disconnect_server(server, true, "server idle timeout"); } else if (age >= cf_server_lifetime) { if (pool->last_lifetime_disconnect + lifetime_kill_gap <= now) { disconnect_server(server, true, "server lifetime over"); pool->last_lifetime_disconnect = now; } } else if (cf_pause_mode == P_PAUSE) { disconnect_server(server, true, "pause mode"); } else if (idle_test && *cf_server_check_query) { if (idle > cf_server_check_delay) change_server_state(server, SV_USED); } } } /* * Check pool size, close conns if too many. Makes pooler * react faster to the case when admin decreased pool size. */ static void check_pool_size(PgPool *pool) { PgSocket *server; int cur = statlist_count(&pool->active_server_list) + statlist_count(&pool->idle_server_list) + statlist_count(&pool->used_server_list) + statlist_count(&pool->tested_server_list); /* cancel pkt may create new srv conn without * taking pool_size into account * * statlist_count(&pool->new_server_list) */ int many = cur - (pool->db->pool_size + pool->db->res_pool_size); Assert(pool->db->pool_size >= 0); while (many > 0) { server = first_socket(&pool->used_server_list); if (!server) server = first_socket(&pool->idle_server_list); if (!server) break; disconnect_server(server, true, "too many servers in the pool"); many--; cur--; } /* launch extra connections to satisfy min_pool_size */ if (cur < cf_min_pool_size && cur < pool->db->pool_size && cf_pause_mode == P_NONE && cf_reboot == 0 && pool_client_count(pool) > 0) { log_debug("Launching new connection to satisfy min_pool_size"); launch_new_connection(pool); } } /* maintain servers in a pool */ static void pool_server_maint(PgPool *pool) { struct List *item, *tmp; usec_t age, now = get_cached_time(); PgSocket *server; /* find and disconnect idle servers */ check_unused_servers(pool, &pool->used_server_list, 0); check_unused_servers(pool, &pool->tested_server_list, 0); check_unused_servers(pool, &pool->idle_server_list, 1); /* where query got did not get answer in query_timeout */ if (cf_query_timeout > 0 || cf_idle_transaction_timeout > 0) { statlist_for_each_safe(item, &pool->active_server_list, tmp) { server = container_of(item, PgSocket, head); Assert(server->state == SV_ACTIVE); if (server->ready) continue; age = now - server->link->request_time; if (cf_query_timeout > 0 && age > cf_query_timeout) { disconnect_server(server, true, "query timeout"); } else if (cf_idle_transaction_timeout > 0 && server->idle_tx && age > cf_idle_transaction_timeout) { disconnect_server(server, true, "idle transaction timeout"); } } } /* find connections that got connect, but could not log in */ if (cf_server_connect_timeout > 0) { statlist_for_each_safe(item, &pool->new_server_list, tmp) { server = container_of(item, PgSocket, head); Assert(server->state == SV_LOGIN); age = now - server->connect_time; if (age > cf_server_connect_timeout) disconnect_server(server, true, "connect timeout"); } } check_pool_size(pool); } static void cleanup_client_logins(void) { struct List *item, *tmp; PgSocket *client; usec_t age; usec_t now = get_cached_time(); if (cf_client_login_timeout <= 0) return; statlist_for_each_safe(item, &login_client_list, tmp) { client = container_of(item, PgSocket, head); age = now - client->connect_time; if (age > cf_client_login_timeout) disconnect_client(client, true, "client_login_timeout"); } } static void kill_database(PgDatabase *db); static void cleanup_inactive_autodatabases(void) { struct List *item, *tmp; PgDatabase *db; usec_t age; usec_t now = get_cached_time(); if (cf_autodb_idle_timeout <= 0) return; /* now kill the old ones */ statlist_for_each_safe(item, &autodatabase_idle_list, tmp) { db = container_of(item, PgDatabase, head); if (db->db_paused) continue; age = now - db->inactive_time; if (age > cf_autodb_idle_timeout) kill_database(db); else break; } } /* full-scale maintenance, done only occasionally */ static void do_full_maint(int sock, short flags, void *arg) { struct List *item, *tmp; PgPool *pool; PgDatabase *db; static unsigned int seq; seq++; /* * Avoid doing anything that may surprise other pgbouncer. */ if (cf_pause_mode == P_SUSPEND) goto skip_maint; statlist_for_each_safe(item, &pool_list, tmp) { pool = container_of(item, PgPool, head); if (pool->db->admin) continue; pool_server_maint(pool); pool_client_maint(pool); /* is autodb active? */ if (pool->db->db_auto && pool->db->inactive_time == 0) { if (pool_client_count(pool) > 0 || pool_server_count(pool) > 0) pool->db->active_stamp = seq; } } /* find inactive autodbs */ statlist_for_each_safe(item, &database_list, tmp) { db = container_of(item, PgDatabase, head); if (db->db_auto && db->inactive_time == 0) { if (db->active_stamp == seq) continue; db->inactive_time = get_cached_time(); statlist_remove(&database_list, &db->head); statlist_append(&autodatabase_idle_list, &db->head); } } cleanup_inactive_autodatabases(); cleanup_client_logins(); if (cf_shutdown == 1 && get_active_server_count() == 0) { log_info("server connections dropped, exiting"); cf_shutdown = 2; event_loopbreak(); return; } if (cf_auth_type >= AUTH_TRUST) loader_users_check(); adns_zone_cache_maint(adns); skip_maint: safe_evtimer_add(&full_maint_ev, &full_maint_period); } /* first-time initializtion */ void janitor_setup(void) { /* launch maintenance */ evtimer_set(&full_maint_ev, do_full_maint, NULL); safe_evtimer_add(&full_maint_ev, &full_maint_period); } void kill_pool(PgPool *pool) { const char *reason = "database removed"; close_client_list(&pool->active_client_list, reason); close_client_list(&pool->waiting_client_list, reason); close_client_list(&pool->cancel_req_list, reason); close_server_list(&pool->active_server_list, reason); close_server_list(&pool->idle_server_list, reason); close_server_list(&pool->used_server_list, reason); close_server_list(&pool->tested_server_list, reason); close_server_list(&pool->new_server_list, reason); pktbuf_free(pool->welcome_msg); list_del(&pool->map_head); statlist_remove(&pool_list, &pool->head); varcache_clean(&pool->orig_vars); slab_free(pool_cache, pool); } static void kill_database(PgDatabase *db) { PgPool *pool; struct List *item, *tmp; log_warning("dropping database '%s' as it does not exist anymore or inactive auto-database", db->name); statlist_for_each_safe(item, &pool_list, tmp) { pool = container_of(item, PgPool, head); if (pool->db == db) kill_pool(pool); } pktbuf_free(db->startup_params); if (db->forced_user) slab_free(user_cache, db->forced_user); if (db->connect_query) free((void *)db->connect_query); if (db->inactive_time) statlist_remove(&autodatabase_idle_list, &db->head); else statlist_remove(&database_list, &db->head); slab_free(db_cache, db); } /* as [pgbouncer] section can be loaded after databases, there's need for review */ void config_postprocess(void) { struct List *item, *tmp; PgDatabase *db; statlist_for_each_safe(item, &database_list, tmp) { db = container_of(item, PgDatabase, head); if (db->db_dead) { kill_database(db); continue; } if (db->pool_size < 0) db->pool_size = cf_default_pool_size; if (db->res_pool_size < 0) db->res_pool_size = cf_res_pool_size; } } pgbouncer-1.5.4/src/pooler.c0000644000175000017500000002616711765176015012706 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Handling of pooler listening sockets */ #include "bouncer.h" #include struct ListenSocket { struct List node; int fd; bool active; struct event ev; PgAddr addr; }; static STATLIST(sock_list); /* hints for getaddrinfo(listen_addr) */ static const struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_protocol = IPPROTO_TCP, .ai_flags = AI_PASSIVE, }; /* should listening sockets be active or suspended? */ static bool need_active = false; /* is it actually active or suspended? */ static bool pooler_active = false; /* on accept() failure sleep 5 seconds */ static struct event ev_err; static struct timeval err_timeout = {5, 0}; static void tune_accept(int sock, bool on); /* atexit() cleanup func */ static void cleanup_sockets(void) { struct ListenSocket *ls; struct List *el; /* avoid cleanup if exit() while suspended */ if (cf_pause_mode == P_SUSPEND) return; while ((el = statlist_pop(&sock_list)) != NULL) { ls = container_of(el, struct ListenSocket, node); if (ls->fd > 0) { safe_close(ls->fd); ls->fd = 0; } if (pga_is_unix(&ls->addr)) { char buf[sizeof(struct sockaddr_un) + 20]; snprintf(buf, sizeof(buf), "%s/.s.PGSQL.%d", cf_unix_socket_dir, cf_listen_port); unlink(buf); } statlist_remove(&sock_list, &ls->node); free(ls); } } /* * initialize another listening socket. */ static bool add_listen(int af, const struct sockaddr *sa, int salen) { struct ListenSocket *ls; int sock, res, val; char buf[128]; const char *errpos; log_debug("add_listen: %s", sa2str(sa, buf, sizeof(buf))); /* create socket */ errpos = "socket"; sock = socket(af, SOCK_STREAM, 0); if (sock < 0) goto failed; /* relaxed binding */ if (af != AF_UNIX) { val = 1; errpos = "setsockopt"; res = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); if (res < 0) goto failed; } /* bind it */ errpos = "bind"; res = bind(sock, sa, salen); if (res < 0) goto failed; /* set common options */ errpos = "tune_socket"; if (!tune_socket(sock, (af == AF_UNIX))) goto failed; /* finally, accept connections */ errpos = "listen"; res = listen(sock, cf_listen_backlog); if (res < 0) goto failed; errpos = "calloc"; ls = calloc(1, sizeof(*ls)); if (!ls) goto failed; list_init(&ls->node); ls->fd = sock; if (sa->sa_family == AF_UNIX) { pga_set(&ls->addr, AF_UNIX, cf_listen_port); } else { pga_copy(&ls->addr, sa); } if (af == AF_UNIX) { struct sockaddr_un *un = (struct sockaddr_un *)sa; change_file_mode(un->sun_path, cf_unix_socket_mode, NULL, cf_unix_socket_group); } else { tune_accept(sock, cf_tcp_defer_accept); } log_info("listening on %s", sa2str(sa, buf, sizeof(buf))); statlist_append(&sock_list, &ls->node); return true; failed: log_warning("Cannot listen on %s: %s(): %s", sa2str(sa, buf, sizeof(buf)), errpos, strerror(errno)); if (sock >= 0) safe_close(sock); return false; } static void create_unix_socket(const char *socket_dir, int listen_port) { struct sockaddr_un un; int res; char lockfile[sizeof(struct sockaddr_un) + 10]; struct stat st; /* fill sockaddr struct */ memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; snprintf(un.sun_path, sizeof(un.sun_path), "%s/.s.PGSQL.%d", socket_dir, listen_port); /* check for lockfile */ snprintf(lockfile, sizeof(lockfile), "%s.lock", un.sun_path); res = lstat(lockfile, &st); if (res == 0) fatal("unix port %d is in use", listen_port); /* expect old bouncer gone */ unlink(un.sun_path); add_listen(AF_UNIX, (const struct sockaddr *)&un, sizeof(un)); } /* * Notify pooler only when also data is arrived. * * optval specifies how long after connection attempt to wait for data. * * Related to tcp_synack_retries sysctl, default 5 (corresponds 180 secs). * * SO_ACCEPTFILTER needs to be set after listern(), maybe TCP_DEFER_ACCEPT too. */ static void tune_accept(int sock, bool on) { const char *act = on ? "install" : "uninstall"; int res = 0; #ifdef TCP_DEFER_ACCEPT int val = 45; /* fixme: proper value */ socklen_t vlen = sizeof(val); res = getsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, &vlen); log_noise("old TCP_DEFER_ACCEPT on %d = %d", sock, val); val = on ? 1 : 0; log_noise("%s TCP_DEFER_ACCEPT on %d", act, sock); res = setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val)); #else #if 0 #ifdef SO_ACCEPTFILTER struct accept_filter_arg af, *afp = on ? &af : NULL; socklen_t af_len = on ? sizeof(af) : 0; memset(&af, 0, sizeof(af)); strcpy(af.af_name, "dataready"); log_noise("%s SO_ACCEPTFILTER on %d", act, sock); res = setsockopt(sock, SOL_SOCKET, SO_ACCEPTFILTER, afp, af_len); #endif #endif #endif if (res < 0) log_warning("tune_accept: %s TCP_DEFER_ACCEPT/SO_ACCEPTFILTER: %s", act, strerror(errno)); } void pooler_tune_accept(bool on) { struct List *el; struct ListenSocket *ls; statlist_for_each(el, &sock_list) { ls = container_of(el, struct ListenSocket, node); if (!pga_is_unix(&ls->addr)) tune_accept(ls->fd, on); } } static void err_wait_func(int sock, short flags, void *arg) { if (cf_pause_mode != P_SUSPEND) resume_pooler(); } static const char *addrpair(const PgAddr *src, const PgAddr *dst) { static char ip1buf[PGADDR_BUF], ip2buf[PGADDR_BUF], buf[2*PGADDR_BUF + 16]; const char *ip1, *ip2; if (pga_is_unix(src)) return "unix->unix"; ip1 = pga_ntop(src, ip1buf, sizeof(ip1buf)); ip2 = pga_ntop(src, ip2buf, sizeof(ip2buf)); snprintf(buf, sizeof(buf), "%s:%d -> %s:%d", ip1, pga_port(src), ip2, pga_port(dst)); return buf; } static const char *conninfo(const PgSocket *sk) { if (is_server_socket(sk)) return addrpair(&sk->local_addr, &sk->remote_addr); else return addrpair(&sk->remote_addr, &sk->local_addr); } /* got new connection, associate it with client struct */ static void pool_accept(int sock, short flags, void *arg) { struct ListenSocket *ls = arg; int fd; PgSocket *client; union { struct sockaddr_in in; struct sockaddr_in6 in6; struct sockaddr_un un; struct sockaddr sa; } raddr; socklen_t len = sizeof(raddr); bool is_unix = pga_is_unix(&ls->addr); if(!(flags & EV_READ)) { log_warning("No EV_READ in pool_accept"); return; } loop: /* get fd */ fd = safe_accept(sock, &raddr.sa, &len); if (fd < 0) { if (errno == EAGAIN) return; else if (errno == ECONNABORTED) return; /* * probably fd limit, pointless to try often * wait a bit, hope that admin resolves somehow */ log_error("accept() failed: %s", strerror(errno)); evtimer_set(&ev_err, err_wait_func, NULL); safe_evtimer_add(&ev_err, &err_timeout); suspend_pooler(); return; } log_noise("new fd from accept=%d", fd); if (is_unix) { uid_t uid; gid_t gid; log_noise("getuid(): %d", (int)getuid()); if (getpeereid(fd, &uid, &gid) >= 0) log_noise("unix peer uid: %d", (int)uid); else log_warning("unix peer uid failed: %s", strerror(errno)); client = accept_client(fd, true); } else { client = accept_client(fd, false); } if (client) slog_debug(client, "P: got connection: %s", conninfo(client)); /* * there may be several clients waiting, * avoid context switch by looping */ goto loop; } bool use_pooler_socket(int sock, bool is_unix) { struct ListenSocket *ls; int res; char buf[PGADDR_BUF]; if (!tune_socket(sock, is_unix)) return false; ls = calloc(1, sizeof(*ls)); ls->fd = sock; if (is_unix) { pga_set(&ls->addr, AF_UNIX, cf_listen_port); } else { struct sockaddr_storage ss; socklen_t len = sizeof(ss); res = getsockname(sock, (struct sockaddr *)&ss, &len); if (res < 0) { log_error("getsockname failed"); free(ls); return false; } pga_copy(&ls->addr, (struct sockaddr *)&ss); } log_info("got pooler socket: %s", pga_str(&ls->addr, buf, sizeof(buf))); statlist_append(&sock_list, &ls->node); return true; } void suspend_pooler(void) { struct List *el; struct ListenSocket *ls; need_active = false; statlist_for_each(el, &sock_list) { ls = container_of(el, struct ListenSocket, node); if (!ls->active) continue; if (event_del(&ls->ev) < 0) { log_warning("suspend_pooler, event_del: %s", strerror(errno)); return; } ls->active = false; } pooler_active = false; } void resume_pooler(void) { struct List *el; struct ListenSocket *ls; need_active = true; statlist_for_each(el, &sock_list) { ls = container_of(el, struct ListenSocket, node); if (ls->active) continue; event_set(&ls->ev, ls->fd, EV_READ | EV_PERSIST, pool_accept, ls); if (event_add(&ls->ev, NULL) < 0) { log_warning("event_add failed: %s", strerror(errno)); return; } ls->active = true; } pooler_active = true; } /* retry previously failed suspend_pooler() / resume_pooler() */ void per_loop_pooler_maint(void) { if (need_active && !pooler_active) resume_pooler(); else if (!need_active && pooler_active) suspend_pooler(); } static bool parse_addr(void *arg, const char *addr) { int res; char service[64]; struct addrinfo *ai, *gaires = NULL; bool ok; if (!*addr) return true; if (strcmp(addr, "*") == 0) addr = NULL; snprintf(service, sizeof(service), "%d", cf_listen_port); res = getaddrinfo(addr, service, &hints, &gaires); if (res != 0) { fatal("getaddrinfo('%s', '%d') = %s [%d]", addr ? addr : "*", cf_listen_port, gai_strerror(res), res); } for (ai = gaires; ai; ai = ai->ai_next) { ok = add_listen(ai->ai_family, ai->ai_addr, ai->ai_addrlen); /* it's unclear whether all or only first result should be used */ if (0 && ok) break; } freeaddrinfo(gaires); return true; } /* listen on socket - should happen after all other initializations */ void pooler_setup(void) { bool ok; static int init_done = 0; if (!init_done) { /* remove socket on shutdown */ atexit(cleanup_sockets); init_done = 1; } ok = parse_word_list(cf_listen_addr, parse_addr, NULL); if (!ok) fatal("failed to parse listen_addr list: %s", cf_listen_addr); if (cf_unix_socket_dir && *cf_unix_socket_dir) create_unix_socket(cf_unix_socket_dir, cf_listen_port); if (!statlist_count(&sock_list)) fatal("nowhere to listen on"); resume_pooler(); } bool for_each_pooler_fd(pooler_cb cbfunc, void *arg) { struct List *el; struct ListenSocket *ls; bool ok; statlist_for_each(el, &sock_list) { ls = container_of(el, struct ListenSocket, node); ok = cbfunc(arg, ls->fd, &ls->addr); if (!ok) return false; } return true; } pgbouncer-1.5.4/src/dnslookup.c0000644000175000017500000005775012044176021013412 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2010 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "bouncer.h" #include /* * Available backends: * * udns - libudns * getaddrinfo_a - glibc only * libevent1 - returns TTL, ignores hosts file. * libevent2 - does not return TTL, uses hosts file. */ #if !defined(USE_EVDNS) && !defined(USE_UDNS) #define USE_GETADDRINFO_A #endif #ifdef USE_EVDNS #ifdef EV_ET #define USE_LIBEVENT2 #include #define addrinfo evutil_addrinfo #define freeaddrinfo evutil_freeaddrinfo #else /* !EV_ET */ #define USE_LIBEVENT1 #include #endif /* !EV_ET */ #endif /* USE_EVDNS */ #ifdef USE_UDNS #include #define ZONE_RECHECK 1 #endif #ifndef ZONE_RECHECK #define ZONE_RECHECK 0 /* no implementation, also avoid 'unused' warning */ #define impl_query_soa_serial(ctx, name) do { if (0) got_zone_serial(ctx, NULL); } while (0) #define cf_dns_zone_check_period (0) #endif /* * There can be several client request (tokens) * attached to single actual request. */ struct DNSToken { struct List node; adns_callback_f cb_func; void *cb_arg; }; /* * Cached DNS query (hostname). */ struct DNSRequest { struct AANode node; /* DNSContext->req_tree */ struct List znode; /* DNSZone->host_list */ struct DNSContext *ctx; struct DNSZone *zone; struct List ucb_list; /* DNSToken->node */ const char *name; int namelen; bool done; struct addrinfo *result; struct addrinfo *current; struct addrinfo *oldres; usec_t res_ttl; }; /* zone name serial */ struct DNSZone { struct List lnode; /* DNSContext->zone_list */ struct AANode tnode; /* DNSContext->zone_tree */ struct StatList host_list; /* DNSRequest->znode */ const char *zonename; uint32_t serial; }; /* * Top struct for DNS data. */ struct DNSContext { struct AATree req_tree; void *edns; struct AATree zone_tree; /* DNSZone->tnode */ struct List zone_list; /* DNSZone->lnode */ struct DNSZone *cur_zone; struct event ev_zone_timer; int zone_state; int active; /* number of in-flight queries */ }; static void deliver_info(struct DNSRequest *req); static void got_result_gai(int result, struct addrinfo *res, void *arg); static void zone_register(struct DNSContext *ctx, struct DNSRequest *req); static void zone_init(struct DNSContext *ctx); static void zone_free(struct DNSContext *ctx); static void got_zone_serial(struct DNSContext *ctx, uint32_t *serial); /* * Custom addrinfo generation */ #if defined(USE_LIBEVENT1) || defined(USE_UDNS) static struct addrinfo *mk_addrinfo(const struct in_addr ip4) { struct addrinfo *ai; struct sockaddr_in *sa; ai = calloc(1, sizeof(*ai)); if (!ai) return NULL; sa = calloc(1, sizeof(*sa)); if (!sa) { free(ai); return NULL; } sa->sin_addr = ip4; sa->sin_family = AF_INET; ai->ai_addr = (struct sockaddr *)sa; ai->ai_addrlen = sizeof(*sa); ai->ai_protocol = IPPROTO_TCP; ai->ai_socktype = SOCK_STREAM; ai->ai_family = AF_INET; return ai; } #define freeaddrinfo(x) local_freeaddrinfo(x) static void freeaddrinfo(struct addrinfo *ai) { struct addrinfo *cur; while (ai) { cur = ai; ai = ai->ai_next; free(cur->ai_addr); free(cur); } } static struct addrinfo *convert_ipv4_result(const struct in_addr *adrs, int count) { struct addrinfo *ai, *last = NULL; int i; for (i = count - 1; i >= 0; i--) { ai = mk_addrinfo(adrs[i]); if (!ai) goto failed; ai->ai_next = last; last = ai; } return last; failed: freeaddrinfo(last); return NULL; } #endif /* custom addrinfo */ /* * ADNS with glibc's getaddrinfo_a() */ #ifdef USE_GETADDRINFO_A const char *adns_get_backend(void) { #ifdef HAVE_GETADDRINFO_A return "libc" #ifdef __GLIBC__ "-" STR(__GLIBC__) "." STR(__GLIBC_MINOR__); #endif ; #else return "compat"; #endif } struct GaiRequest { struct List node; struct DNSRequest *req; struct gaicb gairq; }; struct GaiContext { struct DNSContext *ctx; struct List gairq_list; struct event ev; struct sigevent sev; }; static void dns_signal(int f, short ev, void *arg) { struct GaiContext *gctx = arg; struct List *el, *tmp; struct GaiRequest *rq; int e; list_for_each_safe(el, &gctx->gairq_list, tmp) { rq = container_of(el, struct GaiRequest, node); e = gai_error(&rq->gairq); if (e == EAI_INPROGRESS) continue; /* got one */ list_del(&rq->node); got_result_gai(e, rq->gairq.ar_result, rq->req); free(rq); } } static bool impl_init(struct DNSContext *ctx) { struct GaiContext *gctx = calloc(1, sizeof(*gctx)); if (!gctx) return false; list_init(&gctx->gairq_list); gctx->ctx = ctx; gctx->sev.sigev_notify = SIGEV_SIGNAL; gctx->sev.sigev_signo = SIGALRM; signal_set(&gctx->ev, SIGALRM, dns_signal, gctx); if (signal_add(&gctx->ev, NULL) < 0) { free(gctx); return false; } ctx->edns = gctx; return true; } static void impl_launch_query(struct DNSRequest *req) { static const struct addrinfo hints = { .ai_socktype = SOCK_STREAM }; struct GaiContext *gctx = req->ctx->edns; struct GaiRequest *grq; int res; struct gaicb *cb; grq = calloc(1, sizeof(*grq)); if (!grq) goto failed2; list_init(&grq->node); grq->req = req; grq->gairq.ar_name = req->name; grq->gairq.ar_request = &hints; list_append(&gctx->gairq_list, &grq->node); cb = &grq->gairq; res = getaddrinfo_a(GAI_NOWAIT, &cb, 1, &gctx->sev); if (res != 0) goto failed; return; failed: if (res == EAI_SYSTEM) log_warning("dns: getaddrinfo_a(%s)=%d, errno=%d (%s)", req->name, res, errno, strerror(errno)); else log_warning("dns: getaddrinfo_a(%s)=%d", req->name, res); list_del(&grq->node); free(grq); failed2: req->done = true; deliver_info(req); } static void impl_release(struct DNSContext *ctx) { struct GaiContext *gctx = ctx->edns; if (gctx) { signal_del(&gctx->ev); free(gctx); ctx->edns = NULL; } } #endif /* USE_GETADDRINFO_A */ /* * ADNS with libevent2 */ #ifdef USE_LIBEVENT2 const char *adns_get_backend(void) { return "evdns2"; } static bool impl_init(struct DNSContext *ctx) { ctx->edns = evdns_base_new(NULL, 1); if (!ctx->edns) { log_warning("evdns_base_new failed"); return false; } return true; } static void impl_launch_query(struct DNSRequest *req) { static const struct addrinfo hints = { .ai_socktype = SOCK_STREAM }; struct evdns_getaddrinfo_request *gai_req; struct evdns_base *dns = req->ctx->edns; gai_req = evdns_getaddrinfo(dns, req->name, NULL, &hints, got_result_gai, req); log_noise("dns: evdns_getaddrinfo(%s)=%p", req->name, gai_req); } static void impl_release(struct DNSContext *ctx) { struct evdns_base *dns = ctx->edns; evdns_base_free(dns, 0); } #endif /* USE_LIBEVENT2 */ /* * ADNS with libevent 1.x */ #ifdef USE_LIBEVENT1 const char *adns_get_backend(void) { return "evdns1"; } static void got_result_evdns(int result, char type, int count, int ttl, void *addresses, void *arg) { struct DNSRequest *req = arg; struct addrinfo *ai; log_noise("dns: got_result_evdns: type=%d cnt=%d ttl=%d", type, count, ttl); if (result == DNS_IPv4_A) { ai = convert_ipv4_result(addresses, count); if (ai) { got_result_gai(0, ai, req); return; } } /* lookup failed */ got_result_gai(1, NULL, req); } static bool impl_init(struct DNSContext *ctx) { return evdns_init() == 0; } static void impl_launch_query(struct DNSRequest *req) { int err; err = evdns_resolve_ipv4(req->name, 0, got_result_evdns, req); log_noise("dns(%s): evdns_resolve_ipv4 = %d", req->name, err); if (err != 0 && !req->done) { /* if callback was not yet called, do it now */ got_result_gai(1, NULL, req); } } static void impl_release(struct DNSContext *ctx) { evdns_shutdown(0); } #endif /* USE_LIBEVENT1 */ /* * ADNS with */ #ifdef USE_UDNS struct UdnsMeta { struct dns_ctx *ctx; struct event ev_io; struct event ev_timer; bool timer_active; }; const char *adns_get_backend(void) { return "udns " UDNS_VERSION; } static void udns_timer_setter(struct dns_ctx *uctx, int timeout, void *arg) { struct DNSContext *ctx = arg; struct UdnsMeta *udns = ctx->edns; log_noise("udns_timer_setter: ctx=%p timeout=%d", uctx, timeout); if (udns->timer_active) { event_del(&udns->ev_timer); udns->timer_active = false; } if (uctx && timeout >= 0) { struct timeval tv = { .tv_sec = timeout, .tv_usec = 0 }; evtimer_add(&udns->ev_timer, &tv); udns->timer_active = true; } } static void udns_timer_cb(int d, short fl, void *arg) { struct DNSContext *ctx = arg; struct UdnsMeta *udns = ctx->edns; time_t now = get_cached_time() / USEC; log_noise("udns_timer_cb"); dns_timeouts(udns->ctx, 10, now); } static void udns_io_cb(int fd, short fl, void *arg) { struct DNSContext *ctx = arg; struct UdnsMeta *udns = ctx->edns; time_t now = get_cached_time() / USEC; log_noise("udns_io_cb"); dns_ioevent(udns->ctx, now); } static void udns_result_a4(struct dns_ctx *ctx, struct dns_rr_a4 *a4, void *data) { struct DNSRequest *req = data; struct addrinfo *res = NULL; int err; err = dns_status(ctx); if (a4) { log_noise("udns_result_a4: %s: %d ips", req->name, a4->dnsa4_nrr); res = convert_ipv4_result(a4->dnsa4_addr, a4->dnsa4_nrr); free(a4); } got_result_gai(0, res, req); } static void impl_launch_query(struct DNSRequest *req) { struct UdnsMeta *udns = req->ctx->edns; struct dns_query *q; int flags = 0; q = dns_submit_a4(udns->ctx, req->name, flags, udns_result_a4, req); if (q) { log_noise("dns: udns_launch_query(%s)=%p", req->name, q); } else { log_warning("dns: udns_launch_query(%s)=NULL", req->name); } } static bool impl_init(struct DNSContext *ctx) { int fd; struct dns_ctx *dctx; struct UdnsMeta *udns; dns_init(NULL, 0); dctx = dns_new(NULL); if (!dctx) return false; udns = calloc(1, sizeof(*udns)); if (!udns) return false; ctx->edns = udns; udns->ctx = dctx; /* i/o callback setup */ fd = dns_open(dctx); if (fd <= 0) { log_warning("dns_open failed: fd=%d", fd); return false; } event_set(&udns->ev_io, fd, EV_READ | EV_PERSIST, udns_io_cb, ctx); event_add(&udns->ev_io, NULL); /* timer setup */ evtimer_set(&udns->ev_timer, udns_timer_cb, ctx); dns_set_tmcbck(udns->ctx, udns_timer_setter, ctx); return true; } static void impl_release(struct DNSContext *ctx) { struct UdnsMeta *udns = ctx->edns; event_del(&udns->ev_io); dns_free(udns->ctx); if (udns->timer_active) { event_del(&udns->ev_timer); udns->timer_active = false; } } /* * generic SOA query for UDNS */ struct SOA { dns_rr_common(dnssoa); char *dnssoa_nsname; char *dnssoa_hostmaster; uint32_t dnssoa_serial; uint32_t dnssoa_refresh; uint32_t dnssoa_retry; uint32_t dnssoa_expire; uint32_t dnssoa_minttl; }; typedef void query_soa_fn(struct dns_ctx *ctx, struct SOA *result, void *data); static int parse_soa(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, void **result) { struct SOA *soa = NULL; int res, len; struct dns_parse p; struct dns_rr rr; dnsc_t buf[DNS_MAXDN]; char *s; /* calc size */ len = 0; dns_initparse(&p, qdn, pkt, cur, end); while ((res = dns_nextrr(&p, &rr)) > 0) { cur = rr.dnsrr_dptr; res = dns_getdn(pkt, &cur, end, buf, sizeof(buf)); if (res <= 0) goto failed; len += dns_dntop_size(buf); res = dns_getdn(pkt, &cur, end, buf, sizeof(buf)); if (res <= 0) goto failed; len += dns_dntop_size(buf); if (cur + 5*4 != rr.dnsrr_dend) goto failed; } if (res < 0 || p.dnsp_nrr != 1) goto failed; len += dns_stdrr_size(&p); /* allocate */ soa = malloc(sizeof(*soa) + len); if (!soa) return DNS_E_NOMEM; /* fill with data */ soa->dnssoa_nrr = 1; dns_rewind(&p, qdn); dns_nextrr(&p, &rr); s = (char *)(soa + 1); cur = rr.dnsrr_dptr; soa->dnssoa_nsname = s; dns_getdn(pkt, &cur, end, buf, sizeof(buf)); s += dns_dntop(buf, s, DNS_MAXNAME); soa->dnssoa_hostmaster = s; dns_getdn(pkt, &cur, end, buf, sizeof(buf)); s += dns_dntop(buf, s, DNS_MAXNAME); soa->dnssoa_serial = dns_get32(cur + 0*4); soa->dnssoa_refresh = dns_get32(cur + 1*4); soa->dnssoa_retry = dns_get32(cur + 2*4); soa->dnssoa_expire = dns_get32(cur + 3*4); soa->dnssoa_minttl = dns_get32(cur + 4*4); dns_stdrr_finish((struct dns_rr_null *)soa, s, &p); *result = soa; return 0; failed: free(soa); return DNS_E_PROTOCOL; } static struct dns_query * submit_soa(struct dns_ctx *ctx, const char *name, int flags, query_soa_fn *cb, void *data) { return dns_submit_p(ctx, name, DNS_C_IN, DNS_T_SOA, flags, parse_soa, (dns_query_fn *)cb, data); } /* * actual "get serial" part */ static void udns_result_soa(struct dns_ctx *uctx, struct SOA *soa, void *data) { struct DNSContext *ctx = data; if (!soa) { log_noise("SOA query failed"); got_zone_serial(ctx, NULL); return; } log_noise("SOA1: cname=%s qname=%s ttl=%u nrr=%u", soa->dnssoa_cname, soa->dnssoa_qname, soa->dnssoa_ttl, soa->dnssoa_nrr); log_noise("SOA2: nsname=%s hostmaster=%s serial=%u refresh=%u retry=%u expire=%u minttl=%u", soa->dnssoa_nsname, soa->dnssoa_hostmaster, soa->dnssoa_serial, soa->dnssoa_refresh, soa->dnssoa_retry, soa->dnssoa_expire, soa->dnssoa_minttl); got_zone_serial(ctx, &soa->dnssoa_serial); free(soa); } static int impl_query_soa_serial(struct DNSContext *ctx, const char *zonename) { struct UdnsMeta *udns = ctx->edns; struct dns_query *q; int flags = 0; log_debug("udns: impl_query_soa_serial: name=%s", zonename); q = submit_soa(udns->ctx, zonename, flags, udns_result_soa, ctx); if (!q) { log_error("impl_query_soa_serial failed: %s", zonename); } return 0; } #endif /* USE_UDNS */ /* * Generic framework */ static void deliver_info(struct DNSRequest *req) { struct DNSContext *ctx = req->ctx; struct DNSToken *ucb; struct List *el; const struct addrinfo *ai = req->current; char sabuf[128]; ctx->active--; loop: /* get next req */ el = list_pop(&req->ucb_list); if (!el) return; ucb = container_of(el, struct DNSToken, node); /* launch callback */ log_noise("dns: deliver_info(%s) addr=%s", req->name, ai ? sa2str(ai->ai_addr, sabuf, sizeof(sabuf)) : "NULL"); ucb->cb_func(ucb->cb_arg, ai ? ai->ai_addr : NULL, ai ? ai->ai_addrlen : 0); free(ucb); /* scroll req list */ if (ai) { req->current = ai->ai_next; if (!req->current) req->current = req->result; } goto loop; } static int req_cmp(uintptr_t arg, struct AANode *node) { const char *s1 = (char *)arg; struct DNSRequest *req = container_of(node, struct DNSRequest, node); return strcmp(s1, req->name); } static void req_reset(struct DNSRequest *req) { req->done = false; if (req->result) { if (req->oldres) freeaddrinfo(req->oldres); req->oldres = req->result; } req->result = req->current = NULL; } static void req_free(struct AANode *node, void *arg) { struct DNSToken *ucb; struct DNSRequest *req; struct List *el; req = container_of(node, struct DNSRequest, node); while ((el = list_pop(&req->ucb_list)) != NULL) { ucb = container_of(el, struct DNSToken, node); free(ucb); } req_reset(req); if (req->oldres) { freeaddrinfo(req->oldres); req->oldres = NULL; } if (req->zone) statlist_remove(&req->zone->host_list, &req->znode); free(req->name); free(req); } struct DNSContext *adns_create_context(void) { struct DNSContext *ctx; log_debug("adns_create_context: %s", adns_get_backend()); ctx = calloc(1, sizeof(*ctx)); if (!ctx) return NULL; aatree_init(&ctx->req_tree, req_cmp, req_free); zone_init(ctx); if (!impl_init(ctx)) { adns_free_context(ctx); return NULL; } return ctx; } void adns_free_context(struct DNSContext *ctx) { if (ctx) { impl_release(ctx); aatree_destroy(&ctx->req_tree); zone_free(ctx); free(ctx); } } struct DNSToken *adns_resolve(struct DNSContext *ctx, const char *name, adns_callback_f cb_func, void *cb_arg) { int namelen = strlen(name); struct DNSRequest *req; struct DNSToken *ucb; struct AANode *node; /* setup actual lookup */ node = aatree_search(&ctx->req_tree, (uintptr_t)name); if (node) { req = container_of(node, struct DNSRequest, node); } else { log_noise("dns: new req: %s", name); req = calloc(1, sizeof(*req)); if (!req) goto nomem; req->name = strdup(name); if (!req->name) { free(req); goto nomem; } req->ctx = ctx; req->namelen = namelen; list_init(&req->ucb_list); list_init(&req->znode); aatree_insert(&ctx->req_tree, (uintptr_t)req->name, &req->node); zone_register(ctx, req); ctx->active++; impl_launch_query(req); } /* remember user callback */ ucb = calloc(1, sizeof(*ucb)); if (!ucb) goto nomem; list_init(&ucb->node); ucb->cb_func = cb_func; ucb->cb_arg = cb_arg; list_append(&req->ucb_list, &ucb->node); /* if already have final result, report it */ if (req->done) { if (req->res_ttl < get_cached_time()) { log_noise("dns: ttl over: %s", req->name); req_reset(req); ctx->active++; impl_launch_query(req); } else { deliver_info(req); } } /* if ->done, then we have already reported */ return req->done ? NULL : ucb; nomem: log_warning("dns(%s): req failed, no mem", name); cb_func(cb_arg, NULL, 0); return NULL; } static int cmp_addrinfo(const struct addrinfo *a1, const struct addrinfo *a2) { if (a1->ai_family != a2->ai_family) return a1->ai_family - a2->ai_family; if (a1->ai_addrlen != a2->ai_addrlen) return a1->ai_addrlen - a2->ai_addrlen; return memcmp(a1->ai_addr, a2->ai_addr, a1->ai_addrlen); } /* check if new dns reply is missing some IP compared to old one */ static void check_req_result_changes(struct DNSRequest *req) { struct addrinfo *ai, *aj; for (ai = req->oldres; ai; ai = ai->ai_next) { bool found = false; for (aj = req->result; aj; aj = aj->ai_next) { if (cmp_addrinfo(ai, aj) == 0) { found = true; break; } } /* missing IP (possible DNS failover) make connections to it dirty */ if (!found) tag_host_addr_dirty(req->name, ai->ai_addr); } } /* struct addrinfo -> deliver_info() */ static void got_result_gai(int result, struct addrinfo *res, void *arg) { struct DNSRequest *req = arg; req_reset(req); if (result == 0 && res) { req->result = res; req->current = res; if (req->oldres) check_req_result_changes(req); /* show all results */ if (cf_verbose > 1) { const struct addrinfo *ai = res; int n = 0; char buf[128]; while (ai) { log_noise("DNS: %s[%d] = %s [%s]", req->name, n++, sa2str(ai->ai_addr, buf, sizeof(buf)), ai->ai_socktype == SOCK_STREAM ? "STREAM" : "OTHER"); ai = ai->ai_next; } } } else { /* lookup failed */ log_warning("lookup failed: %s: result=%d", req->name, result); } req->done = true; req->res_ttl = get_cached_time() + cf_dns_max_ttl; deliver_info(req); } void adns_cancel(struct DNSContext *ctx, struct DNSToken *tk) { list_del(&tk->node); memset(tk, 0, sizeof(*tk)); free(tk); } void adns_info(struct DNSContext *ctx, int *names, int *zones, int *queries, int *pending) { *names = ctx->req_tree.count; *zones = ctx->zone_tree.count; *queries = ctx->active; *pending = 0; } /* * zone code */ static void zone_item_free(struct AANode *n, void *arg) { struct DNSZone *z = container_of(n, struct DNSZone, tnode); list_del(&z->lnode); free(z->zonename); free(z); } static int zone_item_cmp(uintptr_t val1, struct AANode *n2) { const char *name1 = (const char *)val1; struct DNSZone *z2 = container_of(n2, struct DNSZone, tnode); return strcasecmp(name1, z2->zonename); } static void zone_init(struct DNSContext *ctx) { aatree_init(&ctx->zone_tree, zone_item_cmp, zone_item_free); list_init(&ctx->zone_list); } static void zone_free(struct DNSContext *ctx) { aatree_destroy(&ctx->zone_tree); } static void zone_register(struct DNSContext *ctx, struct DNSRequest *req) { struct DNSZone *z; struct AANode *n; const char *name; log_debug("zone_register(%s)", req->name); name = strchr(req->name, '.'); if (!name || name[1] == 0) return; name++; log_debug("zone_register(%s): name=%s", req->name, name); n = aatree_search(&ctx->zone_tree, (uintptr_t)name); if (n) { /* already exists */ z = container_of(n, struct DNSZone, tnode); req->zone = z; statlist_append(&z->host_list, &req->znode); return; } /* create struct */ z = calloc(1, sizeof(*z)); if (!z) return; z->zonename = strdup(name); if (!z->zonename) { free(z); return; } statlist_init(&z->host_list, "host_list"); list_init(&z->lnode); /* link */ aatree_insert(&ctx->zone_tree, (uintptr_t)z->zonename, &z->tnode); list_append(&ctx->zone_list, &z->lnode); statlist_append(&z->host_list, &req->znode); req->zone = z; } static void zone_timer(int fd, short flg, void *arg) { struct DNSContext *ctx = arg; struct List *el; struct DNSZone *z; if (list_empty(&ctx->zone_list)) { ctx->zone_state = 0; return; } el = list_first(&ctx->zone_list); z = container_of(el, struct DNSZone, lnode); ctx->zone_state = 1; ctx->cur_zone = z; ctx->active++; impl_query_soa_serial(ctx, z->zonename); } static void launch_zone_timer(struct DNSContext *ctx) { struct timeval tv; tv.tv_sec = cf_dns_zone_check_period / USEC; tv.tv_usec = cf_dns_zone_check_period % USEC; evtimer_set(&ctx->ev_zone_timer, zone_timer, ctx); safe_evtimer_add(&ctx->ev_zone_timer, &tv); ctx->zone_state = 2; } void adns_zone_cache_maint(struct DNSContext *ctx) { if (!cf_dns_zone_check_period) { if (ctx->zone_state == 2) { event_del(&ctx->ev_zone_timer); ctx->zone_state = 0; } ctx->cur_zone = NULL; return; } else if (ctx->zone_state == 0) { if (list_empty(&ctx->zone_list)) return; launch_zone_timer(ctx); } } static void zone_requeue(struct DNSContext *ctx, struct DNSZone *z) { struct List *el; struct DNSRequest *req; statlist_for_each(el, &z->host_list) { req = container_of(el, struct DNSRequest, znode); if (!req->done) continue; req->res_ttl = 0; ctx->active++; impl_launch_query(req); } } static void got_zone_serial(struct DNSContext *ctx, uint32_t *serial) { struct DNSZone *z = ctx->cur_zone; struct List *el; ctx->active--; if (!ctx->zone_state || !z) return; if (serial) { /* wraparound compare */ int32_t s1 = z->serial; int32_t s2 = *serial; int32_t ds = s2 - s1; if (ds > 0) { log_info("zone '%s' serial changed: old=%u new=%u", z->zonename, z->serial, *serial); z->serial = *serial; zone_requeue(ctx, z); } else { log_debug("zone '%s' unchanged: serial=%u", z->zonename, *serial); } } else { log_debug("failure to get zone '%s' serial", z->zonename); } el = z->lnode.next; if (el != &ctx->zone_list) { z = container_of(el, struct DNSZone, lnode); ctx->cur_zone = z; ctx->active++; impl_query_soa_serial(ctx, z->zonename); } else { launch_zone_timer(ctx); } } /* * Cache walkers */ struct WalkInfo { adns_walk_name_f name_cb; adns_walk_zone_f zone_cb; void *arg; }; static void walk_name(struct AANode *n, void *arg) { struct WalkInfo *w = arg; struct DNSRequest *req = container_of(n, struct DNSRequest, node); w->name_cb(w->arg, req->name, req->result, req->res_ttl); } static void walk_zone(struct AANode *n, void *arg) { struct WalkInfo *w = arg; struct DNSZone *z = container_of(n, struct DNSZone, tnode); w->zone_cb(w->arg, z->zonename, z->serial, statlist_count(&z->host_list)); } void adns_walk_names(struct DNSContext *ctx, adns_walk_name_f cb, void *arg) { struct WalkInfo w; w.name_cb = cb; w.arg = arg; aatree_walk(&ctx->req_tree, AA_WALK_IN_ORDER, walk_name, &w); } void adns_walk_zones(struct DNSContext *ctx, adns_walk_zone_f cb, void *arg) { struct WalkInfo w; w.zone_cb = cb; w.arg = arg; aatree_walk(&ctx->zone_tree, AA_WALK_IN_ORDER, walk_zone, &w); } pgbouncer-1.5.4/config.sub0000755000175000017500000010344512055406554012426 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 # Free Software Foundation, Inc. timestamp='2010-01-22' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | ubicom32 \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile-* | tilegx-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; # This must be matched before tile*. tilegx*) basic_machine=tilegx-unknown os=-linux-gnu ;; tile*) basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: pgbouncer-1.5.4/AUTHORS0000644000175000017500000000103311765176015011504 00000000000000 Maintainer ---------- Marko Kreen Contributors ------------ Alexander Schöcke Bjoern Metzdorf Dan McGee David Fetter David Galoyan David Sommerseth Devrim GÜNDÜZ Dimitri Fontaine Dominique Hermsdorff Emmanuel Courreges Filip Rembiałkowski Giorgio Valoti Guillaume Lelarge Greg Sabino Mullane Hannu Krosing Hiroshi Saito Hubert Depesz Lubaczewski Jacob Coby James Pye Jørgen Austvik Lou Picciano Magne Mæhre Martin Pihlak Michael Tharp Peter Eisentraut Petr Jelinek Pierre-Emmanuel André Rich Schaaf Robert Gogolok Teodor Sigaev pgbouncer-1.5.4/autogen.sh0000755000175000017500000000005411765176015012437 00000000000000#! /bin/sh ./lib/mk/std-autogen.sh ./lib pgbouncer-1.5.4/configure0000755000175000017500000072246612055406561012362 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.67 for pgbouncer 1.5.4. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='pgbouncer' PACKAGE_TARNAME='pgbouncer' PACKAGE_VERSION='1.5.4' PACKAGE_STRING='pgbouncer 1.5.4' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="src/janitor.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS enable_debug PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC acx_pthread_config host_os host_vendor host_cpu host build_os build_vendor build_cpu build have_libevent DLLTOOL DLLWRAP WINDRES XMLTO ASCIIDOC ARFLAGS AR RANLIB STRIP SED MKDIR_P AWK EGREP GREP LN_S INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM WFLAGS HAVE_CC_DEPFLAG CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC pkgconfigdir pkgdatadir PORTNAME target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_largefile with_libevent with_udns enable_evdns enable_debug enable_cassert enable_werror ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures pgbouncer 1.5.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/pgbouncer] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of pgbouncer 1.5.4:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-largefile omit support for large files --enable-evdns Use libevent for DNS lookups (default on libevent 2.x) --disable-debug strip binary --enable-cassert turn on assert checking in code --enable-werror add -Werror to CFLAGS Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-libevent=prefix Specify where libevent is installed --with-udns=prefix Specify where udns is installed Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF pgbouncer configure 1.5.4 generated by GNU Autoconf 2.67 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_type # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_find_uintX_t # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_decl cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by pgbouncer $as_me 1.5.4, which was generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5 ; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers lib/usual/config.h" # if building separately from srcdir, write top-level makefile if test "$srcdir" != "."; then echo "include $srcdir/Makefile" > Makefile fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking target host type" >&5 $as_echo_n "checking target host type... " >&6; } xhost="$host_alias" if test "x$xhost" = "x"; then xhost=`uname -s` fi case "$xhost" in *cygwin* | *mingw* | *pw32* | *MINGW*) LIBS="$LIBS -lws2_32" PORTNAME=win32;; *) PORTNAME=unix ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PORTNAME" >&5 $as_echo "$PORTNAME" >&6; } if test "$PORTNAME" = "win32"; then $as_echo "#define WIN32_LEAN_AND_MEAN 1" >>confdefs.h $as_echo "#define WINVER 0x0501" >>confdefs.h else $as_echo "#define _GNU_SOURCE 1" >>confdefs.h fi pkgdatadir='${datarootdir}'/${PACKAGE_TARNAME} pkgconfigdir='${libdir}/pkgconfig' ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5 ; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5 ; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5 ; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test "${ac_cv_path_mkdir+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } case $ac_cv_prog_cc_stdc in #( no) : ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #( *) : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 $as_echo_n "checking for $CC option to accept ISO C99... " >&6; } if test "${ac_cv_prog_cc_c99+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK your preprocessor is broken; #endif #if BIG_OK #else your preprocessor is broken; #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\0'; ++i) continue; return 0; } // Check varargs and va_copy. static void test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str; int number; float fnumber; while (*format) { switch (*format++) { case 's': // string str = va_arg (args_copy, const char *); break; case 'd': // int number = va_arg (args_copy, int); break; case 'f': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); } int main () { // Check bool. _Bool success = false; // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. test_varargs ("s, d' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ; return 0; } _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c99" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c99" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 $as_echo "$ac_cv_prog_cc_c99" >&6; } ;; esac if test "x$ac_cv_prog_cc_c99" != xno; then : ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 else ac_cv_prog_cc_stdc=no fi fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO Standard C" >&5 $as_echo_n "checking for $CC option to accept ISO Standard C... " >&6; } if test "${ac_cv_prog_cc_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 fi case $ac_cv_prog_cc_stdc in #( no) : { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; #( '') : { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; #( *) : { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_stdc" >&5 $as_echo "$ac_cv_prog_cc_stdc" >&6; } ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5 ; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports __func__" >&5 $as_echo_n "checking whether compiler supports __func__... " >&6; } if test "${pgac_cv_funcname_func+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { printf("%s\n", __func__); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : pgac_cv_funcname_func=yes else pgac_cv_funcname_func=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_funcname_func" >&5 $as_echo "$pgac_cv_funcname_func" >&6; } if test x"$pgac_cv_funcname_func" = xyes ; then $as_echo "#define HAVE_FUNCNAME__FUNC 1" >>confdefs.h fi if test "$GCC" = "yes"; then old_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,--as-needed" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether linker supports --as-needed" >&5 $as_echo_n "checking whether linker supports --as-needed... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } LDFLAGS="$old_LDFLAGS" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports dependency generation" >&5 $as_echo_n "checking whether compiler supports dependency generation... " >&6; } old_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -MD -MP -MT conftest.o -MF conftest.o.d" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ void foo(void){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : HAVE_CC_DEPFLAG=yes else HAVE_CC_DEPFLAG=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext rm -f conftest.d CFLAGS="$old_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_CC_DEPFLAG" >&5 $as_echo "$HAVE_CC_DEPFLAG" >&6; } WFLAGS="" if test x"$GCC" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working warning switches" >&5 $as_echo_n "checking for working warning switches... " >&6; } good_CFLAGS="$CFLAGS" flags="-Wall -Wextra" # turn off noise from Wextra flags="$flags -Wno-unused-parameter -Wno-missing-field-initializers" # Wextra does not turn those on? flags="$flags -Wmissing-prototypes -Wpointer-arith -Wendif-labels" flags="$flags -Wdeclaration-after-statement -Wold-style-definition" flags="$flags -Wstrict-prototypes -Wundef -Wformat=2" flags="$flags -Wuninitialized" for f in $flags; do CFLAGS="$good_CFLAGS $WFLAGS $f" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ void foo(void){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : WFLAGS="$WFLAGS $f" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done # avoid -Wextra if missing-field.initializers does not work echo "$WFLAGS" | grep missing-field-initializers > /dev/null \ || WFLAGS=`echo "$WFLAGS"|sed 's/ -Wextra//'` CFLAGS="$good_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AWK+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if test "${ac_cv_path_SED+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB="true" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi ARFLAGS=rcu for ac_prog in asciidoc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ASCIIDOC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ASCIIDOC"; then ac_cv_prog_ASCIIDOC="$ASCIIDOC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ASCIIDOC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ASCIIDOC=$ac_cv_prog_ASCIIDOC if test -n "$ASCIIDOC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ASCIIDOC" >&5 $as_echo "$ASCIIDOC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ASCIIDOC" && break done if test -n "$ASCIIDOC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for asciidoc version >= 8.4" >&5 $as_echo_n "checking for asciidoc version >= 8.4... " >&6; } ver=`$ASCIIDOC --version 2>&1 | sed -e 's/asciidoc //'` case "$ver" in [0-7].*|8.[0-3]|8.[0-3].*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ver, too old" >&5 $as_echo "$ver, too old" >&6; } ASCIIDOC="" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ver, ok" >&5 $as_echo "$ver, ok" >&6; } ;; esac fi if test -n "$ASCIIDOC"; then for ac_prog in xmlto do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_XMLTO+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$XMLTO"; then ac_cv_prog_XMLTO="$XMLTO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_XMLTO="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi XMLTO=$ac_cv_prog_XMLTO if test -n "$XMLTO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 $as_echo "$XMLTO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$XMLTO" && break done fi if test "$PORTNAME" = "win32"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. set dummy ${ac_tool_prefix}windres; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_WINDRES+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$WINDRES"; then ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_WINDRES="${ac_tool_prefix}windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi WINDRES=$ac_cv_prog_WINDRES if test -n "$WINDRES"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WINDRES" >&5 $as_echo "$WINDRES" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_WINDRES"; then ac_ct_WINDRES=$WINDRES # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_WINDRES+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_WINDRES"; then ac_cv_prog_ac_ct_WINDRES="$ac_ct_WINDRES" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_WINDRES="windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_WINDRES=$ac_cv_prog_ac_ct_WINDRES if test -n "$ac_ct_WINDRES"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_WINDRES" >&5 $as_echo "$ac_ct_WINDRES" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_WINDRES" = x; then WINDRES="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac WINDRES=$ac_ct_WINDRES fi else WINDRES="$ac_cv_prog_WINDRES" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dllwrap", so it can be a program name with args. set dummy ${ac_tool_prefix}dllwrap; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_DLLWRAP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLWRAP"; then ac_cv_prog_DLLWRAP="$DLLWRAP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DLLWRAP="${ac_tool_prefix}dllwrap" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLWRAP=$ac_cv_prog_DLLWRAP if test -n "$DLLWRAP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLWRAP" >&5 $as_echo "$DLLWRAP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLWRAP"; then ac_ct_DLLWRAP=$DLLWRAP # Extract the first word of "dllwrap", so it can be a program name with args. set dummy dllwrap; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_DLLWRAP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLWRAP"; then ac_cv_prog_ac_ct_DLLWRAP="$ac_ct_DLLWRAP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DLLWRAP="dllwrap" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLWRAP=$ac_cv_prog_ac_ct_DLLWRAP if test -n "$ac_ct_DLLWRAP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLWRAP" >&5 $as_echo "$ac_ct_DLLWRAP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLWRAP" = x; then DLLWRAP="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLWRAP=$ac_ct_DLLWRAP fi else DLLWRAP="$ac_cv_prog_DLLWRAP" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_DLLTOOL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_DLLTOOL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/socket.h poll.h sys/poll.h sys/un.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in arpa/inet.h netinet/in.h netinet/tcp.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/param.h sys/uio.h pwd.h grp.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/wait.h sys/mman.h syslog.h netdb.h dlfcn.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in err.h pthread.h endian.h sys/endian.h byteswap.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in malloc.h regex.h getopt.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in ucred.h sys/ucred.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" " #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether works on char values" >&5 $as_echo_n "checking whether works on char values... " >&6; } _good_ctype=no if test "$cross_compiling" = yes; then : _good_ctype=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #define W(c) ((signed char)(c)) int main(void) { int c; /* if char is unsigned, all is ok */ if ((int)(char)255 == (int)255) return 0; for (c = 128; c < 256; c++) { if (isalpha(c) != isalpha(W(c))) return 1; if (isalnum(c) != isalnum(W(c))) return 1; if (isascii(c) != isascii(W(c))) return 1; if (isblank(c) != isblank(W(c))) return 1; if (iscntrl(c) != iscntrl(W(c))) return 1; if (isdigit(c) != isdigit(W(c))) return 1; if (islower(c) != islower(W(c))) return 1; if (isprint(c) != isprint(W(c))) return 1; if (ispunct(c) != ispunct(W(c))) return 1; if (isspace(c) != isspace(W(c))) return 1; if (isupper(c) != isupper(W(c))) return 1; if (isxdigit(c) != isxdigit(W(c))) return 1; } return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : _good_ctype=yes else _good_ctype=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_good_ctype" >&5 $as_echo "$_good_ctype" >&6; } if test $_good_ctype = yes; then $as_echo "#define HAVE_CTYPE_ON_CHAR 1" >>confdefs.h fi for ac_header in crypt.h do : ac_fn_c_check_header_mongrel "$LINENO" "crypt.h" "ac_cv_header_crypt_h" "$ac_includes_default" if test "x$ac_cv_header_crypt_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_CRYPT_H 1 _ACEOF fi done for ac_header in sys/resource.h sys/wait.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if test "${ac_cv_c_inline+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 $as_echo_n "checking for C/C++ restrict keyword... " >&6; } if test "${ac_cv_c_restrict+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_restrict=no # The order here caters to the fact that C++ does not require restrict. for ac_kw in __restrict __restrict__ _Restrict restrict; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ typedef int * int_ptr; int foo (int_ptr $ac_kw ip) { return ip[0]; } int main () { int s[1]; int * $ac_kw t = s; t[0] = 0; return foo(t) ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_restrict=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_restrict" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 $as_echo "$ac_cv_c_restrict" >&6; } case $ac_cv_c_restrict in restrict) ;; no) $as_echo "#define restrict /**/" >>confdefs.h ;; *) cat >>confdefs.h <<_ACEOF #define restrict $ac_cv_c_restrict _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if test "${ac_cv_c_bigendian+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if test "${ac_cv_sys_largefile_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if test "${ac_cv_sys_file_offset_bits+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if test "${ac_cv_sys_large_files+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if test "${ac_cv_type_uid_t+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then : ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then $as_echo "#define uid_t int" >>confdefs.h $as_echo "#define gid_t int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) $as_echo "#define _UINT8_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint8_t $ac_cv_c_uint8_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) $as_echo "#define _UINT32_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint32_t $ac_cv_c_uint32_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) $as_echo "#define _UINT64_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint64_t $ac_cv_c_uint64_t _ACEOF ;; esac ### Functions provided if missing for ac_func in strlcpy strlcat getpeereid sigaction sigqueue do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in inet_ntop inet_pton poll getline memrchr regcomp do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in err errx warn warnx getprogname setprogname do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in posix_memalign memalign valloc do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in getopt getopt_long getopt_long_only do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in fls flsl flsll ffs ffsl ffsll do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ### Functions provided only on win32 for ac_func in localtime_r gettimeofday recvmsg sendmsg usleep getrusage do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ### Functions used by libusual itself for ac_func in syslog mmap getpeerucred do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ### win32: link with ws2_32 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing WSAGetLastError" >&5 $as_echo_n "checking for library containing WSAGetLastError... " >&6; } if test "${ac_cv_search_WSAGetLastError+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char WSAGetLastError (); int main () { return WSAGetLastError (); ; return 0; } _ACEOF for ac_lib in '' ws2_32; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_WSAGetLastError=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_WSAGetLastError+set}" = set; then : break fi done if test "${ac_cv_search_WSAGetLastError+set}" = set; then : else ac_cv_search_WSAGetLastError=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_WSAGetLastError" >&5 $as_echo "$ac_cv_search_WSAGetLastError" >&6; } ac_res=$ac_cv_search_WSAGetLastError if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi ac_fn_c_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" if test "x$ac_cv_have_decl_strerror_r" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_STRERROR_R $ac_have_decl _ACEOF for ac_func in strerror_r do : ac_fn_c_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r" if test "x$ac_cv_func_strerror_r" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRERROR_R 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5 $as_echo_n "checking whether strerror_r returns char *... " >&6; } if test "${ac_cv_func_strerror_r_char_p+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_func_strerror_r_char_p=no if test $ac_cv_have_decl_strerror_r = yes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { char buf[100]; char x = *strerror_r (0, buf, sizeof buf); char *p = strerror_r (0, buf, sizeof buf); return !p || x; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_func_strerror_r_char_p=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else # strerror_r is not declared. Choose between # systems that have relatively inaccessible declarations for the # function. BeOS and DEC UNIX 4.0 fall in this category, but the # former has a strerror_r that returns char*, while the latter # has a strerror_r that returns `int'. # This test should segfault on the DEC system. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default extern char *strerror_r (); int main () { char buf[100]; char x = *strerror_r (0, buf, sizeof buf); return ! isalpha (x); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_strerror_r_char_p=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5 $as_echo "$ac_cv_func_strerror_r_char_p" >&6; } if test $ac_cv_func_strerror_r_char_p = yes; then $as_echo "#define STRERROR_R_CHAR_P 1" >>confdefs.h fi ### { $as_echo "$as_me:${as_lineno-$LINENO}: checking for integer enc/dec functions" >&5 $as_echo_n "checking for integer enc/dec functions... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef HAVE_SYS_ENDIAN_H #include #endif #ifdef HAVE_ENDIAN_H #include #endif char p[] = "01234567"; int main(void) { be16enc(p, 0); be32enc(p, 1); be64enc(p, 2); le16enc(p, 2); le32enc(p, 3); le64enc(p, 4); return (int)(be16dec(p) + be32dec(p) + be64dec(p)) + (int)(le16dec(p) + le32dec(p) + le64dec(p)); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } $as_echo "#define HAVE_ENCDEC_FUNCS 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crypt" >&5 $as_echo_n "checking for library containing crypt... " >&6; } if test "${ac_cv_search_crypt+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char crypt (); int main () { return crypt (); ; return 0; } _ACEOF for ac_lib in '' crypt; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_crypt=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_crypt+set}" = set; then : break fi done if test "${ac_cv_search_crypt+set}" = set; then : else ac_cv_search_crypt=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt" >&5 $as_echo "$ac_cv_search_crypt" >&6; } ac_res=$ac_cv_search_crypt if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 $as_echo_n "checking for library containing clock_gettime... " >&6; } if test "${ac_cv_search_clock_gettime+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_clock_gettime+set}" = set; then : break fi done if test "${ac_cv_search_clock_gettime+set}" = set; then : else ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 $as_echo "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getsockname" >&5 $as_echo_n "checking for library containing getsockname... " >&6; } if test "${ac_cv_search_getsockname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getsockname (); int main () { return getsockname (); ; return 0; } _ACEOF for ac_lib in '' socket; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_getsockname=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_getsockname+set}" = set; then : break fi done if test "${ac_cv_search_getsockname+set}" = set; then : else ac_cv_search_getsockname=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getsockname" >&5 $as_echo "$ac_cv_search_getsockname" >&6; } ac_res=$ac_cv_search_getsockname if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5 $as_echo_n "checking for library containing gethostbyname... " >&6; } if test "${ac_cv_search_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_gethostbyname=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_gethostbyname+set}" = set; then : break fi done if test "${ac_cv_search_gethostbyname+set}" = set; then : else ac_cv_search_gethostbyname=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5 $as_echo "$ac_cv_search_gethostbyname" >&6; } ac_res=$ac_cv_search_gethostbyname if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing hstrerror" >&5 $as_echo_n "checking for library containing hstrerror... " >&6; } if test "${ac_cv_search_hstrerror+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char hstrerror (); int main () { return hstrerror (); ; return 0; } _ACEOF for ac_lib in '' resolv; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_hstrerror=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_hstrerror+set}" = set; then : break fi done if test "${ac_cv_search_hstrerror+set}" = set; then : else ac_cv_search_hstrerror=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_hstrerror" >&5 $as_echo "$ac_cv_search_hstrerror" >&6; } ac_res=$ac_cv_search_hstrerror if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi for ac_func in crypt lstat do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done levent=yes { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libevent" >&5 $as_echo_n "checking for libevent... " >&6; } # Check whether --with-libevent was given. if test "${with_libevent+set}" = set; then : withval=$with_libevent; if test "$withval" = "no"; then levent=no elif test "$withval" = "yes"; then levent=yes else levent=yes CPPFLAGS="$CPPFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib" fi fi if test "$levent" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using usual/event" >&5 $as_echo "using usual/event" >&6; } $as_echo "#define HAVE_EVENT_LOOPBREAK 1" >>confdefs.h $as_echo "#define HAVE_EVENT_BASE_NEW 1" >>confdefs.h have_libevent=no else # libevent $as_echo "#define HAVE_LIBEVENT 1" >>confdefs.h LIBS="-levent $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main(void) { struct event ev; event_init(); event_set(&ev, 1, EV_READ, NULL, NULL); /* this checks for 1.2+ but next we check for 1.3b+ anyway */ /* event_base_free(NULL); */ } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } else as_fn_error $? "not found, cannot proceed" "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libevent version >= 1.3b" >&5 $as_echo_n "checking whether libevent version >= 1.3b... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include HTTP_SERVUNAVAIL _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "HTTP_SERVUNAVAIL" >/dev/null 2>&1; then : as_fn_error $? "no, cannot proceed" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi rm -f conftest* for ac_func in event_loopbreak event_base_new evdns_base_new do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done have_libevent=yes fi # libevent use_udns=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use libudns" >&5 $as_echo_n "checking whether to use libudns... " >&6; } # Check whether --with-udns was given. if test "${with_udns+set}" = set; then : withval=$with_udns; if test "$withval" = "no"; then use_udns=no elif test "$withval" = "yes"; then use_udns=yes else use_udns=yes CPPFLAGS="$CPPFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_udns" >&5 $as_echo "$use_udns" >&6; } if test "$use_udns" = "yes"; then $as_echo "#define USE_UDNS 1" >>confdefs.h LIBS="-ludns $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libudns is available" >&5 $as_echo_n "checking whether libudns is available... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main(void) { struct dns_ctx *ctx = NULL; dns_init(ctx, 0); dns_reset(ctx); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } else as_fn_error $? "not found, cannot proceed" "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext else # !udns use_evdns=no if test "$ac_cv_func_evdns_base_new" = "yes"; then use_evdns=yes fi # Check whether --enable-evdns was given. if test "${enable_evdns+set}" = set; then : enableval=$enable_evdns; use_evdns=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use libevent for DNS lookups" >&5 $as_echo_n "checking whether to use libevent for DNS lookups... " >&6; } if test "$use_evdns" = "yes"; then $as_echo "#define USE_EVDNS 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$use_evdns" = no; then # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if test "${ac_cv_build+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if test "${ac_cv_host+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getaddrinfo_a" >&5 $as_echo_n "checking for library containing getaddrinfo_a... " >&6; } if test "${ac_cv_search_getaddrinfo_a+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getaddrinfo_a (); int main () { return getaddrinfo_a (); ; return 0; } _ACEOF for ac_lib in '' anl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_getaddrinfo_a=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_getaddrinfo_a+set}" = set; then : break fi done if test "${ac_cv_search_getaddrinfo_a+set}" = set; then : else ac_cv_search_getaddrinfo_a=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getaddrinfo_a" >&5 $as_echo "$ac_cv_search_getaddrinfo_a" >&6; } ac_res=$ac_cv_search_getaddrinfo_a if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use native getaddinfo_a" >&5 $as_echo_n "checking whether to use native getaddinfo_a... " >&6; } if test "${ac_cv_usual_glibc_gaia+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef HAVE_NETDB_H #include #endif int main () { #if __GLIBC_PREREQ(2,9) getaddrinfo_a(0,NULL,0,NULL); #else none or broken #endif ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_usual_glibc_gaia=yes else ac_cv_usual_glibc_gaia=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_usual_glibc_gaia" >&5 $as_echo "$ac_cv_usual_glibc_gaia" >&6; } if test x"$ac_cv_usual_glibc_gaia" = xyes ; then $as_echo "#define HAVE_GETADDRINFO_A 1" >>confdefs.h else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 $as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_join (); int main () { return pthread_join (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : acx_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 $as_echo "$acx_pthread_ok" >&6; } if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 $as_echo_n "checking whether pthreads work without any flags... " >&6; } ;; -*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 $as_echo_n "checking whether pthreads work with $flag... " >&6; } PTHREAD_CFLAGS="$flag" ;; pthread-config) # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_acx_pthread_config+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$acx_pthread_config"; then ac_cv_prog_acx_pthread_config="$acx_pthread_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_acx_pthread_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_acx_pthread_config" && ac_cv_prog_acx_pthread_config="no" fi fi acx_pthread_config=$ac_cv_prog_acx_pthread_config if test -n "$acx_pthread_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_config" >&5 $as_echo "$acx_pthread_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 $as_echo_n "checking for the pthreads library -l$flag... " >&6; } PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <pthread.h> int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : acx_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 $as_echo "$acx_pthread_ok" >&6; } if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 $as_echo_n "checking for joinable pthread attribute... " >&6; } attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <pthread.h> int main () { int attr=$attr; return attr; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : attr_name=$attr; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 $as_echo "$attr_name" >&6; } if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then cat >>confdefs.h <<_ACEOF #define PTHREAD_CREATE_JOINABLE $attr_name _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 $as_echo_n "checking if more special flags are required for pthreads... " >&6; } flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 $as_echo "${flag}" >&6; } if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then for ac_prog in xlc_r cc_r do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_PTHREAD_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$PTHREAD_CC"; then ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_PTHREAD_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi PTHREAD_CC=$ac_cv_prog_PTHREAD_CC if test -n "$PTHREAD_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 $as_echo "$PTHREAD_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$PTHREAD_CC" && break done test -n "$PTHREAD_CC" || PTHREAD_CC="${CC}" else PTHREAD_CC=$CC fi else PTHREAD_CC="$CC" fi # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then $as_echo "#define HAVE_PTHREAD 1" >>confdefs.h : else acx_pthread_ok=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: Threads not available and fallback getaddrinfo_a() non-functional." >&5 $as_echo "Threads not available and fallback getaddrinfo_a() non-functional." >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$PTHREAD_CC" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$LIBS $PTHREAD_LIBS" fi fi fi # !udns # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; else enable_debug=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build debug binary" >&5 $as_echo_n "checking whether to build debug binary... " >&6; } if test "$enable_debug" = "yes"; then LDFLAGS="-g $LDFLAGS" BININSTALL="$INSTALL" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else BININSTALL="$INSTALL -s" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Check whether --enable-cassert was given. if test "${enable_cassert+set}" = set; then : enableval=$enable_cassert; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable asserts" >&5 $as_echo_n "checking whether to enable asserts... " >&6; } if test "$enable_cassert" = "yes"; then $as_echo "#define CASSERT 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Check whether --enable-werror was given. if test "${enable_werror+set}" = set; then : enableval=$enable_werror; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to fail on warnings" >&5 $as_echo_n "checking whether to fail on warnings... " >&6; } if test "$enable_werror" = "yes"; then CFLAGS="$CFLAGS -Werror" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ac_config_files="$ac_config_files config.mak" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by pgbouncer $as_me 1.5.4, which was generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ pgbouncer config.status 1.5.4 configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "lib/usual/config.h") CONFIG_HEADERS="$CONFIG_HEADERS lib/usual/config.h" ;; "config.mak") CONFIG_FILES="$CONFIG_FILES config.mak" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_t=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_t"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi test -f Makefile || { echo "Linking Makefile" ln -s $srcdir/Makefile } pgbouncer-1.5.4/NEWS0000644000175000017500000006705612055406126011144 000000000000002012-11-28 - PgBouncer 1.5.4 - "No Leaks, Potty-Training Successful" = Fixes = * DNS: Fix memory leak in getaddrinfo_a() backend. * DNS: Fix memory leak in udns backend. * DNS: Fix stats calculation. * DNS: Improve error message handling for getaddrinfo_a(). * Fix win32 compile. * Fix compiler dependency support check in configure. * Few documentation fixes. 2012-09-12 - PgBouncer 1.5.3 - "Quantum Toaster" = Critical fix = * Too long database names can lead to crash, which is remotely triggerable if autodbs are enabled. The original checks assumed all names come from config files, thus using fatal() was fine, but when autodbs are enabled - by '*' in [databases] section - the database name can come from network thus making remote shutdown possible. = Minor Features = * max_packet_size - config parameter to tune maximum packet size that is allowed through. Default is kept same: (2G-1), but now it can be made smaller. * In case of unparseable packet header, show it in hex in log and error message. = Fixes = * AntiMake: it used $(relpath) and $(abspath) to manupulate pathnames, but the result was build failure when source tree path contained symlinks. The code is now changed to work on plain strings only. * console: now SET can be used to set empty string values. * config.txt: show that all timeouts can be set in floats. This is well-hidden feature introduced in 1.4. 2012-05-29 - PgBouncer 1.5.2 - "Don't Chew, Just Swallow" = Fixes = * Due to mistake, reserve_pool_timeout was taken in microseconds, not seconds, effectively activating reserve pool immediately when pool got full. Now use it as seconds, as was intended. (Noticed by Keyur Govande) 2012-04-17 - PgBouncer 1.5.1 - "Abort, Retry, Ignore?" = Features = * Parameters to tune permissions on unix socket: unix_socket_mode=0777, unix_socket_group=''. = Fixes = * Allow empty string for server-side variable - this is needed to get "application_name" properly working, as it's the only parameter that does not have server-side default. * If connect string changes, require refresh of server parameters. Previously PgBouncer continued with old parameters, which breaks in case of Postgres upgrade. * If autodb connect string changes, drop old connections. * cf_setint: Use strtol() instead atoi() to parse integer config parameters. It allows hex, octal and better error detection. * Use sigqueue() to detect union sigval existence - fixes compilation on HPUX. * Remove 'git' command from Makefile, it throws random errors in case of plain-tarball build. * Document stats_period parameter. This tunes the period for stats output. * Require Asciidoc >= 8.4, seems docs are not compatible with earlier versions anymore. * Stop trying to retry on EINTR from close(). 2012-01-05 - PgBouncer 1.5 - "Bouncing Satisified Clients Since 2007" If you use more than 8 IPs behind one DNS name, you now need to use EDNS0 protocol to query. Only getaddrinfo_a()/getaddrinfo() and UDNS backends support it, libevent 1.x/2.x does not. To enable it for libc, add 'options edns0' to /etc/resolv.conf. GNU Make 3.81+ is required for building. = Features = * Detect DNS reply changes and invalidate connections to IPs no longer present in latest reply. (Petr Jelinek) * DNS zone serial based hostname invalidation. When option dns_zone_check_period is set, all DNS zones will be queried for SOA, and when serial has changed, all hostnames will be queried. This is needed to get deterministic connection invalidation, because invalidation on lookup is useless when no lookups are performed. Works only with new UDNS backend. * New SHOW DNS_HOSTS, SHOW DNS_ZONES commands to examine DNS cache. * New param: min_pool_size - avoids dropping all connections when there is no load. (Filip Rembiałkowski) * idle_in_transaction_timeout - kill transaction if idle too long. Not set by default. * New libudns backend for DNS lookups. More featureful than evdns. Use --with-udns to activate. Does not work with IPv6 yet. * KILL command, to immediately kill all connections for one database. (Michael Tharp) * Move to Antimake build system to have better looking Makefiles. Now GNU Make 3.81+ is required for building. = Fixes = * DNS now works with IPv6 hostnames. * Don't change connection state when NOTIFY arrives from server. * Various documentation fixes. (Dan McGee) * Console: Support ident quoting with "". Originally we did not have any commands that took database names, so no quoting was needed. * Console: allow numbers at the stard of word regex. Trying to use strict parser makes things too complex here. * Don't expire auto DBs that are paused. (Michael Tharp) * Create auto databases as needed when doing PAUSE. (Michael Tharp) * Fix wrong log message issued by RESUME command. (Peter Eisentraut) * When user= without password= is in database connect string, password will be taken from userlist. * Parse '*' properly in takeover code. * autogen.sh: work with older autoconf/automake. * Fix run-as-service crash on win32 due to bad basename() from mingw/msvc runtime. Now compat basename() is always used. 2011-06-16 - PgBouncer 1.4.2 - "Strike-First Algorithm" Affected OS-es: *BSD, Solaris, Win32. = Portability Fixes = * Give CFLAGS to linker. Needed when using pthread-based getaddrinfo_a() fallback. * lib/find_modules.sh: Replace split() with index()+substr(). This should make it work with older AWKs. * : Ignore system htoX/Xtoh defines. There may be only subset of macros defined. * : Separate compat sigval from compat sigevent * : Include to get iovec * : Better function autodetection on win32 * : Remove duplicate sigval/sigevent declaration 2011-04-01 - PgBouncer 1.4.1 - "It Was All An Act" = Features = * Support listening/connect for IPv6 addresses. (Hannu Krosing) * Multiple listen addresses in 'listen_addr'. For each getaddrinfo() is called, so names can also be used. * console: Send PgBouncer version as 'server_version' to client. = Important Fixes = * Disable getaddrinfo_a() on glibc < 2.9 as it crashes on older versions. Notable affected OS'es: RHEL/CentOS 5.x (glibc 2.5), Ubuntu 8.04 (glibc 2.7). Also Debian/lenny (glibc 2.7) which has non-crashing getaddrinfo_a() but we have no good way to detect it. Please use libevent 2.x on such OS'es, fallback getaddrinfo_a() is not meant for production systems. And read new 'DNS lookup support' section in README to see how DNS backend is picked. (Hubert Depesz Lubaczewski, Dominique Hermsdorff, David Sommerseth) * Default to --enable-evdns if libevent 2.x is used. * Turn on tcp_keepalive by default, as that's what Postgres also does. (Hubert Depesz Lubaczewski) * Set default server_reset_query to DISCARD ALL to be compatible with Postgres by default. * win32: Fix crashes with NULL unix socket addr. (Hiroshi Saito) * Fix autodb cleanup: old cleanup code was mixing up databases and pools - as soon as one empty pool was found, the database was tagged as 'idle', potentially later killing database with active users. Reported-By: Hubert Depesz Lubaczewski = Fixes = * Make compat getaddrinfo_a() non-blocking, by using single parallel thread to do lookups. * Enable pthread compilation if compat getaddrinfo_a is used. * release_server missed setting ->last_lifetime_disconnect on lifetime disconnect. (Emmanuel Courreges) * win32: fix auth file on DOS line endings - load_file() did not take account of file shringage when loading. (Rich Schaaf) * : add autoconf detection for enc/dec functions so it would not create conflicts on BSD. (James Pye) * Don't crash when config file does not exist. (Lou Picciano) * Don't crash on DNS lookup failure when logging on noise level (-v -v). (Hubert Depesz Lubaczewski, Dominique Hermsdorff) * Use backticks instead of $(cmd) in find_modules.sh to make it more portable. (Lou Picciano) * Use 'awk' instead of 'sed' in find_modules.sh to make it more portable. (Giorgio Valoti) * Log active async DNS backend info on startup. * Fix --disable-evdns to mean 'no' instead 'yes'. * Mention in docs that -R requires unix_socket_dir. * Discuss server_reset_query in faq.txt. * Restore lost memset in slab allocator * Various minor portability fixes in libusual. 2011-01-11 - PgBouncer 1.4 - "Gore Code" = Features = * Async DNS lookup - instead of resolving hostnames at reload time, the names are now resolved at connect time, with configurable caching. (See dns_max_ttl parameter.) By default it uses getaddrinfo_a() (glibc) as backend, if it does not exist, then getaddrinfo_a() is emulated via blocking(!) getaddrinfo(). When --enable-evdns argument to configure, libevent's evdns is used as backend. It is not used by default, because libevent 1.3/1.4 contain buggy implementation. Only evdns in libevent 2.0 seems OK. * New config var: syslog_ident, to tune syslog name. * Proper support for `application_name` startup parameter. * Command line long options (Guillaume Lelarge) * Solaris portability fixes (Hubert Depesz Lubaczewski) * New config var: disable_pqexec. Highly-paranoid environments can disable Simple Query Protocol with that. Requires apps that use only Extended Query Protocol. * Postgres compat: if database name is empty in startup packet, use user name as database. = Fixes = * DateStyle and TimeZone server params need to use exact case. * Console: send datetime, timezone and stdstr server params to client. = Internal cleanups = * Use libusual library for low-level utility functions. * Remove fixed-length limit from server params. 2010-09-09 - PgBouncer 1.3.4 - "Bouncer is always right" = Fixes = * Apply fast-fail logic at connect time. So if server is failing, the clients get error when connecting. * Don't tag automatically generated databases for checking on reload time, otherwise they get killed, because they don't exist in config. * Ignore application_name parameter by default. This avoids the need for all Postgres 9.0 users to add it into ignore_startup_parameters= themselves. * Correct pg_auth quoting. '\' is not used there. * Better error reporting on console, show incoming query to user. * Support OS'es (OpenBSD) where tv_sec is not time_t. * Avoid too noisy warnings on gcc 4.5. 2010-05-10 - PgBouncer 1.3.3 - "NSFW" = Improvements = * Make listen(2) argument configurable: listen_backlog. This is useful on OS'es, where system max allowed is configurable. * Improve disconnect messages to show what username or dbname caused login to fail. = Fixes = * Move fast-fail relaunch logic around. Old one was annoying in case of permanently broken databases or users, by trying to retry even if there is no clients who want to login. * Make logging functions keep old errno, otherwise pgbouncer may act funny on higher loglevels and logging problems. * Increase the size of various startup-related buffers to handle EDB more noisy startup. * Detect V2 protocol startup request and give clear reason for disconnect. 2010-03-15 - PgBouncer 1.3.2 - "Boomerang Bullet" = Fixes = * New config var 'query_wait_timeout'. If client does not get server connection in this many seconds, it will be killed. * If no server connection in pool and last connect failed, then don't put client connections on hold but send error immediately. This together with previous fix avoids unnecessary stalls if a database has gone down. * Track libevent state in sbuf.c to avoid double event_del(). Although it usually is safe, it does not seem to work 100%. Now we should always know whether it has been called or not. * Disable maintenance during SUSPEND. Otherwise with short timeouts the old bouncer could close few connections after sending them over. * Apply client_login_timeout to clients waiting for welcome packet (first server connection). Otherwise they can stay waiting infinitely, unless there is query_timeout set. * win32: Add switch -U/-P to -regservice to let user pick account to run service under. Old automatic choice between Local Service and Local System was not reliable enough. * console: Remove \0 from end of text columns. It was hard to notice, as C clients were fine with it. * Documentation improvements. (Greg Sabino Mullane) * Clarify few login-related log messages. * Change logging level for pooler-sent errors (usually on disconnect) from INFO to WARNING, as they signify problems. * Change log message for query_timeout to "query timeout". 2009-07-06 - PgBouncer 1.3.1 - "Now fully conforming to NSA monitoring requirements" = Fixes = * Fix problem with sbuf_loopcnt which could make connections hang. If query or result length is nearby of multiple of (pktlen*sbuf_loopcnt) [10k by default], it could stay waiting for more data which will not appear. * Make database reconfigure immediate. Currently old connections could be reused after SIGHUP. * Fix SHOW DATABASES which was broken due to column addition. * Console access was disabled when "auth_mode=any" as pgbouncer dropped username. Fix: if "auth_mode=any", allow any user to console as admin. * Fix bad CUSTOM_ALIGN macro. Luckily it's unused if OS already defines ALIGN macro thus seems the bug has not happened in wild. * win32: call WSAStartup() always, not only in daemon mode as config parsing wants to resolve hosts. * win32: put quotes around config filename in service cmdline to allow spaces in paths. Executable path does not seem to need it due to some win32 magic. * Add STATS to SHOW HELP text. * doc/usage.txt: the time units in console results are in microseconds, not milliseconds. 2009-02-18 - PgBouncer 1.3 - "New Ki-Smash Finishing Move" = Features = * IANA has assigned port 6432 to be official port for PgBouncer. Thus the default port number has changed to 6432. Existing individual users do not need to change, but if you distribute packages of PgBouncer, please change the package default to official port. * Dynamic database creation (David Galoyan) Now you can define database with name "*". If defined, it's connect string will be used for all undefined databases. Useful mostly for test / dev environments. * Windows support (Hiroshi Saito) PgBouncer runs on Windows 2000+ now. Command line usage stays same, except it cannot run as daemon and cannot do online reboot. To run as service, define parameter service_name in config. Then: > pgbouncer.exe config.ini -regservice > net start SERVICE_NAME To stop and unregister: > net stop SERVICE_NAME > pgbouncer.exe config.ini -unregservice To use Windows Event Log, event DLL needs to be registered first: > regsrv32 pgbevent.dll Afterwards you can set "syslog = 1" in config. = Minor features = * Database names in config file can now be quoted with standard SQL ident quoting, to allow non-standard characters in db names. * New tunables: 'reserve_pool_size' and 'reserve_pool_timeout'. In case there are clients in pool that have waited more that 'reserve_pool_timeout' seconds, 'reserve_pool_size' specifies the number of connections that can be added to pool. It can also set per-pool with 'reserve_pool' connection variable. * New tunable 'sbuf_loopcnt' to limit time spent on one socket. In some situations - eg SMP server, local Postgres and fast network - pgbouncer can run recv()->send() loop many times without blocking on either side. But that means other connections will stall for a long time. To make processing more fair, limit the times of doing recv()->send() one socket. If count reaches limit, just proceed processing other sockets. The processing for that socket will resume on next event loop. Thanks to Alexander Schöcke for report and testing. * crypt() authentication is now optional, as it was removed from Postgres. If OS does not provide it, pgbouncer works fine without it. * Add milliseconds to log timestamps. * Replace old MD5 implementation with more compact one. * Update ISC licence with the FSF clarification. = Fixes = * In case event_del() reports failure, just proceed with cleanup. Previously pgbouncer retried it, in case the failure was due ENOMEM. But this has caused log floods with inifinite repeats, so it seems libevent does not like it. Why event_del() report failure first time is still mystery. * --enable-debug now just toggles whether debug info is stripped from binary. It no longer plays with -fomit-frame-pointer as it's dangerous. * Fix include order, as otherwise system includes could come before internal ones. Was problem for new md5.h include file. * Include COPYRIGHT file in .tgz... 2008-08-08 - PgBouncer 1.2.3 - "Carefully Selected Bytes" * Disable SO_ACCEPTFILTER code for BSDs which did not work. * Include example etc/userlist.txt in tgz. * Use '$(MAKE)' instead 'make' for recursion (Jørgen Austvik) * Define _GNU_SOURCE as glibc is useless otherwise. * Let the libevent 1.1 pass link test so we can later report "1.3b+ needed" * Detect stale pidfile and remove it. Thanks to Devrim GÜNDÜZ and Bjoern Metzdorf for problem reports and testing. 2008-08-06 - PgBouncer 1.2.2 - "Barf-bag Included" * Remove 'drop_on_error', it was a bad idea. It was added as workaround for broken plan cache behaviour in Postgres, but can cause damage in common case when some queries always return error. 2008-08-04 - PgBouncer 1.2.1 - "Waterproof" = Features = * New parameter 'drop_on_error' - if server throws error the connection will not be reused but dropped after client finished with it. This is needed to refresh plan cache. Automatic refresh does not work even in 8.3. Defaults to 1. = Fixes = * SHOW SOCKETS/CLIENTS/SERVERS: Don't crash if socket has no buffer. * Fix infinite loop on SUSPEND if suspend_timeout triggers. = Minor cleanups = * Use for 'struct iovec'. * Cancel shutdown (from SIGINT) on RESUME/SIGUSR2, otherwise it will trigger on next PAUSE. * Proper log message if console operation is canceled. 2008-07-29 - PgBouncer 1.2 - "Ordinary Magic Flute" PgBouncer 1.2 now requires libevent version 1.3b or newer. Older libevent versions crash with new restart code. = Features = * Command line option (-u) and config parameter (user=) to support user switching at startup. Also now pgbouncer refuses to run as root. (Jacob Coby) * More descriptive usage text (-h). (Jacob Coby) * New database option: connect_query to allow run a query on new connections before they are taken into use. (Teodor Sigaev) * New config var 'ignore_startup_parameters' to allow and ignore extra parameters in startup packet. By default only 'database' and 'user' are allowed, all others raise error. This is needed to tolerate overenthusiastic JDBC wanting to unconditionally set 'extra_float_digits=2' in startup packet. * Logging to syslog: new parameters syslog=0/1 and syslog_facility=daemon/user/local0. * Less scary online restart (-R) - Move FD loading before fork, so it logs to console and can be canceled by ^C - Keep SHUTDOWN after fork, so ^C would be safe - A connect() is attempted to unix socket to see if anyone is listening. Now -R can be used even when no previous process was running. If there is previous process, but -R is not used, startup fails. * New console commands: - SHOW TOTALS that shows stats summary (as goes to log) plus mem usage. - SHOW ACTIVE_SOCKETS - like show sockets; but filter only active ones. = Less visible features = * suspend_timeout - drop stalled conns and long logins. This brings additional safety to reboot. * When remote database throws error on logging in, notify clients. * Removing a database from config and reloading works - all connections are killed and the database is removed. * Fake some parameters on console SHOW/SET commands to be more Postgres-like. That was needed to allow psycopg to connect to console. (client_encoding/default_transaction_isolation/datestyle/timezone) * Make server_lifetime=0 disconnect server connection immediately after first use. Previously "0" made PgBouncer ignore server age. As this behavior was undocumented, there should not be any users depending on it. * Internal improvements: - Packet buffers are allocated lazily and reused. This should bring huge decrease in memory usage. This also makes realistic to use big pktbuf with lot of connections. - Lot's of error handling improvements, PgBouncer should now survive OOM situations gracefully. - Use slab allocator for memory management. - Lots of code cleanups. = Fixes = * Only single accept() was issued per event loop which could cause connection backlog when having high amount of connection attempts. Now the listening socket is always drained fully, which should fix this. * Handle EINTR from connect(). * Make configure.ac compatible with autoconf 2.59. * Solaris compatibility fixes (Magne Mæhre) 2007-12-10 - PgBouncer 1.1.2 - "The Hammer" = Features = * Disconnects because of server_lifetime are now separated by (server_lifetime / pool_size) seconds. This avoids pgbouncer causing reconnect floods. = Fixes = * Online upgrade 1.0 -> 1.1 problems: - 1.0 does not track server parameters, so they stay NULL but 1.1 did not expect it and crashed. - If server params are unknown, but client ones are set, then issue a SET for them, instead complaining. * Remove temp debug statements that were accidentally left in code on INFO level, so they polluted logs. * Unbroke debian/changelog = Cleanup = * reorder struct SBuf fields to get better alignment for buffer. 2007-10-26 - PgBouncer 1.1.1 - "Breakdancing Bee" = Fixes = * Server parameter cache could stay uninitialized, which caused unnecessary SET of them. This caused problem on 8.1 which does not allow touching standard_conforming_strings. (Thanks to Dimitri Fontaine for report & testing.) * Some doc fixes. * Include doc/fixman.py in .tgz. 2007-10-09 - PgBouncer 1.1 - "Mad-Hat Toolbox" = Features = * Keep track of following server parameters: client_encoding datestyle, timezone, standard_conforming_strings * Database connect string enhancements: - Accept hostname in host= - Accept custom unix socket location in host= - Accept quoted values: password=' asd''foo' * New config var: server_reset_query, to be sent immidiately after release * New config var: server_round_robin, to switch between LIFO and RR. * Cancel pkt sent for idle connection does not drop it anymore. * Cancel with ^C from psql works for SUSPEND / PAUSE. * Print FD limits on startup. * When suspending, try to hit packet boundary ASAP. * Add 'timezone' to database parameters. * Use longlived logfile fd. Reopened on SIGHUP / RELOAD; * Local connection endpoint info in SHOW SERVERS/CLIENTS/SOCKETS. = Code cleanup = * More debug log messages include socket info. * Magic number removal and error message cleanup. (David Fetter) * Wrapper struct for current pkt info. Removes lot of compexity. = Fixes = * Detect invalid pkt headers better. * auth_file modification check was broken, which made pgbouncer reload it too often. 2007-06-18 - PgBouncer 1.0.8 - "Undead Shovel Jutsu" = Fixes = * Fix crash in cancel packet handling. (^C from psql) = Features = * PAUSE ; RESUME ; works now. * Cleanup of console command parsing. * Disable expensive in-list assert check. 2007-04-19 - PgBouncer 1.0.7 - "With Vitamin A-Z" * Several error/notice packets with send() blocking between triggered assert. Fix it by removing flushing logic altogether. As pgbouncer does not actively buffer anything, its not needed. It was a remnant from the time when buffering was pushed to kernel with MSG_MORE. * Additionally avoid calling recv() logic when sending unblocks. * List search code for admin_users and stats_users mishandled partial finds. Fix it. * Standardise UNIX socket peer UID finding to getpeereid(). 2007-04-12 - PgBouncer 1.0.6 - "Daily Dose" * The "Disable maintenance during the takeover" fix could disable maintenance altogether. Fix it. * Compilation fix for FreeBSD, requires there. Thanks go to Robert Gogolok for report. 2007-04-11 - PgBouncer 1.0.5 - "Enough for today" * Fix online-restart bugs: - Set ->ready for idle servers. - Remove obsolete code from use_client_socket() - Disable maintenance during the takeover. 2007-04-11 - PgBouncer 1.0.4 - "Last 'last' bug" * Notice from idle server tagged server dirty. release_server() did not expect it. Fix it by dropping them. 2007-04-11 - PgBouncer 1.0.3 - "Fearless Fork" = Fixes = * Some error handling was missing in login path, so dying connection there could trigger asserts. * Cleanup of asserts in sbuf.c to catch problems earlier. * Create core when Assert() triggers. = New stuff = * New config vars: log_connections, log_disconnections, log_pooler_errors to turn on/off noise. * Config var: client_login_timeout to kill dead connections in login phase that could stall SUSPEND and thus online restart. 2007-03-28 - PgBouncer 1.0.2 - "Supersonic Spoon" * libevent may report a deleted event inside same loop. Avoid socket reuse for one loop. * release_server() from disconnect_client() didnt look it the packet was actually sent. 2007-03-15 - PgBouncer 1.0.1 - "Alien technology" = Fixes = * Mixed usage of cached and non-cached time, plus unsiged usec_t typedef created spurious query_timeout errors. * Fix rare case when socket woken up from send-wait could stay stalling. * More fair queueing of server connections. Before, a new query could get a server connections before older one. * Delay server release until everything is guaranteed to be sent. = Features = * SHOW SOCKETS command to have detailed info about state state. * Put PgSocket ptr to log, to help tracking one connection. * In console, allow SELECT in place of SHOW. * Various code cleanups. 2007-03-13 - PgBouncer 1.0 - "Tuunitud bemm" * First public release. pgbouncer-1.5.4/win32/0000755000175000017500000000000012055406737011461 500000000000000pgbouncer-1.5.4/win32/eventmsg.mc0000644000175000017500000000007511765176015013554 00000000000000MessageId=0 SymbolicName=MSG_PGBOUNCER Language=English %1 . pgbouncer-1.5.4/win32/win32support.c0000644000175000017500000002000711776253410014140 00000000000000/*------------------------------------------------------------------------- * win32service.c * * Windows service integration and eventlog * * Copyright (c) 2005, PostgreSQL Global Development Group * Authors: Magnus Hagander, Hiroshi Saito, Marko Kreen *------------------------------------------------------------------------- */ #include "bouncer.h" #if defined(UNICODE) || defined(_UNICODE) #error This code does not support wide characters. #endif /* Globals for service control */ static SERVICE_STATUS_HANDLE hStatus = 0; static SERVICE_STATUS svcStatus = { .dwServiceType = SERVICE_WIN32_OWN_PROCESS, .dwControlsAccepted = 0, .dwWin32ExitCode = NO_ERROR, .dwCheckPoint = 0, .dwWaitHint = 0, .dwCurrentState = SERVICE_START_PENDING, }; /* Event source name for ReportEvent. * * Also used as placeholder for service handling API's, but it is ignored * because our service is defined as WIN32_OWN_PROCESS. */ static char *servicename = "pgbouncer"; static char *service_username = NULL; static char *service_password = NULL; static char *serviceDescription = "Lightweight connection pooler for PostgreSQL."; /* custom help string for win32 exe */ static const char usage_str[] = "Usage: %s [OPTION]... config.ini\n" " -q No console messages\n" " -v Increase verbosity\n" " -V Show version\n" " -h Show this help screen and exit\n" "Windows service registration:\n" " -regservice config.ini [-U username [-P password]]\n" " -unregservice config.ini\n" ""; static void usage(int err, char *exe) { printf(usage_str, basename(exe)); exit(err); } static int exec_real_main(int argc, char *argv[]) { int i, j; /* win32 stdio seems to be fully buffered by default */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); /* check if regular arguments are in allowed list */ for (i = 1; i < argc; i++) { char *p = argv[i]; if (p[0] != '-') continue; for (j = 1; p[j]; j++) { if (!strchr("qvhV", p[j])) usage(1, argv[0]); if (p[j] == 'h') usage(0, argv[0]); } } /* call actual main() */ return real_main(argc, argv); } /* Set the current service status */ static void win32_setservicestatus(DWORD state) { svcStatus.dwCurrentState = state; switch (state) { case SERVICE_START_PENDING: case SERVICE_STOP_PENDING: svcStatus.dwControlsAccepted = 0; svcStatus.dwWaitHint = 5000; break; default: svcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; svcStatus.dwWaitHint = 0; } SetServiceStatus(hStatus, &svcStatus); } /* * Handle any events sent by the service control manager * NOTE! Events are sent on a different thread! And it's * not a pthreads thread, so avoid calling anything that * may use pthreads - like pgbouncer_log() */ static void WINAPI win32_servicehandler(DWORD request) { switch (request) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: win32_setservicestatus(SERVICE_STOP_PENDING); cf_shutdown = 2; break; case SERVICE_CONTROL_INTERROGATE: SetServiceStatus(hStatus, &svcStatus); break; } } /* notify control thread about stop */ static void win32_service_cleanup(void) { if (hStatus) win32_setservicestatus(SERVICE_STOPPED); hStatus = 0; /* may get called twice from atexit */ } /* * Entrypoint for actual service work. * * Service is set-up and then actual main() is called. */ static void WINAPI win32_servicemain(DWORD argc, LPSTR *argv) { int new_argc = 2; char *new_argv[] = { servicename, cf_config_file, NULL }; /* register control request handler */ hStatus = RegisterServiceCtrlHandler(servicename, win32_servicehandler); if (hStatus == 0) { fatal("could not connect to service control handler: %s", strerror(GetLastError())); exit(1); } /* Tell SCM we are running before we make any API calls */ win32_setservicestatus(SERVICE_RUNNING); /* register with system atexit(), in case somebody calls exit() */ atexit(win32_service_cleanup); /* Execute actual main() */ exec_real_main(new_argc, new_argv); win32_service_cleanup(); } /* Start running as a service */ static void win32_servicestart(void) { SERVICE_TABLE_ENTRY st[] = { {servicename, win32_servicemain}, {NULL, NULL} }; if (StartServiceCtrlDispatcher(st) == 0) { fprintf(stderr, "could not start service control dispatcher: %s\n", strerror(GetLastError())); exit(1); } } /* Open Service Control Manager */ static SC_HANDLE openSCM(void) { SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (!manager) { fprintf(stderr, "Failed to open service control manager: %s\n", strerror(GetLastError())); exit(1); } return manager; } /* Full path to current config file. */ static const char *get_config_fullpath(void) { DWORD r; static char buf[PATH_MAX]; r = GetFullPathName(cf_config_file, sizeof(buf), buf, NULL); if (r == 0 || r >= sizeof(buf)) { fprintf(stderr, "Failed to get full pathname for '%s': %s\n", cf_config_file, strerror(GetLastError())); exit(1); } return buf; } /* Register a service with the specified name with the local service control manager */ static void RegisterService(void) { char self[1024]; char cmdline[2048]; const char *config_fn = get_config_fullpath(); SC_HANDLE manager; SC_HANDLE service; SERVICE_DESCRIPTION sd; DWORD r; r = GetModuleFileName(NULL, self, sizeof(self)); if (!r || r >= sizeof(self)) { fprintf(stderr, "Failed to determine path name: %s\n", strerror(GetLastError())); exit(1); } snprintf(cmdline, sizeof(cmdline), "%s -service \"%s\"", self, config_fn); manager = openSCM(); service = CreateService(manager, cf_jobname, cf_jobname, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, cmdline, NULL, NULL, "RPCSS\0", service_username, service_password); if (!service) { fprintf(stderr, "Failed to create service: %s\n", strerror(GetLastError())); exit(1); } /* explain the service purpose */ sd.lpDescription = serviceDescription; ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &sd); CloseServiceHandle(service); CloseServiceHandle(manager); printf("Service registered.\n"); if (service_username == NULL) { printf("\nWARNING! Service is registered to run as Local System. You are\n"); printf("encouraged to change this to a low privilege account to increase\n"); printf("system security. (Eg. NT AUTHORITY\\Local Service)\n"); } } /* Remove a service with the specified name from the local service control manager */ static void UnRegisterService(void) { SC_HANDLE manager; SC_HANDLE service; manager = openSCM(); service = OpenService(manager, cf_jobname, SC_MANAGER_ALL_ACCESS); if (!service) { fprintf(stderr, "Failed to open service: %s\n", strerror(GetLastError())); exit(1); } if (!DeleteService(service)) { fprintf(stderr, "Failed to delete service: %s\n", strerror(GetLastError())); exit(1); } CloseServiceHandle(service); CloseServiceHandle(manager); printf("Service removed.\n"); } /* config loader for service register/unregister */ static void win32_load_config(char *conf) { cf_config_file = conf; init_objects(); load_config(); } /* * Wrapper around actual main() that handles win32 hacks. */ #undef main int main(int argc, char *argv[]) { WSADATA wsaData; /* initialize socket subsystem */ if (WSAStartup(MAKEWORD(2,0), &wsaData)) fatal("Cannot start the network subsystem"); /* service cmdline */ if (argc >= 3) { if (!strcmp(argv[1], "-service")) { cf_quiet = 1; cf_config_file = argv[2]; win32_servicestart(); return 0; } if (!strcmp(argv[1], "-regservice")) { int i; win32_load_config(argv[2]); for (i = 3; i < argc; i++) { if (!strcmp(argv[i], "-U") && i + 1 < argc) { service_username = argv[++i]; } else if (!strcmp(argv[i], "-P") && i + 1 < argc) { service_password = argv[++i]; } else { printf("unknown arg: %s\n", argv[i]); usage(1, argv[0]); } } RegisterService(); return 0; } if (!strcmp(argv[1], "-unregservice")) { win32_load_config(argv[2]); UnRegisterService(); return 0; } } return exec_real_main(argc, argv); } pgbouncer-1.5.4/win32/win32support.h0000644000175000017500000000014011765176015014144 00000000000000 /* redirect main() */ #define main(a,b) real_main(a,b) int real_main(int argc, char *argv[]); pgbouncer-1.5.4/win32/Makefile0000644000175000017500000000011711765176015013040 00000000000000 # create eventmsg.rc + MSG*.bin eventmsg.rc: eventmsg.mc mc.exe eventmsg.mc pgbouncer-1.5.4/win32/pgbevent.c0000644000175000017500000000512511765176015013362 00000000000000/*------------------------------------------------------------------------- * pgbevent.c * Defines the entry point for pgbevent dll. * The DLL defines event source for pgbouncer tools *------------------------------------------------------------------------- */ #define WIN32_LEAN_AND_MEAN #include #include #include #define APP_KEY "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\pgbouncer" /* Global variables */ static HANDLE g_module = NULL; /* hModule of DLL */ /* Prototypes */ STDAPI DllRegisterServer(void); STDAPI DllUnregisterServer(void); BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved); /* * DllRegisterServer --- Instructs DLL to create its registry entries */ STDAPI DllRegisterServer(void) { HKEY key; DWORD data; char buffer[_MAX_PATH]; /* Set the name of DLL full path name. */ if (!GetModuleFileName((HMODULE)g_module, buffer, sizeof(buffer))) { MessageBox(NULL, "Could not retrieve DLL filename", "pgbouncer error", MB_OK | MB_ICONSTOP); return SELFREG_E_TYPELIB; } /* * Add our source name as a subkey under the Application key in * the EventLog registry key. */ if (RegCreateKey(HKEY_LOCAL_MACHINE, APP_KEY, &key)) { MessageBox(NULL, "Could not create the registry key.", "pgbouncer error", MB_OK | MB_ICONSTOP); return SELFREG_E_TYPELIB; } /* Add the name to the EventMessageFile subkey. */ if (RegSetValueEx(key, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE)buffer, strlen(buffer) + 1)) { MessageBox(NULL, "Could not set the event message file.", "pgbouncer error", MB_OK | MB_ICONSTOP); return SELFREG_E_TYPELIB; } /* Set the supported event types in the TypesSupported subkey. */ data = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; if (RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, (LPBYTE)&data, sizeof(DWORD))) { MessageBox(NULL, "Could not set the supported types.", "pgbouncer error", MB_OK | MB_ICONSTOP); return SELFREG_E_TYPELIB; } RegCloseKey(key); return S_OK; } /* * DllUnregisterServer --- Instructs DLL to remove only those entries created through DllRegisterServer */ STDAPI DllUnregisterServer(void) { if (RegDeleteKey(HKEY_LOCAL_MACHINE, APP_KEY)) { MessageBox(NULL, "Could not delete the registry key.", "pgbouncer error", MB_OK | MB_ICONSTOP); return SELFREG_E_TYPELIB; } return S_OK; } /* * DllMain --- is an optional entry point into a DLL. */ BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) g_module = hModule; return TRUE; } pgbouncer-1.5.4/win32/MSG00001.bin0000644000175000017500000000004011765176015013074 00000000000000%1 pgbouncer-1.5.4/win32/eventmsg.rc0000644000175000017500000000004711765176015013560 00000000000000LANGUAGE 0x9,0x1 1 11 "MSG00001.bin" pgbouncer-1.5.4/Makefile0000644000175000017500000000670012055406004012065 00000000000000 include config.mak bin_PROGRAMS = pgbouncer pgbouncer_SOURCES = \ src/admin.c \ src/client.c \ src/dnslookup.c \ src/janitor.c \ src/loader.c \ src/main.c \ src/objects.c \ src/pktbuf.c \ src/pooler.c \ src/proto.c \ src/sbuf.c \ src/server.c \ src/stats.c \ src/system.c \ src/takeover.c \ src/util.c \ src/varcache.c \ include/admin.h \ include/bouncer.h \ include/client.h \ include/dnslookup.h \ include/iobuf.h \ include/janitor.h \ include/loader.h \ include/objects.h \ include/pktbuf.h \ include/pooler.h \ include/proto.h \ include/sbuf.h \ include/server.h \ include/stats.h \ include/system.h \ include/takeover.h \ include/util.h \ include/varcache.h pgbouncer_CPPFLAGS = -Iinclude # include libusual sources directly AM_FEATURES = libusual pgbouncer_EMBED_LIBUSUAL = 1 # docs to install as-is dist_doc_DATA = README NEWS etc/pgbouncer.ini etc/userlist.txt DISTCLEANFILES = config.mak config.status lib/usual/config.h config.log SUBDIRS = doc # files in tgz EXTRA_DIST = AUTHORS COPYRIGHT Makefile \ config.mak.in etc/mkauth.py \ config.sub config.guess install-sh autogen.sh \ configure configure.ac \ debian/compat debian/changelog debian/control debian/rules debian/copyright \ test/Makefile test/asynctest.c test/conntest.sh test/ctest6000.ini \ test/ctest7000.ini test/run-conntest.sh test/stress.py test/test.ini \ test/test.sh test/userlist.txt etc/example.debian.init.sh \ win32/Makefile \ $(LIBUSUAL_DIST) # libusual files (fixme: list should be provided by libusual...) LIBUSUAL_DIST = $(filter-out %/config.h, $(wildcard \ lib/usual/*.[chg] lib/m4/*.m4 \ lib/usual/config.h.in \ lib/mk/*.mk \ lib/mk/antimake.mk lib/mk/antimake.txt \ lib/mk/install-sh lib/mk/std-autogen.sh \ lib/README lib/COPYRIGHT \ lib/find_modules.sh )) ifeq ($(enable_debug),yes) CPPFLAGS += -DDBGVER="\"compiled by <$${USER}@`hostname`> at `date '+%Y-%m-%d %H:%M:%S'`\"" endif # # win32 # pgbouncer_LDADD := $(LIBS) LIBS := EXTRA_pgbouncer_SOURCES = win32/win32support.c win32/win32support.h EXTRA_PROGRAMS = pgbevent ifeq ($(PORTNAME),win32) pgbouncer_CPPFLAGS += -Iwin32 pgbouncer_SOURCES += $(EXTRA_pgbouncer_SOURCES) bin_PROGRAMS += pgbevent endif pgbevent_SOURCES = win32/pgbevent.c win32/eventmsg.rc \ win32/eventmsg.mc win32/MSG00001.bin pgbevent_EXT = .dll pgbevent_LINK = $(CC) -shared -Wl,--export-all-symbols -Wl,--add-stdcall-alias -o $@ $^ # .rc->.o AM_LANGUAGES = RC AM_LANG_RC_SRCEXTS = .rc AM_LANG_RC_COMPILE = $(WINDRES) $< -o $@ --include-dir=$(srcdir)/win32 AM_LANG_RC_LINK = false # # now load antimake # USUAL_DIR = lib abs_top_srcdir ?= $(CURDIR) include $(abs_top_srcdir)/lib/mk/antimake.mk config.mak: @echo "Please run ./configure" @exit 1 deb: debuild -b -us -uc w32zip = pgbouncer-$(PACKAGE_VERSION)-win32.zip zip: configure clean rm -rf buildexe mkdir buildexe cd buildexe \ && ../configure --host=i586-mingw32msvc --disable-debug \ --with-libevent=/opt/apps/win32 --enable-evdns \ && make \ && i586-mingw32msvc-strip pgbouncer.exe pgbevent.dll \ && zip pgbouncer.zip pgbouncer.exe pgbevent.dll doc/*.html zip -l buildexe/pgbouncer.zip etc/pgbouncer.ini etc/userlist.txt mv buildexe/pgbouncer.zip $(w32zip) zip-up: $(w32zip) rsync $(w32zip) pgf:web/pgbouncer/htdocs/win32/ tgz = pgbouncer-$(PACKAGE_VERSION).tar.gz tgz-up: $(tgz) rsync $(tgz) pgf:web/pgbouncer/htdocs/testing/ .PHONY: tags tags: ctags src/*.c include/*.h lib/usual/*.[ch] pgbouncer-1.5.4/config.mak.in0000644000175000017500000000254711765176015013013 00000000000000PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PORTNAME = @PORTNAME@ EXEEXT = @EXEEXT@ HAVE_CC_DEPFLAG = @HAVE_CC_DEPFLAG@ CC = @CC@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CFLAGS = @CFLAGS@ DEFS = @DEFS@ WFLAGS = @WFLAGS@ CXX = @CXX@ CXXFLAGS = @CXXFLAGS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ AR = @AR@ ARFLAGS = @ARFLAGS@ RANLIB = @RANLIB@ LIBTOOL = @LIBTOOL@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_DATA = @INSTALL_DATA@ MKDIR_P = @MKDIR_P@ SED = @SED@ AWK = @AWK@ GREP = @GREP@ EGREP = @EGREP@ STRIP = @STRIP@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ includedir = @includedir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datarootdir = @datarootdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ docdir = @docdir@ mandir = @mandir@ libdir = @libdir@ localedir = @localedir@ pkgdatadir = @pkgdatadir@ pkgconfigdir = @pkgconfigdir@ abs_top_srcdir ?= @abs_top_srcdir@ abs_top_builddir ?= @abs_top_builddir@ nosub_top_srcdir ?= @top_srcdir@ nosub_top_builddir ?= @top_builddir@ XMLTO = @XMLTO@ ASCIIDOC = @ASCIIDOC@ DLLWRAP = @DLLWRAP@ DLLTOOL = @DLLTOOL@ WINDRES = @WINDRES@ enable_debug = @enable_debug@ have_libevent = @have_libevent@ pgbouncer-1.5.4/include/0000755000175000017500000000000012055406736012141 500000000000000pgbouncer-1.5.4/include/dnslookup.h0000644000175000017500000000347211765176015014257 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2010 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct DNSContext; struct DNSToken; struct addrinfo; typedef void (*adns_callback_f)(void *arg, const struct sockaddr *sa, int salen); struct DNSContext *adns_create_context(void); void adns_reload(struct DNSContext *ctx); void adns_free_context(struct DNSContext *ctx); struct DNSToken *adns_resolve(struct DNSContext *ctx, const char *name, adns_callback_f cb_func, void *arg); void adns_cancel(struct DNSContext *ctx, struct DNSToken *tk); const char *adns_get_backend(void); void adns_zone_cache_maint(struct DNSContext *ctx); void adns_info(struct DNSContext *ctx, int *names, int *zones, int *queries, int *pending); typedef void (*adns_walk_name_f)(void *arg, const char *name, const struct addrinfo *ai, usec_t ttl); typedef void (*adns_walk_zone_f)(void *arg, const char *name, uint32_t serial, int nhosts); void adns_walk_names(struct DNSContext *ctx, adns_walk_name_f cb, void *arg); void adns_walk_zones(struct DNSContext *ctx, adns_walk_zone_f cb, void *arg); pgbouncer-1.5.4/include/takeover.h0000644000175000017500000000176311765176015014062 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void takeover_init(void); bool takeover_login(PgSocket *bouncer) _MUSTCHECK; void takeover_login_failed(void); void takeover_finish(void); pgbouncer-1.5.4/include/sbuf.h0000644000175000017500000000666512006550770013200 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * event types for protocol handler */ typedef enum { SBUF_EV_READ, /* got new packet */ SBUF_EV_RECV_FAILED, /* error */ SBUF_EV_SEND_FAILED, /* error */ SBUF_EV_CONNECT_FAILED, /* error */ SBUF_EV_CONNECT_OK, /* got connection */ SBUF_EV_FLUSH, /* data is sent, buffer empty */ SBUF_EV_PKT_CALLBACK, /* next part of pkt data */ } SBufEvent; /* * If less that this amount of data is pending, then * prefer to merge it with next recv(). * * It needs to be larger than data handler wants * to see completely. Generally just header, * but currently also ServerParam pkt. */ #define SBUF_SMALL_PKT 64 /* fwd def */ typedef struct SBuf SBuf; /* callback should return true if it used one of sbuf_prepare_* on sbuf, false if it used sbuf_pause(), sbuf_close() or simply wants to wait for next event loop (eg. too few data available). */ typedef bool (*sbuf_cb_t)(SBuf *sbuf, SBufEvent evtype, struct MBuf *mbuf); /* for some reason, libevent has no typedef for callback */ typedef void (*sbuf_libevent_cb)(int, short, void *); /* * Stream Buffer. * * Stream is divided to packets. On each packet start * protocol handler is called that decides what to do. */ struct SBuf { struct event ev; /* libevent handle */ uint8_t wait_type; /* track wait state */ uint8_t pkt_action; /* method for handling current pkt */ int sock; /* fd for this socket */ unsigned pkt_remain; /* total packet length remaining */ sbuf_cb_t proto_cb; /* protocol callback */ SBuf *dst; /* target SBuf for current packet */ IOBuf *io; /* data buffer, lazily allocated */ }; #define sbuf_socket(sbuf) ((sbuf)->sock) void sbuf_init(SBuf *sbuf, sbuf_cb_t proto_fn); bool sbuf_accept(SBuf *sbuf, int read_sock, bool is_unix) _MUSTCHECK; bool sbuf_connect(SBuf *sbuf, const struct sockaddr *sa, int sa_len, int timeout_sec) _MUSTCHECK; bool sbuf_pause(SBuf *sbuf) _MUSTCHECK; void sbuf_continue(SBuf *sbuf); bool sbuf_close(SBuf *sbuf) _MUSTCHECK; /* proto_fn can use those functions to order behaviour */ void sbuf_prepare_send(SBuf *sbuf, SBuf *dst, unsigned amount); void sbuf_prepare_skip(SBuf *sbuf, unsigned amount); void sbuf_prepare_fetch(SBuf *sbuf, unsigned amount); bool sbuf_answer(SBuf *sbuf, const void *buf, unsigned len) _MUSTCHECK; bool sbuf_continue_with_callback(SBuf *sbuf, sbuf_libevent_cb cb) _MUSTCHECK; /* * Returns true if SBuf is has no data buffered * and is not in a middle of a packet. */ static inline bool sbuf_is_empty(SBuf *sbuf) { return iobuf_empty(sbuf->io) && sbuf->pkt_remain == 0; } static inline bool sbuf_is_closed(SBuf *sbuf) { return sbuf->sock == 0; } pgbouncer-1.5.4/include/loader.h0000644000175000017500000000211212013151606013457 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* connstring parsing */ bool parse_database(void *base, const char *name, const char *connstr); /* user file parsing */ bool load_auth_file(const char *fn) /* _MUSTCHECK */; bool loader_users_check(void) /* _MUSTCHECK */; pgbouncer-1.5.4/include/bouncer.h0000644000175000017500000003021012013151606013646 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * core structures */ #include "system.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DBGVER #define FULLVER PACKAGE_NAME " version " PACKAGE_VERSION " (" DBGVER ")" #else #define FULLVER PACKAGE_NAME " version " PACKAGE_VERSION #endif /* each state corresponts to a list */ enum SocketState { CL_FREE, /* free_client_list */ CL_JUSTFREE, /* justfree_client_list */ CL_LOGIN, /* login_client_list */ CL_WAITING, /* pool->waiting_client_list */ CL_ACTIVE, /* pool->active_client_list */ CL_CANCEL, /* pool->cancel_req_list */ SV_FREE, /* free_server_list */ SV_JUSTFREE, /* justfree_server_list */ SV_LOGIN, /* pool->new_server_list */ SV_IDLE, /* pool->idle_server_list */ SV_ACTIVE, /* pool->active_server_list */ SV_USED, /* pool->used_server_list */ SV_TESTED /* pool->tested_server_list */ }; enum PauseMode { P_NONE = 0, /* active pooling */ P_PAUSE = 1, /* wait for client to finish work */ P_SUSPEND = 2 /* wait for buffers to be empty */ }; #define is_server_socket(sk) ((sk)->state >= SV_FREE) typedef struct PgSocket PgSocket; typedef struct PgUser PgUser; typedef struct PgDatabase PgDatabase; typedef struct PgPool PgPool; typedef struct PgStats PgStats; typedef union PgAddr PgAddr; typedef enum SocketState SocketState; typedef struct PktHdr PktHdr; extern int cf_sbuf_len; #include "util.h" #include "iobuf.h" #include "sbuf.h" #include "pktbuf.h" #include "varcache.h" #include "dnslookup.h" #include "admin.h" #include "loader.h" #include "client.h" #include "server.h" #include "pooler.h" #include "proto.h" #include "objects.h" #include "stats.h" #include "takeover.h" #include "janitor.h" /* to avoid allocations will use static buffers */ #define MAX_DBNAME 64 #define MAX_USERNAME 64 #define MAX_PASSWORD 64 /* auth modes, should match PG's */ #define AUTH_ANY -1 /* same as trust but without username check */ #define AUTH_TRUST 0 #define AUTH_PLAIN 3 #define AUTH_CRYPT 4 #define AUTH_MD5 5 #define AUTH_CREDS 6 /* type codes for weird pkts */ #define PKT_STARTUP_V2 0x20000 #define PKT_STARTUP 0x30000 #define PKT_CANCEL 80877102 #define PKT_SSLREQ 80877103 #define POOL_SESSION 0 #define POOL_TX 1 #define POOL_STMT 2 /* old style V2 header: len:4b code:4b */ #define OLD_HEADER_LEN 8 /* new style V3 packet header len - type:1b, len:4b */ #define NEW_HEADER_LEN 5 #define BACKENDKEY_LEN 8 /* buffer size for startup noise */ #define STARTUP_BUF 1024 /* * Remote/local address */ /* buffer for pgaddr string conversions (with port) */ #define PGADDR_BUF (INET6_ADDRSTRLEN + 10) /* * AF_INET,AF_INET6 are stored as-is, * AF_UNIX uses sockaddr_in port. */ union PgAddr { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_in6 sin6; }; static inline bool pga_is_unix(const PgAddr *a) { return a->sa.sa_family == AF_UNIX; } int pga_port(const PgAddr *a); void pga_set(PgAddr *a, int fam, int port); void pga_copy(PgAddr *a, const struct sockaddr *sa); bool pga_pton(PgAddr *a, const char *s, int port); const char *pga_ntop(const PgAddr *a, char *dst, int dstlen); const char *pga_str(const PgAddr *a, char *dst, int dstlen); int pga_cmp_addr(const PgAddr *a, const PgAddr *b); /* * Stats, kept per-pool. */ struct PgStats { uint64_t request_count; uint64_t server_bytes; uint64_t client_bytes; usec_t query_time; /* total req time in us */ }; /* * Contains connections for one db+user pair. * * Stats: * ->stats is updated online. * for each stats_period: * ->older_stats = ->newer_stats * ->newer_stats = ->stats */ struct PgPool { struct List head; /* entry in global pool_list */ struct List map_head; /* entry in user->pool_list */ PgDatabase *db; /* corresponging database */ PgUser *user; /* user logged in as */ struct StatList active_client_list; /* waiting events logged in clients */ struct StatList waiting_client_list; /* client waits for a server to be available */ struct StatList cancel_req_list; /* closed client connections with server key */ struct StatList active_server_list; /* servers linked with clients */ struct StatList idle_server_list; /* servers ready to be linked with clients */ struct StatList used_server_list; /* server just unlinked from clients */ struct StatList tested_server_list; /* server in testing process */ struct StatList new_server_list; /* servers in login phase */ PgStats stats; PgStats newer_stats; PgStats older_stats; /* database info to be sent to client */ struct PktBuf *welcome_msg; /* ServerParams without VarCache ones */ VarCache orig_vars; /* default params from server */ usec_t last_lifetime_disconnect;/* last time when server_lifetime was applied */ /* if last connect failed, there should be delay before next */ usec_t last_connect_time; unsigned last_connect_failed:1; unsigned welcome_msg_ready:1; }; #define pool_server_count(pool) ( \ statlist_count(&(pool)->active_server_list) + \ statlist_count(&(pool)->idle_server_list) + \ statlist_count(&(pool)->new_server_list) + \ statlist_count(&(pool)->tested_server_list) + \ statlist_count(&(pool)->used_server_list)) #define pool_client_count(pool) ( \ statlist_count(&(pool)->active_client_list) + \ statlist_count(&(pool)->waiting_client_list)) /* * A user in login db. * * fixme: remove ->head as ->tree_node should be enough. * * For databases where remote user is forced, the pool is: * first(db->forced_user->pool_list), where pool_list has only one entry. * * Otherwise, ->pool_list contains multiple pools, for all PgDatabases * whis user has logged in. */ struct PgUser { struct List head; /* used to attach user to list */ struct List pool_list; /* list of pools where pool->user == this user */ struct AANode tree_node; /* used to attach user to tree */ char name[MAX_USERNAME]; char passwd[MAX_PASSWORD]; }; /* * A database entry from config. */ struct PgDatabase { struct List head; char name[MAX_DBNAME]; /* db name for clients */ bool db_paused; /* PAUSE ; was issued */ bool db_dead; /* used on RELOAD/SIGHUP to later detect removed dbs */ bool db_auto; /* is the database auto-created by autodb_connstr */ bool admin; /* internal console db */ struct PktBuf *startup_params; /* partial StartupMessage (without user) be sent to server */ PgUser *forced_user; /* if not NULL, the user/psw is forced */ const char *host; /* host or unix socket name */ int port; int pool_size; /* max server connections in one pool */ int res_pool_size; /* additional server connections in case of trouble */ const char *dbname; /* server-side name, pointer to inside startup_msg */ /* startup commands to send to server after connect. malloc-ed */ const char *connect_query; usec_t inactive_time; /* when auto-database became inactive (to kill it after timeout) */ unsigned active_stamp; /* set if autodb has connections */ }; /* * A client or server connection. * * ->state corresponds to various lists the struct can be at. */ struct PgSocket { struct List head; /* list header */ PgSocket *link; /* the dest of packets */ PgPool *pool; /* parent pool, if NULL not yet assigned */ PgUser *auth_user; /* presented login, for client it may differ from pool->user */ SocketState state:8; /* this also specifies socket location */ bool ready:1; /* server: accepts new query */ bool idle_tx:1; /* server: idling in tx */ bool close_needed:1; /* server: this socket must be closed ASAP */ bool setting_vars:1; /* server: setting client vars */ bool exec_on_connect:1; /* server: executing connect_query */ bool wait_for_welcome:1;/* client: no server yet in pool, cannot send welcome msg */ bool suspended:1; /* client/server: if the socket is suspended */ bool admin_user:1; /* console client: has admin rights */ bool own_user:1; /* console client: client with same uid on unix socket */ bool wait_for_response:1;/* console client: waits for completion of PAUSE/SUSPEND cmd */ usec_t connect_time; /* when connection was made */ usec_t request_time; /* last activity time */ usec_t query_start; /* query start moment */ uint8_t cancel_key[BACKENDKEY_LEN]; /* client: generated, server: remote */ PgAddr remote_addr; /* ip:port for remote endpoint */ PgAddr local_addr; /* ip:port for local endpoint */ struct DNSToken *dns_token; /* ongoing request */ VarCache vars; /* state of interesting server parameters */ SBuf sbuf; /* stream buffer, must be last */ }; #define RAW_IOBUF_SIZE offsetof(IOBuf, buf) #define IOBUF_SIZE (RAW_IOBUF_SIZE + cf_sbuf_len) /* where to store old fd info during SHOW FDS result processing */ #define tmp_sk_oldfd request_time #define tmp_sk_linkfd query_start /* takeover_clean_socket() needs to clean those up */ /* where the salt is temporarly stored */ #define tmp_login_salt cancel_key /* main.c */ extern int cf_daemon; extern char *cf_config_file; extern char *cf_jobname; extern char *cf_unix_socket_dir; extern int cf_unix_socket_mode; extern char *cf_unix_socket_group; extern char *cf_listen_addr; extern int cf_listen_port; extern int cf_listen_backlog; extern int cf_pool_mode; extern int cf_max_client_conn; extern int cf_default_pool_size; extern int cf_min_pool_size; extern int cf_res_pool_size; extern usec_t cf_res_pool_timeout; extern char * cf_autodb_connstr; extern usec_t cf_autodb_idle_timeout; extern usec_t cf_suspend_timeout; extern usec_t cf_server_lifetime; extern usec_t cf_server_idle_timeout; extern char * cf_server_reset_query; extern char * cf_server_check_query; extern usec_t cf_server_check_delay; extern usec_t cf_server_connect_timeout; extern usec_t cf_server_login_retry; extern usec_t cf_query_timeout; extern usec_t cf_query_wait_timeout; extern usec_t cf_client_idle_timeout; extern usec_t cf_client_login_timeout; extern usec_t cf_idle_transaction_timeout; extern int cf_server_round_robin; extern int cf_disable_pqexec; extern usec_t cf_dns_max_ttl; extern usec_t cf_dns_zone_check_period; extern int cf_auth_type; extern char *cf_auth_file; extern char *cf_pidfile; extern char *cf_ignore_startup_params; extern char *cf_admin_users; extern char *cf_stats_users; extern int cf_stats_period; extern int cf_pause_mode; extern int cf_shutdown; extern int cf_reboot; extern unsigned int cf_max_packet_size; extern int cf_sbuf_loopcnt; extern int cf_tcp_keepalive; extern int cf_tcp_keepcnt; extern int cf_tcp_keepidle; extern int cf_tcp_keepintvl; extern int cf_tcp_socket_buffer; extern int cf_tcp_defer_accept; extern int cf_log_connections; extern int cf_log_disconnections; extern int cf_log_pooler_errors; extern usec_t g_suspend_start; extern struct DNSContext *adns; static inline PgSocket * _MUSTCHECK pop_socket(struct StatList *slist) { struct List *item = statlist_pop(slist); if (item == NULL) return NULL; return container_of(item, PgSocket, head); } static inline PgSocket * first_socket(struct StatList *slist) { if (statlist_empty(slist)) return NULL; return container_of(slist->head.next, PgSocket, head); } void load_config(void); bool set_config_param(const char *key, const char *val); void config_for_each(void (*param_cb)(void *arg, const char *name, const char *val, bool reloadable), void *arg); pgbouncer-1.5.4/include/util.h0000644000175000017500000000452112005217606013200 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * logging about specific socket */ int log_socket_prefix(enum LogLevel lev, void *ctx, char *dst, unsigned int dstlen); #define slog_error(sk, args...) log_generic(LG_ERROR, sk, ## args) #define slog_warning(sk, args...) log_generic(LG_WARNING, sk, ## args) #define slog_info(sk, args...) log_generic(LG_INFO, sk, ## args) #define slog_debug(sk, args...) do { \ if (unlikely(cf_verbose > 0)) \ log_generic(LG_DEBUG, sk, ## args); \ } while (0) #define slog_noise(sk, args...) do { \ if (unlikely(cf_verbose > 1)) \ log_generic(LG_NOISE, sk, ## args); \ } while (0) /* * password tools */ #define MD5_PASSWD_LEN 35 #define isMD5(passwd) (memcmp(passwd, "md5", 3) == 0 \ && strlen(passwd) == MD5_PASSWD_LEN) void pg_md5_encrypt(const char *part1, const char *part2, size_t p2len, char *dest); void get_random_bytes(uint8_t *dest, int len); const char *bin2hex(const uint8_t *src, unsigned srclen, char *dst, unsigned dstlen); bool tune_socket(int sock, bool is_unix) _MUSTCHECK; bool strlist_contains(const char *liststr, const char *str); void fill_remote_addr(PgSocket *sk, int fd, bool is_unix); void fill_local_addr(PgSocket *sk, int fd, bool is_unix); void rescue_timers(void); void safe_evtimer_add(struct event *ev, struct timeval *tv); /* log truncated strings */ #define safe_strcpy(dst, src, dstlen) do { \ size_t needed = strlcpy(dst, src, dstlen); \ if (unlikely(needed >= (dstlen))) \ log_warning("bug in %s:%d - string truncated", __FILE__, __LINE__); \ } while (0) pgbouncer-1.5.4/include/pooler.h0000644000175000017500000000225011765176015013532 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void pooler_setup(void); bool use_pooler_socket(int fd, bool is_unix) _MUSTCHECK; void resume_pooler(void); void suspend_pooler(void); void per_loop_pooler_maint(void); void pooler_tune_accept(bool on); typedef bool (*pooler_cb)(void *arg, int fd, const PgAddr *addr); bool for_each_pooler_fd(pooler_cb cb, void *arg); pgbouncer-1.5.4/include/admin.h0000644000175000017500000000246012013151606013307 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ bool admin_handle_client(PgSocket *client, PktHdr *pkt) _MUSTCHECK; bool admin_pre_login(PgSocket *client) _MUSTCHECK; void admin_setup(void); bool admin_error(PgSocket *console, const char *fmt, ...) _PRINTF(2, 3) /* _MUSTCHECK */; void admin_pause_done(void); bool admin_flush(PgSocket *admin, PktBuf *buf, const char *desc) /* _MUSTCHECK */; bool admin_ready(PgSocket *admin, const char *desc) _MUSTCHECK; void admin_handle_cancel(PgSocket *client); pgbouncer-1.5.4/include/server.h0000644000175000017500000000166712013151606013535 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ bool server_proto(SBuf *sbuf, SBufEvent evtype, struct MBuf *pkt) _MUSTCHECK; pgbouncer-1.5.4/include/system.h0000644000175000017500000000340711765176015013563 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Required system headers */ #include #include #ifdef WIN32 #include "win32support.h" #endif #include #include #include #ifdef HAVE_CRYPT_H #include #endif #ifdef HAVE_LIBGEN_H #include #endif #ifdef HAVE_SYS_UIO_H #include #endif #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX 128 /* actual sizeof() will be applied later anyway */ #endif /* * PostgreSQL type OIDs for resultsets. */ #define INT8OID 20 #define INT4OID 23 #define TEXTOID 25 /* * libc compat functions. */ #ifndef HAVE_CRYPT static inline char *crypt(const char *p, const char *s) { return NULL; } #endif #ifndef HAVE_LSTAT static inline int lstat(const char *path, struct stat *st) { return stat(path, st); } #endif void change_user(const char *user); void change_file_mode(const char *fn, mode_t mode, const char *user, const char *group); pgbouncer-1.5.4/include/objects.h0000644000175000017500000000635412013151606013656 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ extern struct StatList user_list; extern struct AATree user_tree; extern struct StatList pool_list; extern struct StatList database_list; extern struct StatList autodatabase_idle_list; extern struct StatList login_client_list; extern struct Slab *client_cache; extern struct Slab *server_cache; extern struct Slab *db_cache; extern struct Slab *pool_cache; extern struct Slab *user_cache; extern struct Slab *iobuf_cache; PgDatabase *find_database(const char *name); PgUser *find_user(const char *name); PgPool *get_pool(PgDatabase *, PgUser *); bool find_server(PgSocket *client) _MUSTCHECK; bool release_server(PgSocket *server) /* _MUSTCHECK */; bool finish_client_login(PgSocket *client) _MUSTCHECK; bool check_fast_fail(PgSocket *client) _MUSTCHECK; PgSocket *accept_client(int sock, bool is_unix) _MUSTCHECK; void disconnect_server(PgSocket *server, bool notify, const char *reason, ...) _PRINTF(3, 4); void disconnect_client(PgSocket *client, bool notify, const char *reason, ...) _PRINTF(3, 4); PgDatabase * add_database(const char *name) _MUSTCHECK; PgDatabase *register_auto_database(const char *name); PgUser * add_user(const char *name, const char *passwd) _MUSTCHECK; PgUser * force_user(PgDatabase *db, const char *username, const char *passwd) _MUSTCHECK; void accept_cancel_request(PgSocket *req); void forward_cancel_request(PgSocket *server); void launch_new_connection(PgPool *pool); bool use_client_socket(int fd, PgAddr *addr, const char *dbname, const char *username, uint64_t ckey, int oldfd, int linkfd, const char *client_end, const char *std_string, const char *datestyle, const char *timezone) _MUSTCHECK; bool use_server_socket(int fd, PgAddr *addr, const char *dbname, const char *username, uint64_t ckey, int oldfd, int linkfd, const char *client_end, const char *std_string, const char *datestyle, const char *timezone) _MUSTCHECK; void activate_client(PgSocket *client); void change_client_state(PgSocket *client, SocketState newstate); void change_server_state(PgSocket *server, SocketState newstate); int get_active_client_count(void); int get_active_server_count(void); void tag_database_dirty(PgDatabase *db); void tag_autodb_dirty(void); void tag_host_addr_dirty(const char *host, const struct sockaddr *sa); void for_each_server(PgPool *pool, void (*func)(PgSocket *sk)); void reuse_just_freed_objects(void); void init_objects(void); void init_caches(void); pgbouncer-1.5.4/include/client.h0000644000175000017500000000201612013151606013472 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ bool client_proto(SBuf *sbuf, SBufEvent evtype, struct MBuf *pkt) _MUSTCHECK; bool set_pool(PgSocket *client, const char *dbname, const char *username) _MUSTCHECK; pgbouncer-1.5.4/include/iobuf.h0000644000175000017500000001040212006550770013325 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Temporary buffer for single i/o. * * Pattern: * * iobuf_get_and_reset() * start: * iobuf_recv() * loop: * if (new_pkt) * iobuf_parse() * * if (send) { * iobuf_tag_send() * } else { * send_pending() * iobuf_tag_skip() * } * if (more-unparsed) * goto loop; * send_pending(); */ /* * 0 .. done_pos -- sent * done_pos .. parse_pos -- parsed, to send * parse_pos .. recv_pos -- received, to parse */ struct iobuf { unsigned done_pos; unsigned parse_pos; unsigned recv_pos; uint8_t buf[FLEX_ARRAY]; }; typedef struct iobuf IOBuf; static inline bool iobuf_sane(const IOBuf *io) { return (io == NULL) || ( io->parse_pos >= io->done_pos && io->recv_pos >= io->parse_pos && (unsigned)cf_sbuf_len >= io->recv_pos); } static inline bool iobuf_empty(const IOBuf *io) { return io == NULL || io->done_pos == io->recv_pos; } /* unsent amount */ static inline unsigned iobuf_amount_pending(const IOBuf *buf) { return buf->parse_pos - buf->done_pos; } /* max possible to parse (tag_send/tag_skip) */ static inline unsigned iobuf_amount_parse(const IOBuf *buf) { return buf->recv_pos - buf->parse_pos; } /* max possible to recv */ static inline unsigned iobuf_amount_recv(const IOBuf *buf) { return cf_sbuf_len - buf->recv_pos; } /* put all unparsed to mbuf */ static inline unsigned iobuf_parse_all(const IOBuf *buf, struct MBuf *mbuf) { unsigned avail = iobuf_amount_parse(buf); const uint8_t *pos = buf->buf + buf->parse_pos; mbuf_init_fixed_reader(mbuf, pos, avail); return avail; } /* put all unparsed to mbuf, with size limit */ static inline unsigned iobuf_parse_limit(const IOBuf *buf, struct MBuf *mbuf, unsigned limit) { unsigned avail = iobuf_amount_parse(buf); const uint8_t *pos = buf->buf + buf->parse_pos; if (avail > limit) avail = limit; mbuf_init_fixed_reader(mbuf, pos, avail); return avail; } /* recv */ static inline int _MUSTCHECK iobuf_recv_limit(IOBuf *io, int fd, unsigned len) { uint8_t *pos = io->buf + io->recv_pos; int got; unsigned avail = iobuf_amount_recv(io); if (len > avail) len = avail; Assert(len > 0); got = safe_recv(fd, pos, len, 0); if (got > 0) io->recv_pos += got; return got; } static inline int _MUSTCHECK iobuf_recv_max(IOBuf *io, int fd) { return iobuf_recv_limit(io, fd, iobuf_amount_recv(io)); } /* send tagged data */ static inline int _MUSTCHECK iobuf_send_pending(IOBuf *io, int fd) { uint8_t *pos = io->buf + io->done_pos; int len, res; len = io->parse_pos - io->done_pos; Assert(len > 0); res = safe_send(fd, pos, len, 0); if (res > 0) io->done_pos += res; return res; } static inline void iobuf_tag_send(IOBuf *io, unsigned len) { Assert(len > 0 && len <= iobuf_amount_parse(io)); io->parse_pos += len; } static inline void iobuf_tag_skip(IOBuf *io, unsigned len) { Assert(io->parse_pos == io->done_pos); /* no send pending */ Assert(len > 0 && len <= iobuf_amount_parse(io)); io->parse_pos += len; io->done_pos = io->parse_pos; } static inline void iobuf_try_resync(IOBuf *io, unsigned small_pkt) { unsigned avail = io->recv_pos - io->done_pos; if (avail == 0) { if (io->recv_pos > 0) io->recv_pos = io->parse_pos = io->done_pos = 0; } else if (avail <= small_pkt && io->done_pos > 0) { memmove(io->buf, io->buf + io->done_pos, avail); io->parse_pos -= io->done_pos; io->recv_pos = avail; io->done_pos = 0; } } static inline void iobuf_reset(IOBuf *io) { io->recv_pos = io->parse_pos = io->done_pos = 0; } pgbouncer-1.5.4/include/proto.h0000644000175000017500000000407512006550770013375 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * parsed packet header, plus whatever data is * available in SBuf for this packet. * * if (pkt->len == mbuf_avail(&pkt->data)) * packet is fully in buffer * * get_header() points pkt->data.pos after header. * to packet body. */ struct PktHdr { unsigned type; unsigned len; struct MBuf data; }; bool get_header(struct MBuf *data, PktHdr *pkt) _MUSTCHECK; bool send_pooler_error(PgSocket *client, bool send_ready, const char *msg) /*_MUSTCHECK*/; void log_server_error(const char *note, PktHdr *pkt); void parse_server_error(PktHdr *pkt, const char **level_p, const char **msg_p); bool add_welcome_parameter(PgPool *pool, const char *key, const char *val) _MUSTCHECK; void finish_welcome_msg(PgSocket *server); bool welcome_client(PgSocket *client) _MUSTCHECK; bool answer_authreq(PgSocket *server, PktHdr *pkt) _MUSTCHECK; bool send_startup_packet(PgSocket *server) _MUSTCHECK; int scan_text_result(struct MBuf *pkt, const char *tupdesc, ...) _MUSTCHECK; /* is packet completely in our buffer */ static inline bool incomplete_pkt(const PktHdr *pkt) { return mbuf_written(&pkt->data) != pkt->len; } /* one char desc */ static inline char pkt_desc(const PktHdr *pkt) { return pkt->type > 256 ? '!' : pkt->type; } pgbouncer-1.5.4/include/stats.h0000644000175000017500000000204711765176015013374 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void stats_setup(void); bool admin_database_stats(PgSocket *client, struct StatList *pool_list) _MUSTCHECK; bool show_stat_totals(PgSocket *client, struct StatList *pool_list) _MUSTCHECK; pgbouncer-1.5.4/include/varcache.h0000644000175000017500000000100311765176015014001 00000000000000 enum VarCacheIdx { VDateStyle = 0, VClientEncoding, VTimeZone, VStdStr, VAppName, NumVars }; typedef struct VarCache VarCache; struct VarCache { struct PStr *var_list[NumVars]; }; bool varcache_set(VarCache *cache, const char *key, const char *value) /* _MUSTCHECK */; bool varcache_apply(PgSocket *server, PgSocket *client, bool *changes_p) _MUSTCHECK; void varcache_fill_unset(VarCache *src, PgSocket *dst); void varcache_clean(VarCache *cache); void varcache_add_params(PktBuf *pkt, VarCache *vars); pgbouncer-1.5.4/include/janitor.h0000644000175000017500000000205411765176015013702 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void janitor_setup(void); void config_postprocess(void); void resume_all(void); void per_loop_maint(void); bool suspend_socket(PgSocket *sk, bool force) _MUSTCHECK; void kill_pool(PgPool *pool); pgbouncer-1.5.4/include/pktbuf.h0000644000175000017500000001024612006550770013522 00000000000000/* * PgBouncer - Lightweight connection pooler for PostgreSQL. * * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Safe & easy creation of PostgreSQL packets. */ typedef struct PktBuf PktBuf; struct PktBuf { uint8_t *buf; int buf_len; int write_pos; int pktlen_pos; int send_pos; struct event *ev; unsigned failed:1; unsigned sending:1; unsigned fixed_buf:1; }; /* * pktbuf creation */ PktBuf *pktbuf_dynamic(int start_len) _MUSTCHECK; void pktbuf_static(PktBuf *buf, uint8_t *data, int len); void pktbuf_free(PktBuf *buf); void pktbuf_reset(struct PktBuf *pkt); struct PktBuf *pktbuf_temp(void); /* * sending */ bool pktbuf_send_immediate(PktBuf *buf, PgSocket *sk) _MUSTCHECK; bool pktbuf_send_queued(PktBuf *buf, PgSocket *sk) _MUSTCHECK; /* * low-level ops */ void pktbuf_start_packet(PktBuf *buf, int type); void pktbuf_put_char(PktBuf *buf, char val); void pktbuf_put_uint16(PktBuf *buf, uint16_t val); void pktbuf_put_uint32(PktBuf *buf, uint32_t val); void pktbuf_put_uint64(PktBuf *buf, uint64_t val); void pktbuf_put_string(PktBuf *buf, const char *str); void pktbuf_put_bytes(PktBuf *buf, const void *data, int len); void pktbuf_finish_packet(PktBuf *buf); #define pktbuf_written(buf) ((buf)->write_pos) /* * Packet writing */ void pktbuf_write_generic(PktBuf *buf, int type, const char *fmt, ...); void pktbuf_write_RowDescription(PktBuf *buf, const char *tupdesc, ...); void pktbuf_write_DataRow(PktBuf *buf, const char *tupdesc, ...); /* * Shortcuts for actual packets. */ #define pktbuf_write_ParameterStatus(buf, key, val) \ pktbuf_write_generic(buf, 'S', "ss", key, val) #define pktbuf_write_AuthenticationOk(buf) \ pktbuf_write_generic(buf, 'R', "i", 0) #define pktbuf_write_ReadyForQuery(buf) \ pktbuf_write_generic(buf, 'Z', "c", 'I') #define pktbuf_write_CommandComplete(buf, desc) \ pktbuf_write_generic(buf, 'C', "s", desc) #define pktbuf_write_BackendKeyData(buf, key) \ pktbuf_write_generic(buf, 'K', "b", key, 8) #define pktbuf_write_CancelRequest(buf, key) \ pktbuf_write_generic(buf, PKT_CANCEL, "b", key, 8) #define pktbuf_write_StartupMessage(buf, user, parms, parms_len) \ pktbuf_write_generic(buf, PKT_STARTUP, "bsss", parms, parms_len, "user", user, "") #define pktbuf_write_PasswordMessage(buf, psw) \ pktbuf_write_generic(buf, 'p', "s", psw) #define pktbuf_write_Notice(buf, msg) \ pktbuf_write_generic(buf, 'N', "sscss", "SNOTICE", "C00000", 'M', msg, ""); /* * Shortcut for creating DataRow in memory. */ #define BUILD_DataRow(reslen, dst, dstlen, args...) do { \ PktBuf _buf; \ pktbuf_static(&_buf, dst, dstlen); \ pktbuf_write_DataRow(&_buf, ## args); \ reslen = _buf.failed ? -1 : _buf.write_pos; \ } while (0) /* * Shortcuts for immediate send of one packet. */ #define SEND_wrap(buflen, pktfn, res, sk, args...) do { \ uint8_t _data[buflen]; PktBuf _buf; \ pktbuf_static(&_buf, _data, sizeof(_data)); \ pktfn(&_buf, ## args); \ res = pktbuf_send_immediate(&_buf, sk); \ } while (0) #define SEND_RowDescription(res, sk, args...) \ SEND_wrap(512, pktbuf_write_RowDescription, res, sk, ## args) #define SEND_generic(res, sk, args...) \ SEND_wrap(512, pktbuf_write_generic, res, sk, ## args) #define SEND_ReadyForQuery(res, sk) \ SEND_wrap(8, pktbuf_write_ReadyForQuery, res, sk) #define SEND_CancelRequest(res, sk, key) \ SEND_wrap(16, pktbuf_write_CancelRequest, res, sk, key) #define SEND_PasswordMessage(res, sk, psw) \ SEND_wrap(512, pktbuf_write_PasswordMessage, res, sk, psw) pgbouncer-1.5.4/configure.ac0000644000175000017500000000701712055406023012716 00000000000000dnl Process this file with autoconf to produce a configure script. AC_INIT(pgbouncer, 1.5.4) AC_CONFIG_SRCDIR(src/janitor.c) AC_CONFIG_HEADER(lib/usual/config.h) AC_PREREQ([2.59]) dnl basic init AC_USUAL_INIT dnl Checks for programs. AC_USUAL_PROGRAM_CHECK dnl asciidoc >= 8.4 AC_CHECK_PROGS(ASCIIDOC, asciidoc) if test -n "$ASCIIDOC"; then AC_MSG_CHECKING([for asciidoc version >= 8.4]) ver=`$ASCIIDOC --version 2>&1 | sed -e 's/asciidoc //'` case "$ver" in dnl hack to make possible to use [, ] in regex changequote({, })dnl [0-7].*|8.[0-3]|8.[0-3].*) changequote([, ])dnl AC_MSG_RESULT([$ver, too old]) ASCIIDOC="" ;; *) AC_MSG_RESULT([$ver, ok]) ;; esac fi dnl check for xmlto, but only if asciidoc is found if test -n "$ASCIIDOC"; then AC_CHECK_PROGS(XMLTO, xmlto) fi dnl check for windows tools if test "$PORTNAME" = "win32"; then AC_CHECK_TOOL([WINDRES], [windres]) AC_CHECK_TOOL([DLLWRAP], [dllwrap]) AC_CHECK_TOOL([DLLTOOL], [dlltool]) fi AC_CHECK_TOOL([STRIP], [strip]) dnl Checks for header files. AC_USUAL_HEADER_CHECK AC_CHECK_HEADERS([crypt.h]) AC_CHECK_HEADERS([sys/resource.h sys/wait.h]) dnl Checks for typedefs, structures, and compiler characteristics. AC_USUAL_TYPE_CHECK dnl autoconf 2.59 does not have UINT macros nor docdir m4_ifdef([AC_TYPE_UINT8_T], [ AC_TYPE_UINT8_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T ], [ datarootdir='${prefix}/share' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' AC_SUBST(datarootdir) AC_SUBST(docdir) ]) dnl Checks for library functions. AC_USUAL_FUNCTION_CHECK AC_SEARCH_LIBS(crypt, crypt) AC_SEARCH_LIBS(clock_gettime, rt) AC_SEARCH_LIBS(getsockname, socket) AC_SEARCH_LIBS(gethostbyname, nsl) AC_SEARCH_LIBS(hstrerror, resolv) AC_CHECK_FUNCS(crypt lstat) dnl Find libevent AC_USUAL_LIBEVENT dnl Find libudns use_udns=no AC_MSG_CHECKING([whether to use libudns]) AC_ARG_WITH(udns, AC_HELP_STRING([--with-udns=prefix],[Specify where udns is installed]), [ if test "$withval" = "no"; then use_udns=no elif test "$withval" = "yes"; then use_udns=yes else use_udns=yes CPPFLAGS="$CPPFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib" fi ], []) AC_MSG_RESULT([$use_udns]) if test "$use_udns" = "yes"; then AC_DEFINE(USE_UDNS, 1, [Use UDNS for name resolution.]) LIBS="-ludns $LIBS" AC_MSG_CHECKING([whether libudns is available]) AC_LINK_IFELSE([AC_LANG_SOURCE([ #include #include #include #include int main(void) { struct dns_ctx *ctx = NULL; dns_init(ctx, 0); dns_reset(ctx); } ])], [AC_MSG_RESULT([found])], [AC_MSG_ERROR([not found, cannot proceed])]) else # !udns dnl On libevent 2.x use evdns by default use_evdns=no if test "$ac_cv_func_evdns_base_new" = "yes"; then use_evdns=yes fi dnl Allow user to override the decision AC_ARG_ENABLE(evdns, AC_HELP_STRING([--enable-evdns],[Use libevent for DNS lookups (default on libevent 2.x)]), [use_evdns=$enableval]) AC_MSG_CHECKING([whether to use libevent for DNS lookups]) if test "$use_evdns" = "yes"; then AC_DEFINE(USE_EVDNS, 1, [Use libevent for DNS lookups.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi dnl Check if need getaddinfo_a compat if test "$use_evdns" = no; then AC_USUAL_GETADDRINFO_A fi fi # !udns AC_USUAL_DEBUG AC_USUAL_CASSERT AC_USUAL_WERROR dnl Output findings AC_OUTPUT([config.mak]) dnl If separate build dir, link Makefile over test -f Makefile || { echo "Linking Makefile" ln -s $srcdir/Makefile } pgbouncer-1.5.4/install-sh0000755000175000017500000003253712055406554012452 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: pgbouncer-1.5.4/doc/0000755000175000017500000000000012055406736011263 500000000000000pgbouncer-1.5.4/doc/faq.txt0000644000175000017500000001507411765176015012523 00000000000000 = PgBouncer FAQ = == How to connect to PgBouncer? == PgBouncer acts as Postgres server, so simply point your client to PgBouncer port. == How to load-balance queries between several servers? == 1. Use a TCP connection load-balancer. Either http://www.linuxvirtualserver.org/[LVS] or http://haproxy.1wt.eu/[HAProxy] seem to be good choices. On PgBouncer side it may be good idea to make `server_lifetime` smaller and also turn `server_round_robin` on - by default idle connections are reused by LIFO algorithm which may work not so well when load-balancing is needed. 2. DNS round-robin. Use several IPs behind one DNS name. PgBouncer does not look up DNS each time new connection is launched. Instead it caches all IPs and does round-robin internally. Note: if there is more than 8 IPs behind one name, the DNS backend must support EDNS0 protocol. See README for details. == How to use SSL connections with PgBouncer? == Use http://www.stunnel.org/[Stunnel]. Since version 4.27 it supports PostgreSQL protocol for both client and server side. It is activated by setting `protocol=pgsql`. For older 4.2x versions the support code is available as patch: http://pgbouncer.projects.postgresql.org/patches/stunnel-postgres.diff[stunnel-postgres.diff] Alternative is to use Stunnel on both sides of connection, then the protocol support is not needed. == How to use prepared statements with session pooling? == In session pooling mode, the reset query must clean old prepared statements. === Cleaning prepared statements on PostgreSQL 8.3 and newer === This is easy - just set `server_reset_query = DISCARD ALL;` or at least to `DEALLOCATE ALL;` === Cleaning prepared statements on PostgreSQL 8.2 and older === This is problematic as older versions of PostgreSQL do not allow easy way to drop prepared statements. Luckily there is system view that shows prepared plans in current session. So as a workaround following function can be created: ---------------- CREATE OR REPLACE FUNCTION deallocate_all() RETURNS void AS $$ DECLARE sql text; BEGIN FOR sql IN SELECT 'deallocate ' || quote_ident(name) FROM pg_catalog.pg_prepared_statements LOOP EXECUTE sql; END LOOP; END; $$ LANGUAGE plpgsql; ---------------- Then the `server_reset_query` can be set to call it: ---------------- server_reset_query = RESET ALL; SET SESSION AUTHORIZATION DEFAULT; SELECT deallocate_all(); ---------------- == How to use prepared statements with transaction pooling? == To make prepared statements work in this mode would need PgBouncer to keep track of them internally, which it does not do. So only way to keep using PgBouncer in this mode is to disable prepared statements in the client. === Disabling prepared statements in JDBC === The proper way to do it for JDBC is adding `prepareThreshold=0` parameter to connect string. But current JDBC code ignores the setting for BEGIN/COMMIT/ROLLBACK statements and still tries to cache their plans. This can be fixed with following patch: http://treehou.se/~omar/postgresql-jdbc-8.4-701-pgbouncer_txn.patch[] described here: http://pgfoundry.org/pipermail/pgbouncer-general/2010-February/000507.html[] === Disabling prepared statements in PHP/PDO === To disable use of server-side prepared statements, the PDO attribute `PDO::ATTR_EMULATE_PREPARES` must be set to `true`. Either at connect-time: ---------------- $db = new PDO("dsn", "user", "pass", array(PDO::ATTR_EMULATE_PREPARES => true)); ---------------- or later: ---------------- $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); ---------------- == How to upgrade PgBouncer without dropping connections? == This is as easy as launching new PgBouncer process with `-R` switch and same config: ---------------- $ pgbouncer -R -d config.ini ---------------- The `-R` (reboot) switch makes new process connect to console of the old process (dbname=pgbouncer) via unix socket and issue following commands: ---------------- SUSPEND; SHOW FDS; SHUTDOWN; ---------------- After that if new one notices old one gone it resumes work with old connections. The magic happens during `SHOW FDS` command which transports actual file descriptors to new process. If the takeover does not work for whatever reason, the new process can be simply killed, old one notices this and resumes work. == What should my server_reset_query be? == This depends on pool mode. But in any case there is no need to put `ROLLBACK;` into it, as PgBouncer never re-uses connections where transaction was left open. If client went away in the middle of transaction, the associated server connection will be simply closed. === Session pooling === ---------------- server_reset_query = DISCARD ALL; ---------------- This will clean everything. === Transaction pooling === ---------------- server_reset_query = ---------------- Yes, empty. In transaction pooling mode the clients should not use any session-based features, so there is no need to clean anything. The `server_reset_query` would only add unnecessary round-trip between transactions and would drop various caches that the next transaction would unnecessarily need to fill again. == How to know which client is on which server connection? == Use SHOW CLIENTS and SHOW SERVERS views on console. 1. Use `ptr` and `link` to map local client connection to server connection. 2. Use `addr` and `port` of client connection to identify TCP connection from client. 3. Use `local_addr` and `local_port` to identify TCP connection to server. === Overview of important fields in SHOW CLIENTS === addr + port:: unique port on client host local_addr + local_port:: pgbouncer port ptr:: unique id for this connection link:: unique id for server connection this is currently linked to === Overview of important fields in SHOW SERVERS === addr + port:: server port this connects to local_addr + local_port:: unique port on pgbouncer host ptr:: unique id for this connection link:: unique id for client connection this is currently linked to == Should PgBouncer be installed on webserver or database server? == It depends. Installing on webserver is good when short-connections are used, then the connection setup latency is minimised - TCP requires couple of packet roundtrips before connection is usable. Installing on database server is good when there are many different hosts (eg. webservers) connecting to it, then their connections can be optimised together. It is also possible to install PgBouncer on both webserver and database servers. Only negative aspect of that is that each PgBouncer hop adds small amount of latency to each query. So it's probably best to simply test whether the payoff is worth the cost. pgbouncer-1.5.4/doc/pgbouncer.50000644000175000017500000005563212043260171013254 00000000000000'\" t .\" Title: pgbouncer .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 10/28/2012 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" .TH "PGBOUNCER" "5" "10/28/2012" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" pgbouncer \- Lightweight connection pooler for PostgreSQL\&. .SH "SYNOPSIS" .sp .nf [databases] db = \&.\&.\&. .fi .sp .nf [pgbouncer] \&.\&.\&. .fi .SH "DESCRIPTION" .sp Config file is in "ini" format\&. Section names are between " and "\&. Lines starting with ";" or "" are taken as comments and ignored\&. The characters ";" and "" are not recognized when they appear later in the line\&. .SH "SECTION [PGBOUNCER]" .SS "Generic settings" .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBlogfile\fR .RS 4 .sp Specifies log file\&. Log file is kept open so after rotation kill \-HUP or on console RELOAD; should be done\&. Note: On Windows machines, the service must be stopped and started\&. .sp Default: not set\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBpidfile\fR .RS 4 .sp Specifies the pid file\&. Without a pidfile, daemonization is not allowed\&. .sp Default: not set\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBlisten_addr\fR .RS 4 .sp Specifies list of addresses, where to listen for TCP connections\&. You may also use * meaning "listen on all addresses"\&. When not set, only Unix socket connections are allowed\&. .sp Addresses can be specified numerically (IPv4/IPv6) or by name\&. .sp Default: not set .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBlisten_port\fR .RS 4 .sp Which port to listen on\&. Applies to both TCP and Unix sockets\&. .sp Default: 6432 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBunix_socket_dir\fR .RS 4 .sp Specifies location for Unix sockets\&. Applies to both listening socket and server connections\&. If set to an empty string, Unix sockets are disabled\&. Required for online reboot (\-R) to work\&. Note: Not supported on Windows machines\&. .sp Default: /tmp .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBunix_socket_mode\fR .RS 4 .sp Filesystem mode for unix socket\&. .sp Default: 0777 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBunix_socket_group\fR .RS 4 .sp Group name to use for unix socket\&. .sp Default: not set .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBuser\fR .RS 4 .sp If set, specifies the Unix user to change to after startup\&. Works only if PgBouncer is started as root or if user is the same as the current user\&. Note: Not supported on Windows machines\&. .sp Default: not set .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBauth_file\fR .RS 4 .sp The name of the file to load user names and passwords from\&. The file format is the same as the PostgreSQL pg_auth/pg_pwd file, so this setting can be pointed directly to one of those backend files\&. .sp Default: not set\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBauth_type\fR .RS 4 .sp How to authenticate users\&. .PP md5 .RS 4 Use MD5\-based password check\&. auth_file may contain both MD5\-encrypted or plain\-text passwords\&. This is the default authentication method\&. .RE .PP crypt .RS 4 Use crypt(3) based password check\&. auth_file must contain plain\-text passwords\&. .RE .PP plain .RS 4 Clear\-text password is sent over wire\&. .RE .PP trust .RS 4 No authentication is done\&. Username must still exist in auth_file\&. .RE .PP any .RS 4 Like the trust method, but the username given is ignored\&. Requires that all databases are configured to log in as specific user\&. Additionally, the console database allows any user to log in as admin\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBpool_mode\fR .RS 4 .sp Specifies when a server connection can be reused by other clients\&. .PP session .RS 4 Server is released back to pool after client disconnects\&. Default\&. .RE .PP transaction .RS 4 Server is released back to pool after transaction finishes\&. .RE .PP statement .RS 4 Server is released back to pool after query finishes\&. Long transactions spanning multiple statements are disallowed in this mode\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBmax_client_conn\fR .RS 4 .sp Maximum number of client connections allowed\&. When increased then the file descriptor limits should also be increased\&. Note that actual number of file descriptors used is more than max_client_conn\&. Theoretical maximum used is: .sp .if n \{\ .RS 4 .\} .nf max_client_conn + (max_pool_size * total_databases * total_users) .fi .if n \{\ .RE .\} .sp if each user connects under its own username to server\&. If a database user is specified in connect string (all users connect under same username), the theoretical maximum is: .sp .if n \{\ .RS 4 .\} .nf max_client_conn + (max_pool_size * total_databases) .fi .if n \{\ .RE .\} .sp The theoretical maximum should be never reached, unless somebody deliberately crafts special load for it\&. Still, it means you should set the number of file descriptors to a safely high number\&. .sp Search for ulimit in your favourite shell man page\&. Note: ulimit does not apply in a Windows environment\&. .sp Default: 100 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBdefault_pool_size\fR .RS 4 .sp How many server connections to allow per user/database pair\&. Can be overridden in the per\-database configuration\&. .sp Default: 20 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBmin_pool_size\fR .RS 4 .sp Add more server connections to pool if below this number\&. Improves behaviour when usual load comes suddenly back after period of total inactivity\&. .sp Default: 0 (disabled) .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBreserve_pool_size\fR .RS 4 .sp How many additional connections to allow to a pool\&. 0 disables\&. .sp Default: 0 (disabled) .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBreserve_pool_timeout\fR .RS 4 .sp If a client has not been serviced in this many seconds, pgbouncer enables use of additional connections from reserve pool\&. 0 disables\&. .sp Default: 5\&.0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBserver_round_robin\fR .RS 4 .sp By default, pgbouncer reuses server connections in LIFO (last\-in, first\-out) manner, so that few connections get the most load\&. This gives best performance if you have a single server serving a database\&. But if there is TCP round\-robin behind a database IP, then it is better if pgbouncer also uses connections in that manner, thus achieving uniform load\&. .sp Default: 0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBignore_startup_parameters\fR .RS 4 .sp By default, PgBouncer allows only parameters it can keep track of in startup packets \- client_encoding, datestyle, timezone and standard_conforming_strings\&. .sp All others parameters will raise an error\&. To allow others parameters, they can be specified here, so that pgbouncer knows that they are handled by admin and it can ignore them\&. .sp Default: empty .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBdisable_pqexec\fR .RS 4 .sp Disable Simple Query protocol (PQexec)\&. Unlike Extended Query protocol, Simple Query allows multiple queries in one packet, which allows some classes of SQL\-injection attacks\&. Disabling it can improve security\&. Obviously this means only clients that exclusively use Extended Query protocol will stay working\&. .sp Default: 0 .RE .SS "Log settings" .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBsyslog\fR .RS 4 .sp Toggles syslog on/off As for windows environment, eventlog is used instead\&. .sp Default: 0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBsyslog_ident\fR .RS 4 .sp Under what name to send logs to syslog\&. .sp Default: pgbouncer (program name) .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBsyslog_facility\fR .RS 4 .sp Under what facility to send logs to syslog\&. Possibilities: auth, authpriv, daemon, user, local0\-7 .sp Default: daemon .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBlog_connections\fR .RS 4 .sp Log successful logins\&. .sp Default: 1 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBlog_disconnections\fR .RS 4 .sp Log disconnections with reasons\&. .sp Default: 1 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBlog_pooler_errors\fR .RS 4 .sp Log error messages pooler sends to clients\&. .sp Default: 1 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBstats_period\fR .RS 4 .sp Period for writing aggregated stats into log\&. .sp Default: 60 .RE .SS "Console access control" .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBadmin_users\fR .RS 4 .sp Comma\-separated list of database users that are allowed to connect and run all commands on console\&. Ignored when auth_mode=any, in which case any username is allowed in as admin\&. .sp Default: empty .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBstats_users\fR .RS 4 .sp Comma\-separated list of database users that are allowed to connect and run read\-only queries on console\&. Thats means all SHOW commands except SHOW FDS\&. .sp Default: empty\&. .RE .SS "Connection sanity checks, timeouts" .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBserver_reset_query\fR .RS 4 .sp Query sent to server on connection release, before making it available to other clients\&. At that moment no transaction is in progress so it should not include ABORT or ROLLBACK\&. .sp A good choice for Postgres 8\&.2 and below is: .sp .if n \{\ .RS 4 .\} .nf server_reset_query = RESET ALL; SET SESSION AUTHORIZATION DEFAULT; .fi .if n \{\ .RE .\} .sp for 8\&.3 and above its enough to do: .sp .if n \{\ .RS 4 .\} .nf server_reset_query = DISCARD ALL; .fi .if n \{\ .RE .\} .sp When transaction pooling is used, the server_reset_query should be empty, as clients should not use any session features\&. .sp Default: DISCARD ALL .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBserver_check_delay\fR .RS 4 .sp How long to keep released connections available for immediate re\-use, without running sanity\-check queries on it\&. If 0 then the query is ran always\&. .sp Default: 30\&.0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBserver_check_query\fR .RS 4 .sp Simple do\-nothing query to check if the server connection is alive\&. .sp If an empty string, then sanity checking is disabled\&. .sp Default: SELECT 1; .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBserver_lifetime\fR .RS 4 .sp The pooler will try to close server connections that have been connected longer than this\&. Setting it to 0 means the connection is to be used only once, then closed\&. [seconds] .sp Default: 3600\&.0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBserver_idle_timeout\fR .RS 4 .sp If a server connection has been idle more than this many seconds it will be dropped\&. If 0 then timeout is disabled\&. [seconds] .sp Default: 600\&.0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBserver_connect_timeout\fR .RS 4 .sp If connection and login won\(cqt finish in this amount of time, the connection will be closed\&. [seconds] .sp Default: 15\&.0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBserver_login_retry\fR .RS 4 .sp If login failed, because of failure from connect() or authentication that pooler waits this much before retrying to connect\&. [seconds] .sp Default: 15\&.0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBclient_login_timeout\fR .RS 4 .sp If a client connects but does not manage to login in this amount of time, it will be disconnected\&. Mainly needed to avoid dead connections stalling SUSPEND and thus online restart\&. [seconds] .sp Default: 60\&.0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBautodb_idle_timeout\fR .RS 4 .sp If the automatically created (via "*") database pools have been unused this many seconds, they are freed\&. The negative aspect of that is that their statistics are also forgotten\&. [seconds] .sp Default: 3600\&.0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBdns_max_ttl\fR .RS 4 .sp How long the DNS lookups can be cached\&. If a DNS lookup returns several answers, pgbouncer will robin\-between them in the meantime\&. Actual DNS TTL is ignored\&. [seconds] .sp Default: 15\&.0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBdns_zone_check_period\fR .RS 4 .sp Period to check if zone serial has changed\&. .sp PgBouncer can collect dns zones from hostnames (everything after first dot) and then periodically check if zone serial changes\&. If it notices changes, all hostnames under that zone are looked up again\&. If any host ip changes, it\(cqs connections are invalidated\&. .sp Works only with UDNS backend (\-\-with\-udns to configure)\&. .sp Default: 0\&.0 (disabled) .RE .SS "Dangerous timeouts" .sp Setting following timeouts cause unexpected errors\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBquery_timeout\fR .RS 4 .sp Queries running longer than that are canceled\&. This should be used only with slightly smaller server\-side statement_timeout, to apply only for network problems\&. [seconds] .sp Default: 0\&.0 (disabled) .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBquery_wait_timeout\fR .RS 4 .sp Maximum time queries are allowed to spend waiting for execution\&. If the query is not assigned to a server during that time, the client is disconnected\&. This is used to prevent unresponsive servers from grabbing up connections\&. [seconds] .sp Default: 0\&.0 (disabled) .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBclient_idle_timeout\fR .RS 4 .sp Client connections idling longer than this many seconds are closed\&. This should be larger than the client\-side connection lifetime settings, and only used for network problems\&. [seconds] .sp Default: 0\&.0 (disabled) .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBidle_transaction_timeout\fR .RS 4 .sp If client has been in "idle in transaction" state longer, it will be disconnected\&. [seconds] .sp Default: 0\&.0 (disabled) .RE .SS "Low\-level network settings" .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBpkt_buf\fR .RS 4 .sp Internal buffer size for packets\&. Affects size of TCP packets sent and general memory usage\&. Actual libpq packets can be larger than this so, no need to set it large\&. .sp Default: 2048 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBmax_packet_size\fR .RS 4 .sp Maximum size for Postgres packets that PgBouncer allows through\&. One packet is either one query or one resultset row\&. Full resultset can be larger\&. .sp Default: 2147483647 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBlisten_backlog\fR .RS 4 .sp Backlog argument for listen(2)\&. Determines how many new unanswered connection attempts are kept in queue\&. When queue is full, further new connections are dropped\&. .sp Default: 128 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBsbuf_loopcnt\fR .RS 4 .sp How many times to process data on one connection, before proceeding\&. Without this limit, one connection with a big resultset can stall PgBouncer for a long time\&. One loop processes one pkt_buf amount of data\&. 0 means no limit\&. .sp Default: 5 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBtcp_defer_accept\fR .RS 4 .sp For details on this and other tcp options, please see man 7 tcp\&. .sp Default: 45 on Linux, otherwise 0 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBtcp_socket_buffer\fR .RS 4 .sp Default: not set .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBtcp_keepalive\fR .RS 4 .sp Turns on basic keepalive with OS defaults\&. .sp On Linux, the system defaults are tcp_keepidle=7200, tcp_keepintvl=75, tcp_keepcnt=9\&. They are probably similar on other OS\-es\&. .sp Default: 1 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBtcp_keepcnt\fR .RS 4 .sp Default: not set .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBtcp_keepidle\fR .RS 4 .sp Default: not set .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBtcp_keepintvl\fR .RS 4 .sp Default: not set .RE .SH "SECTION [DATABASES]" .sp This contains key=value pairs where key will be taken as a database name and value as a libpq connect\-string style list of key=value pairs\&. As actual libpq is not used, so not all features from libpq can be used (service=, \&.pgpass)\&. .sp Database name can contain characters [0\-9A\-Za\-z_\&.\-] without quoting\&. Names that contain other chars need to be quoted with standard SQL ident quoting: double quotes where "" is taken as single quote\&. .sp "*" acts as fallback database: if the exact name does not exist, its value is taken as connect string for requested database\&. Such automatically created database entries are cleaned up if they stay idle longer then the time specified in autodb_idle_timeout parameter\&. .SS "Location parameters" .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBdbname\fR .RS 4 .sp Destination database name\&. .sp Default: same as client\-side database name\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBhost\fR .RS 4 .sp Hostname or IP address to connect to\&. Hostnames are resolved on connect time, the result is cached per dns_max_ttl parameter\&. If DNS returns several results, they are used in round\-robin manner\&. .sp Default: not set, meaning to use a Unix socket\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBport\fR .RS 4 .sp Default: 5432 .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBuser, password\fR .RS 4 .sp If user= is set, all connections to the destination database will be done with the specified user, meaning that there will be only one pool for this database\&. .sp Otherwise PgBouncer tries to log into the destination database with client username, meaning that there will be one pool per user\&. .RE .SS "Pool configuration" .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBpool_size\fR .RS 4 .sp Set maximum size of pools for this database\&. If not set, the default_pool_size is used\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBconnect_query\fR .RS 4 .sp Query to be executed after a connection is established, but before allowing the connection to be used by any clients\&. If the query raises errors, they are logged but ignored otherwise\&. .RE .SS "Extra parameters" .sp They allow setting default parameters on server connection\&. .sp Note that since version 1\&.1 PgBouncer tracks client changes for their values, so their use in pgbouncer\&.ini is deprecated now\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBclient_encoding\fR .RS 4 .sp Ask specific client_encoding from server\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBdatestyle\fR .RS 4 .sp Ask specific datestyle from server\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBtimezone\fR .RS 4 .sp Ask specific timezone from server\&. .RE .SH "AUTHENTICATION FILE FORMAT" .sp PgBouncer needs its own user database\&. The users are loaded from a text file in following format: .sp .if n \{\ .RS 4 .\} .nf "username1" "password" \&.\&.\&. "username2" "md5abcdef012342345" \&.\&.\&. .fi .if n \{\ .RE .\} .sp There should be at least 2 fields, surrounded by double quotes\&. The first field is the username and the second is either a plain\-text or a MD5\-hidden password\&. PgBouncer ignores the rest of the line\&. .sp This file format is equivalent to text files used by PostgreSQL 8\&.x for authentication info, thus allowing PgBouncer to work directly on PostgreSQL authentication files in data directory\&. .sp Since PostgreSQL 9\&.0, the text files are not used anymore\&. Thus the auth file needs to be generated\&. See \&./etc/mkauth\&.py for sample script to generate auth file from pg_shadow table\&. .sp PostgreSQL MD5\-hidden password format: .sp .if n \{\ .RS 4 .\} .nf "md5" + md5(password + username) .fi .if n \{\ .RE .\} .sp So user admin with password 1234 will have MD5\-hidden password md545f2603610af569b6155c45067268c6b\&. .SH "EXAMPLE" .SS "Minimal config" .sp .if n \{\ .RS 4 .\} .nf [databases] template1 = host=127\&.0\&.0\&.1 dbname=template1 .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf [pgbouncer] pool_mode = session listen_port = 6543 listen_addr = 127\&.0\&.0\&.1 auth_type = md5 auth_file = users\&.txt logfile = pgbouncer\&.log pidfile = pgbouncer\&.pid admin_users = someuser stats_users = stat_collector .fi .if n \{\ .RE .\} .SS "Database defaults" .sp .if n \{\ .RS 4 .\} .nf [databases] .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf ; foodb over unix socket foodb = .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf ; redirect bardb to bazdb on localhost bardb = host=127\&.0\&.0\&.1 dbname=bazdb .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf ; access to destination database will go with single user forcedb = host=127\&.0\&.0\&.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO .fi .if n \{\ .RE .\} .SH "SEE ALSO" .sp pgbouncer(1) \- manpage for general usage, console commands\&. .sp \m[blue]\fBhttp://wiki\&.postgresql\&.org/wiki/PgBouncer\fR\m[] pgbouncer-1.5.4/doc/Makefile0000644000175000017500000000164511765176015012652 00000000000000-include ../config.mak web = pgf:/home/pgfoundry.org/groups/pgbouncer/htdocs/ manpages = pgbouncer.1 pgbouncer.5 EXTRA_DIST = config.txt usage.txt todo.txt faq.txt Makefile $(manpages) htmls = config.html usage.html todo.html faq.html README.html ifeq ($(ASCIIDOC),) ifneq ($(wildcard pgbouncer.[15]),) # no asciidoc, but we have manpages dist_man_MANS = $(manpages) endif else # we have asciidoc, build everything dist_man_MANS = $(manpages) doc_DATA = $(htmls) endif SUBLOC = doc abs_top_srcdir ?= $(CURDIR)/.. include $(abs_top_srcdir)/lib/mk/antimake.mk # add rules only if asciidoc is defined ifneq ($(ASCIIDOC),) pgbouncer.1: usage.xml $(XMLTO) man $< pgbouncer.5: config.xml $(XMLTO) man $< %.xml: %.txt $(ASCIIDOC) -b docbook -d manpage -o $@ $< %.html: %.txt $(ASCIIDOC) -a toc -o $@ $< README.html: ../README $(ASCIIDOC) -a toc -o $@ $< web: $(doc_DATA) rsync -av $(htmls) $(web)/doc/ endif # ASCIIDOC pgbouncer-1.5.4/doc/pgbouncer.10000644000175000017500000003715312043260545013253 00000000000000'\" t .\" Title: pgbouncer .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 10/28/2012 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" .TH "PGBOUNCER" "1" "10/28/2012" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" pgbouncer \- Lightweight connection pooler for PostgreSQL\&. .SH "SYNOPSIS" .sp .nf pgbouncer [\-d][\-R][\-v][\-u user] pgbouncer \-V|\-h .fi .sp On Windows computers, the options are: .sp .nf pgbouncer\&.exe [\-v][\-u user] pgbouncer\&.exe \-V|\-h .fi .sp Additional options for setting up a Windows service: .sp .nf pgbouncer\&.exe \-regservice pgbouncer\&.exe \-unregservice .fi .SH "DESCRIPTION" .sp pgbouncer is a PostgreSQL connection pooler\&. Any target application can be connected to pgbouncer as if it were a PostgreSQL server, and pgbouncer will create a connection to the actual server, or it will reuse one of its existing connections\&. .sp The aim of pgbouncer is to lower the performance impact of opening new connections to PostgreSQL\&. .sp In order not to compromise transaction semantics for connection pooling, pgbouncer supports several types of pooling when rotating connections: .PP Session pooling .RS 4 Most polite method\&. When client connects, a server connection will be assigned to it for the whole duration the client stays connected\&. When the client disconnects, the server connection will be put back into the pool\&. This is the default method\&. .RE .PP Transaction pooling .RS 4 A server connection is assigned to client only during a transaction\&. When PgBouncer notices that transaction is over, the server connection will be put back into the pool\&. .RE .PP Statement pooling .RS 4 Most aggressive method\&. The server connection will be put back into pool immediately after a query completes\&. Multi\-statement transactions are disallowed in this mode as they would break\&. .RE .sp The administration interface of pgbouncer consists of some new SHOW commands available when connected to a special \fIvirtual\fR database pgbouncer\&. .SH "QUICK-START" .sp Basic setup and usage as following\&. .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} Create a pgbouncer\&.ini file\&. Details in pgbouncer(5)\&. Simple example: .sp .if n \{\ .RS 4 .\} .nf [databases] template1 = host=127\&.0\&.0\&.1 port=5432 dbname=template1 .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf [pgbouncer] listen_port = 6543 listen_addr = 127\&.0\&.0\&.1 auth_type = md5 auth_file = users\&.txt logfile = pgbouncer\&.log pidfile = pgbouncer\&.pid admin_users = someuser .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} Create a users\&.txt file: .sp .if n \{\ .RS 4 .\} .nf "someuser" "same_password_as_in_server" .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} Launch pgbouncer: .sp .if n \{\ .RS 4 .\} .nf $ pgbouncer \-d pgbouncer\&.ini .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} Have your application (or the psql client) connect to pgbouncer instead of directly to PostgreSQL server\&. .sp .if n \{\ .RS 4 .\} .nf $ psql \-p 6543 \-U someuser template1 .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 5.\h'+01'\c .\} .el \{\ .sp -1 .IP " 5." 4.2 .\} Manage pgbouncer by connecting to the special administration database pgbouncer and issuing show help; to begin: .sp .if n \{\ .RS 4 .\} .nf $ psql \-p 6543 \-U someuser pgbouncer pgbouncer=# show help; NOTICE: Console usage DETAIL: SHOW [HELP|CONFIG|DATABASES|FDS|POOLS|CLIENTS|SERVERS|SOCKETS|LISTS|VERSION] SET key = arg RELOAD PAUSE SUSPEND RESUME SHUTDOWN .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 6.\h'+01'\c .\} .el \{\ .sp -1 .IP " 6." 4.2 .\} If you made changes to the pgbouncer\&.ini file, you can reload it with: .sp .if n \{\ .RS 4 .\} .nf pgbouncer=# RELOAD; .fi .if n \{\ .RE .\} .RE .SH "COMMAND LINE SWITCHES" .PP \-d .RS 4 Run in background\&. Without it the process will run in foreground\&. Note: Does not work on Windows, pgbouncer need to run as service there\&. .RE .PP \-R .RS 4 Do an online restart\&. That means connecting to the running process, loading the open sockets from it, and then using them\&. If there is no active process, boot normally\&. Note: Works only if OS supports Unix sockets and the unix_socket_dir is not disabled in config\&. Does not work on Windows machines\&. .RE .PP \-u user .RS 4 Switch to the given user on startup\&. .RE .PP \-v .RS 4 Increase verbosity\&. Can be used multiple times\&. .RE .PP \-q .RS 4 Be quiet \- do not log to stdout\&. Note this does not affect logging verbosity, only that stdout is not to be used\&. For use in init\&.d scripts\&. .RE .PP \-V .RS 4 Show version\&. .RE .PP \-h .RS 4 Show short help\&. .RE .PP \-regservice .RS 4 Win32: Register pgbouncer to run as Windows service\&. The service_name config parameter value is used as name to register under\&. .RE .PP \-unregservice .RS 4 Win32: Unregister Windows service\&. .RE .SH "ADMIN CONSOLE" .sp The console is available by connecting as normal to the database pgbouncer .sp .if n \{\ .RS 4 .\} .nf $ psql \-p 6543 pgbouncer .fi .if n \{\ .RE .\} .sp Only users listed in configuration parameters admin_users or stats_users are allowed to login to the console\&. (Except when auth_mode=any, then any user is allowed in as an admin\&.) .sp Additionally, the username pgbouncer is allowed to log in without password, if the login comes via Unix socket and the client has same Unix user uid as the running process\&. .SS "SHOW COMMANDS" .sp The SHOW commands output information\&. Each command is described below\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW STATS;\fR .RS 4 .sp Shows statistics\&. .PP database .RS 4 Statistics are presented per database\&. .RE .PP total_requests .RS 4 Total number of SQL requests pooled by pgbouncer\&. .RE .PP total_received .RS 4 Total volume in bytes of network traffic received by pgbouncer\&. .RE .PP total_sent .RS 4 Total volume in bytes of network traffic sent by pgbouncer\&. .RE .PP total_query_time .RS 4 Total number of microseconds spent by pgbouncer when actively connected to PostgreSQL\&. .RE .PP avg_req .RS 4 Average requests per second in last stat period\&. .RE .PP avg_recv .RS 4 Average received (from clients) bytes per second\&. .RE .PP avg_sent .RS 4 Average sent (to clients) bytes per second\&. .RE .PP avg_query .RS 4 Average query duration in microseconds\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW SERVERS;\fR .RS 4 .PP type .RS 4 S, for server\&. .RE .PP user .RS 4 Username pgbouncer uses to connect to server\&. .RE .PP database .RS 4 Database name\&. .RE .PP state .RS 4 State of the pgbouncer server connection, one of active, used or idle\&. .RE .PP addr .RS 4 IP address of PostgreSQL server\&. .RE .PP port .RS 4 Port of PostgreSQL server\&. .RE .PP local_addr .RS 4 Connection start address on local machine\&. .RE .PP local_port .RS 4 Connection start port on local machine\&. .RE .PP connect_time .RS 4 When the connection was made\&. .RE .PP request_time .RS 4 When last request was issued\&. .RE .PP ptr .RS 4 Address of internal object for this connection\&. Used as unique ID\&. .RE .PP link .RS 4 Address of client connection the server is paired with\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW CLIENTS;\fR .RS 4 .PP type .RS 4 C, for client\&. .RE .PP user .RS 4 Client connected user\&. .RE .PP database .RS 4 Database name\&. .RE .PP state .RS 4 State of the client connection, one of active, used, waiting or idle\&. .RE .PP addr .RS 4 IP address of client\&. .RE .PP port .RS 4 Port client is connected to\&. .RE .PP local_addr .RS 4 Connection end address on local machine\&. .RE .PP local_port .RS 4 Connection end port on local machine\&. .RE .PP connect_time .RS 4 Timestamp of connect time\&. .RE .PP request_time .RS 4 Timestamp of latest client request\&. .RE .PP ptr .RS 4 Address of internal object for this connection\&. Used as unique ID\&. .RE .PP link .RS 4 Address of server connection the client is paired with\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW POOLS;\fR .RS 4 .sp A new pool entry is made for each couple of (database, user)\&. .PP database .RS 4 Database name\&. .RE .PP user .RS 4 User name\&. .RE .PP cl_active .RS 4 Client connections that are linked to server connection and can process queries\&. .RE .PP cl_waiting .RS 4 Client connections have sent queries but have not yet got a server connection\&. .RE .PP sv_active .RS 4 Server connections that linked to client\&. .RE .PP sv_idle .RS 4 Server connections that unused and immediately usable for client queries\&. .RE .PP sv_used .RS 4 Server connections that have been idle more than server_check_delay, so they needs server_check_query to run on it before it can be used\&. .RE .PP sv_tested .RS 4 Server connections that are currently running either server_reset_query or server_check_query\&. .RE .PP sv_login .RS 4 Server connections currently in logging in process\&. .RE .PP maxwait .RS 4 How long the first (oldest) client in queue has waited, in seconds\&. If this starts increasing, then the current pool of servers does not handle requests quick enough\&. Reason may be either overloaded server or just too small of a pool_size setting\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW LISTS;\fR .RS 4 .sp Show following internal information, in columns (not rows): .PP databases .RS 4 Count of databases\&. .RE .PP users .RS 4 Count of users\&. .RE .PP pools .RS 4 Count of pools\&. .RE .PP free_clients .RS 4 Count of free clients\&. .RE .PP used_clients .RS 4 Count of used clients\&. .RE .PP login_clients .RS 4 Count of clients in login state\&. .RE .PP free_servers .RS 4 Count of free servers\&. .RE .PP used_servers .RS 4 Count of used servers\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW USERS;\fR .RS 4 .sp Shows one line per user, under the name column name\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW DATABASES;\fR .RS 4 .PP name .RS 4 Name of configured database entry\&. .RE .PP host .RS 4 Host pgbouncer connects to\&. .RE .PP port .RS 4 Port pgbouncer connects to\&. .RE .PP database .RS 4 Actual database name pgbouncer connects to\&. .RE .PP force_user .RS 4 When user is part of the connection string, the connection between pgbouncer and PostgreSQL is forced to the given user, whatever the client user\&. .RE .PP pool_size .RS 4 Maximum number of server connections\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW FDS;\fR .RS 4 .sp Shows list of fds in use\&. When the connected user has username "pgbouncer", connects through Unix socket and has same UID as running process, the actual fds are passed over the connection\&. This mechanism is used to do an online restart\&. Note: This does not work on Windows machines\&. .PP fd .RS 4 File descriptor numeric value\&. .RE .PP task .RS 4 One of pooler, client or server\&. .RE .PP user .RS 4 User of the connection using the FD\&. .RE .PP database .RS 4 Database of the connection using the FD\&. .RE .PP addr .RS 4 IP address of the connection using the FD, unix if a unix socket is used\&. .RE .PP port .RS 4 Port used by the connection using the FD\&. .RE .PP cancel .RS 4 Cancel key for this connection\&. .RE .PP link .RS 4 fd for corresponding server/client\&. NULL if idle\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW CONFIG;\fR .RS 4 .sp Show the current configuration settings, one per row, with following columns: .PP key .RS 4 Configuration variable name .RE .PP value .RS 4 Configuration value .RE .PP changeable .RS 4 Either yes or no, shows if the variable can be changed while running\&. If no, the variable can be changed only boot\-time\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW DNS_HOSTS\fR .RS 4 .sp Show hostnames in DNS cache\&. .PP hostname .RS 4 Host name\&. .RE .PP ttl .RS 4 How meny seconds until next lookup\&. .RE .PP addrs .RS 4 Comma separated list of addresses\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHOW DNS_ZONES\fR .RS 4 .sp Show DNS zones in cache\&. .PP zonename .RS 4 Zone name\&. .RE .PP serial .RS 4 Current serial\&. .RE .PP count .RS 4 Hostnames belonging to this zone\&. .RE .RE .SS "PROCESS CONTROLLING COMMANDS" .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBPAUSE [db];\fR .RS 4 .sp PgBouncer tries to disconnect from all servers, first waiting for all queries to complete\&. The command will not return before all queries are finished\&. To be used at the time of database restart\&. .sp If database name is given, only that database will be paused\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBKILL db;\fR .RS 4 .sp Immediately drop all client and server connections on given database\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSUSPEND;\fR .RS 4 .sp All socket buffers are flushed and PgBouncer stops listening for data on them\&. The command will not return before all buffers are empty\&. To be used at the time of PgBouncer online reboot\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBRESUME [db];\fR .RS 4 .sp Resume work from previous PAUSE or SUSPEND command\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSHUTDOWN;\fR .RS 4 .sp The PgBouncer process will exit\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBRELOAD;\fR .RS 4 .sp The PgBouncer process will reload its configuration file and update changeable settings\&. .RE .SS "SIGNALS" .PP SIGHUP .RS 4 Reload config\&. Same as issuing command RELOAD; on console\&. .RE .PP SIGINT .RS 4 Safe shutdown\&. Same as issuing PAUSE; and SHUTDOWN; on console\&. .RE .PP SIGTERM .RS 4 Immediate shutdown\&. Same as issuing SHUTDOWN; on console\&. .RE .SS "LIBEVENT SETTINGS" .sp From libevent docs: .sp .if n \{\ .RS 4 .\} .nf It is possible to disable support for epoll, kqueue, devpoll, poll or select by setting the environment variable EVENT_NOEPOLL, EVENT_NOKQUEUE, EVENT_NODEVPOLL, EVENT_NOPOLL or EVENT_NOSELECT, respectively\&. .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf By setting the environment variable EVENT_SHOW_METHOD, libevent displays the kernel notification method that it uses\&. .fi .if n \{\ .RE .\} .SH "SEE ALSO" .sp pgbouncer(5) \- manpage of configuration settings descriptions\&. .sp \m[blue]\fBhttp://wiki\&.postgresql\&.org/wiki/PgBouncer\fR\m[] pgbouncer-1.5.4/doc/config.txt0000644000175000017500000003744612035006035013211 00000000000000= pgbouncer(5) = == NAME == pgbouncer - Lightweight connection pooler for PostgreSQL. == SYNOPSIS == [databases] db = ... [pgbouncer] ... == DESCRIPTION == Config file is in "ini" format. Section names are between " and ". Lines starting with ";" or "#" are taken as comments and ignored. The characters ";" and "#" are not recognized when they appear later in the line. == SECTION [pgbouncer] == === Generic settings === ==== logfile ==== Specifies log file. Log file is kept open so after rotation `kill -HUP` or on console `RELOAD;` should be done. Note: On Windows machines, the service must be stopped and started. Default: not set. ==== pidfile ==== Specifies the pid file. Without a pidfile, daemonization is not allowed. Default: not set. ==== listen_addr ==== Specifies list of addresses, where to listen for TCP connections. You may also use `*` meaning "listen on all addresses". When not set, only Unix socket connections are allowed. Addresses can be specified numerically (IPv4/IPv6) or by name. Default: not set ==== listen_port ==== Which port to listen on. Applies to both TCP and Unix sockets. Default: 6432 ==== unix_socket_dir ==== Specifies location for Unix sockets. Applies to both listening socket and server connections. If set to an empty string, Unix sockets are disabled. Required for online reboot (-R) to work. Note: Not supported on Windows machines. Default: +/tmp+ ==== unix_socket_mode ==== Filesystem mode for unix socket. Default: 0777 ==== unix_socket_group ==== Group name to use for unix socket. Default: not set ==== user ==== If set, specifies the Unix user to change to after startup. Works only if PgBouncer is started as root or if `user` is the same as the current user. Note: Not supported on Windows machines. Default: not set ==== auth_file ==== The name of the file to load user names and passwords from. The file format is the same as the PostgreSQL pg_auth/pg_pwd file, so this setting can be pointed directly to one of those backend files. Default: not set. ==== auth_type ==== How to authenticate users. md5:: Use MD5-based password check. `auth_file` may contain both MD5-encrypted or plain-text passwords. This is the default authentication method. crypt:: Use crypt(3) based password check. `auth_file` must contain plain-text passwords. plain:: Clear-text password is sent over wire. trust:: No authentication is done. Username must still exist in `auth_file`. any:: Like the `trust` method, but the username given is ignored. Requires that all databases are configured to log in as specific user. Additionally, the console database allows any user to log in as admin. ==== pool_mode ==== Specifies when a server connection can be reused by other clients. session:: Server is released back to pool after client disconnects. Default. transaction:: Server is released back to pool after transaction finishes. statement:: Server is released back to pool after query finishes. Long transactions spanning multiple statements are disallowed in this mode. ==== max_client_conn ==== Maximum number of client connections allowed. When increased then the file descriptor limits should also be increased. Note that actual number of file descriptors used is more than max_client_conn. Theoretical maximum used is: max_client_conn + (max_pool_size * total_databases * total_users) if each user connects under its own username to server. If a database user is specified in connect string (all users connect under same username), the theoretical maximum is: max_client_conn + (max_pool_size * total_databases) The theoretical maximum should be never reached, unless somebody deliberately crafts special load for it. Still, it means you should set the number of file descriptors to a safely high number. Search for `ulimit` in your favourite shell man page. Note: `ulimit` does not apply in a Windows environment. Default: 100 ==== default_pool_size ==== How many server connections to allow per user/database pair. Can be overridden in the per-database configuration. Default: 20 ==== min_pool_size ==== Add more server connections to pool if below this number. Improves behaviour when usual load comes suddenly back after period of total inactivity. Default: 0 (disabled) ==== reserve_pool_size ==== How many additional connections to allow to a pool. 0 disables. Default: 0 (disabled) ==== reserve_pool_timeout ==== If a client has not been serviced in this many seconds, pgbouncer enables use of additional connections from reserve pool. 0 disables. Default: 5.0 ==== server_round_robin ==== By default, pgbouncer reuses server connections in LIFO (last-in, first-out) manner, so that few connections get the most load. This gives best performance if you have a single server serving a database. But if there is TCP round-robin behind a database IP, then it is better if pgbouncer also uses connections in that manner, thus achieving uniform load. Default: 0 ==== ignore_startup_parameters ==== By default, PgBouncer allows only parameters it can keep track of in startup packets - `client_encoding`, `datestyle`, `timezone` and `standard_conforming_strings`. All others parameters will raise an error. To allow others parameters, they can be specified here, so that pgbouncer knows that they are handled by admin and it can ignore them. Default: empty ==== disable_pqexec ==== Disable Simple Query protocol (PQexec). Unlike Extended Query protocol, Simple Query allows multiple queries in one packet, which allows some classes of SQL-injection attacks. Disabling it can improve security. Obviously this means only clients that exclusively use Extended Query protocol will stay working. Default: 0 === Log settings === ==== syslog ==== Toggles syslog on/off As for windows environment, eventlog is used instead. Default: 0 ==== syslog_ident ==== Under what name to send logs to syslog. Default: pgbouncer (program name) ==== syslog_facility ==== Under what facility to send logs to syslog. Possibilities: auth, authpriv, daemon, user, local0-7 Default: daemon ==== log_connections ==== Log successful logins. Default: 1 ==== log_disconnections ==== Log disconnections with reasons. Default: 1 ==== log_pooler_errors ==== Log error messages pooler sends to clients. Default: 1 ==== stats_period ==== Period for writing aggregated stats into log. Default: 60 === Console access control === ==== admin_users ==== Comma-separated list of database users that are allowed to connect and run all commands on console. Ignored when `auth_mode=any`, in which case any username is allowed in as admin. Default: empty ==== stats_users ==== Comma-separated list of database users that are allowed to connect and run read-only queries on console. Thats means all SHOW commands except SHOW FDS. Default: empty. === Connection sanity checks, timeouts === ==== server_reset_query ==== Query sent to server on connection release, before making it available to other clients. At that moment no transaction is in progress so it should not include `ABORT` or `ROLLBACK`. A good choice for Postgres 8.2 and below is: server_reset_query = RESET ALL; SET SESSION AUTHORIZATION DEFAULT; for 8.3 and above its enough to do: server_reset_query = DISCARD ALL; When transaction pooling is used, the `server_reset_query` should be empty, as clients should not use any session features. Default: DISCARD ALL ==== server_check_delay ==== How long to keep released connections available for immediate re-use, without running sanity-check queries on it. If 0 then the query is ran always. Default: 30.0 ==== server_check_query ==== Simple do-nothing query to check if the server connection is alive. If an empty string, then sanity checking is disabled. Default: SELECT 1; ==== server_lifetime ==== The pooler will try to close server connections that have been connected longer than this. Setting it to 0 means the connection is to be used only once, then closed. [seconds] Default: 3600.0 ==== server_idle_timeout ==== If a server connection has been idle more than this many seconds it will be dropped. If 0 then timeout is disabled. [seconds] Default: 600.0 ==== server_connect_timeout ==== If connection and login won't finish in this amount of time, the connection will be closed. [seconds] Default: 15.0 ==== server_login_retry ==== If login failed, because of failure from connect() or authentication that pooler waits this much before retrying to connect. [seconds] Default: 15.0 ==== client_login_timeout ==== If a client connects but does not manage to login in this amount of time, it will be disconnected. Mainly needed to avoid dead connections stalling SUSPEND and thus online restart. [seconds] Default: 60.0 ==== autodb_idle_timeout ==== If the automatically created (via "*") database pools have been unused this many seconds, they are freed. The negative aspect of that is that their statistics are also forgotten. [seconds] Default: 3600.0 ==== dns_max_ttl ==== How long the DNS lookups can be cached. If a DNS lookup returns several answers, pgbouncer will robin-between them in the meantime. Actual DNS TTL is ignored. [seconds] Default: 15.0 ==== dns_zone_check_period ==== Period to check if zone serial has changed. PgBouncer can collect dns zones from hostnames (everything after first dot) and then periodically check if zone serial changes. If it notices changes, all hostnames under that zone are looked up again. If any host ip changes, it's connections are invalidated. Works only with UDNS backend (`--with-udns` to configure). Default: 0.0 (disabled) === Dangerous timeouts === Setting following timeouts cause unexpected errors. ==== query_timeout ==== Queries running longer than that are canceled. This should be used only with slightly smaller server-side statement_timeout, to apply only for network problems. [seconds] Default: 0.0 (disabled) ==== query_wait_timeout ==== Maximum time queries are allowed to spend waiting for execution. If the query is not assigned to a server during that time, the client is disconnected. This is used to prevent unresponsive servers from grabbing up connections. [seconds] Default: 0.0 (disabled) ==== client_idle_timeout ==== Client connections idling longer than this many seconds are closed. This should be larger than the client-side connection lifetime settings, and only used for network problems. [seconds] Default: 0.0 (disabled) ==== idle_transaction_timeout ==== If client has been in "idle in transaction" state longer, it will be disconnected. [seconds] Default: 0.0 (disabled) === Low-level network settings === ==== pkt_buf ==== Internal buffer size for packets. Affects size of TCP packets sent and general memory usage. Actual libpq packets can be larger than this so, no need to set it large. Default: 2048 ==== max_packet_size ==== Maximum size for Postgres packets that PgBouncer allows through. One packet is either one query or one resultset row. Full resultset can be larger. Default: 2147483647 ==== listen_backlog ==== Backlog argument for listen(2). Determines how many new unanswered connection attempts are kept in queue. When queue is full, further new connections are dropped. Default: 128 ==== sbuf_loopcnt ==== How many times to process data on one connection, before proceeding. Without this limit, one connection with a big resultset can stall PgBouncer for a long time. One loop processes one `pkt_buf` amount of data. 0 means no limit. Default: 5 ==== tcp_defer_accept ==== For details on this and other tcp options, please see `man 7 tcp`. Default: 45 on Linux, otherwise 0 ==== tcp_socket_buffer ==== Default: not set ==== tcp_keepalive ==== Turns on basic keepalive with OS defaults. On Linux, the system defaults are tcp_keepidle=7200, tcp_keepintvl=75, tcp_keepcnt=9. They are probably similar on other OS-es. Default: 1 ==== tcp_keepcnt ==== Default: not set ==== tcp_keepidle ==== Default: not set ==== tcp_keepintvl ==== Default: not set == SECTION [databases] == This contains key=value pairs where key will be taken as a database name and value as a libpq connect-string style list of key=value pairs. As actual libpq is not used, so not all features from libpq can be used (service=, .pgpass). Database name can contain characters [0-9A-Za-z_.-] without quoting. Names that contain other chars need to be quoted with standard SQL ident quoting: double quotes where "" is taken as single quote. "*" acts as fallback database: if the exact name does not exist, its value is taken as connect string for requested database. Such automatically created database entries are cleaned up if they stay idle longer then the time specified in `autodb_idle_timeout` parameter. === Location parameters === ==== dbname ==== Destination database name. Default: same as client-side database name. ==== host ==== Hostname or IP address to connect to. Hostnames are resolved on connect time, the result is cached per +dns_max_ttl+ parameter. If DNS returns several results, they are used in round-robin manner. Default: not set, meaning to use a Unix socket. ==== port ==== Default: 5432 ==== user, password ==== If +user=+ is set, all connections to the destination database will be done with the specified user, meaning that there will be only one pool for this database. Otherwise PgBouncer tries to log into the destination database with client username, meaning that there will be one pool per user. === Pool configuration === ==== pool_size ==== Set maximum size of pools for this database. If not set, the default_pool_size is used. ==== connect_query ==== Query to be executed after a connection is established, but before allowing the connection to be used by any clients. If the query raises errors, they are logged but ignored otherwise. === Extra parameters === They allow setting default parameters on server connection. Note that since version 1.1 PgBouncer tracks client changes for their values, so their use in pgbouncer.ini is deprecated now. ==== client_encoding ==== Ask specific +client_encoding+ from server. ==== datestyle ==== Ask specific +datestyle+ from server. ==== timezone ==== Ask specific +timezone+ from server. == AUTHENTICATION FILE FORMAT == PgBouncer needs its own user database. The users are loaded from a text file in following format: "username1" "password" ... "username2" "md5abcdef012342345" ... There should be at least 2 fields, surrounded by double quotes. The first field is the username and the second is either a plain-text or a MD5-hidden password. PgBouncer ignores the rest of the line. This file format is equivalent to text files used by PostgreSQL 8.x for authentication info, thus allowing PgBouncer to work directly on PostgreSQL authentication files in data directory. Since PostgreSQL 9.0, the text files are not used anymore. Thus the auth file needs to be generated. See `./etc/mkauth.py` for sample script to generate auth file from `pg_shadow` table. PostgreSQL MD5-hidden password format: "md5" + md5(password + username) So user `admin` with password `1234` will have MD5-hidden password `md545f2603610af569b6155c45067268c6b`. == EXAMPLE == === Minimal config === [databases] template1 = host=127.0.0.1 dbname=template1 [pgbouncer] pool_mode = session listen_port = 6543 listen_addr = 127.0.0.1 auth_type = md5 auth_file = users.txt logfile = pgbouncer.log pidfile = pgbouncer.pid admin_users = someuser stats_users = stat_collector === Database defaults === [databases] ; foodb over unix socket foodb = ; redirect bardb to bazdb on localhost bardb = host=127.0.0.1 dbname=bazdb ; access to destination database will go with single user forcedb = host=127.0.0.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO == SEE ALSO == pgbouncer(1) - manpage for general usage, console commands. http://wiki.postgresql.org/wiki/PgBouncer[] pgbouncer-1.5.4/doc/todo.txt0000644000175000017500000000467612013151606012711 00000000000000= PgBouncer TODO list = == Highly visible missing features == Significant amount of users feel the need for those. * auth_conn - access to pg_shadow, so auth_file is not needed. [ flat-text files are gone in 9.0+ ] * Protocol-level plan cache. * LISTEN/NOTIFY. Requires strict SQL format. * SSL support. Although stunnel works for plain SSL, it cannot be linked with Postgres authentication. * Load-balancing / failover. Waiting for contributors... == Problems / cleanups == * hba-style access control * per-db pool_mode * per-user pool_mode, other settings ([users], user=connstr?) * identd authentication * Maintenance order vs. lifetime_kill_gap: http://lists.pgfoundry.org/pipermail/pgbouncer-general/2011-February/000679.html[] * per_loop_maint/per_loop_activate take too much time in case of moderate load and lots of pools. Perhaps active_pool_list would help, which contains only pools touched in current loop. * new states for clients: idle and in-query. That allows to apply client_idle_timeout and query_timeout without walking all clients on maintenance time. * check if SQL error codes are correct * removing user should work - kill connections * keep stats about error counts * cleanup of logging levels, to make log more useful * to test: - signal flood - no mem / no fds handling * fix high-freq maintenance timer - it's only needed when PAUSE/RESUME/shutdown is issued. * Get rid of SBUF_SMALL_PKT logic - it makes processing code complex. Needs a new sbuf_prepare_*() to notify sbuf about short data. [Plain 'false' from handler postpones processing to next event loop.] == Dubious/complicated features == * User-based route. Simplest would be to move db info to pool and fill username into dns. * units for config parameters. * some preliminary notification that fd limit is full * Move all "look-at-full-packet" situtations to SBUF_EV_PKT_CALLBACK * `pool_mode = plproxy` - use postgres in full-duplex mode for autocommit queries, multiplexing several queries into one connection. Should result in more effiicent CPU usage of server. * SMP: spread sockets over per-cpu threads. needs confirmation that single-threadedness can be problem. it can also be that only accept() + login handling of short connection is problem. that could be solved by just having threads for login handling, which would be lot simpler. or just deciding that its not worth fixing. pgbouncer-1.5.4/doc/usage.txt0000644000175000017500000002661112043260476013052 00000000000000= pgbouncer(1) = == NAME == pgbouncer - Lightweight connection pooler for PostgreSQL. == SYNOPSIS == pgbouncer [-d][-R][-v][-u user] pgbouncer -V|-h On Windows computers, the options are: pgbouncer.exe [-v][-u user] pgbouncer.exe -V|-h Additional options for setting up a Windows service: pgbouncer.exe -regservice pgbouncer.exe -unregservice == DESCRIPTION == +pgbouncer+ is a PostgreSQL connection pooler. Any target application can be connected to +pgbouncer+ as if it were a PostgreSQL server, and +pgbouncer+ will create a connection to the actual server, or it will reuse one of its existing connections. The aim of +pgbouncer+ is to lower the performance impact of opening new connections to PostgreSQL. In order not to compromise transaction semantics for connection pooling, +pgbouncer+ supports several types of pooling when rotating connections: Session pooling:: Most polite method. When client connects, a server connection will be assigned to it for the whole duration the client stays connected. When the client disconnects, the server connection will be put back into the pool. This is the default method. Transaction pooling:: A server connection is assigned to client only during a transaction. When PgBouncer notices that transaction is over, the server connection will be put back into the pool. Statement pooling:: Most aggressive method. The server connection will be put back into pool immediately after a query completes. Multi-statement transactions are disallowed in this mode as they would break. The administration interface of +pgbouncer+ consists of some new +SHOW+ commands available when connected to a special 'virtual' database +pgbouncer+. == QUICK-START == Basic setup and usage as following. 1. Create a pgbouncer.ini file. Details in +pgbouncer(5)+. Simple example: [databases] template1 = host=127.0.0.1 port=5432 dbname=template1 [pgbouncer] listen_port = 6543 listen_addr = 127.0.0.1 auth_type = md5 auth_file = users.txt logfile = pgbouncer.log pidfile = pgbouncer.pid admin_users = someuser 2. Create a users.txt file: "someuser" "same_password_as_in_server" 3. Launch +pgbouncer+: $ pgbouncer -d pgbouncer.ini 4. Have your application (or the +psql+ client) connect to +pgbouncer+ instead of directly to PostgreSQL server. $ psql -p 6543 -U someuser template1 5. Manage +pgbouncer+ by connecting to the special administration database +pgbouncer+ and issuing +show help;+ to begin: $ psql -p 6543 -U someuser pgbouncer pgbouncer=# show help; NOTICE: Console usage DETAIL: SHOW [HELP|CONFIG|DATABASES|FDS|POOLS|CLIENTS|SERVERS|SOCKETS|LISTS|VERSION] SET key = arg RELOAD PAUSE SUSPEND RESUME SHUTDOWN 6. If you made changes to the pgbouncer.ini file, you can reload it with: pgbouncer=# RELOAD; == COMMAND LINE SWITCHES == -d:: Run in background. Without it the process will run in foreground. Note: Does not work on Windows, +pgbouncer+ need to run as service there. -R:: Do an online restart. That means connecting to the running process, loading the open sockets from it, and then using them. If there is no active process, boot normally. Note: Works only if OS supports Unix sockets and the `unix_socket_dir` is not disabled in config. Does not work on Windows machines. -u user:: Switch to the given user on startup. -v:: Increase verbosity. Can be used multiple times. -q:: Be quiet - do not log to stdout. Note this does not affect logging verbosity, only that stdout is not to be used. For use in init.d scripts. -V:: Show version. -h:: Show short help. -regservice:: Win32: Register pgbouncer to run as Windows service. The +service_name+ config parameter value is used as name to register under. -unregservice:: Win32: Unregister Windows service. == ADMIN CONSOLE == The console is available by connecting as normal to the database +pgbouncer+ $ psql -p 6543 pgbouncer Only users listed in configuration parameters +admin_users+ or +stats_users+ are allowed to login to the console. (Except when `auth_mode=any`, then any user is allowed in as an admin.) Additionally, the username +pgbouncer+ is allowed to log in without password, if the login comes via Unix socket and the client has same Unix user uid as the running process. === SHOW COMMANDS === The +SHOW+ commands output information. Each command is described below. ==== SHOW STATS; ==== Shows statistics. database:: Statistics are presented per database. total_requests:: Total number of +SQL+ requests pooled by +pgbouncer+. total_received:: Total volume in bytes of network traffic received by +pgbouncer+. total_sent:: Total volume in bytes of network traffic sent by +pgbouncer+. total_query_time:: Total number of microseconds spent by +pgbouncer+ when actively connected to PostgreSQL. avg_req:: Average requests per second in last stat period. avg_recv:: Average received (from clients) bytes per second. avg_sent:: Average sent (to clients) bytes per second. avg_query:: Average query duration in microseconds. ==== SHOW SERVERS; ==== type:: S, for server. user:: Username +pgbouncer+ uses to connect to server. database:: Database name. state:: State of the pgbouncer server connection, one of +active+, +used+ or +idle+. addr:: IP address of PostgreSQL server. port:: Port of PostgreSQL server. local_addr:: Connection start address on local machine. local_port:: Connection start port on local machine. connect_time:: When the connection was made. request_time:: When last request was issued. ptr:: Address of internal object for this connection. Used as unique ID. link:: Address of client connection the server is paired with. ==== SHOW CLIENTS; ==== type:: C, for client. user:: Client connected user. database:: Database name. state:: State of the client connection, one of +active+, +used+, +waiting+ or +idle+. addr:: IP address of client. port:: Port client is connected to. local_addr:: Connection end address on local machine. local_port:: Connection end port on local machine. connect_time:: Timestamp of connect time. request_time:: Timestamp of latest client request. ptr:: Address of internal object for this connection. Used as unique ID. link:: Address of server connection the client is paired with. ==== SHOW POOLS; ==== A new pool entry is made for each couple of (database, user). database:: Database name. user:: User name. cl_active:: Client connections that are linked to server connection and can process queries. cl_waiting:: Client connections have sent queries but have not yet got a server connection. sv_active:: Server connections that linked to client. sv_idle:: Server connections that unused and immediately usable for client queries. sv_used:: Server connections that have been idle more than `server_check_delay`, so they needs `server_check_query` to run on it before it can be used. sv_tested:: Server connections that are currently running either `server_reset_query` or `server_check_query`. sv_login:: Server connections currently in logging in process. maxwait:: How long the first (oldest) client in queue has waited, in seconds. If this starts increasing, then the current pool of servers does not handle requests quick enough. Reason may be either overloaded server or just too small of a +pool_size+ setting. ==== SHOW LISTS; ==== Show following internal information, in columns (not rows): databases:: Count of databases. users:: Count of users. pools:: Count of pools. free_clients:: Count of free clients. used_clients:: Count of used clients. login_clients:: Count of clients in +login+ state. free_servers:: Count of free servers. used_servers:: Count of used servers. ==== SHOW USERS; ==== Shows one line per user, under the +name+ column name. ==== SHOW DATABASES; ==== name:: Name of configured database entry. host:: Host pgbouncer connects to. port:: Port pgbouncer connects to. database:: Actual database name pgbouncer connects to. force_user:: When user is part of the connection string, the connection between pgbouncer and PostgreSQL is forced to the given user, whatever the client user. pool_size:: Maximum number of server connections. ==== SHOW FDS; ==== Shows list of fds in use. When the connected user has username "pgbouncer", connects through Unix socket and has same UID as running process, the actual fds are passed over the connection. This mechanism is used to do an online restart. Note: This does not work on Windows machines. fd:: File descriptor numeric value. task:: One of +pooler+, +client+ or +server+. user:: User of the connection using the FD. database:: Database of the connection using the FD. addr:: IP address of the connection using the FD, +unix+ if a unix socket is used. port:: Port used by the connection using the FD. cancel:: Cancel key for this connection. link:: fd for corresponding server/client. NULL if idle. ==== SHOW CONFIG; ==== Show the current configuration settings, one per row, with following columns: key:: Configuration variable name value:: Configuration value changeable:: Either +yes+ or +no+, shows if the variable can be changed while running. If +no+, the variable can be changed only boot-time. ==== SHOW DNS_HOSTS ==== Show hostnames in DNS cache. hostname:: Host name. ttl:: How meny seconds until next lookup. addrs:: Comma separated list of addresses. ==== SHOW DNS_ZONES ==== Show DNS zones in cache. zonename:: Zone name. serial:: Current serial. count:: Hostnames belonging to this zone. === PROCESS CONTROLLING COMMANDS === ==== PAUSE [db]; ==== PgBouncer tries to disconnect from all servers, first waiting for all queries to complete. The command will not return before all queries are finished. To be used at the time of database restart. If database name is given, only that database will be paused. ==== KILL db; ==== Immediately drop all client and server connections on given database. ==== SUSPEND; ==== All socket buffers are flushed and PgBouncer stops listening for data on them. The command will not return before all buffers are empty. To be used at the time of PgBouncer online reboot. ==== RESUME [db]; ==== Resume work from previous +PAUSE+ or +SUSPEND+ command. ==== SHUTDOWN; ==== The PgBouncer process will exit. ==== RELOAD; ==== The PgBouncer process will reload its configuration file and update changeable settings. === SIGNALS === SIGHUP:: Reload config. Same as issuing command +RELOAD;+ on console. SIGINT:: Safe shutdown. Same as issuing +PAUSE;+ and +SHUTDOWN;+ on console. SIGTERM:: Immediate shutdown. Same as issuing +SHUTDOWN;+ on console. === LIBEVENT SETTINGS === From libevent docs: It is possible to disable support for epoll, kqueue, devpoll, poll or select by setting the environment variable EVENT_NOEPOLL, EVENT_NOKQUEUE, EVENT_NODEVPOLL, EVENT_NOPOLL or EVENT_NOSELECT, respectively. By setting the environment variable EVENT_SHOW_METHOD, libevent displays the kernel notification method that it uses. == SEE ALSO == pgbouncer(5) - manpage of configuration settings descriptions. http://wiki.postgresql.org/wiki/PgBouncer[] pgbouncer-1.5.4/debian/0000755000175000017500000000000012055406736011740 500000000000000pgbouncer-1.5.4/debian/rules0000755000175000017500000000035311765176015012742 00000000000000#! /usr/bin/make -f DH_VERBOSE = 1 DEB_BUILD_OPTIONS = nostrip export DEB_BUILD_OPTIONS override DEB_CONFIGURE_EXTRA_FLAGS = --enable-debug include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/autotools.mk pgbouncer-1.5.4/debian/changelog0000644000175000017500000001407612055406023013527 00000000000000pgbouncer (1.5.4-1) unstable; urgency=low * v1.5.4 -- Marko Kreen Wed, 28 Nov 2012 12:44:39 +0200 pgbouncer (1.5.3-1) unstable; urgency=low * v1.5.3 -- Marko Kreen Wed, 12 Sep 2012 13:36:51 +0300 pgbouncer (1.5.2-1) unstable; urgency=low * v1.5.2 -- Marko Kreen Tue, 29 May 2012 11:02:48 +0300 pgbouncer (1.5.1-1) unstable; urgency=low * v1.5.1 -- Marko Kreen Tue, 17 Apr 2012 16:04:13 +0300 pgbouncer (1.5.1rc1-1) unstable; urgency=low * v1.5.1rc1 -- Marko Kreen Wed, 14 Mar 2012 14:31:54 +0200 pgbouncer (1.5-1) unstable; urgency=low * v1.5 -- Marko Kreen Thu, 05 Jan 2012 14:59:43 +0200 pgbouncer (1.5rc1-1) unstable; urgency=low * v1.5rc1 -- Marko Kreen Tue, 13 Dec 2011 00:28:43 +0200 pgbouncer (1.4.3dev1-1) unstable; urgency=low * v1.4.3dev1 -- Marko Kreen Thu, 01 Sep 2011 11:49:12 +0300 pgbouncer (1.4.2rc1-1) unstable; urgency=low * v1.4.2rc1 -- Marko Kreen Thu, 02 Jun 2011 18:36:27 +0300 pgbouncer (1.4.1-1) unstable; urgency=low * v1.4.1 -- Marko Kreen Fri, 01 Apr 2011 21:51:54 +0300 pgbouncer (1.4.1rc5-1) unstable; urgency=low * v1.4.1rc5 -- Marko Kreen Tue, 29 Mar 2011 17:00:55 +0300 pgbouncer (1.4.1rc3-1) unstable; urgency=low * v1.4.1rc4 -- Marko Kreen Sat, 26 Mar 2011 00:40:50 +0200 pgbouncer (1.4.1rc3-1) unstable; urgency=low * v1.4.1rc3 -- Marko Kreen Wed, 23 Mar 2011 18:06:01 +0200 pgbouncer (1.4.1rc2-1) unstable; urgency=low * v1.4.1rc2 -- Marko Kreen Mon, 21 Mar 2011 23:24:00 +0200 pgbouncer (1.4.1rc1-1) unstable; urgency=low * v1.4.1rc1 -- Marko Kreen Mon, 28 Feb 2011 23:11:27 +0200 pgbouncer (1.4-1) unstable; urgency=low * v1.4 -- Marko Kreen Wed, 08 Dec 2010 17:30:06 +0200 pgbouncer (1.4-0rc4) unstable; urgency=low * v1.4rc4 -- Marko Kreen Tue, 30 Nov 2010 11:54:55 +0200 pgbouncer (1.4-0rc3) unstable; urgency=low * v1.4rc3 -- Marko Kreen Mon, 29 Nov 2010 13:44:46 +0200 pgbouncer (1.4-0rc2.1) unstable; urgency=low * v1.4rc2.1 -- Marko Kreen Thu, 18 Nov 2010 10:26:25 +0200 pgbouncer (1.4-0rc2) unstable; urgency=low * v1.4rc2 -- Marko Kreen Wed, 17 Nov 2010 15:11:13 +0200 pgbouncer (1.4-0rc1.1) unstable; urgency=low * v1.4rc1.1 -- Marko Kreen Wed, 17 Nov 2010 14:10:25 +0200 pgbouncer (1.4-0rc1) unstable; urgency=low * v1.4rc1 -- Marko Kreen Mon, 08 Nov 2010 11:02:57 +0200 pgbouncer (1.4-0rc0) unstable; urgency=low * v1.4rc0 -- Marko Kreen Wed, 03 Nov 2010 15:14:10 +0200 pgbouncer (1.4-0alpha1) unstable; urgency=low * v1.4 alpha 1 -- Marko Kreen Mon, 20 Sep 2010 13:37:15 -0700 pgbouncer (1.3.3-0rc1) unstable; urgency=low * v1.3.3rc1 -- Marko Kreen Fri, 23 Apr 2010 17:33:07 +0300 pgbouncer (1.3.2-1) unstable; urgency=low * v1.3.2 -- Marko Kreen Mon, 15 Mar 2010 16:09:16 +0200 pgbouncer (1.3.2rc1-1) unstable; urgency=low * v1.3.2rc1 -- Marko Kreen Fri, 04 Dec 2009 13:18:26 +0200 pgbouncer (1.3.1-1) unstable; urgency=low * v1.3.1 -- Marko Kreen Mon, 06 Jul 2009 16:12:53 +0300 pgbouncer (1.3.1rc1-1) unstable; urgency=low * v1.3.1rc1 -- Marko Kreen Fri, 26 Jun 2009 14:25:42 +0300 pgbouncer (1.3-1) unstable; urgency=low * v1.3 -- Marko Kreen Wed, 18 Feb 2009 14:11:41 +0200 pgbouncer (1.3rc1-0) unstable; urgency=low * v1.3rc1 -- Marko Kreen Fri, 16 jan 2009 15:28:49 +0200 pgbouncer (1.2.3-1) unstable; urgency=low * v.1.2.3 -- Marko Kreen Fri, 08 Aug 2008 14:35:27 +0300 pgbouncer (1.2.2-1) unstable; urgency=low * v1.2.2 -- Marko Kreen Wed, 06 Aug 2008 09:44:15 +0300 pgbouncer (1.2.1-1) unstable; urgency=low * v1.2.1 -- Marko Kreen Fri, 01 Aug 2008 13:00:30 +0300 pgbouncer (1.2-1) unstable; urgency=low * v1.2 -- Marko Kreen Tue, 29 Jul 2008 14:18:59 +0300 pgbouncer (1.2-0rc1) unstable; urgency=low * v1.2rc1 -- Marko Kreen Wed, 25 Jun 2008 21:02:08 +0300 pgbouncer (1.1.1-1) unstable; urgency=low * PgBouncer 1.1.1 -- Marko Kreen Mon, 15 Oct 2007 17:41:05 +0300 pgbouncer (1.0.8-1) unstable; urgency=low * Fix crash with ^C from psql. * PAUSE db; RESUME db; -- Marko Kreen Mon, 18 Jun 2007 15:23:32 +0300 pgbouncer (1.0.7-1) unstable; urgency=low * Fix send() blocking on flush packets. -- Marko Kreen Wed, 18 Apr 2007 16:43:45 +0300 pgbouncer (1.0.6-1) unstable; urgency=low * previous fix could broke maint. -- Marko Kreen Thu, 12 Apr 2007 11:30:53 +0300 pgbouncer (1.0.5-1) unstable; urgency=low * fix online restart bugs. -- Marko Kreen Wed, 11 Apr 2007 13:50:50 +0300 pgbouncer (1.0.4-1) unstable; urgency=low * last bug, honestly. -- Marko Kreen Wed, 11 Apr 2007 12:03:52 +0300 pgbouncer (1.0.3-1) unstable; urgency=low * more error handling fixes. -- Marko Kreen Tue, 10 Apr 2007 17:22:49 +0300 pgbouncer (1.0.2-1) unstable; urgency=low * 2 more bugs. -- Marko Kreen Wed, 28 Mar 2007 12:04:39 +0300 pgbouncer (1.0.1) unstable; urgency=low * Couple hotfixes. -- Marko Kreen Wed, 14 Mar 2007 21:30:44 +0200 pgbouncer (1.0) unstable; urgency=low * Public release. -- Marko Kreen Tue, 13 Mar 2007 17:30:02 +0200 pgbouncer-1.5.4/debian/control0000644000175000017500000000055311765176015013267 00000000000000Source: pgbouncer Section: database Priority: extra Maintainer: Marko Kreen Standards-Version: 3.6.2 Build-Depends: cdbs, debhelper (>= 7), libevent-dev (>= 1.3b), asciidoc, xmlto, make (>= 3.81) Package: pgbouncer Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Lightweight connection pooler for PostgreSQL . pgbouncer-1.5.4/debian/copyright0000644000175000017500000000136411765176015013620 00000000000000 Copyright (C) 2007-2011 Marko Kreen, Skype Technologies Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. pgbouncer-1.5.4/debian/compat0000644000175000017500000000000211765176015013057 000000000000005 pgbouncer-1.5.4/README0000644000175000017500000000651711765176015011330 00000000000000 PgBouncer ========= Lightweight connection pooler for PostgreSQL. Homepage: http://wiki.postgresql.org/wiki/PgBouncer Downloads, bugtracking: http://pgfoundry.org/projects/pgbouncer Building --------- GNU Make 3.81+ is required for building. PgBouncer uses libevent for low-level socket handling. Libevent needs to be at least version 1.3b. Preferably 2.x as Libevent 2.x has proper async DNS implementation. When this is installed just run: $ ./configure --prefix=/usr/local --with-libevent=libevent-prefix $ make $ make install If the OS does not have libevent available as package, it can be downloaded from http://monkey.org/~provos/libevent/ DNS lookup support ------------------ Starting from PgBouncer 1.4, it does hostname lookups at connect time instead just once at config load time. This requires proper async DNS implementation. Following list shows supported backends and their probing order: .DNS backends [options="header"] |=========================================================================================== | backend | parallel | EDNS0 (1) | /etc/hosts | SOA lookup (2) | note | udns | yes | yes | no | yes | ipv4-only | evdns, libevent 2.x | yes | no | yes | no | | getaddrinfo_a, glibc 2.9+ | yes | yes (3) | yes | no | N/A on non-linux | getaddrinfo, libc | no | yes (3) | yes | no | N/A on win32, requires pthreads | evdns, libevent 1.x | yes | no | no | no | buggy |=========================================================================================== 1. EDNS0 is required to have more then 8 addresses behind one hostname. 2. SOA lookup is needed to re-check hostnames on zone serial change 3. To enable EDNS0, add `options edns0` to /etc/resolv.conf `./configure` also has flags `--enable-evdns` and `--disable-evdns` which turn off automatic probing and force use of either `evdns` or `getaddrinfo_a()`. Building from GIT ----------------- Building PgBouncer from GIT requires that you fetch libusual submodule and generate the header and config files before you can run configure: $ git clone git://git.postgresql.org/git/pgbouncer.git $ cd pgbouncer $ git submodule init $ git submodule update $ ./autogen.sh $ ./configure ... $ make $ make install Additional packages required: autoconf, automake, libtool, autoconf-archive, asciidoc 8.x, xmlto. Building for WIN32 ------------------ At the moment only build env tested is MINGW32 / MSYS. Cygwin and Visual $ANYTHING are untested. Libevent 2.x is required for DNS hostname lookup. Then do the usual: $ ./configure ... $ make If cross-compiling from Unix: $ ./configure --host=i586-mingw32msvc ... Running on WIN32 ---------------- Running from command-line goes as usual, except -d (daemonize), -R (reboot) and -u (switch user) switches will not work. To run pgbouncer as a Windows service, you need to configure `service_name` parameter to set name for service. Then: $ pgbouncer -regservice config.ini To uninstall service: $ pgbouncer -unregservice config.ini To use Windows Event Log, set "syslog = 1" in config file. But before you need to register pgbevent.dll: $ regsvr32 pgbevent.dll To unregister it, do `regsvr32 /u pgbevent.dll`. pgbouncer-1.5.4/COPYRIGHT0000644000175000017500000000146311765176015011736 00000000000000PgBouncer - Lightweight connection pooler for PostgreSQL. Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. pgbouncer-1.5.4/etc/0000755000175000017500000000000012055406736011271 500000000000000pgbouncer-1.5.4/etc/example.debian.init.sh0000644000175000017500000000205111665176317015366 00000000000000#!/bin/bash # # pgbouncer Start the PgBouncer PostgreSQL pooler. # # The variables below are NOT to be changed. They are there to make the # script more readable. NAME=pgbouncer DAEMON=/usr/bin/$NAME PIDFILE=/var/run/$NAME.pid CONF=/etc/$NAME.ini OPTS="-d $CONF" # note: SSD is required only at startup of the daemon. SSD=`which start-stop-daemon` ENV="env -i LANG=C PATH=/bin:/usr/bin:/usr/local/bin" trap "" 1 # Check if configuration exists test -f $CONF || exit 0 case "$1" in start) echo -n "Starting server: $NAME" $ENV $SSD --start --pidfile $PIDFILE --exec $DAEMON -- $OPTS > /dev/null ;; stop) echo -n "Stopping server: $NAME" start-stop-daemon --stop --pidfile $PIDFILE ;; reload | force-reload) echo -n "Reloading $NAME configuration" start-stop-daemon --stop --pidfile $PIDFILE --signal HUP ;; restart) $0 stop $0 start ;; *) echo "Usage: /etc/init.d/$NAME {start|stop|reload|restart}" exit 1 ;; esac if [ $? -eq 0 ]; then echo . exit 0 else echo " failed" exit 1 fi pgbouncer-1.5.4/etc/pgbouncer.ini0000644000175000017500000001262111765176015013701 00000000000000;; database name = connect string ;; ;; connect string params: ;; dbname= host= port= user= password= ;; client_encoding= datestyle= timezone= ;; pool_size= connect_query= [databases] ; foodb over unix socket ;foodb = ; redirect bardb to bazdb on localhost ;bardb = host=localhost dbname=bazdb ; acceess to dest database will go with single user ;forcedb = host=127.0.0.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO connect_query='SELECT 1' ; use custom pool sizes ;nondefaultdb = pool_size=50 reserve_pool=10 ; fallback connect string ;* = host=testserver ;; Configuration section [pgbouncer] ;;; ;;; Administrative settings ;;; logfile = /var/log/pgbouncer/pgbouncer.log pidfile = /var/run/pgbouncer/pgbouncer.pid ;;; ;;; Where to wait for clients ;;; ; ip address or * which means all ip-s listen_addr = 127.0.0.1 listen_port = 6432 ; unix socket is also used for -R. ; On debian it should be /var/run/postgresql ;unix_socket_dir = /tmp ;unix_socket_mode = 0777 ;unix_socket_group = ;;; ;;; Authentication settings ;;; ; any, trust, plain, crypt, md5 auth_type = trust ;auth_file = /8.0/main/global/pg_auth auth_file = /etc/pgbouncer/userlist.txt ;;; ;;; Users allowed into database 'pgbouncer' ;;; ; comma-separated list of users, who are allowed to change settings ;admin_users = user2, someadmin, otheradmin ; comma-separated list of users who are just allowed to use SHOW command ;stats_users = stats, root ;;; ;;; Pooler personality questions ;;; ; When server connection is released back to pool: ; session - after client disconnects ; transaction - after transaction finishes ; statement - after statement finishes pool_mode = session ; ; Query for cleaning connection immediately after releasing from client. ; No need to put ROLLBACK here, pgbouncer does not reuse connections ; where transaction is left open. ; ; Query for 8.3+: ; DISCARD ALL; ; ; Older versions: ; RESET ALL; SET SESSION AUTHORIZATION DEFAULT ; ; Empty if transaction pooling is in use. ; server_reset_query = DISCARD ALL ; ; Comma-separated list of parameters to ignore when given ; in startup packet. Newer JDBC versions require the ; extra_float_digits here. ; ;ignore_startup_parameters = extra_float_digits ; ; When taking idle server into use, this query is ran first. ; SELECT 1 ; ;server_check_query = select 1 ; If server was used more recently that this many seconds ago, ; skip the check query. Value 0 may or may not run in immediately. ;server_check_delay = 30 ;;; ;;; Connection limits ;;; ; total number of clients that can connect max_client_conn = 100 ; default pool size. 20 is good number when transaction pooling ; is in use, in session pooling it needs to be the number of ; max clients you want to handle at any moment default_pool_size = 20 ; how many additional connection to allow in case of trouble ;reserve_pool_size = 5 ; if a clients needs to wait more than this many seconds, use reserve pool ;reserve_pool_timeout = 3 ; log if client connects or server connection is made ;log_connections = 1 ; log if and why connection was closed ;log_disconnections = 1 ; log error messages pooler sends to clients ;log_pooler_errors = 1 ; If off, then server connections are reused in LIFO manner ;server_round_robin = 0 ;;; ;;; Timeouts ;;; ;; Close server connection if its been connected longer. ;server_lifetime = 1200 ;; Close server connection if its not been used in this time. ;; Allows to clean unnecessary connections from pool after peak. ;server_idle_timeout = 60 ;; Cancel connection attempt if server does not answer takes longer. ;server_connect_timeout = 15 ;; If server login failed (server_connect_timeout or auth failure) ;; then wait this many second. ;server_login_retry = 15 ;; Dangerous. Server connection is closed if query does not return ;; in this time. Should be used to survive network problems, ;; _not_ as statement_timeout. (default: 0) ;query_timeout = 0 ;; Dangerous. Client connection is closed if the query is not assigned ;; to a server in this time. Should be used to limit the number of queued ;; queries in case of a database or network failure. (default: 0) ;query_wait_timeout = 0 ;; Dangerous. Client connection is closed if no activity in this time. ;; Should be used to survive network problems. (default: 0) ;client_idle_timeout = 0 ;; Disconnect clients who have not managed to log in after connecting ;; in this many seconds. ;client_login_timeout = 60 ;; Clean automatically created database entries (via "*") if they ;; stay unused in this many seconds. ; autodb_idle_timeout = 3600 ;;; ;;; Low-level tuning options ;;; ;; buffer for streaming packets ;pkt_buf = 2048 ;; man 2 listen ;listen_backlog = 128 ;; networking options, for info: man 7 tcp ;; Linux: notify program about new connection only if there ;; is also data received. (Seconds to wait.) ;; On Linux the default is 45, on other OS'es 0. ;tcp_defer_accept = 0 ;; In-kernel buffer size (Linux default: 4096) ;tcp_socket_buffer = 0 ;; whether tcp keepalive should be turned on (0/1) ;tcp_keepalive = 1 ;; following options are Linux-specific. ;; they also require tcp_keepalive=1 ;; count of keepaliva packets ;tcp_keepcnt = 0 ;; how long the connection can be idle, ;; before sending keepalive packets ;tcp_keepidle = 0 ;; The time between individual keepalive probes. ;tcp_keepintvl = 0 ;; DNS lookup caching time ;dns_max_ttl = 15 ;; DNS zone SOA lookup period ;dns_zone_check_period = 0 pgbouncer-1.5.4/etc/mkauth.py0000755000175000017500000000143611765176015013064 00000000000000#! /usr/bin/env python import sys, os, tempfile, psycopg2 if len(sys.argv) != 3: print 'usage: mkauth DSTFN CONNSTR' sys.exit(1) # read old file fn = sys.argv[1] try: old = open(fn, 'r').read() except IOError: old = '' # create new file data db = psycopg2.connect(sys.argv[2]) curs = db.cursor() curs.execute("select usename, passwd from pg_shadow order by 1") lines = [] for user, psw in curs.fetchall(): user = user.replace('"', '""') if not psw: psw = '' psw = psw.replace('"', '""') lines.append('"%s" "%s" ""\n' % (user, psw)) db.commit() cur = "".join(lines) # if changed, replace data securely if old != cur: fd, tmpfn = tempfile.mkstemp(dir = os.path.split(fn)[0]) f = os.fdopen(fd, 'w') f.write(cur) f.close() os.rename(tmpfn, fn) pgbouncer-1.5.4/etc/userlist.txt0000644000175000017500000000007011671464171013621 00000000000000"marko" "asdasd" "postgres" "asdasd" "pgbouncer" "fake" pgbouncer-1.5.4/config.guess0000755000175000017500000012763712055406554012774 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 # Free Software Foundation, Inc. timestamp='2009-12-30' # This file 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: pgbouncer-1.5.4/test/0000755000175000017500000000000012055406737011476 500000000000000pgbouncer-1.5.4/test/test.sh0000755000175000017500000002010311765176015012730 00000000000000#!/bin/sh # Notes: # - uses iptables and -F with some tests, probably not very friendly to your firewall # - uses nc (netcat) with some tests, skips if not in path # - assumes postgres 8.2 fix your path so that it comes first export PATH=/usr/lib/postgresql/8.4/bin:$PATH export PGDATA=$PWD/pgdata export PGHOST=localhost export PGPORT=6667 export EF_ALLOW_MALLOC_0=1 BOUNCER_LOG=test.log BOUNCER_INI=test.ini BOUNCER_PID=test.pid BOUNCER_PORT=`sed -n '/^listen_port/s/listen_port.*=[^0-9]*//p' $BOUNCER_INI` BOUNCER_EXE="./pgbouncer" LOGDIR=log NC_PORT=6668 PG_PORT=6666 PG_LOG=$LOGDIR/pg.log pgctl() { pg_ctl -o "-p $PG_PORT" -D $PGDATA $@ >>$PG_LOG 2>&1 } ulimit -c unlimited mkdir -p $LOGDIR rm -f $BOUNCER_LOG $PG_LOG # rm -r $PGDATA if [ ! -d $PGDATA ]; then mkdir $PGDATA initdb >> $PG_LOG 2>&1 sed -i "/unix_socket_directory/s:.*unix_socket_directory.*:unix_socket_directory = '/tmp':" pgdata/postgresql.conf fi pgctl start sleep 5 psql -p $PG_PORT -l |grep p0 > /dev/null || { psql -p $PG_PORT -c "create user bouncer" template1 createdb -p $PG_PORT p0 createdb -p $PG_PORT p1 } $BOUNCER_EXE -d $BOUNCER_INI sleep 1 # # fw hacks # fw_drop_port() { case `uname` in Linux) sudo iptables -A OUTPUT -p tcp --dport $1 -j DROP;; Darwin) sudo ipfw add 100 drop tcp from any to 127.0.0.1 dst-port $1;; *) echo "Unknown OS";; esac } fw_reject_port() { case `uname` in Linux) sudo iptables -A OUTPUT -p tcp --dport $1 -j REJECT --reject-with tcp-reset;; Darwin) sudo ipfw add 100 reset tcp from any to 127.0.0.1 dst-port $1;; *) echo "Unknown OS";; esac } fw_reset() { case `uname` in Linux) sudo iptables -F OUTPUT;; Darwin) sudo ipfw del 100;; *) echo "Unknown OS"; exit 1;; esac } # # util functions # complete() { test -f $BOUNCER_PID && kill `cat $BOUNCER_PID` >/dev/null 2>&1 pgctl -m fast stop rm -f $BOUNCER_PID } die() { echo $@ complete exit 1 } admin() { psql -h /tmp -U pgbouncer pgbouncer -c "$@;" || die "Cannot contact bouncer!" } runtest() { echo -n "`date` running $1 ... " eval $1 >$LOGDIR/$1.log 2>&1 if [ $? -eq 0 ]; then echo "ok" else echo "FAILED" fi date >> $LOGDIR/$1.log # allow background processing to complete wait # start with fresh config kill -HUP `cat $BOUNCER_PID` } # server_lifetime test_server_lifetime() { admin "set server_lifetime=2" psql -c "select now()" p0 sleep 3 rc=`psql -p $PG_PORT -tAqc "select count(1) from pg_stat_activity where usename='bouncer' and datname='p0'" p0` psql -c "select now()" p0 return $rc } # server_idle_timeout test_server_idle_timeout() { admin "set server_idle_timeout=2" psql -c "select now()" p0 sleep 3 rc=`psql -p $PG_PORT -tAqc "select count(1) from pg_stat_activity where usename='bouncer' and datname='p0'" p0` psql -c "select now()" p0 return $rc } # query_timeout test_query_timeout() { admin "set query_timeout=3" psql -c "select pg_sleep(5)" p0 && return 1 return 0 } # client_idle_timeout test_client_idle_timeout() { admin "set client_idle_timeout=2" psql --set ON_ERROR_STOP=1 p0 <<-PSQL_EOF select now(); \! sleep 3 select now(); PSQL_EOF test $? -eq 0 && return 1 return 0 } # server_login_retry test_server_login_retry() { admin "set query_timeout=10" admin "set server_login_retry=1" (pgctl -m fast stop; sleep 3; pgctl start) & sleep 1 psql -c "select now()" p0 rc=$? wait return $rc } # server_connect_timeout - uses netcat to start dummy server test_server_connect_timeout_establish() { which nc >/dev/null || return 1 echo nc -q 5 -l $NC_PORT nc -l -q 5 $NC_PORT >/dev/null & sleep 2 admin "set query_timeout=3" admin "set server_connect_timeout=2" psql -c "select now()" p2 # client will always see query_timeout, need to grep for connect timeout grep "closing because: connect timeout" $BOUNCER_LOG rc=$? # didnt seem to die otherwise killall nc return $rc } # server_connect_timeout - block with iptables test_server_connect_timeout_reject() { test -z $CAN_SUDO && return 1 admin "set query_timeout=5" admin "set server_connect_timeout=3" fw_drop_port $PG_PORT psql -c "select now()" p0 fw_reset # client will always see query_timeout, need to grep for connect timeout grep "closing because: connect failed" $BOUNCER_LOG } # server_check_delay test_server_check_delay() { test -z $CAN_SUDO && return 1 admin "set server_check_delay=2" admin "set server_login_retry=3" admin "set query_timeout=10" psql p0 -c "select now()" fw_reject_port $PG_PORT sleep 3 psql -tAq p0 -c "select 1" >$LOGDIR/test.tmp & sleep 1 fw_reset echo `date` rules flushed wait echo `date` done waiting test "`cat $LOGDIR/test.tmp`" = "1" } # max_client_conn test_max_client_conn() { admin "set max_client_conn=5" admin "show config" for i in `seq 1 4`; do psql p1 -c "select now() as sleeping from pg_sleep(3);" & done # last conn allowed psql p1 -c "select now() as last_conn" || return 1 # exhaust it psql p1 -c "select now() as sleeping from pg_sleep(3);" & sleep 1 # shouldn't be allowed psql p1 -c "select now() as exhausted" && return 1 # should be ok echo 'waiting for clients to complete ...' wait psql p1 -c "select now() as ok" || return 1 return 0 } # - max pool size test_pool_size() { docount() { for i in `seq 10`; do psql $1 -c "select pg_sleep(0.5)" & done wait cnt=`psql -tAqc "select count(1) from pg_stat_activity where usename='bouncer' and datname='$1'" $1` echo $cnt } test `docount p0` -ne 2 && return 1 test `docount p1` -ne 5 && return 1 return 0 } # test online restart while clients running test_online_restart() { # max_client_conn=10 # default_pool_size=5 for i in `seq 1 5`; do echo "`date` attempt $i" for j in `seq 1 5`; do psql -c "select now() as sleeping from pg_sleep(2)" p1 & done pid1=`cat $BOUNCER_PID` echo "old bouncer is $pid1" $BOUNCER_EXE -d -R $BOUNCER_INI sleep 2 pid2=`cat $BOUNCER_PID` echo "new bouncer is $pid2" [ $pid1 = $pid2 ] && return 1 done return 0 } # test pause/resume test_pause_resume() { rm -f $LOGDIR/test.tmp for i in `seq 1 50`; do psql -tAq p0 -c 'select 1 from pg_sleep(0.1)' >>$LOGDIR/test.tmp done & for i in `seq 1 5`; do admin "pause" sleep 1 admin "resume" sleep 1 done wait test `wc -l <$LOGDIR/test.tmp` -eq 50 } # test suspend/resume test_suspend_resume() { rm -f $LOGDIR/test.tmp for i in `seq 1 50`; do psql -tAq p0 -c 'select 1 from pg_sleep(0.1)' >>$LOGDIR/test.tmp done & for i in `seq 1 5`; do psql -h /tmp -p $BOUNCER_PORT pgbouncer -U pgbouncer <<-PSQL_EOF suspend; \! sleep 1 resume; \! sleep 1 PSQL_EOF done wait test `wc -l <$LOGDIR/test.tmp` -eq 50 } # test pool database restart test_database_restart() { admin "set server_login_retry=1" psql p0 -c "select now() as p0_before_restart" pgctl -m fast restart echo `date` restart 1 psql p0 -c "select now() as p0_after_restart" || return 1 # do with some more clients for i in `seq 1 5`; do psql p0 -c "select pg_sleep($i)" & psql p1 -c "select pg_sleep($i)" & done pgctl -m fast restart echo `date` restart 2 wait psql p0 -c "select now() as p0_after_restart" || return 1 } # test connect string change test_database_change() { admin "set server_lifetime=2" db1=`psql -tAq p1 -c "select current_database()"` cp test.ini test.ini.bak sed 's/\(p1 = port=6666 host=127.0.0.1 dbname=\)\(p1\)/\1p0/g' test.ini >test2.ini mv test2.ini test.ini kill -HUP `cat $BOUNCER_PID` sleep 3 db2=`psql -tAq p1 -c "select current_database()"` echo "db1=$db1 db2=$db2" cp test.ini.bak test.ini rm test.ini.bak admin "show databases" admin "show pools" test $db1 = "p1" -a $db2 = "p0" } echo "Testing for sudo access." sudo true && CAN_SUDO=1 testlist=" test_server_login_retry test_client_idle_timeout test_server_lifetime test_server_idle_timeout test_query_timeout test_server_connect_timeout_establish test_server_connect_timeout_reject test_server_check_delay test_max_client_conn test_pool_size test_online_restart test_pause_resume test_suspend_resume test_database_restart test_database_change " if [ $# -gt 0 ]; then testlist=$@ fi for test in $testlist do runtest $test done complete # vim: sts=0 sw=8 noet nosmarttab: pgbouncer-1.5.4/test/ctest7000.ini0000644000175000017500000000140711765176015013552 00000000000000;; database name = connect string [databases] ; redirect bardb to bazdb on localhost conntest = host=127.0.0.1 port=5432 dbname=marko password=kama ;; Configuation section [pgbouncer] logfile = ctest7000.log pidfile = ctest7000.pid listen_addr = 127.0.0.1 listen_port = 7000 unix_socket_dir = /tmp auth_type = md5 auth_file = userlist.txt admin_users = marko stats_users = stats pool_mode = transaction server_reset_query = reset all server_check_query = select 1 server_check_delay = 2 max_client_conn = 5000 default_pool_size = 20 log_connections = 0 log_disconnections = 0 log_pooler_errors = 0 server_lifetime = 30 server_idle_timeout = 3 server_connect_timeout = 2 server_login_retry = 5 query_timeout = 5 client_idle_timeout = 10 client_login_timeout = 50 pgbouncer-1.5.4/test/stress.py0000755000175000017500000000473411665176317013332 00000000000000#! /usr/bin/env python import sys, os, re, time, psycopg import threading, thread, random n_thread = 100 longtx = 0 tx_sleep = 0 tx_sleep = 8 conn_data = { 'dbname': 'marko', #'host': '127.0.0.1', 'host': '/tmp', 'port': '6000', 'user': 'marko', #'password': '', 'connect_timeout': '5', } def get_connstr(): tmp = [] for k, v in conn_data.items(): tmp.append(k+'='+v) return " ".join(tmp) class WorkThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.setDaemon(True) self.stat_lock = threading.Lock() self.query_cnt = 0 def inc_cnt(self): self.stat_lock.acquire() self.query_cnt += 1 self.stat_lock.release() def fetch_cnt(self): self.stat_lock.acquire() val = self.query_cnt self.query_cnt = 0 self.stat_lock.release() return val def run(self): try: time.sleep(random.random() * 10.0) except: pass while 1: try: self.main_loop() except KeyboardInterrupt: break except SystemExit: break except Exception, d: print d try: time.sleep(5) except: pass def main_loop(self): db = psycopg.connect(get_connstr()) if not longtx: db.autocommit(1) n = 0 while n < 10: self.do_work(db) self.inc_cnt() n += 1 def do_work(self, db): curs = db.cursor() q = "select pg_sleep(%.02f)" % (random.random() * 1) curs.execute(q) time.sleep(tx_sleep * random.random() + 1) if longtx: db.commit() def main(): print "connstr", get_connstr() thread_list = [] while len(thread_list) < n_thread: t = WorkThread() t.start() thread_list.append(t) print "started %d threads" % len(thread_list) last = time.time() while 1: time.sleep(1) now = time.time() dur = now - last if dur >= 5: last = now cnt = 0 for t in thread_list: cnt += t.fetch_cnt() avg = cnt / dur print "avg", avg if __name__ == '__main__': try: main() except SystemExit: pass except KeyboardInterrupt: pass #except Exception, d: # print d pgbouncer-1.5.4/test/test.ini0000644000175000017500000000566712055400522013076 00000000000000;; database name = connect string [databases] p0 = port=6666 host=127.0.0.1 dbname=p0 user=bouncer pool_size=2 p1 = port=6666 host=127.0.0.1 dbname=p1 user=bouncer p2 = port=6668 host=127.0.0.1 dbname=p2 user=bouncer ;; Configuation section [pgbouncer] ;;; ;;; Administrative settings ;;; logfile = test.log pidfile = test.pid ;;; ;;; Where to wait for clients ;;; ; ip address or * which means all ip-s listen_addr = 127.0.0.1 listen_port = 6667 unix_socket_dir = /tmp ;;; ;;; Authentication settings ;;; ; any, trust, plain, crypt, md5 auth_type = trust #auth_file = 8.0/main/global/pg_auth auth_file = userlist.txt ;;; ;;; Pooler personality questions ;;; ; When server connection is released back to pool: ; session - after client disconnects ; transaction - after transaction finishes ; statement - after statement finishes pool_mode = statement ; When taking idle server into use, this query is ran first. ; ; Query for session pooling: ; ABORT; RESET ALL; SET SESSION AUTHORIZATION DEFAULT ; Query for statement/transaction pooling: ; SELECT 1 ; Empty query disables the functionality server_check_query = select 1 ; If server was used more recently that this many seconds ago, ; skip the check query. If 0, the check query is always ran. server_check_delay = 10 ;;; ;;; Connection limits ;;; ; total number of clients that can connect max_client_conn = 10 default_pool_size = 5 ;;; ;;; Timeouts ;;; ; Close server connection if its been connected longer. server_lifetime = 120 ; Close server connection if its not been used in this time. ; Allows to clean unneccessary connections from pool after peak. server_idle_timeout = 60 ; Cancel connection attepmt if server does not answer takes longer. server_connect_timeout = 15 ; If server login failed (server_connect_timeout or auth failure) ; then wait this many second. server_login_retry = 15 ; Dangerous. Server connection is closed if query does not return ; in this time. Should be used to survive network problems, ; _not_ as statement_timeout. (default: 0) query_timeout = 0 ; Dangerous. Client connection is closed if no activity in this time. ; Should be used to survive network problems. (default: 0) client_idle_timeout = 0 ;;; ;;; Low-level tuning options ;;; ; buffer for streaming packets pkt_buf = 2048 ;;; ;;; networking options, for info: man 7 tcp ;;; ; linux: notify program about new connection only if there ; is also data received. (Seconds to wait.) tcp_defer_accept = 0 ;; following options are reloadable, but apply only to ;; new connections. ; in-kernel buffer size (linux default: 4096) tcp_socket_buffer = 0 ; whether tcp keepalive should be turned on (0/1) tcp_keepalive = 0 ;; following options are linux-specific. ;; they also require tcp_keepalive=1 ; count of keepaliva packets tcp_keepcnt = 0 ; how long the connection can be idle, ; before sending keepalive packets tcp_keepidle = 0 ; The time between individual keepalive probes. tcp_keepintvl = 0 pgbouncer-1.5.4/test/Makefile0000644000175000017500000000055611765176015013064 00000000000000 PGINC = -I$(shell pg_config --includedir) PGLIB = -L$(shell pg_config --libdir) include ../config.mak CPPFLAGS += -I../include $(PGINC) LDFLAGS += $(PGLIB) LIBS := -lpq $(LIBS) ifeq ($(PORTNAME),win32) CPPFLAGS += -I../win32 endif all: asynctest asynctest: asynctest.c $(CC) -o $@ $< $(DEFS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LIBS) clean: rm -f asynctest pgbouncer-1.5.4/test/conntest.sh0000755000175000017500000000147111665176317013621 00000000000000#!/bin/sh fw_drop_port() { echo "fw_drop_port" case `uname` in Linux) sudo iptables -A OUTPUT -p tcp --dport $1 -j DROP;; Darwin) sudo ipfw add 100 drop tcp from any to 127.0.0.1 dst-port $1;; *) echo "Unknown OS";; esac } fw_reject_port() { echo "fw_reject_port" case `uname` in Linux) sudo iptables -A OUTPUT -p tcp --dport $1 -j REJECT --reject-with tcp-reset;; Darwin) sudo ipfw add 100 reset tcp from any to 127.0.0.1 dst-port $1;; *) echo "Unknown OS";; esac } fw_reset() { echo "fw_reset" case `uname` in Linux) sudo iptables -F;; Darwin) sudo ipfw del 100;; *) echo "Unknown OS"; exit 1;; esac } port=5432 port=7000 fw_reset while true; do fw_drop_port $port sleep 12 fw_reset sleep 12 fw_reject_port $port sleep 3 fw_reset sleep 6 done pgbouncer-1.5.4/test/asynctest.c0000644000175000017500000003104111765176015013576 00000000000000/* * Things to test: * - Conn per query * - show tx * - long tx * - variable-size query */ #include "system.h" #ifdef WIN32 #undef strerror #undef main #endif #include #include #include static void log_error(const char *, ...); static void log_debug(const char *, ...); static void fatal(const char *fmt, ...); static void fatal_noexit(const char *fmt, ...); #include "list.h" static char *simple_query = "select 1"; typedef void (*libev_cb_f)(int sock, short flags, void *arg); typedef struct DbConn { List head; const char *connstr; struct event ev; PGconn *con; bool logged_in; //time_t connect_time; int query_count; //const char *query; int _arglen; } DbConn; #define QT_SIMPLE 1 #define QT_BIGDATA 2 #define QT_SLEEP 4 static unsigned QueryTypes = 0; static uint64_t LoginOkCount = 0; static uint64_t LoginFailedCount = 0; static uint64_t SqlErrorCount = 0; static uint64_t QueryCount = 0; static char *bulk_data; static int bulk_data_max = 128*1024; /* power of 2 */ static int verbose = 0; static int throttle_connects = 0; static int throttle_queries = 0; static int per_conn_queries = 1; static STATLIST(idle_list); static STATLIST(active_list); static usec_t _time_cache = 0; /* * utility functions */ static usec_t get_time_usec(void) { struct timeval tv; gettimeofday(&tv, NULL); return (usec_t)tv.tv_sec * USEC + tv.tv_usec; } static usec_t get_cached_time(void) { if (!_time_cache) _time_cache = get_time_usec(); return _time_cache; } static void reset_time_cache(void) { _time_cache = 0; } /* fill mem with random junk */ static void init_bulk_data(void) { int i; bulk_data = malloc(bulk_data_max + 1); for (i = 0; i < bulk_data_max; i++) { bulk_data[i] = 'a' + (i % 26); } bulk_data[i] = 0; } static DbConn *new_db(const char *connstr) { DbConn *db = malloc(sizeof(*db)); memset(db, 0, sizeof(*db)); list_init(&db->head); db->connstr = connstr; return db; } static void set_idle(DbConn *db) { Assert(item_in_list(&db->head, &active_list.head)); statlist_remove(&db->head, &active_list); statlist_append(&db->head, &idle_list); log_debug("%p: set_idle", db); } static void set_active(DbConn *db) { Assert(item_in_list(&db->head, &idle_list.head)); statlist_remove(&db->head, &idle_list); statlist_append(&db->head, &active_list); log_debug("%p: set_active", db); } static void fatal_perror(const char *err) { log_error("%s: %s", err, strerror(errno)); exit(1); } static void fatal_noexit(const char *fmt, ...) { va_list ap; char buf[1024]; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); printf("FATAL: %s\n", buf); } static void fatal(const char *fmt, ...) { va_list ap; char buf[1024]; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); printf("FATAL: %s\n", buf); exit(1); } static void log_debug(const char *fmt, ...) { va_list ap; char buf[1024]; if (verbose == 0) return; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); printf("dbg: %s\n", buf); } static void log_error(const char *fmt, ...) { va_list ap; char buf[1024]; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); printf("ERR: %s\n", buf); } static void wait_event(DbConn *db, short ev, libev_cb_f fn) { event_set(&db->ev, PQsocket(db->con), ev, fn, db); if (event_add(&db->ev, NULL) < 0) fatal_perror("event_add"); } static void disconnect(DbConn *db, bool is_err, const char *reason, ...) { char buf[1024]; va_list ap; if (is_err) { if (db->logged_in) SqlErrorCount++; else LoginFailedCount++; } if (db->con) { va_start(ap, reason); vsnprintf(buf, sizeof(buf), reason, ap); va_end(ap); log_debug("disconnect because: %s", buf); PQfinish(db->con); db->con = NULL; db->logged_in = 0; set_idle(db); } } /* some error happened */ static void conn_error(DbConn *db, const char *desc) { static int ecount = 0; if (db->con) { if (ecount++ < 3) printf("\r%s (arglen=%d)\n", PQerrorMessage(db->con), db->_arglen); disconnect(db, true, "%s: %s", desc, PQerrorMessage(db->con)); } else { printf("random error: %s\n", desc); exit(1); } } /* * Connection has a resultset avalable, fetch it. * * Returns true if there may be more results coming, * false if all done. */ static bool another_result(DbConn *db) { PGresult *res; /* got one */ res = PQgetResult(db->con); if (res == NULL) { QueryCount++; set_idle(db); return false; } switch (PQresultStatus(res)) { case PGRES_TUPLES_OK: // todo: check result if (db->_arglen > 0) { int curlen = strlen(PQgetvalue(res, 0, 0)); if (curlen != db->_arglen) { printf("result does not match: sent=%d got=%d\n", db->_arglen, curlen); } } case PGRES_COMMAND_OK: PQclear(res); break; default: PQclear(res); conn_error(db, "weird result"); return false; } return true; } /* * Called when select() told that conn is avail for reading/writing. * * It should call postgres handlers and then change state if needed. */ static void result_cb(int sock, short flags, void *arg) { DbConn *db = arg; int res; res = PQconsumeInput(db->con); if (res == 0) { conn_error(db, "PQconsumeInput"); return; } /* loop until PQgetResult returns NULL */ while (1) { /* if PQisBusy, then incomplete result */ if (PQisBusy(db->con)) { wait_event(db, EV_READ, result_cb); break; } /* got one */ if (!another_result(db)) break; } } static void send_cb(int sock, short flags, void *arg) { int res; DbConn *db = arg; res = PQflush(db->con); if (res > 0) { wait_event(db, EV_WRITE, send_cb); } else if (res == 0) { wait_event(db, EV_READ, result_cb); } else conn_error(db, "PQflush"); } static int send_query_bigdata(DbConn *db) { const char *values[1]; int lengths[1]; int fmts[1]; int arglen; char *q = "select $1::text"; arglen = random() % bulk_data_max; db->_arglen = arglen; values[0] = bulk_data + bulk_data_max - arglen; lengths[0] = arglen; fmts[0] = 1; return PQsendQueryParams(db->con, q, 1, NULL, values, lengths, fmts, 1); } static int send_query_sleep(DbConn *db) { const char *q = "select pg_sleep(0.2)"; return PQsendQueryParams(db->con, q, 0, NULL, NULL, NULL, NULL, 0); } static int send_query_simple(DbConn *db) { const char *q = simple_query; return PQsendQueryParams(db->con, q, 0, NULL, NULL, NULL, NULL, 0); } /* send the query to server connection */ static void send_query(DbConn *db) { int res; if (db->query_count >= per_conn_queries) { disconnect(db, false, "query count full"); return; } db->query_count++; /* send query */ if (QueryTypes & QT_SLEEP) { res = send_query_sleep(db); } else if (QueryTypes & QT_BIGDATA) { res = send_query_bigdata(db); } else { res = send_query_simple(db); } if (!res) { conn_error(db, "PQsendQueryParams"); return; } /* flush it down */ res = PQflush(db->con); if (res > 0) { wait_event(db, EV_WRITE, send_cb); } else if (res == 0) { wait_event(db, EV_READ, result_cb); } else conn_error(db, "PQflush"); } static void connect_cb(int sock, short flags, void *arg) { DbConn *db = arg; PostgresPollingStatusType poll_res; poll_res = PQconnectPoll(db->con); switch (poll_res) { case PGRES_POLLING_WRITING: wait_event(db, EV_WRITE, connect_cb); break; case PGRES_POLLING_READING: wait_event(db, EV_READ, connect_cb); break; case PGRES_POLLING_OK: log_debug("login ok: fd=%d", PQsocket(db->con)); LoginOkCount++; db->logged_in = 1; send_query(db); break; default: conn_error(db, "PQconnectPoll"); } } static void launch_connect(DbConn *db) { /* launch new connection */ db->logged_in = 0; db->query_count = 0; db->con = PQconnectStart(db->connstr); if (db->con == NULL) { log_error("PQconnectStart: no mem"); exit(1); } if (PQstatus(db->con) == CONNECTION_BAD) { conn_error(db, "PQconnectStart"); return; } wait_event(db, EV_WRITE, connect_cb); } #define ACT_ONCE 10 static void handle_idle(void) { DbConn *db; List *item, *tmp; int allow_connects = 100000; int allow_queries = 100000; static usec_t startup_time = 0; usec_t now = get_cached_time(); usec_t diff; int once; if (startup_time == 0) startup_time = get_cached_time(); diff = now - startup_time; if (diff < USEC) diff = USEC; if (throttle_connects > 0) { allow_connects = throttle_connects - LoginOkCount * USEC / diff; once = throttle_connects / ACT_ONCE; if (!once) once = 1; if (once < allow_connects) allow_connects = once; } if (throttle_queries > 0) { allow_queries = throttle_queries - QueryCount * USEC / diff; once = throttle_connects / ACT_ONCE; if (!once) once = 1; if (once < allow_connects) allow_connects = once; } statlist_for_each_safe(item, &idle_list, tmp) { db = container_of(item, DbConn, head); if (db->con && allow_queries > 0) { set_active(db); send_query(db); allow_queries--; } else if (allow_connects > 0) { set_active(db); launch_connect(db); allow_connects--; } } } static void run_stats(int fd, short ev, void *arg) { static struct event ev_stats; struct timeval period = { 5, 0 }; static usec_t last_time = 0; static uint64_t last_query_count = 0; static uint64_t last_login_failed_count = 0; static uint64_t last_login_ok_count = 0; static uint64_t last_sql_error_count = 0; double time_diff, qcount_diff, loginerr_diff, loginok_diff, sqlerr_diff; usec_t now = get_cached_time(); time_diff = now - last_time; if (last_time && time_diff) { qcount_diff = QueryCount - last_query_count; loginerr_diff = LoginFailedCount - last_login_failed_count; sqlerr_diff = SqlErrorCount - last_sql_error_count; loginok_diff = LoginOkCount - last_login_ok_count; if (verbose == 0) { printf(">> loginok,loginerr,sqlerr,qcount: %6.1f / %6.1f / %6.1f / %6.1f active/idle: %3d / %3d \r", USEC * loginok_diff / time_diff, USEC * loginerr_diff / time_diff, USEC * sqlerr_diff / time_diff, USEC * qcount_diff / time_diff, statlist_count(&active_list), statlist_count(&idle_list)); fflush(stdout); } } if (!last_time) evtimer_set(&ev_stats, run_stats, NULL); if (evtimer_add(&ev_stats, &period) < 0) fatal_perror("evtimer_add"); last_query_count = QueryCount; last_login_failed_count = LoginFailedCount; last_sql_error_count = SqlErrorCount; last_login_ok_count = LoginOkCount; last_time = now; } static const char usage_str [] = "usage: asynctest [-d connstr][-n numconn][-s seed][-t ][-C maxconn][-Q maxquery][-q perconnq]\n" " -d connstr libpq connect string\n" " -n num number of connections\n" " -s seed random number seed\n" " -t type of queries query type, see below\n" " -C maxcps max number of connects per sec\n" " -Q maxqps max number of queries per sec\n" " -q num queries per connection (default 1)\n" " -S sql set simple query\n" "accepted query types:\n" " B - bigdata\n" " S - sleep occasionally\n" " 1 - simple 'select 1'\n"; int main(int argc, char *argv[]) { int i, c; DbConn *db; unsigned seed = time(NULL) ^ getpid(); char *cstr = NULL; int numcon = 50; #ifdef WIN32 int wsresult; WSADATA wsaData; #endif while ((c = getopt(argc, argv, "S:d:n:s:t:hvC:Q:q:")) != EOF) { switch (c) { default: case 'h': printf("%s", usage_str); return 0; case 'S': simple_query = optarg; break; case 'd': cstr = optarg; break; case 'C': throttle_connects = atoi(optarg); break; case 'Q': throttle_queries = atoi(optarg); break; case 'n': numcon = atoi(optarg); break; case 's': seed = atoi(optarg); break; case 'v': verbose++; break; case 'q': per_conn_queries = atoi(optarg); break; case 't': for (i = 0; optarg[i]; i++) { switch (optarg[i]) { case 'B': QueryTypes = QT_BIGDATA; break; case 'S': QueryTypes = QT_SLEEP; break; case '1': QueryTypes = QT_SIMPLE; break; default: log_error("bad type"); break; } } } } if (!cstr) { printf(usage_str); return 1; } #ifdef WIN32 wsresult = WSAStartup(MAKEWORD(2,0),&wsaData); if (wsresult != 0) { fatal("Cannot start the network subsystem -%d", wsresult); } #endif if (throttle_connects < 0 || throttle_queries < 0 || numcon < 0) fatal("invalid parameter"); if (QueryTypes == 0) QueryTypes = QT_SIMPLE; printf("using seed: %u\n", seed); srandom(seed); init_bulk_data(); for (i = 0; i < numcon; i++) { db = new_db(cstr); statlist_append(&db->head, &idle_list); } event_init(); run_stats(0, 0, NULL); printf("running..\n"); while (1) { handle_idle(); reset_time_cache(); if (event_loop(EVLOOP_ONCE) < 0) log_error("event_loop: %s", strerror(errno)); } return 0; } pgbouncer-1.5.4/test/ctest6000.ini0000644000175000017500000000137411665176317013560 00000000000000;; database name = connect string [databases] ; redirect bardb to bazdb on localhost conntest = host=127.0.0.1 port=7000 dbname=conntest ;; Configuation section [pgbouncer] logfile = ctest6000.log pidfile = ctest6000.pid listen_addr = 127.0.0.1 listen_port = 6000 unix_socket_dir = /tmp auth_type = md5 auth_file = userlist.txt admin_users = marko stats_users = stats pool_mode = transaction server_reset_query = reset all server_check_query = select 1 server_check_delay = 2 max_client_conn = 1000 default_pool_size = 20 log_connections = 0 log_disconnections = 0 log_pooler_errors = 0 server_lifetime = 30 server_idle_timeout = 3 server_connect_timeout = 2 server_login_retry = 5 query_timeout = 5 client_idle_timeout = 10 client_login_timeout = 50 pgbouncer-1.5.4/test/userlist.txt0000644000175000017500000000006611665176317014037 00000000000000"marko" "kama" "postgres" "asdasd" "pgbouncer" "fake" pgbouncer-1.5.4/test/run-conntest.sh0000644000175000017500000000022111665176317014410 00000000000000#! /bin/sh createdb conntest ./pgbouncer -d ctest6000.ini ./pgbouncer -d ctest7000.ini ./asynctest # now run conntest.sh on another console