daemon-0.8/0000755000175000017500000000000014020203361010715 5ustar rafrafdaemon-0.8/conf/0000755000175000017500000000000014020200631011637 5ustar rafrafdaemon-0.8/conf/destdir0000755000175000017500000000213114020065106013226 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile to change DESTDIR. # # 20210304 raf # Strip off the leading "--destdir=" from the command line option if [ x"$1" = x ] then echo "usage: $0 --destdir=..." exit 1 fi destdir="${1#--destdir=}" [ x"$destdir" != x ] && destdir=" $destdir" perl -pi \ -e 's{^(DESTDIR :=).*$}{$1'"$destdir"'}' \ Makefile # vi:set ts=4 sw=4: daemon-0.8/conf/ccenv0000755000175000017500000000200014020200340012650 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile to use $CC as CC # # 20210304 raf if [ "x$CC" != x ] then perl -pi \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's,^# (CC := .*other)$,CC := '"$CC"' # other,;' \ `find . -name Makefile` fi # vi:set ts=4 sw=4: daemon-0.8/conf/freebsd0000755000175000017500000001673014020200340013203 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on FreeBSD # # 20210304 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^# (CC := cc)$/$1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-overlength-strings)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-address)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-nonnull)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-format)$/$1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-pointer-bool-conversion)$/$1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^(\w*LIBS \+= pthread)$/# $1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^# (\w*LDFLAGS \+= -pthread)$/$1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/man/;' \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/\* #undef $1 \*\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCPY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCAT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SOCKADDR_SA_LEN) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SVR4) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_LIBUTIL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/gnuhurd0000755000175000017500000001675614020200340013255 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to exercise optional code # # 20210304 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^(GETOPT := getopt)$/# $1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_GETOPT_LONG=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-overlength-strings)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-address)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-nonnull)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-format)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-restrict)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_GETOPT_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ISOC_REALLOC) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LINUX_POLL_BUG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UNIX_DOMAIN_WILDCARD) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTY_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#undef (HAVE_VHANGUP) 1$/\/* #define $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_TTYNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/kfreebsd0000755000175000017500000001674114020200340013360 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on Linux # # 20210304 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^(GETOPT := getopt)$/# $1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_GETOPT_LONG=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-overlength-strings)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-address)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-nonnull)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-format)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-restrict)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_GETOPT_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ISOC_REALLOC) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LINUX_POLL_BUG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UNIX_DOMAIN_WILDCARD) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTY_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_TTYNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/linux0000755000175000017500000001702314020200340012724 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on Linux # # 20210304 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^(GETOPT := getopt)$/# $1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_GETOPT_LONG=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-overlength-strings)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-address)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-nonnull)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-format)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-restrict)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(PREFIX := ).*$/$1\/usr\/local/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_GETOPT_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ISOC_REALLOC) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LINUX_POLL_BUG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UNIX_DOMAIN_WILDCARD) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTY_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VHANGUP) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_TTYNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^\/\* #undef (HAVE_SYS_TTYDEFAULTS_H) \*\/$/#define $1 1/;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/macosx0000755000175000017500000002033214020200340013054 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on FreeBSD # # 20210304 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_POSIX_C_SOURCE=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_POSIX_SOURCE=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_XOPEN_SOURCE=1)$/$1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-pointer-bool-conversion)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-deprecated-declarations)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ -e 's/^(\w*CCFLAGS \+= -O3)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^\/\* #undef (NO_POSIX_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (NO_XOPEN_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STDINT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCPY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCAT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SOCKADDR_SA_LEN) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SVR4) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UTIL_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) \*\/$/#define $1 1/;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # Old versions of macOS (e.g. 10.6.8) don't handle some newer clang -Wno-* options. # But don't test if macports (which uses a newer compiler than Xcode's). # We know it's macports because CC is set. if [ -z "$CC" ] then if conf/test-gcc-opt -Wno-gnu-folding-constant then perl -pi \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ `find . -name macros.mk` else perl -pi \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ `find . -name macros.mk` fi if conf/test-gcc-opt -Wno-pointer-bool-conversion then perl -pi \ -e 's/^# (\S+ \+= -Wno-pointer-bool-conversion)$/$1/;' \ `find . -name macros.mk` else perl -pi \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ `find . -name macros.mk` fi fi # vi:set ts=4 sw=4: daemon-0.8/conf/netbsd0000755000175000017500000001673114020200340013051 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on NetBSD # # 20210304 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DNO_POSIX_SOURCE=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_XOPEN_SOURCE=1)$/$1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^(\w*LIBS \+= pthread)$/# $1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^# (\w*LDFLAGS \+= -pthread)$/$1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/man/;' \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ -e 's/^(PREFIX := \/usr\/local)$/# $1/;' \ -e 's/^# (PREFIX := \/usr\/pkg)$/$1/;' \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^\/\* #undef (NO_POSIX_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (NO_XOPEN_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCPY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCAT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SOCKADDR_SA_LEN) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SVR4) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UTIL_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/openbsd0000755000175000017500000001673614020200340013231 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on OpenBSD # # 20210304 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DNO_POSIX_SOURCE=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_XOPEN_SOURCE=1)$/$1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^(\w*LIBS \+= pthread)$/# $1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^# (\w*LDFLAGS \+= -pthread)$/$1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/man/;' \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^\/\* #undef (NO_POSIX_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (NO_XOPEN_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCPY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCAT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SOCKADDR_SA_LEN) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SVR4) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UTIL_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_TTYNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/prefix0000755000175000017500000000557314020200340013071 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile and macros.mk to change # PREFIX/CONF_INSDIR/CONFIG_PATH/ROOT_PID_DIR together. # But can be reversed with --prefix=default. # # 20210304 raf # Strip off the leading "--prefix=" from the command line option prefix="${1#--prefix=}" # With --prefix=default, set PREFIX to /usr/local. # Otherwise, set it to the given argument. if [ "$prefix" = "default" ] then perl -pi \ -e 's{^(PREFIX := ).*$}{$1/usr/local}' \ `find . -name Makefile` else perl -pi \ -e 's{^(PREFIX := ).*$}{$1'"$prefix"'}' \ `find . -name Makefile` fi # With --prefix=default or --prefix=/usr, CONF_INSDIR and ROOT_PID_DIR # stay as /etc and /var/run. Otherwise, we want them to be $(PREFIX)/etc # and $(PREFIX)/var/run. # # The operating system specific conf/* scripts mostly handle this fine. # # But for macports on macOS, we need this to move the system configuration # files to /opt/local/etc, and to move root's pidfiles to # /opt/local/var/run. # # In summary, if the --prefix option argument is /usr, then the system # configuration files are under /etc and root's pidfiles are in /var/run. # # If the --prefix argument is /usr/local or /opt/local or other, then the # system configuration files are under /usr/local/etc or /opt/local/etc or # other, and root's pidfiles are in /usr/local/var/run or /opt/local/var/run # or other. if [ "$prefix" = "/usr" -o "$prefix" = "default" ] then perl -pi \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ `find . -name Makefile` perl -pi \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(\S+ \+= -DETC_DIR)=.*$/# $1=\\"\/etc\\"/;' \ `find . -name macros.mk` else perl -pi \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ `find . -name Makefile` perl -pi \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ -e 's/^(?:# )?(\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\$(PREFIX)\/var\/run\\"/;' \ -e 's/^(?:# )?(\S+ \+= -DETC_DIR)=.*$/$1=\\"\$(PREFIX)\/etc\\"/;' \ `find . -name macros.mk` fi # vi:set ts=4 sw=4: daemon-0.8/conf/slackware0000755000175000017500000000203614020200340013537 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile to compile/install on Slackware (after conf/linux) # # 20210304 raf perl -pi \ -e 's{^(PREFIX := ).*$}{$1/usr};' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/man/;' \ `find . -name Makefile` # vi:set ts=4 sw=4: daemon-0.8/conf/solaris10-cc0000755000175000017500000001741114020200340013766 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 10 with cc # # 20210304 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^# (\S+ \+= m)$/$1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^# (CC := cc)$/$1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^(\S+ \+= -Wno-long-long)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -O3)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -Wall -pedantic)$/# $1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -xO4)$/$1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` # Solaris10 has /usr/ucb/install but OpenSolaris 200906 doesn't # so we use own version rather than trying to get their native # (weird) install program to work the way the normal one does. if [ ! -f /usr/ucb/install ] then perl -pi \ -e 's/install -m/.\/myinstall -m/' \ `find . -name rules.mk` else perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` fi perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^#define (HAVE_POLL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/solaris10-gcc0000755000175000017500000002023114020200340014127 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 10 with gcc # # 20210304 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` # Solaris10 has /usr/ucb/install but OpenSolaris 200906 doesn't # so we use own version rather than trying to get their native # (weird) install program to work the way the normal one does. if [ ! -f /usr/ucb/install ] then perl -pi \ -e 's/install -m/.\/myinstall -m/' \ `find . -name rules.mk` else perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` fi # On 64-bit Solaris/OpenSolaris gcc generates 32-bit binaries by # default so we have to ask explicitly for 64-bit. if [ "`isainfo -k`" = "amd64" ] then perl -pi \ -e 's/^# (\w*(?:CC|LD)FLAGS \+= -m64)$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` else perl -pi \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` fi perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) \*\/$/#define $1 1/;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/solaris6-cc0000755000175000017500000001670214020200340013715 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 6 with cc # # 20210304 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^# (\S+ \+= m)$/$1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\/etc\\"/;' \ -e 's/^# (CC := cc)$/$1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^(\S+ \+= -Wno-long-long)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -O3)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -Wall -pedantic)$/# $1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -xO4)$/$1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^#define (HAVE_POLL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTHREAD_RWLOCK) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_MSGHDR_MSG_CONTROL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_INDEXTONAME) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_NAMETOINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/solaris6-gcc0000755000175000017500000001670514020200340014067 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 6 with gcc # # 20210304 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\/etc\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTHREAD_RWLOCK) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_MSGHDR_MSG_CONTROL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_INDEXTONAME) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_NAMETOINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/solaris8-cc0000755000175000017500000001671014020200340013716 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 8 with cc # # 20210304 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^# (\S+ \+= m)$/$1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\/etc\\"/;' \ -e 's/^# (CC := cc)$/$1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^(\S+ \+= -Wno-long-long)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -O3)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -Wall -pedantic)$/# $1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -xO4)$/$1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^#define (HAVE_POLL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_INDEXTONAME) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_NAMETOINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/solaris8-gcc0000755000175000017500000001671514020200340014072 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 8 with gcc # # 20210304 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\/etc\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_INDEXTONAME) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_NAMETOINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) \*\/$/#define $1 1/;' \ `find . -name config.h` perl -pi \ -e 's/^#define (HAVE_SYS_TTYDEFAULTS_H) 1$/\/\* #undef $1 \*\//;' \ config.h # vi:set ts=4 sw=4: daemon-0.8/conf/test0000755000175000017500000000315514020200340012545 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify macros.mk and config.h to exercise optional code # # 20210304 raf perl -pi \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ `find . -name macros.mk` perl -pi \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/conf/test-gcc-opt0000755000175000017500000000164714020200340014103 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Test if the supplied gcc argument is supported # # 20210304 raf option="$1" gcc -E -xc /dev/null -Werror $option >/dev/null 2>/dev/null exit $? # vi:set ts=4 sw=4: daemon-0.8/conf/test_logind.c0000644000175000017500000000277614020200340014327 0ustar rafraf/* * * daemon - http://libslack.org/daemon/ * * Copyright (C) 1999-2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ /* * Test program for logind/elogind (Linux only). This program can't * be run. It is only to be compiled so as to make sure that we have * all of these functions and types available. On Linux systems * with systemd, it needs to be linkd again * * 20210304 raf */ #include #include int main() { sd_login_monitor *lg_mon = NULL; int lg_mon_events = 0; int lg_mon_fd; int lg_uid = 1000; int ret; uint64_t t; ret = sd_login_monitor_new("uid", &lg_mon); lg_mon_fd = sd_login_monitor_get_fd(lg_mon); sd_login_monitor_get_timeout(lg_mon, &t); lg_mon_events = sd_login_monitor_get_events(lg_mon); ret = sd_uid_get_sessions(lg_uid, 0, NULL); sd_login_monitor_flush(lg_mon); sd_login_monitor_unref(lg_mon); } /* vi:set ts=4 sw=4: */ daemon-0.8/conf/logind0000755000175000017500000000414314020200577013054 0ustar rafraf#!/bin/sh # # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Enable/disable support for systemd-logind or elogind (Linux only) # # 20210304 raf if [ x"$1" = x--enable ] then # Look for libsystemd (e.g. Debian) src="conf/test_logind.c" out="conf/test_logind" ${CC:-gcc} -o $out $src -lsystemd 2>/dev/null rc=$? rm -f $out if [ $rc = 0 ] then echo Configuring libsystemd perl -pi \ -e 's/^# (DAEMON_LIBS \+= systemd)/$1/;' \ macros.mk perl -pi \ -e 's/^\/\* #undef (HAVE_LOGIND) \*\/$/#define $1 1/;' \ config.h exit 0 fi # Look for libelogind and /usr/include/elogind (e.g. Slackware) ${CC:-gcc} -I/usr/include/elogind -o $out $src -lelogind 2>/dev/null rc=$? rm -f $out if [ $rc = 0 ] then echo Configuring libelogind perl -pi \ -e 's{^# (DAEMON_INCDIRS \+= /usr/include/elogind)$}{$1};' \ Makefile perl -pi \ -e 's/^# (DAEMON_LIBS \+= elogind)/$1/;' \ macros.mk perl -pi \ -e 's/^\/\* #undef (HAVE_LOGIND) \*\/$/#define $1 1/;' \ config.h exit 0 fi echo "Failed to find libsystemd or libelogind and headers" fi if [ x"$1" = x--disable ] then perl -pi \ -e 's{^(DAEMON_INCDIRS \+= /usr/include/elogind)$}{# $1};' \ Makefile perl -pi \ -e 's/^(DAEMON_LIBS \+= systemd)/# $1/;' \ -e 's/^(DAEMON_LIBS \+= elogind)/# $1/;' \ macros.mk perl -pi \ -e 's/^#define (HAVE_LOGIND) 1$/\/* #undef $1 *\//;' \ config.h exit 0 fi # vi:set ts=4 sw=4: daemon-0.8/example/0000755000175000017500000000000014020200340012342 5ustar rafrafdaemon-0.8/example/daemon.initd0000755000175000017500000000706614020200340014652 0ustar rafraf#!/bin/sh # daemon - http://libslack.org/daemon/ # # Copyright (C) 1999-2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 20210304 raf # This is an example /etc/init.d script that shows how to use daemon(1) # in that context. Note that this would need to be modified quite a bit # to meet the usual conventions of any specific system but if you aren't # concerned about that it should be usable. At least it's a starting point. # The daemon's name (to ensure uniqueness and for stop, restart and status) name="EXAMPLE" # The path of the client executable command="/usr/bin/EXAMPLE" # Any command line arguments for the client executable command_args="" # The path of the daemon executable daemon="/usr/bin/daemon" [ -x "$daemon" ] || exit 0 [ -x "$command" ] || exit 0 # Note: The following daemon option arguments could be in /etc/daemon.conf # instead. That would probably be better because if the command itself were # there as well then we could just use the name here to start the daemon. # Here's some code to do it here in case you prefer that. # Any command line arguments for the daemon executable (when starting) daemon_start_args="" # e.g. --inherit --env="ENV=VAR" --unsafe # The pidfile directory (need to force this so status works for normal users) pidfiles="/var/run" # The user[:group] to run as (if not to be run as root) user="" # The path to chroot to (otherwise /) chroot="" # The path to chdir to (otherwise /) chdir="" # The umask to adopt, if any umask="" # The syslog facility or filename for the client's stdout (otherwise discarded) stdout="daemon.info" # The syslog facility or filename for the client's stderr (otherwise discarded) stderr="daemon.err" case "$1" in start) # This if statement isn't strictly necessary but it's user friendly if "$daemon" --running --name "$name" --pidfiles "$pidfiles" then echo "$name is already running." else echo -n "Starting $name..." "$daemon" --respawn $daemon_start_args \ --name "$name" --pidfiles "$pidfiles" \ ${user:+--user $user} ${chroot:+--chroot $chroot} \ ${chdir:+--chdir $chdir} ${umask:+--umask $umask} \ ${stdout:+--stdout $stdout} ${stderr:+--stderr $stderr} \ -- \ "$command" $command_args echo done. fi ;; stop) # This if statement isn't strictly necessary but it's user friendly if "$daemon" --running --name "$name" --pidfiles "$pidfiles" then echo -n "Stopping $name..." "$daemon" --stop --name "$name" --pidfiles "$pidfiles" echo done. else echo "$name is not running." fi ;; restart|reload) if "$daemon" --running --name "$name" --pidfiles "$pidfiles" then echo -n "Restarting $name..." "$daemon" --restart --name "$name" --pidfiles "$pidfiles" echo done. else echo "$name is not running." exit 1 fi ;; status) "$daemon" --running --name "$name" --pidfiles "$pidfiles" --verbose ;; *) echo "usage: $0 " >&2 exit 1 esac exit 0 # vi:set ts=4 sw=4: daemon-0.8/libslack/0000755000175000017500000000000014020203361012501 5ustar rafrafdaemon-0.8/libslack/conf/0000755000175000017500000000000014020166546013443 5ustar rafrafdaemon-0.8/libslack/conf/ccenv0000755000175000017500000000200114014141213014443 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile to use $CC as CC # # 20210220 raf if [ "x$CC" != x ] then perl -pi \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's,^# (CC := .*other)$,CC := '"$CC"' # other,;' \ `find . -name Makefile` fi # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/test0000755000175000017500000000315614014141213014340 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify macros.mk and config.h to exercise optional code # # 20210220 raf perl -pi \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ `find . -name macros.mk` perl -pi \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/test-gcc-opt0000755000175000017500000000165014014141213015667 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Test if the supplied gcc argument is supported # # 20210220 raf option="$1" gcc -E -xc /dev/null -Werror $option >/dev/null 2>/dev/null exit $? # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/test-rwlock-start0000755000175000017500000000224014014141213016763 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Swap to supplied implementation of rwlocks # # 20210220 raf perl -pi \ -e 's/pthread_rwlock/test_pthread_rwlock/g;' \ -e 's/\bPTHREAD_RWLOCK/TEST_PTHREAD_RWLOCK/g;' \ ${@:-`find . -name '*.[ch]'`} perl -pi \ -e 's/^(\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/# $1/;' \ `find . -name macros.mk` perl -pi \ -e 's/^#define (HAVE_PTHREAD_RWLOCK) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/test-rwlock-stop0000755000175000017500000000224214014141213016615 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Revert to system implementation of rwlocks # # 20210220 raf perl -pi \ -e 's/test_pthread_rwlock/pthread_rwlock/g;' \ -e 's/\bTEST_PTHREAD_RWLOCK/PTHREAD_RWLOCK/g;' \ ${@:-`find . -name '*.[ch]'`} perl -pi \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ `find . -name macros.mk` perl -pi \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/prefix0000755000175000017500000000557414020153455014674 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile and macros.mk to change # PREFIX/CONF_INSDIR/CONFIG_PATH/ROOT_PID_DIR together. # But can be reversed with --prefix=default. # # 20210220 raf # Strip off the leading "--prefix=" from the command line option prefix="${1#--prefix=}" # With --prefix=default, set PREFIX to /usr/local. # Otherwise, set it to the given argument. if [ "$prefix" = "default" ] then perl -pi \ -e 's{^(PREFIX := ).*$}{$1/usr/local}' \ `find . -name Makefile` else perl -pi \ -e 's{^(PREFIX := ).*$}{$1'"$prefix"'}' \ `find . -name Makefile` fi # With --prefix=default or --prefix=/usr, CONF_INSDIR and ROOT_PID_DIR # stay as /etc and /var/run. Otherwise, we want them to be $(PREFIX)/etc # and $(PREFIX)/var/run. # # The operating system specific conf/* scripts mostly handle this fine. # # But for macports on macOS, we need this to move the system configuration # files to /opt/local/etc, and to move root's pidfiles to # /opt/local/var/run. # # In summary, if the --prefix option argument is /usr, then the system # configuration files are under /etc and root's pidfiles are in /var/run. # # If the --prefix argument is /usr/local or /opt/local or other, then the # system configuration files are under /usr/local/etc or /opt/local/etc or # other, and root's pidfiles are in /usr/local/var/run or /opt/local/var/run # or other. if [ "$prefix" = "/usr" -o "$prefix" = "default" ] then perl -pi \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ `find . -name Makefile` perl -pi \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(\S+ \+= -DETC_DIR)=.*$/# $1=\\"\/etc\\"/;' \ `find . -name macros.mk` else perl -pi \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ `find . -name Makefile` perl -pi \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ -e 's/^(?:# )?(\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\$(PREFIX)\/var\/run\\"/;' \ -e 's/^(?:# )?(\S+ \+= -DETC_DIR)=.*$/$1=\\"\$(PREFIX)\/etc\\"/;' \ `find . -name macros.mk` fi # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/freebsd0000755000175000017500000001657614020166502015012 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on FreeBSD # # 20210220 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^# (CC := cc)$/$1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-overlength-strings)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-address)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-nonnull)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-format)$/$1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-pointer-bool-conversion)$/$1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^(\w*LIBS \+= pthread)$/# $1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^# (\w*LDFLAGS \+= -pthread)$/$1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/man/;' \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/\* #undef $1 \*\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCPY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCAT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SOCKADDR_SA_LEN) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SVR4) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_LIBUTIL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/gnuhurd0000755000175000017500000001662414020166504015050 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to exercise optional code # # 20210220 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^(GETOPT := getopt)$/# $1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_GETOPT_LONG=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-overlength-strings)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-address)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-nonnull)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-format)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-restrict)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_GETOPT_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ISOC_REALLOC) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LINUX_POLL_BUG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UNIX_DOMAIN_WILDCARD) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTY_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#undef (HAVE_VHANGUP) 1$/\/* #define $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_TTYNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/kfreebsd0000755000175000017500000001660714020166510015157 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on Linux # # 20210220 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^(GETOPT := getopt)$/# $1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_GETOPT_LONG=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-overlength-strings)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-address)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-nonnull)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-format)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-restrict)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_GETOPT_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ISOC_REALLOC) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LINUX_POLL_BUG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UNIX_DOMAIN_WILDCARD) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTY_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_TTYNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/linux0000755000175000017500000001661514020166514014534 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on Linux # # 20210220 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^(GETOPT := getopt)$/# $1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_GETOPT_LONG=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-overlength-strings)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-address)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-nonnull)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-format)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-restrict)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_GETOPT_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ISOC_REALLOC) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LINUX_POLL_BUG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_6) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UNIX_DOMAIN_WILDCARD) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTY_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VHANGUP) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_TTYNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/macosx0000755000175000017500000002020014020166516014652 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on FreeBSD # # 20210220 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_POSIX_C_SOURCE=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_POSIX_SOURCE=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_XOPEN_SOURCE=1)$/$1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-pointer-bool-conversion)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-deprecated-declarations)$/$1/;' \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ -e 's/^(\w*CCFLAGS \+= -O3)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 0$/MAN_GZIP := 1/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^\/\* #undef (NO_POSIX_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (NO_XOPEN_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STDINT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCPY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCAT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SOCKADDR_SA_LEN) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SVR4) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UTIL_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) \*\/$/#define $1 1/;' \ `find . -name config.h` # Old versions of macOS (e.g. 10.6.8) don't handle some newer clang -Wno-* options. # But don't test if macports (which uses a newer compiler than Xcode's). # We know it's macports because CC is set. if [ -z "$CC" ] then if conf/test-gcc-opt -Wno-gnu-folding-constant then perl -pi \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ `find . -name macros.mk` else perl -pi \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ `find . -name macros.mk` fi if conf/test-gcc-opt -Wno-pointer-bool-conversion then perl -pi \ -e 's/^# (\S+ \+= -Wno-pointer-bool-conversion)$/$1/;' \ `find . -name macros.mk` else perl -pi \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ `find . -name macros.mk` fi fi # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/netbsd0000755000175000017500000001657714020166520014660 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on NetBSD # # 20210220 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DNO_POSIX_SOURCE=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_XOPEN_SOURCE=1)$/$1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^(\w*LIBS \+= pthread)$/# $1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^# (\w*LDFLAGS \+= -pthread)$/$1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/man/;' \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ -e 's/^(PREFIX := \/usr\/local)$/# $1/;' \ -e 's/^# (PREFIX := \/usr\/pkg)$/$1/;' \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^\/\* #undef (NO_POSIX_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (NO_XOPEN_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCPY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCAT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SOCKADDR_SA_LEN) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SVR4) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UTIL_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/openbsd0000755000175000017500000001660414020166522015024 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify Makefile, macros.mk and config.h to compile on OpenBSD # # 20210220 raf perl -pi \ -e 's/^(\S+ \+= xnet)$/# $1/;' \ -e 's/^(\S+ \+= socket)$/# $1/;' \ -e 's/^(\S+ \+= nsl)$/# $1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^(SNPRINTF := snprintf)$/# $1/;' \ -e 's/^(VSSCANF := vsscanf)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_VSSCANF=1)$/$1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DNO_POSIX_SOURCE=1)$/$1/;' \ -e 's/^# (\S+ \+= -DNO_XOPEN_SOURCE=1)$/$1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-comment)$/$1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^# (\S+ \+= -Wno-gnu-folding-constant)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^(\w*LIBS \+= pthread)$/# $1/;' \ -e 's/^# (\w*LIBS \+= util)$/$1/;' \ -e 's/^# (\w*LDFLAGS \+= -pthread)$/$1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/man/;' \ -e 's/^CONF_INSDIR := \/etc$/CONF_INSDIR := \$(PREFIX)\/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^# (DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^\/\* #undef (NO_POSIX_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (NO_XOPEN_SOURCE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VSNPRINTF) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_VSSCANF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRNCASECMP) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCPY) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_STRLCAT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_ASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_VASPRINTF) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_5) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_IFINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IFREQ_IFR_MTU) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SOCKADDR_SA_LEN) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^#define (MLOCK_REQUIRES_PAGE_BOUNDARY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_ALTERNATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_SIGNED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NIL) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_STR_FMT_NULL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NOALT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SVR4) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_OPENPTY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_UTIL_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_TTYNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME_R) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/solaris10-cc0000755000175000017500000001725714020166526015603 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 10 with cc # # 20210220 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^# (\S+ \+= m)$/$1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^# (CC := cc)$/$1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^(\S+ \+= -Wno-long-long)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -O3)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -Wall -pedantic)$/# $1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -xO4)$/$1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` # Solaris10 has /usr/ucb/install but OpenSolaris 200906 doesn't # so we use own version rather than trying to get their native # (weird) install program to work the way the normal one does. if [ ! -f /usr/ucb/install ] then perl -pi \ -e 's/install -m/.\/myinstall -m/' \ `find . -name rules.mk` else perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` fi perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^#define (HAVE_POLL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/solaris10-gcc0000755000175000017500000002007714020166530015737 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 10 with gcc # # 20210220 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DROOT_PID_DIR)=.*$/# $1=\\"\/var\/run\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` # Solaris10 has /usr/ucb/install but OpenSolaris 200906 doesn't # so we use own version rather than trying to get their native # (weird) install program to work the way the normal one does. if [ ! -f /usr/ucb/install ] then perl -pi \ -e 's/install -m/.\/myinstall -m/' \ `find . -name rules.mk` else perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` fi # On 64-bit Solaris/OpenSolaris gcc generates 32-bit binaries by # default so we have to ask explicitly for 64-bit. if [ "`isainfo -k`" = "amd64" ] then perl -pi \ -e 's/^# (\w*(?:CC|LD)FLAGS \+= -m64)$/$1/;' \ `find . -name Makefile` \ `find . -name macros.mk` else perl -pi \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` fi perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_IF_INDEXTONAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_IF_NAMETOINDEX) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) \*\/$/#define $1 1/;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/solaris6-cc0000755000175000017500000001655014020166531015517 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 6 with cc # # 20210220 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^# (\S+ \+= m)$/$1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\/etc\\"/;' \ -e 's/^# (CC := cc)$/$1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^(\S+ \+= -Wno-long-long)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -O3)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -Wall -pedantic)$/# $1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -xO4)$/$1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^#define (HAVE_POLL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTHREAD_RWLOCK) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_MSGHDR_MSG_CONTROL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_INDEXTONAME) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_NAMETOINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/solaris6-gcc0000755000175000017500000001655314020166533015673 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 6 with gcc # # 20210220 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\/etc\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PTHREAD_RWLOCK) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_MSGHDR_MSG_CONTROL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_INDEXTONAME) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_NAMETOINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/solaris8-cc0000755000175000017500000001655614020166534015532 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 8 with cc # # 20210220 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^# (\S+ \+= m)$/$1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\/etc\\"/;' \ -e 's/^# (CC := cc)$/$1/;' \ -e 's/^(CC := gcc)$/# $1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^(\S+ \+= -Wno-long-long)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -O3)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -Wall -pedantic)$/# $1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -xO4)$/$1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^#define (HAVE_POLL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_INDEXTONAME) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_NAMETOINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) 1$/\/* #undef $1 *\//;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/conf/solaris8-gcc0000755000175000017500000001656314020166536015701 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # Modify the macros.mk make include files to compile on Solaris 8 with gcc # # 20210220 raf perl -pi \ -e 's/^# (\S+ \+= xnet)$/$1/;' \ -e 's/^# (\S+ \+= socket)$/$1/;' \ -e 's/^# (\S+ \+= nsl)$/$1/;' \ -e 's/^(\S+ \+= m)$/# $1/;' \ -e 's/^# (GETOPT := getopt)$/$1/;' \ -e 's/^# (SNPRINTF := snprintf)$/$1/;' \ -e 's/^# (VSSCANF := vsscanf)$/$1/;' \ -e 's/^(\S+ \+= -DHAVE_GETOPT_LONG=1)$/# $1/;' \ -e 's/^(\S+ \+= -DHAVE_VSSCANF=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DHAVE_PTHREAD_RWLOCK=1)$/$1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_C_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_POSIX_SOURCE=1)$/# $1/;' \ -e 's/^(\S+ \+= -DNO_XOPEN_SOURCE=1)$/# $1/;' \ -e 's/^# (\S+ \+= -DROOT_PID_DIR)=.*$/$1=\\"\/etc\\"/;' \ -e 's/^(CC := cc)$/# $1/;' \ -e 's/^# (CC := gcc)$/$1/;' \ -e 's/^(CC := .*other)$/# CC := other/;' \ -e 's/^# (\S+ \+= -Wno-long-long)$/$1/;' \ -e 's/^(\S+ \+= -Wno-overlength-strings)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-address)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-nonnull)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-format)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-restrict)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-comment)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-pointer-bool-conversion)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-deprecated-declarations)$/# $1/;' \ -e 's/^(\S+ \+= -Wno-gnu-folding-constant)$/# $1/;' \ -e 's/^# (\w*CCFLAGS \+= -O3)$/$1/;' \ -e 's/^# (\w*CCFLAGS \+= -Wall -pedantic)$/$1/;' \ -e 's/^(\w*(?:CC|LD)FLAGS \+= -m64)$/# $1/;' \ -e 's/^(\w*CCFLAGS \+= -xO4)$/# $1/;' \ -e 's/^# (\w*LIBS \+= pthread)$/$1/;' \ -e 's/^(\w*LIBS \+= util)$/# $1/;' \ -e 's/^(\w*LDFLAGS \+= -pthread)$/# $1/;' \ -e 's/^MAN_GZIP := 1$/MAN_GZIP := 0/;' \ -e 's/^(MAN_SYSDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^(MAN_LOCDIR\s*:=).*$/$1 \$(PREFIX)\/share\/man/;' \ -e 's/^CONF_INSDIR := \$\(PREFIX\)\/etc$/CONF_INSDIR := \/etc/;' \ -e 's/^# (PREFIX := \/usr\/local)$/$1/;' \ -e 's/^(PREFIX := \/usr\/pkg)$/# $1/;' \ -e 's/^(DAEMON_DEFINES \+= -DCONFIG_PATH=\\"\$\(PREFIX\)\/etc\/daemon\.conf\\")$/# $1/;' \ `find . -name Makefile` \ `find . -name macros.mk` perl -pi \ -e 's/\.\/myinstall -m/install -m/' \ `find . -name rules.mk` perl -pi \ -e 's/^#define (NO_POSIX_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (NO_XOPEN_SOURCE) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_STDARG_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_STDINT_H) 1$/\/\* #undef $1 \*\//;' \ -e 's/^\/\* #undef (HAVE_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_POLL_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_SYS_SELECT_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_REGEX_H) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_DOUBLE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_LONG_LONG) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_SNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSNPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_GETOPT_LONG) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VSSCANF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRNCASECMP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCPY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_STRLCAT) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_ASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_VASPRINTF) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FLOCKFILE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_FCNTL_THAT_CAN_LOCK_FIFOS) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_ISOC_REALLOC) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_POLL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_LINUX_POLL_BUG) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_MLOCK) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETHOSTBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETHOSTBYNAME_R_3) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_6) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_FUNC_GETSERVBYNAME_R_5) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_FUNC_GETSERVBYNAME_R_4) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_PRIVATE) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_PROCESS_SHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_INIT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_CONDATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_MUTEXATTR_SETPSHARED) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PTHREAD_RWLOCK) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_MSGHDR_MSG_CONTROL) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_IFREQ_IFR_IFINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IFREQ_IFR_MTU) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_SOCKADDR_SA_LEN) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_INDEXTONAME) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_IF_NAMETOINDEX) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (MLOCK_REQUIRES_PAGE_BOUNDARY) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_ALTERNATE) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_SIGNED) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_PTR_FMT_NIL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_STR_FMT_NULL) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PRINTF_FLT_FMT_G_STD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PRINTF_PTR_FMT_NOALT) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_PRINTF_WITH_SOLARIS8_ZERO_PRECISION_ALT_OCTAL_BEHAVIOUR) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_UNIX_DOMAIN_WILDCARD) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (SVR4) \*\/$/#define $1 1/;' \ -e 's/^#define (SOCKS) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_CYGWIN) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_DEV_PTMX) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_DEV_PTS_AND_PTC) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_OPENPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTY_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_UTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_LIBUTIL_H) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_SYS_STROPTS_H) \*\/$/#define $1 1/;' \ -e 's/^#define (HAVE_VHANGUP) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE__GETPTY) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_TTYNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^#define (HAVE_PTSNAME_R) 1$/\/* #undef $1 *\//;' \ -e 's/^\/\* #undef (HAVE_PTSNAME) \*\/$/#define $1 1/;' \ -e 's/^\/\* #undef (HAVE_POLL_THAT_ABORTS_WHEN_POLLFDS_IS_NULL) \*\/$/#define $1 1/;' \ `find . -name config.h` # vi:set ts=4 sw=4: daemon-0.8/libslack/tools/0000755000175000017500000000000014020173633013651 5ustar rafrafdaemon-0.8/libslack/tools/README0000644000175000017500000000602014014141214014520 0ustar rafrafThis directory contains several utilities. Most of them are only useful to me during development. The last few might be useful to libslack users. For libslack development ------------------------ check-pod-prototypes # check description = source check-pod-header # check header = description check-pod-synopsis # check synopsis = header check-pod # check source = description = header = synopsis These scripts help to guarantee that at least the formal parts of the libslack documentation accurately reflect the code. The first checks that the function prototypes that will appear in the DESCRIPTION sections of each module's manpage exactly matches the header of the function itself. The second checks that the typedefs and function prototypes in the header files exactly match the same information in the SYNOPSIS section of the corresponding module's manpage. The third checks that the function prototypes in each header file exactly matches the function prototypes in the DESCRIPTION section of the corresponding module's manpage. Together, these three scripts guarantee that the typedefs and function prototypes in the manpages match the header files and the source code. The fourth combines the above checks. check-examples # check the examples in the manpages This script extracts the example programs in the module manpages and compiles and executes them to make sure that they are correct. It asks the user for command line arguments for each example. Html.pm [not included in the distribution (43KB) - available on request] There's a butchered version of Html.pm that I use to generate the HTML versions of the documentation. It is used by pod2html. The original version tries to make hyperlinks to things that it shouldn't because it assumes that the POD being converted into HTML is a perl related manpage. The assumptions that it makes are wrong for C library manpages. viconf There's a script to help me maintain the stupid configuration files at least until I start using autoconf. For client development ---------------------- analyse-debug-locker This script might be useful to users. It reads the output of the debug lockers defined in the locker module and shows where any deadlocks have occurred. prefix This script might also be useful to users. It adds a prefix to all identifiers (or selected identifiers) in libslack in case you need to guarantee local uniqueness of C identifiers on your system. Makefile The Makefile lets you install and uninstall analyse-debug-locker and the header files generated by prefix onto your system. Type "make help" for details. migrate-properties Version 0.6.2 changed the format of properties files. Before then, leading spaces in values used to be kept, now they're stripped unless quoted so this quotes them. Spaces before the '=' character used to be stripped from the property name as well and now they're only stripped if not quoted. This does nothing about that because it is assumed that nobody was doing things like "a\ =b" when the "\" meant nothing. daemon-0.8/libslack/tools/analyse-debug-locker0000755000175000017500000000523114014141214017566 0ustar rafraf#!/usr/bin/env perl use warnings; use strict; # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 20210220 raf # =head1 NAME I - scan debug locker output to locate deadlocks =head1 SYNOPSIS analyse-debug-locker =head1 DESCRIPTION The I module of I provides decoupled synchronisation of data shared between multiple threads. Application developers (rather than library developers) and users (rather than application developers) can specify synchronisation strategies. There are versions of the mutex and readers/writer lock lockers and produce debugging information. This program reads the output of these lockers, keeping track of which thread owns which lock. When the input stops, this program prints out which threads still own locks. Such output indicates a deadlock. You should be able to compare the original debugging information with the output of this program to locate deadlocks in client code. =head1 SEE ALSO I, I =head1 AUTHOR 20020916 raf =cut my %rwlock_thread; my %rwlock_state; while (<>) { if ($_ =~ /^\[(\d+)\]\s+rwlock_rdlock (\w+)\.\.\./) { $rwlock_thread{$2} = $1; $rwlock_state{$2} = 'rdlock...'; } elsif ($_ =~ /^\[(\d+)\]\s+rwlock_rdlock (\w+) locked/) { $rwlock_thread{$2} = $1; $rwlock_state{$2} = 'rdlock'; } elsif ($_ =~ /^\[(\d+)\]\s+rwlock_wrlock (\w+)\.\.\./) { $rwlock_thread{$2} = $1; $rwlock_state{$2} = 'wrlock...'; } elsif ($_ =~ /^\[(\d+)\]\s+rwlock_wrlock (\w+) locked/) { $rwlock_thread{$2} = $1; $rwlock_state{$2} = 'wrlock'; } elsif ($_ =~ /^\[(\d+)\]\s+rwlock_unlock (\w+)\.\.\./) { $rwlock_thread{$2} = $1; $rwlock_state{$2} = 'unlock...'; } elsif ($_ =~ /^\[(\d+)\]\s+rwlock_unlock (\w+) unlocked/) { delete $rwlock_thread{$2}; delete $rwlock_state{$2}; } } for (keys %rwlock_state) { print 'rwlock ', $_, ' ', $rwlock_state{$_}, ' [', $rwlock_thread{$_} , ']', "\n"; } # vi:set ts=4 sw=4: daemon-0.8/libslack/tools/check-examples0000755000175000017500000000317714014141214016471 0ustar rafraf#!/usr/bin/env perl use warnings; use strict; $| = 1; # Compiles and executes the examples from the manpages. # Run this from the source directory. die("usage: $0 *.c\n") if $#ARGV == -1; my $total = 0; for my $src (@ARGV) { next unless $src =~ /\.c$/; #next if $src =~ /getopt\.c$/; warn("Failed to open $src for reading: $!\n"), next unless open SRC, $src; my $state = ''; my $desc = ''; my $code = ''; my $num = 0; while () { $state = 'X', next if /^=head\d EXAMPLE/; $state = '', next if $state eq 'X' && (/^=head/ || /^=cut/); next unless $state eq 'X'; s/\s*(?; return if $response =~ /n/i; warn("Failed to open example.c for writing: $!\n"), return unless open(EXAMPLE, "> example.c"); print EXAMPLE $code; close EXAMPLE; print 'Arguments: '; chop(my $args = ); system("echo Compiling...; cc -o example example.c `libslack-config --cflags --libs` && echo Executing... && ./example $args; echo rc=\$?"); unlink 'example', 'example.c'; print 'Press return to continue or Ctrl-C to quit.'; ; } # vi:set ts=4 sw=4: daemon-0.8/libslack/tools/check-pod0000755000175000017500000000032214014141214015422 0ustar rafraf#!/bin/bash # Perform all the other pod checks on all modules. [ "${0%/*}" = "$0" ] && path="./" || path="${0%/*}/" ${path}check-pod-prototypes *.c ${path}check-pod-header *.c ${path}check-pod-synopsis *.c daemon-0.8/libslack/tools/check-pod-header0000755000175000017500000000423014014141214016652 0ustar rafraf#!/usr/bin/env perl use warnings; use strict; # Compares the function prototypes in each module's header file against the # function prototypes in the pod manpage source. All differences are reported. die("usage: $0 *.c\n") if $#ARGV == -1; my @src; my @hdr; for my $src (@ARGV) { next unless $src =~ /\.c$/; next if $src eq 'getopt.c'; next if $src eq 'hsort.c'; next if $src eq 'vsscanf.c'; my $hdr = $src; $hdr =~ s/\.c$/.h/; my $src_state = ''; my $hdr_state = ''; @src = (); @hdr = (); my $done_rwlock_skip = 0; open(SRC, $src) or die("failed to open $src\n"); while () { next if $_ =~ /^$/; next if $_ =~ /^\s+#/; $src_state = $1, next if $_ =~ /^=head1 (.*)$/; if ($src_state eq 'DESCRIPTION' && $_ =~ /^=item [CI]<(.*)>$/) { my $proto = $1 . ';'; next if $proto =~ /^ #define/; next unless $proto =~ /^extern/ || $proto =~ /\);$/; push(@src, $proto); } } close(SRC); open(HDR, $hdr) or die("failed to open $hdr\n"); while () { if ($_ =~ /^#ifndef HAVE_PTHREAD_RWLOCK/ && $done_rwlock_skip == 0) { my $jnk; do { $jnk = ; } while $jnk !~ /^#endif$/; $done_rwlock_skip = 1; } next if $_ =~ /^$/; next if $_ =~ /^#/; next if $_ =~ /^\//; next if $_ =~ /^\*/; $hdr_state = 'decls', next if $_ =~ /^_begin_decls$/; last if $_ =~ /^_end_decls$/; if ($hdr_state eq 'decls') { my $proto = $_; #warn "$hdr: _args missing: $proto\n" if $proto =~ /\);\s*$/ && $proto !~ / _args /; #$proto =~ s/ _args \(//; #$proto =~ s/\)\);/);/; chop($proto); push(@hdr, $proto); } } close(HDR); show("$src != $hdr (line number mismatch)"), next if $#src != $#hdr; my $i; my $first = 1; for ($i = 0; $i <= $#src; ++$i) { if ($src[$i] ne $hdr[$i]) { print("$src != $hdr\n") if $first; print("doc = $src[$i]\n"); print("hdr = $hdr[$i]\n"); $first = 0; } } print("\n") unless $first; } sub show { my ($msg) = @_; print("$msg\n"); print("-- doc ---\n"); my $i; for ($i = 0; $i <= $#src; ++$i) { print("$src[$i]\n"); } print("-- hdr ---\n"); for ($i = 0; $i <= $#hdr; ++$i) { print("$hdr[$i]\n"); } print("----------\n\n"); } # vi:set ts=4 sw=4: daemon-0.8/libslack/tools/check-pod-prototypes0000755000175000017500000000475614014141214017667 0ustar rafraf#!/usr/bin/env perl use warnings; use strict; # Compares the function prototypes in the pod manpage source against the # actual function header itself. All differences are reported. die("usage: $0 *.c\n") if $#ARGV == -1; my $state = 0; my $doc; my $src; my $jnk; my $line = 0; my $debug = 0; while ($_ = <>) { ++$line; print("line $line state $state $_") if $debug; if ($state == 0 && /^=item C[<](.*)[>]$/) # pod function prototype doco { next if $1 =~ /^E/ || $1 =~ / #def/; $state = 1; $doc = $1; } elsif ($state == 1 && /^=back$/) # bail out { $state = 0; } elsif ($state == 1 && /^=cut$/) # end of pod section { $state = 2; } elsif ($state == 2 && /^\*\/$/) # end of pod comment { do { $_ = <>; ++$line; } while /^$/; # skip blank lines while (/^static / || /^#/) # skip static functions and macros { if (/^static.*;$/) # skip forward declaration { do { $_ = <>; ++$line; } while /^$/; # skip blank lines } elsif (/^static/) # static functions or forward declarations { do { $_ = <>; ++$line; } until /^}$/; # end of static helper function do { $_ = <>; ++$line; } while /^$/; # blank lines between functions } elsif (/^#define/) # macros { while (/\\$/) { $_ = <>; ++$line; } # skip multi line macros do { $_ = <>; ++$line; } while /^$/; # skip blank lines } else # other cpp directives { do { $_ = <>; ++$line; } while /^$/; # skip blank lines } } chop(); $_ =~ s/\((\w+)\)([^;])/$1$2/; # handle special case of avoiding cpp expansion if ($doc ne $_) { my ($doc_type, $doc_name, $doc_args) = $doc =~ /^(\w+ \*?)([a-zA-Z_0-9]+)\((.*)\)/; my ($src_type, $src_name, $src_args) = $_ =~ /^(\w+ \*?)([()a-zA-Z_0-9]+)\((.*)\)/; if ((!defined $doc_type || !defined $doc_name || !defined $doc_args || !defined $src_type || !defined $src_name || !defined $src_args)) { print STDERR 'doc = ', $doc, "\n"; print STDERR 'src = ', $_, "\n"; print STDERR 'line = ', $line, "\n"; print STDERR 'doc_type = ', $doc_type, "\n"; print STDERR 'doc_name = ', $doc_name, "\n"; print STDERR 'doc_args = ', $doc_args, "\n"; print STDERR 'src_type = ', $src_type, "\n"; print STDERR 'src_name = ', $src_name, "\n"; print STDERR 'src_args = ', $src_args, "\n"; } print("doc = '$doc'\nsrc = '$_'\n\n") if $src_type ne $doc_type || $src_name ne "($doc_name)" || $src_args ne $doc_args; } else { print(" ok $doc\n") if $debug; } $state = 0; $doc = undef; } } # vi:set ts=4 sw=4: daemon-0.8/libslack/tools/check-pod-synopsis0000755000175000017500000000443514014141214017320 0ustar rafraf#!/usr/bin/env perl use warnings; use strict; # Compares the contents of each module's header file against the synposis # section of the corresponding manpage which should contain all typedefs # and function prototypes that appear in the header file. All differences # are reported. die("usage: $0 *.c\n") if $#ARGV == -1; my @src; my @hdr; for my $src (@ARGV) { next unless $src =~ /\.c$/; next if $src eq 'getopt.c'; my $hdr = $src; $hdr =~ s/\.c$/.h/; my $src_state = ''; my $hdr_state = ''; @src = (); @hdr = (); my $done_rwlock_skip = 0; open(SRC, $src) or die("failed to open $src\n"); while () { next if $_ =~ /^$/; next if $_ =~ /^\s+#/; $src_state = $1, next if $_ =~ /^=head1 (.*)$/; last if $src_state eq 'DESCRIPTION'; if ($src_state eq 'SYNOPSIS') { my $line = $_; $line =~ s/^ //; chop($line); push(@src, $line); } } close(SRC); open(HDR, $hdr) or die("failed to open $hdr\n"); while () { if ($_ =~ /^#ifndef HAVE_PTHREAD_RWLOCK/ && $done_rwlock_skip == 0) { my $jnk; do { $jnk = ; } while $jnk !~ /^#endif$/; $done_rwlock_skip = 1; } next if $_ =~ /^$/; next if $_ =~ /^#/; next if $_ =~ /^\//; next if $_ =~ /^ ?\*/; $hdr_state = 'decls', next if $_ =~ /^_begin_decls$/; last if $_ =~ /^_end_decls$/; if ($hdr_state eq '') { my $line = $_; chop($line); $line =~ s/ / /g; $line =~ s/\/\*.*\*\/$//; $line =~ s/\s+$//; push(@hdr, $line); } if ($hdr_state eq 'decls') { my $line = $_; # $line =~ s/ _args \(//; # $line =~ s/\)\);/);/; chop($line); push(@hdr, $line); } } close(HDR); show("$src != $hdr (line number mismatch)"), next if $#src != $#hdr; my $i; my $first = 1; for ($i = 0; $i <= $#src; ++$i) { $src[$i] =~ s/\((\w+)\)([^;])/$1$2/; # handle special case of avoiding cpp expansion if ($src[$i] ne $hdr[$i]) { print("$src != $hdr\n") if $first; print("syn = $src[$i]\n"); print("hdr = $hdr[$i]\n"); $first = 0; } } print("\n") unless $first; } sub show { my ($msg) = @_; print("$msg\n"); print("-- syn ---\n"); my $i; for ($i = 0; $i <= $#src; ++$i) { print("$src[$i]\n"); } print("-- hdr ---\n"); for ($i = 0; $i <= $#hdr; ++$i) { print("$hdr[$i]\n"); } print("----------\n\n"); } # vi:set ts=4 sw=4: daemon-0.8/libslack/tools/migrate-properties0000755000175000017500000000225014014141214017411 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 20210220 raf # Convert an old libslack property file into a libslack-0.5.2 property file. # Previously, leading spaces were kept. Now they're stripped unless quoted. # This script quotes leading spaces in old properties files so that they'll # be preserved by newer versions of libslack. if [ $# = 0 ] then echo usage: $0 '/etc/properties/* ~/.properties/*' >&2 exit 1 fi exec perl -p -i -e 's/(? # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 20210220 raf # =head1 NAME I - add a prefix to libslack's public identifiers =head1 SYNOPSIS prefix [options] prefix [identifier...] options: -h - Print the help message then exit -d - Print debug messages -n - Don't modify anything. Run diff instead -r - Remove the prefix from identifiers -a - Include all public identifiers (no exceptions) -m module - Modify identifiers in the specified module only -s srcdir - Specify the source directory (".." by default) -P - Generage prefix.h (adds prefixes in client code) -R - Generate remove_prefix.h (removes prefixes in client code) =head1 DESCRIPTION There is little attempt to make the public identifiers in I unique across the entire C identifier space. Proper libraries usually insert a prefix to all public identifiers. Unfortunately, this doesn't actually guarantee uniqueness and things can get rather ugly. Without a global prefix registry, any number of developers could choose the same prefix. To quarantee uniqueness, system administrators who install libraries must define locally unique prefixes to libraries when necessary. This program adds the specified prefix to public identifiers in libslack. If no identifiers are specified on the command line, all public identifiers are modified. Otherwise, just those that are specified on the command line are modified. Note that the manual pages are modified as well as the source code and header files. If the C<-r> option is supplied, the prefix is removed. This makes it possible to change an existing prefix. Note that this program must be run before the library is compiled and before the manual pages are generated. It has no effect on an already installed instance of libslack. =head1 OPTIONS =over 4 =item C<-h> Print the help message then exit. =item C<-d> Print debug messages. =item C<-n> Don't modify any files. Run diff instead. =item C<-r> Remove the prefix from identifiers. =item C<-a> Include all public identifiers (no exceptions). See the EXCEPTIONS section for more information. This option only makes sense when no identifiers are supplied on the command line. =item C<-m module> Modify identifiers in the specified module only. =item C<-s srcdir> Specify the source directory (".." by default). =item C<-P> Generate the C header file which contains macros that translate the original I identifiers into the prefixed identifiers. Client code that includes this header file can use the original I identifiers when compiled on systems that have I installed with prefixed identifiers. Can't be used if the C<-r> option is supplied. =item C<-R> Generate the C header file which contains macros that translate prefixed identifiers into the original I identifiers. Client code written on a system that installed I with prefixes can use those identifiers when compiled on systems that have I installed with the original identifiers. Can't be used if the C<-r> option is supplied. =back =head1 EXCEPTIONS By default, this program does not alter the identifiers of functions that are only included in I as a backup in case your system doesn't already have them. These are I, I, I, I, I, I, I, I, I and the entire I module. This is so I will use your system's implementations if they exist. If they don't exist, then there's little harm in defining them here. Also excluded from renaming are C and C since these are only defined if they have not already been defined so they won't clash with an existing C<#define> as long as the I headers are included last. If you require any of these to be renamed, supply them on the command line. If you require all of them to be renamed, supply the C<-a> option. =head1 EXAMPLES prefix org_libslack_ # prefix everything with "org_libslack_" prefix s_ error fatal debug # prefix a few identifiers with "s_" prefix -r s_ debug # remove "s_" prefix from debug prefix -r -m daemon daemon_ # remove "daemon_" prefix from daemon module prefix -n -r -m daemon daemon_ # see what removing "daemon_" would do prefix -P libslack_ # prefix with "libslack.h" and make prefix.h prefix -n -R libslack_ # just make remove_prefix.h =head1 ADVICE If you need to use this program, use C<"libslack_"> as the prefix. It would be best if everyone used the same prefix whenever possible. Technically, the prefix should probably be C<"org_libslack_libslack_"> but that's ridiculous. Also generate the C header file and install it. If client code can separate uses of I from uses of other libraries with clashing names into separate translation units, then it is possible to never see the I prefixes and still have everything link. =head1 NOTES This program only renames functions, not modules. If you don't like this, install I into a directory under C so the module names can't clash with anything else. This program works on the I source code. Don't expect it to work on anything else. =head1 SEE ALSO I, C =head1 AUTHOR 20020916 raf =cut use Getopt::Std; $| = 1; my $srcdir = '..'; my ($name) = $0 =~ /([^\/]+)$/; my $usage = << "USAGE"; usage: $name [options] prefix [identifier...] options: -h - Print the help message then exit -d - Print debug messages -n - Don't modify anything. Run diff instead -r - Remove the prefix from identifiers -a - Include all public identifiers (no exceptions) -m module - Modify identifiers in the specified module only -s srcdir - Specify the source directory ("$srcdir" by default) -P - Generage prefix.h (adds prefixes in client code) -R - Generate remove_prefix.h (removes prefixes in client code) Type \"perldoc -F `which $name`\" for the manpage. USAGE sub usage { my ($msg) = @_; die "$msg\n$usage"; } # check the arguments my %opt; usage('Illegal option') unless getopts('hdnram:s:PR', \%opt); usage('') if defined $opt{h}; my $debug = defined $opt{d}; my $test = defined $opt{n}; my $reverse = defined $opt{r}; my $all = defined $opt{a}; my @modules = split / /, $opt{m} if defined $opt{m}; $srcdir = $opt{s} if defined $opt{s}; my $prefix_h = defined $opt{P}; my $remove_prefix_h = defined $opt{R}; usage('Must specify prefix') unless defined $ARGV[0]; my $prefix = shift @ARGV; usage("Not a valid identifier prefix: '$prefix'") if $prefix =~ /(^[0-9])|([^a-zA-Z0-9_])/; my @targets = @ARGV; my %identifiers; my $total = $#modules == -1 && $#targets == -1; # build the module list my %exclude_modules = (getopt => 1) unless $all; if ($#modules != -1) { # check module names supplied on the command line for (my $i = 0; $i <= $#modules; ++$i) { usage("No such module: '$srcdir/$modules[$i]'") unless -f "$srcdir/$modules[$i].h" && -f "$srcdir/$modules[$i].c"; } } else { # find all module names (i.e. header files with corresponding source files) opendir(SRCDIR, $srcdir) || die "failed to open $srcdir: $!\n"; @modules = grep { /.*\.h$/ && s/\.h$// && -f "$srcdir/$_.c" && !defined $exclude_modules{$_} } readdir(SRCDIR); closedir SRCDIR; } print("modules:\n\n ", join("\n ", sort @modules), "\n\n") if $debug; # build the identifier list my %exclude_identifiers = ( snprintf => 1, # use system implementation if possible vsnprintf => 1, # use system implementation if possible asprintf => 1, # use system implementation if possible vasprintf => 1, # use system implementation if possible strcasecmp => 1, # use system implementation if possible strncasecmp => 1, # use system implementation if possible strlcpy => 1, # use system implementation if possible strlcat => 1, # use system implementation if possible vsscanf => 1, # use system implementation if possible option => 1, # use system implementation if possible null => 1, # only defined if not already defined nul => 1 # only defined if not already defined ) unless $all; for (my $i = 0; $i <= $#modules; ++$i) { my $module = "$srcdir/$modules[$i].h"; my $hdr_state = ''; open(HDR, $module) or die("failed to open $module\n"); while () { if ($_ =~ /^#ifndef HAVE_PTHREAD_RWLOCK/) { my $skip; do { $skip = ; } while $skip !~ /^#endif$/; } next if $_ =~ /^$/; next if $_ =~ /^#/ && $_ !~ /^#\s*define\s+[a-z_0-9]+/; next if $_ =~ /^\//; next if $_ =~ /^\*/; $hdr_state = 'decls', next if $_ =~ /^_begin_decls$/; last if $_ =~ /^_end_decls$/; if (/^#\s*define\s+[a-z_0-9]+(\s|\()/) { my $macro = $_; chop($macro); $macro =~ s/^#\s*define\s+//; $macro =~ s/^([a-z_0-9]+).*$/$1/; $identifiers{$macro} = 1 unless defined $exclude_identifiers{$macro}; } elsif (/^typedef.*;$/) { my $type = $_; chop($type); $type =~ s/;$//; $type =~ s/\([^)]*\)$//; $type =~ s/^[^(]+\(\*(\w+)\)$/$1/ if $type =~ /\(\*\w+\)$/; $type =~ s/^.*\W(\w+)$/$1/; $identifiers{$type} = 1 unless defined $exclude_identifiers{$type}; } elsif ($hdr_state eq 'decls') { my $proto = $_; chop($proto); #warn "$module: _args missing: $proto\n" if $proto =~ /\);\s*$/ && $proto !~ / _args /; #$proto =~ s/ _args.*$//; $proto =~ s/\(.*$//; $proto =~ s/^.*\W(\w+)$/$1/; $proto = $1 if $proto =~ /^extern\s+\w+\s+(\w+)/; $identifiers{$proto} = 1 unless defined $exclude_identifiers{$proto}; } } close(HDR); } print("identifiers:\n\n ", join("\n ", sort keys %identifiers), "\n\n") if $debug; # set up the target list if ($#targets != -1) { # check identifiers supplied on the command line for (my $i = 0; $i <= $#targets; ++$i) { usage("Not an identifier: '$targets[$i]'") if $targets[$i] =~ /(^[0-9])|([^a-zA-Z0-9_])/; usage("No such identifier: '$targets[$i]'") unless defined $identifiers{$targets[$i]}; } } else { # use all identifiers as targets @targets = keys %identifiers; } print("targets:\n\n ", join("\n ", sort @targets), "\n\n") if $debug; # modify every instance of the public identifiers opendir(SRCDIR, $srcdir) || die "failed to open $srcdir: $!\n"; my @sources = grep { (/.*\.h$/ || /.*\.c$/) && -f "$srcdir/$_" } readdir(SRCDIR); closedir SRCDIR; my %patterns; for my $target (@targets) { if ($reverse) { usage("Identifier $target does not begin with $prefix") unless $target =~ /^$prefix/; my ($sans_prefix) = $target =~ /^$prefix([a-zA-Z0-9_]+)$/; usage("Result will not be an identifier: '$target' -> '$sans_prefix'") unless defined $sans_prefix && $sans_prefix =~ /^[a-zA-Z_][a-zA-Z0-9_]*$/; $patterns{$target} = $sans_prefix; } else { $patterns{$target} = $prefix . $target; } } print("pattern:\n\n ", join("\n ", map { "s/\\b$_\\b/$patterns{$_}/" } sort keys %patterns), "\n\n") if $debug; my %reverse_patterns = map { ($patterns{$_}, $_) } keys %patterns unless $reverse; print("reverse pattern:\n\n ", join("\n ", map { "s/\\b$_\\b/$reverse_patterns{$_}/" } sort keys %reverse_patterns), "\n\n") if $debug && !$reverse; # modify every instance of every target in every source file $/ = undef; for (my $i = 0; $i <= $#sources; ++$i) { my $src = "$srcdir/$sources[$i]"; open(SRC, $src) or die("failed to open $src\n"); my $text = ; my $copy = $text; close(SRC); $text =~ s/(? $out") or die("failed to open $out for writing\n"); print SRC $text; close(SRC); print("diff -du $src $out\n") if $test; system("diff -du $src $out") if $test; unlink($out) if $test; } } # generate prefix.h hdr('prefix.h', map { "#define $_ $patterns{$_}\n" } sort keys %patterns) if $prefix_h && !$reverse; # generate remove_prefix.h hdr('remove_prefix.h', map { "#define $patterns{$_} $_\n" } sort keys %patterns) if $remove_prefix_h && !$reverse; # generate a header file with a macro for each changed identifier sub hdr { my ($name, @macros) = @_; my $name_macro = $name; $name_macro =~ tr/a-z./A-Z_/; open(HDR, "> $name") or die "failed to open $name for writing\n"; print HDR << "EOT"; /* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_$name_macro #define LIBSLACK_$name_macro EOT print HDR @macros, "\n#endif\n"; close(HDR); } # undo prefix changes on ordinary words in the manpages # ordinary words do not appear inside C<...> or I<...> sub fixdoco { my ($text) = @_; my (@lines) = split(/\n/, $text); my $pod = 0; for (my $i = 0; $i <= $#lines; ++$i) { $pod = 0, next if $lines[$i] =~ /^=cut$/; # pod start $pod = 1 if $lines[$i] =~ /^=/; # pod stop next if $lines[$i] =~ /^=\w+\s+[CI] # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 20210220 raf prefix := /usr/local help: @echo "This makefile provides the following targets"; \ echo; \ echo " help -- shows this list of targets"; \ echo " install-analyse-debug-locker -- installs analyse-debug-locker"; \ echo " install-prefix -- installs prefix"; \ echo " install-prefix-h -- installs prefix.h"; \ echo " install-remove-prefix-h -- installs remove_prefix.h"; \ echo " uninstall-analyse-debug-locker -- uninstalls analyse-debug-locker"; \ echo " uninstall-prefix -- uninstalls prefix"; \ echo " uninstall-prefix-h -- uninstalls prefix.h"; \ echo " uninstall-remove-prefix-h -- uninstalls remove_prefix.h"; \ echo; \ echo "Note: There should be no reason to install prefix"; \ echo " except perhaps to install its manpage."; \ echo analyse-debug-locker.1: analyse-debug-locker pod2man --center='User Commands' --section=1 $< > $@ prefix.1: prefix pod2man --center='User Commands' --section=1 $< > $@ install-analyse-debug-locker: analyse-debug-locker.1 install -m 755 analyse-debug-locker $(prefix)/bin install -m 644 analyse-debug-locker.1 $(prefix)/man/man1 install-prefix: prefix.1 install -m 755 prefix $(prefix)/bin install -m 644 prefix.1 $(prefix)/man/man1 install-prefix-h: install -m 644 prefix.h $(prefix)/include/slack install-remove-prefix-h: install -m 644 remove_prefix.h $(prefix)/include/slack uninstall-analyse-debug-locker: rm -f $(prefix)/bin/analyse-debug-locker rm -f $(prefix)/man/man1/analyse-debug-locker.1 uninstall-prefix: rm -f $(prefix)/bin/prefix rm -f $(prefix)/man/man1/prefix.1 uninstall-prefix-h: rm -f $(prefix)/include/slack/prefix.h uninstall-remove-prefix-h: rm -f $(prefix)/include/slack/remove_prefix.h # vi:set ts=4 sw=4: daemon-0.8/libslack/CHANGELOG0000644000175000017500000004377614014141213013734 0ustar rafrafCHANGELOG ========= 0.7.1 (20210220) - Fixed make distclean/clobber on Debian (use debian-clobber instead of clobber) (spotted by Marc Haber) - Fixed parallel make test (race condition creating test directory) (spotted by Marc Haber) - Fixed manpage headers and footers and various other minor fixes and improvements - Fixed limitation in test code for daemon_path_is_safe() in deep directory (spotted by Kurt Hindenburg) - Added elaboration in mem module test output for pool_destroy_secure() - Replaced some 0 with EXIT_SUCCESS and 1 with EXIT_FAILURE in libslack module tests - Added configure --prefix=/opt/local for macports (spotted by Kurt Hindenburg) - Added mention of file locations on macOS/macports to the daemon(1) manpage - Added checks for gcc -W options that fail on old macosx (e.g. 10.6.8) without macports - Fixed return value on error (unlikely) for prog_out_none()/prog_err_none()/prog_dbg_none()/prog_alert_none() - Added support for using $CC in configure (spotted by Ryan Schmidt) - Fixed missing client defines in output of libslack-config --cflags (needed for configure --prefix) - Fixed Makefile (wasn't inheriting CPPFLAGS, CFLAGS or LDFLAGS from caller) (spotted by Ryan Schmidt) 0.7 (20201111) - Fixed bug: race condition causing failure with "exec daemon ..." (with Askar Safin safinaskar at mail.ru) - Added $DAEMON_INIT_EXIT_DELAY_MSEC workaround for obscure konsole bug (with Askar Safin safinaskar at mail.ru) - Removed O_NOCTTY-related manpage "bug" (now historical) (spotted by Askar Safin safinaskar at mail.ru) - Always double fork for safety on systems of unknown flavour (suggested by Askar Safin safinaskar at mail.ru) - Added support for GNU/Hurd (by Svante Signell svante.signell at telia.com) - Fixed bug: daemon_lock_pidfile() leaked fd across exec (spotted by Tilman Baumann tilman.baumann at grandeye.com) - Added fcntl_set_fdflag() and fcntl_clear_fdflag() to the fio module - Added signal_set_siginfo_handler() to the sig module - Added msg_filter_t, msg_create_filter(), msg_create_filter_with_locker() to the msg module - Test secure memory in the mem module for non-root users as well (now that they can do it) - Added prog_{out,err,dbg,alert}_push_filter() to the prog module - Added recvcred(), recvfromcred() to the net module - Fixed harmless format string bug in prog_opt_process() (spotted by Jong-Gwon Kim and Woosuk Lee {jgkim,wslee} at ropas.snu.ac.kr) - Fixed bug in parallelized make: "make ready" first so do it in configure (spotted by ilovezfs at icloud.com) - Fixed copyright messages (list actual years of publication, not just a range of years) - Fixed all sscanf "%s" to limit output (e.g. "%63s") to prevent buffer overruns (was only in test and example code) - Added more tests in the prop module - Fixed buglet: Removed vhangup() in pty_make_controlling_tty() as it broke some coproc module tests run as root - Fixed str.h to not clash with new strlcpy/strlcat macros on OSX/macOS - Updated to avoid new warnings in recent versions of gcc - Split README into multiple files (README.md INSTALL COPYING REFERENCES CHANGELOG) - Changed "config" script name to "configure" (not an alias anymore) (but it's not GNU configure) - Changed installation location prefix to /usr/pkg on NetBSD - Replaced racist pty jargon in code with more descriptive terms 0.6 (20100612) - Stopped accidentally installing config.h (spotted by rrt at sc3d.org) - Fixed bug: need double-fork on Linux (spotted by Joey Hess joeyh at debian.org) - Fixed bug checking argument validity in agent_recv() - Updated makefiles to work with recent versions of GNU make - Changed opt module to be ISO C compliant (backwards-incompatible!) - Updated to avoid new warnings in recent versions of gcc - Fixed pidfile race condition (with Hilko Bengen bengen at hilluzination.de) - 64-bit-related fixes for pack() and snprintf() - Updated to use va_copy() with vsnprintf() in str module - Made daemon_is_running() work when readonly (spotted by Thomas Koch thomas at koch.ro) - Ported to GNU/kFreeBSD (with Cyril Brulebois cyril.brulebois at enst-bretagne.fr) - Ported to NetBSD - Added make nbsd nbsd-daemon nbsd-slack (netbsd binary packages) - Ported to Solaris10 and OpenSolaris - Tested on ubuntu-10.04, debian-5.0.4, fedora-13 (x86_64, i386) - Tested on solaris-10-200910, opensolaris-200906 (amd64, i386) - Tested on openbsd-4.7, freebsd-8.0, netbsd-5.0.2 (amd64, i386) - Tested on macosx-10.{4,5,6} (x86_64, i386, ppc) - Tested on kfreebsd-20090729 (i386) - Updated make rpm sol obsd fbsd osx to continue working 0.5.2 (20040102) - Fixed API bug: didn't include - Fixed bug: -lm wasn't in `libslack-config --libs` on Solaris - Changed daemon_path_is_safe() to give an explanation when unsafe - Fixed bug: reset agent state to IDLE when interrupted (bte at kamash.com) - Trim unquoted leading spaces from property values (with bte at kamash.com) - Also trim only unquoted trailing spaces from property names - Added tools/migrate-properties utility (preserves old propfile behaviour) - Fixed bug: ownership partially lost in map_resize (with bte at kamash.com) - Fixed bug: mem_resize was broken since libslack-0.4 (bte at kamash.com) - Fixed DOC bug: stated the importance of including first - Added sections to libslack(3) features list (coproc+pty, low level api) - Fixed bug: if select() failed (unlikely), coproc wasn't closed properly - Fixed bug: when tty_raw() failed (unlikely), it returned the wrong value - Added many examples to the manpages (there are now 91 runnable examples) - Added tools/check-examples to verify that all examples work - Fixed bug: str_fgetline() returned empty string rather than null on eof - Fixed bug: cstrstr() didn't always work due to a typo - Added sections to libslack(3) features list (documentation, testing) - Added intel solaris8 binary package - Ported to Mac OS X (Darwin) 10.3.2 - Added make osx osx-daemon osx-slack (macosx binary packages) - Dropped support for K&R clients (suggested by skaller at ozemail.com.au) - Added hsort_closure(3) (suggested by skaller at maxtal.com.au) - Added make slack.swig (generate a SWIG input file for libslack) 0.5.1 (20020916) - Added HEADER FILES section to libslack(3) manpage - Added #include to example sections of module manpages - Added conf/freebsd (mmoraes at teleias.com) - Added tools/prefix utility (add prefix to all libslack identifiers) - Added manpage for tools/analyse-debug-locker utility - Separated stdout and stderr in coproc_open() and coproc_close() - Changed coproc open functions to take action() and data arguments - Exposed daemon_pidfile() - Added daemon_is_running() - Added daemon_stop() - Renamed sighandler_t to signal_handler_t (glibc clash - gdr at gno.org) - Ported to Solaris 8 - Split Solaris configuration scripts into conf/solaris[68]-[g]cc - Added support for installing gzipped manpages - Stopped generating debian package (until it's a shared library) - Added make fbsd fbsd-daemon fbsd-slack (freebsd binary packages) - Added support for absolute path in daemon_pidfile() - Added daemon_getpid() - Added libslack-config --upgrade option - Added lame ./config script that just calls existing lame conf/* scripts 0.5 (20011109) - Fixed Makefile bug: decoupled libslack optlevel from module test optlevel - Fixed API bug: str_length_unlocked() was static - Fixed API bug: prop_locker() prototype wasn't in prop.h - Added prop_clear() to prop module - Added octal/hex and error handling to command line integer option handling - Fixed bug: check() just called dump() without testing the condition first - Added variants of six standard C string functions with more useful APIs - Added thread module tests (and locker timing tests) - Changed locker function return values (now same as pthread return values) - Improved speed of lockers (now overhead = 1 test + 1 deref + 1 offset) - Changed item/length/size, bin/hex/oct functions to return -1 on error - Changed error returns to consistently set errno (str, list, map) - Added set_errnull() to err module - Added relative index/range semantics to list functions (same as with str) - Changed fifo_open() to take writefd return arg to prevent fd leaks - Simplified mem_resize() assuming ISO C compliant realloc() - Added internal ISO C compliant realloc() for systems that don't have it - Fixed bug: optval/optlen for getsockopt(SO_ERROR) not initialised - Fixed inode leak: fifo_open() didn't unlink fifo created on error - Removed thread_init(), thread_setcancel() and barriers from thread module - Renamed thread module to locker (decoupled thread safety) - Stopped daemon_revoke_privileges() from clearing supplementary group list - Added support for "debug sections" to debug messaging - Added daemon_become_user() to daemon module - Added "_unlocked" versions of functions in str, list and map modules - Renamed "_locked" functions to "_with_locker" to avoid confusion - Fixed bug: removed highly dubious synchronisation from internal iterators - Added read locked iterators - Added alert functions to prog, err and msg modules - Systematically corrected function prototype typos in manpages - Added net_options() to net module (sets multiple socket options) - Added soundex() to str module - Removed caching and mutex locks in daemon_started_by_init/inetd() - Added ignoring SIGHUP before losing session leadership in daemon_init() - Improved IPv6 support in net module (i.e. can now bind to IPv6 wildcard) - Added support for UNIX domain sockets to net module - Increased socket listen queue length from 5 to 1024 - Fixed bug: net service port selection only used numeric port arg - Added handling of name lookup returning multiple addresses for net clients - Added default host to net client functions (i.e. null host == loopback) - Changed net_create_server() and net_create_client() to take sockopt list - Added support for net clients binding to a specific local port - Added net_gethostbyname() and net_getservbyname() to net module - Made net server and client functions threadsafe - Added socket option notes to net module manpage (from W. Richard Stevens) - Added protocol design notes to net module manpage (from Radia Perlman) - Added sendfd() and recvfd() to net module (send/recv open file descriptor) - Replaced ioctl() with fcntl() in nonblock functions - Added support for net client/server service argument being numeric - Added link module (singly/doubly linked lists and "growable" freelists) - Added agent module (poll/select plus hierarchical timing wheel scheduler) - Added net_interfaces() to net module (retrieve list of network interfaces) - Added support for IPv4 and IPv6 multicasting to net module - Added Reliability over UDP functions to net module (net_rudp_transact()) - Added Type of Service (TOS) functions to net module - Changed net_pack/net_unpack functions to take a timeout arg - Added nap() function to fio module (subsecond sleep) - Added threadsafe snprintf() function for systems that don't have it - Added asprintf() to str module for systems that don't have it - Added config.h to simplify compile commands (prelude to autoconf) - Removed thread_attr_{init,set}() (not useful enough or portable enough) - Ported to OpenBSD 2.9 - Added pseudo module (pseudo terminals by Tatu Ylonen from openssh) - Added coproc module (coprocesses with or without a pseudo terminal) - Changed syslog functions to take a priority parameter - Added make obsd obsd-daemon obsd-slack (openbsd binary packages) - Added libslack-config --uninstall - Proofread all of the doco (just once) - Added setting appropriate TOS values in mail() - Fixed validation of relative index/range values in str/list modules - Added relative index semantics to list_item() - Added read locked versions of map_apply() and list_apply() - Added make and dist-html-slack (manpages as html.tar.gz) 0.4 (20010215) - Fixed memory usage bugs - Changed net server/client functions to use service name else port number - Fixed security bug: daemon_file_is_safe() wasn't following symlinks (doh!) - Renamed daemon_file_is_safe() to daemon_path_is_safe() - Added daemon_absolute_path() to daemon module - Added memory pool functions to mem module - Fixed bug: optional option arguments were handled in dodgy C - Made supplied snprintf() POSIX compliant (was using getpagesize()) - Removed conf module (Added daemon_parse_config() to daemon module) - Removed net_chat(), rfc822_localtime(), rfc822_gmtime() (not useful enough) - Added secure memory/pool functions to mem module - Fixed Makefile bug: $(CCFLAGS) for daemon and libslack weren't separate - Added fgetline() to fifo module (reads a line with any line ending) - Added str_fgetline() to str module (like fgetline but handles any length) - Renamed fifo module to fio - Fixed Makefile bug: wasn't uninstalling everything properly - Changed net_send() to take a timeout argument like next_expect() does - Added strlcpy(), strlcat(), strcasecmp() and strncasecmp() to str module - Renamed conf/solaris to solaris-gcc and added solaris-cc for sun workshop - Added support for root and user pidfiles in separate directories - Added make rpm rpm-daemon rpm-slack (with Edward Avis ed at membled.com) - Added installation of manpages for each function (link to module manpage) - Added libslack(3) overview manpage - Added list_break(), map_break() - Renamed assert() to check() for obvious reasons - Renamed re funcs in str module: s/regex/regexpr/g - Added thread module and made everything MT-Safe or MT-Disciplined - Added relative index/range semantics to string functions - Added make deb deb-daemon deb-slack (debian binary packages) - Added make pkg pkg-daemon pkg-slack (solaris binary packages) - Added setsockopt(SO_REUSEADDR) for net servers - Changed net server/client API to allow optional setsockopt(RCVBUF/SNDBUF) - Added REFERENCES section to README file - Stopped net_expect/net_send from interfering with SIGALRM/alarm/setitimer - Added read_timeout(), write_timeout() and rw_timeout() to fio module - Changed net_read() and net_write() to take a timeout argument - Added '?' field size specifier to unpack() (for packet length fields) - Added libslack-config administration utility - Renamed sockaddr typedef to sockaddr_t - Changed net_client to take a timeout parameter - Fixed fd leak in error handling code in net server/client functions - Fixed bug: str_regsub() didn't handle empty string matches at all - Changed str_regexpr_split() to take cflags and eflags arguments - Changed all *_destroy macros to functions that take address of pointer - Changed mem_resize macro so client must explicitly provide address of mem - Changed all *_destroy_t typedefs to *_release_t - Added make [un]install-{daemon|slack}-html (not part of make [un]install) - Temporarily removed snprintf module (not MT-Safe, not essential) - Merged lognames module into msg module - Merged opt module into prog module - Renamed _* functions in err module to *f (not ANSI compliant) - Removed MANIFEST 0.3 (20000902) - Started using GNU getopt_long() instead of getopt_long_only() - Added -DSVR4 in conf/solaris (doh!) - Added conditional compilation of debug functions - Added assert macro that calls dump() - Fixed bug: SIG_IGN, SIG_DFL and nasty signals weren't treated specially - Made lists grow/shrink exponentially rather than linearly - Made maps grow as needed and use arbitrary hash functions and key types - Added multi-dimensional array allocator to the mem module - Added net module: clients/servers, expect/send, pack/unpack, mail - Added internal iterators and some more functions to list and map - Added examples sections to some libprog manpages - Added str module: decent strings + tr, regex, regsub, fmt, trim, lc, uc ... - Added vsscanf(3) implementation for systems that don't have it (e.g. solaris) - Renamed libprog to libslack (thanks, fred) - Added socks.h - Added daemon_revoke_privileges(), daemon_file_is_safe() to daemon module 0.2 (19991223) - Decoupled core file prevention from daemon_init() into its own function, daemon_prevent_core() - Decoupled signal handling from daemon_init() - Cached daemon_started_by_init() and daemon_started_by_inetd() results - Added some modules to libprog: conf, list, hsort, map, prop - Added timestamps to msg_out_file() - Included source to GNU getopt_long_only() (if necessary) - Added hdr.h to allow non-ANSI compilers to parse libprog's headers - Moved libprog to a subdirectory using a "Whole Project" Makefile - Converted "Whole Project" Makefile into "Scalable" Makefiles - Added verbosity functions to libprog(prog) - Fixed bug when constructing data for GNU getopt_long_only() - Fixed bugs in the options table for libprog(prog) - Changed help message format: separated option chunks by a blank line - Fixed bug when obtaining names associated with syslog constants - Added pathetic conf/linux and conf/solaris scripts - Added manpages 0.1 (19991020) - Initial version TODO ==== - Add epoll and kqueue to the agent module - Decouple memory type and allocation strategy from List/Map/String code - Use autoconf and libtool -------------------------------------------------------------------------------- URL: http://libslack.org URL: http://raf.org/libslack GIT: https://github.com/raforg/libslack Date: 20210220 Author: raf daemon-0.8/libslack/COPYING0000644000175000017500000000514314014141213013537 0ustar rafrafCOPYING ======= libslack - A UNIX/C library of general utilities for programmers with Slack Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf This library 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 library 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 library; if not, see . $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ $OpenBSD: strlcat.c,v 1.5 2001/01/13 16:17:24 millert Exp $ Copyright (c) 1998 Todd C. Miller All rights reserved. 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. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. -------------------------------------------------------------------------------- URL: http://libslack.org URL: http://raf.org/libslack GIT: https://github.com/raforg/libslack Date: 20210220 Author: raf daemon-0.8/libslack/LICENSE0000644000175000017500000004313114014141213013510 0ustar rafraf GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. daemon-0.8/libslack/README.md0000644000175000017500000000432314014141213013762 0ustar rafrafREADME ====== *libslack* - A *UNIX/C* library of general utilities for programmers with Slack Slack(n.): The state in which you need nothing, because you already have it. -- J. R. "Bob" Dobbs, 1956 DESCRIPTION =========== *Libslack* is a library of general utilities designed to make *UNIX/C* programming a bit easier on the eye. It is a seemingly random collection of modules and functions that I find commonly useful. It's a small library with lots of functionality, accurately documented and thoroughly tested. Good library naming conventions are not rigorously observed on the principle that common operations should always be easy to write and code should always be easy to read. *Libslack* contains the following modules: agent - agent-oriented programming coproc - coprocess using pipes or pseudo terminals daemon - becoming a daemon err - message/error/debug/verbosity/alert messaging fio - fifo and file control and some I/O getopt - GNU getopt_long() for systems that don't have it hsort - generic heap sort lim - POSIX.1 limits convenience functions link - abstract linked lists with optional growable free lists list - list (growable pointer array) data type locker - abstract locking and reader/writer lock implementation map - map (hash table) data type mem - memory helper functions, secure memory, memory pools msg - message handling and syslog helper functions net - network functions (clients/servers, expect/send, pack/unpack, mail) prog - program framework and flexible command line option handling prop - program properties files pseudo - pseudo terminals sig - ISO C compliant signal handling snprintf - safe sprintf for systems that don't have it str - string data type (tr, regex, regsub, fmt, trim, lc, uc, ...) vsscanf - sscanf() with va_list argument for systems that don't have it -------------------------------------------------------------------------------- URL: http://libslack.org URL: http://raf.org/libslack GIT: https://github.com/raforg/libslack Date: 20210220 Author: raf daemon-0.8/libslack/REFERENCES0000644000175000017500000000663514014141213014057 0ustar rafrafREFERENCES ========== Advanced Programming in the UNIX Environment W. Richard Stevens Addison-Wesley Professional Computing Series, 1992 UNIX Network Programming W. Richard Stevens Prentice Hall Software Series, 1990 UNIX System V Network Programming Stephen A. Rago Addison-Wesley Professional Computing Series, 1993 TCP/IP Illustrated Volume 1, The Protocols W. Richard Stevens Addison-Wesley Professional Computing Series, 1994 UNIX Network Programming Volume 1, Networking APIs: Sockets and XTI W. Richard Stevens Prentice Hall Software Series, 1998 The Practice of Programming Brian W. Kernighan and Rob Pike, Addison-Wesley Professional Computing Series, 1999 Multithreaded Programming with Pthreads Bil Lewis and Daniel J. Berg Sun Microsystem Press/Prentice Hall, 1998 Effective TCP/IP Programming Jon C. Snader Addison-Wesley, 2000 Design Patterns - Elements of Reusable Object-Oriented Software Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides Addison-Wesley Professional Computing Series, 1995 The Standard C Library P. J. Plauger Prentice Hall, 1992 The Discipline and Method Architecture for Reusable Libraries Kiem-Phong Vo Software - Practice & Experience, v.30, pp.107-128, 2000 http://www.research.att.com/sw/tools/sfio/dm-spe.ps strlcpy and strlcat--Consistent, Safe, String Copy and Concatenation Todd C. Miller and Theo De Raadt Proceedings of the FREENIX Track: 1999 USENIX Annual Technical Conference http://www.usenix.org/events/usenix99/millert.html The Perl manpages Larry Wall http://www.perl.com/ Practical UNIX and Internet Security Simson Garfinkel and Gene Spafford O'Reilly, 1996 Interconnections - Bridges, Routers, Switches and Internetworking Protocols Radia Perlman Addison-Wesley Professional Computing Series, 2000 MT-Disciplined raf http://raf.org/papers/mt-disciplined.html, 2001 I/O Event Handling Under Linux Richard Gooch http://www.atnf.csiro.au/~rgooch/linux/docs/io-events.html, 1999 Scalable kernel performance for Internet servers under realistic loads Gaurav Banga and Jeffrey C. Mogul Proceeding of the Refereed Papers Track: 1998 USENIX Annual Technical Conference http://www.usenix.org/publications/library/proceedings/usenix98/banga.html TCP Buffering and Performance Over An ATM Network Purdue Technical Report CSD-TR 94-026 (Revision) Journal of Internetworking: Research and Experience, Vol. 6 (1), Pages 1-13 Douglas E. Comer and John C. Lin ftp://gwen.cs.purdue.edu/pub/lin/TCP.atm.ps.Z, 1994 Experimental and Simulation Performance Results of TCP/IP over High-Speed ATM over ACTS Charalambos, C.; Lazarou, G.; Frost, V.; Evans, J.; Jonkman, R. Information and Telecommunication Technology Center, Department of Electrical Engineering & Computer Science, The University of Kansas http://acts.lerc.nasa.gov/library/docs/gsn/charalambous.pdf Revelation X: The "Bob" Apocryphon Translated by The Subgenius Foundation, Edited by Reverend Ivan Stang, Simon & Schuster, 1994 -------------------------------------------------------------------------------- URL: http://libslack.org URL: http://raf.org/libslack GIT: https://github.com/raforg/libslack Date: 20210220 Author: raf daemon-0.8/libslack/agent.h0000644000175000017500000000603414014141213013753 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_AGENT_H #define LIBSLACK_AGENT_H #include #include typedef struct Agent Agent; typedef int agent_action_t(Agent *agent, void *arg); typedef int agent_reaction_t(Agent *agent, int fd, int revents, void *arg); _begin_decls Agent *agent_create(void); Agent *agent_create_with_locker(Locker *locker); Agent *agent_create_measured(void); Agent *agent_create_measured_with_locker(Locker *locker); Agent *agent_create_using_select(void); Agent *agent_create_using_select_with_locker(Locker *locker); void agent_release(Agent *agent); void *agent_destroy(Agent **agent); int agent_rdlock(const Agent *agent); int agent_wrlock(const Agent *agent); int agent_unlock(const Agent *agent); int agent_connect(Agent *agent, int fd, int events, agent_reaction_t *reaction, void *arg); int agent_connect_unlocked(Agent *agent, int fd, int events, agent_reaction_t *reaction, void *arg); int agent_disconnect(Agent *agent, int fd); int agent_disconnect_unlocked(Agent *agent, int fd); int agent_transfer(Agent *agent, int fd, Agent *dst); int agent_transfer_unlocked(Agent *agent, int fd, Agent *dst); int agent_send(Agent *agent, int fd, int sockfd); int agent_send_unlocked(Agent *agent, int fd, int sockfd); int agent_recv(Agent *agent, int sockfd, agent_reaction_t *reaction, void *arg); int agent_recv_unlocked(Agent *agent, int sockfd, agent_reaction_t *reaction, void *arg); int agent_detail(Agent *agent, int fd); int agent_detail_unlocked(Agent *agent, int fd); const struct timeval * const agent_last(Agent *agent, int fd); const struct timeval * const agent_last_unlocked(Agent *agent, int fd); int agent_velocity(Agent *agent, int fd); int agent_velocity_unlocked(Agent *agent, int fd); int agent_acceleration(Agent *agent, int fd); int agent_acceleration_unlocked(Agent *agent, int fd); int agent_dadt(Agent *agent, int fd); int agent_dadt_unlocked(Agent *agent, int fd); void *agent_schedule(Agent *agent, long sec, long usec, agent_action_t *action, void *arg); void *agent_schedule_unlocked(Agent *agent, long sec, long usec, agent_action_t *action, void *arg); int agent_cancel(Agent *agent, void *action_id); int agent_cancel_unlocked(Agent *agent, void *action_id); int agent_start(Agent *agent); int agent_stop(Agent *agent); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/configure0000755000175000017500000000512114014141213014407 0ustar rafraf#!/bin/sh # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 20210220 raf die() { echo "$0: $@" >&2; exit 1; } case "`uname -a`" in Linux*) echo "Configuring for linux" conf/linux ;; GNU/kFreeBSD*) echo "Configuring for kfreebsd" conf/kfreebsd ;; GNU*) echo "Configuring for GNU/Hurd" conf/gnuhurd ;; FreeBSD*) echo "Configuring for freebsd" conf/freebsd ;; NetBSD*) echo "Configuring for netbsd" conf/netbsd ;; OpenBSD*) echo "Configuring for openbsd" conf/openbsd ;; SunOS*) cc="" solaris="solaris10" [ "x`uname -r`" = "x5.8" ] && solaris="solaris8" [ "x`uname -r`" = "x5.6" ] && solaris="solaris6" if [ "`uname -m`" = sun4u ] then [ "x`which gcc 2>&-`" != "x" ] && cc="gcc" [ "x`which cc 2>&-`" != "x" ] && cc="cc" else [ "x`which cc 2>&-`" != "x" ] && cc="cc" [ "x`which gcc 2>&-`" != "x" ] && cc="gcc" fi [ "$cc" = "" ] && die "Failed to find a compiler" echo "Configuring for $solaris (with $cc)" conf/$solaris-$cc ;; Darwin*) echo "Configuring for macosx" conf/macosx ;; *) die "Unknown platform: please configure manually" ;; esac # Set CC from $CC (for macports) if [ "x$CC" != x ] then echo "Configuring CC as $CC" conf/ccenv fi # Process command line options for opt in "$@" do case "$opt" in --prefix=*) echo "Configuring $opt" conf/prefix "$opt" ;; --enable-test) echo "Configuring to include backup function implementations." conf/test ;; --enable-test-rwlock) echo "Configuring to include backup rwlock implementation." conf/test-rwlock-start ;; --disable-test-rwlock) echo "Configuring to exclude backup rwlock implementation (default)." conf/test-rwlock-stop ;; *) echo "$0: Unknown argument: $@" >&2 exit 1 ;; esac done # Prepare for parallel make if [ x"`which gmake`" != x"" ] then gmake ready else make ready fi exit 0 # vi:set ts=4 sw=4: daemon-0.8/libslack/coproc.h0000644000175000017500000000300314014141213014133 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_COPROC_H #define LIBSLACK_COPROC_H #include #include #include #include _begin_decls pid_t coproc_open(int *to, int *from, int *err, const char *cmd, char * const *argv, char * const *envv, void (*action)(void *data), void *data); int coproc_close(pid_t pid, int *to, int *from, int *err); pid_t coproc_pty_open(int *pty_user_fd, char *pty_device_name, size_t pty_device_name_size, const struct termios *pty_device_termios, const struct winsize *pty_device_winsize, const char *cmd, char * const *argv, char * const *envv, void (*action)(void *data), void *data); int coproc_pty_close(pid_t pid, int *pty_user_fd, const char *pty_device_name); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/daemon.c0000644000175000017500000014647714014141213014133 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ /* =head1 NAME I - daemon module =head1 SYNOPSIS #include #include typedef void daemon_config_parser_t(void *obj, const char *path, char *line, size_t lineno); int daemon_started_by_init(void); int daemon_started_by_inetd(void); int daemon_prevent_core(void); int daemon_revoke_privileges(void); int daemon_become_user(uid_t uid, gid_t gid, char *user); char *daemon_absolute_path(const char *path); int daemon_path_is_safe(const char *path, char *explanation, size_t explanation_size); void *daemon_parse_config(const char *path, void *obj, daemon_config_parser_t *parser); int daemon_pidfile(const char *name); int daemon_init(const char *name); int daemon_close(void); pid_t daemon_getpid(const char *name); int daemon_is_running(const char *name); int daemon_stop(const char *name); =head1 DESCRIPTION This module provides functions for writing daemons. There are many tasks that need to be performed to correctly set up a daemon process. This can be tedious. These functions perform these tasks for you. =over 4 =cut */ #include "config.h" #ifndef NO_POSIX_SOURCE #define NO_POSIX_SOURCE /* For ELOOP on FreeBSD-8.0 */ #endif #ifndef _BSD_SOURCE #define _BSD_SOURCE /* For setgroups(2) and S_ISLNK(2) on Linux */ #endif #ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE /* New name for _BSD_SOURCE */ #endif #ifndef __BSD_VISIBLE #define __BSD_VISIBLE 1 /* For setgroups(2) and initgroups(2) on FreeBSD-8.0 */ #endif #ifndef _NETBSD_SOURCE #define _NETBSD_SOURCE /* For endpwent, endgrent, setgroups, initgroups, lstat, readlink on NetBSD-5.0.2 */ #endif #include "std.h" #include #include #include #include #include #include #include "daemon.h" #include "mem.h" #include "err.h" #include "lim.h" #include "fio.h" #ifndef HAVE_SNPRINTF #include "snprintf.h" #endif #ifndef TEST static struct { pthread_mutex_t lock; /* Mutex lock for structure */ char *pidfile; /* Name of the locked pid file */ } g = { PTHREAD_MUTEX_INITIALIZER, NULL }; #define ptry(action) { int err = (action); if (err) return set_errno(err); } /* =item C If this process was started by I (i.e. if the parent process id is 1), returns 1. If not, returns C<0>. If it was, we might be getting respawned so I and I would be a big mistake (and unnecessary anyway, since there is no controlling terminal). On error, returns C<-1> with C set appropriately. =cut */ int daemon_started_by_init(void) { return (getppid() == 1); } /* =item C If this process was started by I (i.e. if I is a socket), returns C<1>. If not, returns C<0>. On error, returns C<-1> with C set appropriately. If it was, C, C and C would be opened to a socket. Closing them would be a big mistake. We also would not need to I and I because there is no controlling terminal. =cut */ int daemon_started_by_inetd(void) { size_t optlen = sizeof(int); int optval; return (getsockopt(STDIN_FILENO, SOL_SOCKET, SO_TYPE, &optval, (void *)&optlen) == 0); } /* =item C Prevents core files from being generated. This is used to prevent leaking sensitive information in daemons run by I. On success, returns C<0>. On error, returns C<-1> with C set appropriately. =cut */ int daemon_prevent_core(void) { struct rlimit limit[1] = {{ 0, 0 }}; if (getrlimit(RLIMIT_CORE, limit) == -1) return -1; limit->rlim_cur = 0; return setrlimit(RLIMIT_CORE, limit); } /* =item C Revokes setuid and setgid privileges. Useful when your program does not require any special privileges, and may become unsafe if incorrectly installed with special privileges. Also useful when your program only requires special privileges initially upon startup (e.g. binding to a privileged socket). Performs the following tasks: Sets the effective gid to the real gid if they differ. Checks that they no longer differ. Sets the effective uid to the real uid if they differ. Checks that they no longer differ. Also closes /etc/passwd and /etc/group in case they were opened by I and give access to user and group passwords. On success, returns C<0>. On error, returns C<-1> with C set appropriately. =cut */ int daemon_revoke_privileges(void) { uid_t uid = getuid(); gid_t gid = getgid(); uid_t euid = geteuid(); gid_t egid = getegid(); if (egid != gid && (setgid(gid) == -1 || getegid() != getgid())) return -1; if (euid != uid && (setuid(uid) == -1 || geteuid() != getuid())) return -1; endpwent(); endgrent(); return 0; } /* =item C Changes the owner and group of the process to C and C, respectively. If C is not null, the supplementary group list will be initialised with I. Otherwise, the supplementary group list will be cleared of all groups. On success, returns C<0>. On error, returns C<-1> with C set appropriately. Only I can use this function. =cut */ int daemon_become_user(uid_t uid, gid_t gid, char *user) { gid_t gids[10]; int g = 0; if (setgroups(0, NULL) == -1 || (g = getgroups(0, NULL)) != 0) { /* FreeBSD always returns the primary group */ if (g != 1 || getgroups(10, gids) != 1 || gids[0] != getgid()) return -1; } if (setgid(gid) == -1 || getgid() != gid || getegid() != gid) return -1; if (user && initgroups(user, gid) == -1) return -1; if (setuid(uid) == -1 || getuid() != uid || geteuid() != uid) return -1; return 0; } /* =item C Returns C converted into an absolute path. Cleans up any C<.> and C<..> and C and trailing C found in the returned path. Note that the returned path looks canonical but isn't, because symbolic links are not followed and expanded. It is the caller's responsibility to deallocate the path returned with I or I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the absolute path. On error, returns C with C set appropriately. =cut */ char *daemon_absolute_path(const char *path) { size_t path_len; char *abs_path; char *p; if (!path) return set_errnull(EINVAL); /* Make path absolute and mostly canonical (don't follow symbolic links) */ if (*path != PATH_SEP) { long lim = limit_path(); char *cwd = mem_create(lim, char); size_t cwd_len; int rc; if (!cwd) return NULL; if (!getcwd(cwd, lim)) { mem_release(cwd); return NULL; } cwd_len = strlen(cwd); if (cwd_len + 1 + strlen(path) >= lim) { mem_release(cwd); return set_errnull(ENAMETOOLONG); } rc = snprintf(cwd + cwd_len, lim - cwd_len, "%c%s", PATH_SEP, path); if (rc == -1 || rc >= lim - cwd_len) { mem_release(cwd); return set_errnull(ENAMETOOLONG); } abs_path = cwd; } else { if (!(abs_path = mem_strdup(path))) return NULL; } /* Clean up any // and . and .. in the absolute path */ path_len = strlen(abs_path); for (p = abs_path; *p; ++p) { if (p[0] == PATH_SEP) { if (p[1] == PATH_SEP) { memmove(p, p + 1, path_len + 1 - (p + 1 - abs_path)); --path_len; --p; } else if (p[1] == '.') { if (p[2] == PATH_SEP || p[2] == nul) { int keep_sep = (p == abs_path && p[2] == nul); memmove(p + keep_sep, p + 2, path_len + 1 - (p + 2 - abs_path)); path_len -= 2 - keep_sep; --p; } else if (p[2] == '.' && (p[3] == PATH_SEP || p[3] == nul)) { char *scan, *parent; int keep_sep; for (scan = parent = p; scan > abs_path; ) { if (*--scan == PATH_SEP) { parent = scan; break; } } keep_sep = (parent == abs_path && p[3] == nul); memmove(parent + keep_sep, p + 3, path_len + 1 - (p + 3 - abs_path)); path_len -= p + 3 - parent; p = parent - 1; } } } } /* Strip off any trailing / */ while (path_len > 1 && abs_path[path_len - 1] == PATH_SEP) abs_path[--path_len] = nul; return abs_path; } /* =item C Checks that the file referred to by C is not group- or world-writable. Also checks that the containing directories are not group- or world-writable, following symbolic links. Useful when you need to know whether or not you can trust a user supplied configuration/command file before reading and acting upon its contents. On success, returns C<1> if C is safe or C<0> if it is not. When the path is not safe, an explanation is written to the C buffer (if it is not C). No more than C bytes including the terminating C byte will be written to the C buffer. On error, returns C<-1> with C set appropriately. =cut */ static int daemon_check_path(char *path, char *explanation, size_t explanation_size, int level) { struct stat status[1]; char *sep; int rc; if (level > 16) return set_errno(ELOOP); for (sep = path + strlen(path); sep; sep = strrchr(path, PATH_SEP)) { sep[sep == path] = nul; if (lstat(path, status) == -1) return -1; if (S_ISLNK(status->st_mode)) { size_t lim; char *sym_linked; char *tmp; lim = limit_path(); if (!(sym_linked = mem_create(lim, char))) return -1; memset(sym_linked, 0, lim); if (readlink(path, sym_linked, lim) == -1) { mem_release(sym_linked); return -1; } if (*sym_linked != PATH_SEP) { if (!(tmp = mem_create(lim, char))) { mem_release(sym_linked); return -1; } rc = snprintf(tmp, lim, "%s%c..%c%s", path, PATH_SEP, PATH_SEP, sym_linked); if (rc == -1 || rc >= lim) { mem_release(sym_linked); mem_release(tmp); return set_errno(ENAMETOOLONG); } rc = snprintf(sym_linked, lim, "%s", tmp); mem_release(tmp); if (rc == -1 || rc >= lim) { mem_release(sym_linked); return set_errno(ENAMETOOLONG); } } tmp = daemon_absolute_path(sym_linked); mem_release(sym_linked); if (!(sym_linked = tmp)) return -1; rc = daemon_check_path(sym_linked, explanation, explanation_size, level + 1); mem_release(sym_linked); switch (rc) { case -1: return -1; case 0: return 0; case 1: break; } } else if (status->st_mode & (S_IWGRP | S_IWOTH)) { if (explanation) { snprintf(explanation, explanation_size, "%s is %s%s%swritable", path, (status->st_mode & S_IWGRP) ? "group-" : "", ((status->st_mode & (S_IWGRP | S_IWOTH)) == (S_IWGRP | S_IWOTH)) ? " and " : "", (status->st_mode & S_IWOTH) ? "world-" : "" ); } return 0; } if (sep == path) break; } return 1; } int daemon_path_is_safe(const char *path, char *explanation, size_t explanation_size) { char *abs_path; int rc; if (!path) return set_errno(EINVAL); abs_path = daemon_absolute_path(path); if (!abs_path) return -1; rc = daemon_check_path(abs_path, explanation, explanation_size, 0); mem_release(abs_path); return rc; } /* =item C Parses the text configuration file named C. Blank lines are ignored. Comments (C<'#'> to end of line) are ignored. Lines that end with C<'\'> are joined with the following line. There may be whitespace characters, and even a comment, after the C<'\'> character, but nothing else. The C function is called with the client supplied C, the file name, the line and the line number as arguments. On success, returns C. On error, returns C (i.e. if the configuration file could not be read). Note: Don't parse config files unless they are "safe" as determined by I. =cut */ void *daemon_parse_config(const char *path, void *obj, daemon_config_parser_t *parser) { FILE *conf; char line[BUFSIZ]; char buf[BUFSIZ]; int lineno; int rc; if (!(conf = fopen(path, "r"))) return NULL; line[0] = nul; for (lineno = 1; fgets(buf, BUFSIZ, conf); ++lineno) { char *start = buf; char *end; size_t length; int cont_line; /* Strip trailing comments */ if ((end = strchr(start, '#'))) *end = nul; else end = start + strlen(start); /* Skip trailing spaces (allows comments after line continuation) */ while (end > start && isspace((int)(unsigned char)end[-1])) --end; /* Skip empty lines */ if (*start == nul || start == end) continue; /* Perform line continuation */ if ((cont_line = (end[-1] == '\\'))) --end; length = strlen(line); rc = snprintf(line + length, BUFSIZ - length, "%*.*s", (int)(end - start), (int)(end - start), start); if (rc == -1 || rc >= BUFSIZ - length) return NULL; if (cont_line) continue; /* Parse the resulting line */ parser(obj, path, line, lineno); line[0] = nul; } fclose(conf); return obj; } /* C Constructs the pidfile for the given C in C. If C is already an absolute path, it is just copied into the new buffer directly. On success, returns C<0>, and the resulting buffer in C must be deallocated by the caller. On error, returns C<-1> with C set appropriately. */ static int daemon_construct_pidfile(const char *name, char **pidfile) { long path_len; const char *pid_dir; char *suffix = ".pid"; size_t size; /* Copnstruct the pidfile */ path_len = limit_path(); pid_dir = (getuid()) ? USER_PID_DIR : ROOT_PID_DIR; size = ((*name == PATH_SEP) ? strlen(name) : sizeof(pid_dir) + 1 + strlen(name) + strlen(suffix)) + 1; if (size > path_len) return set_errno(ENAMETOOLONG); if (!*pidfile && !(*pidfile = mem_create(path_len, char))) return -1; if (*name == PATH_SEP) snprintf(*pidfile, path_len, "%s", name); else snprintf(*pidfile, path_len, "%s%c%s%s", pid_dir, PATH_SEP, name, suffix); return 0; } /* C Open and lock the file referred to by C. On success, returns the file descriptor of the opened and locked file. On error, returns C<-1> with C set appropriately. */ static int daemon_lock_pidfile(char *pidfile) { mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; struct stat statbuf_fd[1], statbuf_fs[1]; int pid_fd; start: /* This is broken over NFS (Linux). So pidfiles must reside locally. */ if ((pid_fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, mode)) == -1) { if (errno != EEXIST) return -1; /* ** The pidfile already exists. Is it locked? ** If so, another invocation is still alive. ** If not, the invocation that created it has died. ** Open the pidfile to attempt a lock. */ if ((pid_fd = open(pidfile, O_RDWR)) == -1) { /* ** We couldn't open the file. That means that it existed ** a moment ago but has been since been deleted. Maybe if ** we try again now, it'll work (unless another process is ** about to re-create it before we do, that is). */ if (errno == ENOENT) goto start; return -1; } } if (fcntl_lock(pid_fd, F_SETLK, F_WRLCK, SEEK_SET, 0, 0) == -1) { close(pid_fd); return -1; } /* ** The pidfile may have been unlinked, after we opened it, by another daemon ** process that was dying between the last open() and the fcntl(). There's ** no use hanging on to a locked file that doesn't exist (and there's ** nothing to stop another daemon process from creating and locking a ** new instance of the file. So, if the pidfile has been deleted, we ** abandon this lock and start again. Note that it may have been deleted ** and subsequently re-created by yet another daemon process just starting ** up so check that that hasn't happened as well by comparing inode ** numbers. If it has, we also abandon this lock and start again. */ if (fstat(pid_fd, statbuf_fd) == -1) { /* This shouldn't happen */ close(pid_fd); return -1; } if (stat(pidfile, statbuf_fs) == -1) { /* The pidfile has been unlinked so we start again */ if (errno == ENOENT) { close(pid_fd); goto start; } close(pid_fd); return -1; } else if (statbuf_fd->st_ino != statbuf_fs->st_ino) { /* The pidfile has been unlinked and re-created so we start again */ close(pid_fd); goto start; } /* Prevent leaking this file descriptor into child processes. */ fcntl_set_fdflag(pid_fd, FD_CLOEXEC); return pid_fd; } /* C Equivalent to I except that the daemon module's mutex is not locked and unlocked. */ static int daemon_pidfile_unlocked(const char *name) { char pid[32]; int pid_fd; /* Check argument */ if (!name) return set_errno(EINVAL); /* Build the pidfile path */ if (daemon_construct_pidfile(name, &g.pidfile) == -1) return -1; /* Open it and lock it (if possible) */ if ((pid_fd = daemon_lock_pidfile(g.pidfile)) == -1) { mem_destroy(&g.pidfile); return -1; } /* Store our pid */ snprintf(pid, 32, "%d\n", (int)getpid()); if (write(pid_fd, pid, strlen(pid)) != strlen(pid)) { daemon_close(); return -1; } /* ** Flaw: If someone unceremoniously unlinks the pidfile, ** we won't know about it and nothing will stop another ** invocation from starting up. */ return 0; } /* =item C Creates a pid file for a daemon and locks it. The file has one line containing the process id of the daemon. The well-known locations for the file is defined in C for I (C<"/var/run"> by default) and C for all other users (C<"/tmp"> by default). The name of the file is the name of the daemon (given by the I argument) followed by C<".pid"> (If I is an absolute file path, it is used as is). The presence of this file will prevent two daemons with the same name from running at the same time. On success, returns C<0>. On error, returns C<-1> with C set appropriately. B This is called by I, so there is usually no need to call this function directly. =cut */ int daemon_pidfile(const char *name) { int rc; ptry(pthread_mutex_lock(&g.lock)) rc = daemon_pidfile_unlocked(name); ptry(pthread_mutex_unlock(&g.lock)) return rc; } /* =item C Initialises a daemon by performing the following tasks: =over 4 =item * If the process was not invoked by I (i.e. parent process id is 1) or I (i.e. C is a socket): =over 4 =item * Ignore C signals in case the current process session leader terminates while attached to a controlling terminal causing us to receive a C signal before we start our own process session below. This can happen when the process that calls I was itself invoked interactively via the shell builtin C. When this initial process terminates below, the terminal emulator that invoked the shell also terminates. =item * Background the process to lose process group leadership. =item * Start a new process session. =item * Background the process again to lose process session leadership. Under I, this prevents the process from ever gaining a controlling terminal. This is only necessary under I, but is always done for simplicity. Note that ignoring C signals earlier means that when the newly created process session leader terminates, then even if it has a controlling terminal open, the newly backgrounded process won't receive the corresponding C signal that is sent to all processes in the process session's foreground process group, because it inherited signal dispositions from the initial process. =back =item * Change the current directory to the root directory so as not to hamper umounts. =item * Clear the umask to enable explicit file creation modes. =item * Close all open file descriptors. If the process was invoked by I, C, C and C are left open, because they are open to a socket. =item * Open C, C and C to C in case something requires them to be open. Of course, this is not done if the process was invoked by I. =item * If C is non-null, create and lock a file containing the process id of the process. The presence of this locked file prevents two instances of a daemon with the same name from running at the same time. The default location of the pidfile is C for I (C on I, C on I when installed via I), and C for ordinary users. =back On success, returns C<0>. On error, returns C<-1> with C set appropriately. =cut */ int daemon_init(const char *name) { pid_t pid; long nopen; int fd; /* ** Don't setup a daemon-friendly process context ** if started by init(8) or inetd(8). */ if (!(daemon_started_by_init() || daemon_started_by_inetd())) { /* ** Ignore SIGHUP signals in case the current process session leader ** terminates while attached to a controlling terminal causing us to ** receive a SIGHUP signal before we start our own process session below. */ struct sigaction act[1]; act->sa_handler = SIG_IGN; sigemptyset(&act->sa_mask); act->sa_flags = 0; if (sigaction(SIGHUP, act, NULL) == -1) return -1; /* ** Background the process. ** Lose process session/group leadership. */ if ((pid = fork()) == -1) return -1; if (pid) { #ifndef DISABLE_DAEMON_INIT_EXIT_DELAY_MSEC /* ** If the user has requested an exit delay because they use ** "exec daemon" to run KDE applications that are failing ** immediately, then delay the parent's exit by the given ** number of milliseconds. ** ** Note: We are not delaying the start of the client, just the ** exit of the initial parent process. ** ** Note Also: I have no idea why this delay seems to fix ** "exec daemon kde-app" failures. ** ** Also Note: This has nothing to do with daemon. The same ** failures occur with "exec kde-app". ** ** Also note: Setting DAEMON_INIT_EXIT_DELAY_MSEC to at least 400 ** (i.e. 0.4 seconds) seems to be enough. Your mileage may vary. */ char *delay_var; long delay_msec; if ((delay_var = getenv("DAEMON_INIT_EXIT_DELAY_MSEC")) && (delay_msec = atol(delay_var)) > 0) nap(delay_msec / 1000, (delay_msec & 1000) * 1000); #endif exit(EXIT_SUCCESS); } /* Become a process session leader. */ /* This can only fail when we're already a session leader. */ setsid(); /* ** Lose process session leadership to prevent gaining a controlling ** terminal in SVR4. Always do it in case we don't know what flavour ** of UNIX this system is. */ if ((pid = fork()) == -1) return -1; if (pid) exit(EXIT_SUCCESS); } /* Enter the root directory to prevent hampering umounts. */ if (chdir(ROOT_DIR) == -1) return -1; /* Clear umask to enable explicit file modes. */ umask(0); /* ** We need to close all open file descriptors. Check how ** many file descriptors we have (If indefinite, a usable ** number (1024) will be returned). ** ** Flaw: If many files were opened and then this limit ** was reduced to below the highest file descriptor, ** we may not close all file descriptors. */ if ((nopen = limit_open()) == -1) return -1; /* ** Close all open file descriptors. If started by inetd, ** we don't close stdin, stdout and stderr. ** Don't forget to open any future tty devices with O_NOCTTY ** so as to prevent gaining a controlling terminal ** (not necessary with SVR4 or modern versions of BSD). */ if (daemon_started_by_inetd()) { for (fd = 0; fd < nopen; ++fd) { switch (fd) { case STDIN_FILENO: case STDOUT_FILENO: case STDERR_FILENO: break; default: close(fd); } } } else { for (fd = 0; fd < nopen; ++fd) close(fd); /* ** Open stdin, stdout and stderr to /dev/null just in case some ** code buried in a library somewhere expects them to be open. */ if ((fd = open("/dev/null", O_RDWR)) == -1) return -1; /* ** This is only needed for very strange (hypothetical) ** POSIX implementations where STDIN_FILENO != 0 or ** STDOUT_FILE != 1 or STDERR_FILENO != 2 (yeah, right). */ if (fd != STDIN_FILENO) { if (dup2(fd, STDIN_FILENO) == -1) return -1; close(fd); } if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) return -1; if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) return -1; } /* Place our process id in the file system and lock it. */ if (name) return daemon_pidfile(name); return 0; } /* =item C Unlinks the locked pid file, if any. Returns 0. =cut */ int daemon_close(void) { ptry(pthread_mutex_lock(&g.lock)) if (g.pidfile) { unlink(g.pidfile); mem_destroy(&g.pidfile); } ptry(pthread_mutex_unlock(&g.lock)) return 0; } /* =item C Returns the process id of the daemon with the given C. If the daemon in question is owned by I, then this function must be invoked by I. Similarly, if the daemon in question is owned by an ordinary user, then this function must be invoked by an ordinary user. If C is the absolute path to the pidfile (rather than just the daemon name), then any user may call this function. On success, returns the process id of the daemon. On error, returns C<-1> with C set appropriately. =cut */ pid_t daemon_getpid(const char *name) { char *pidfile = NULL; char buf[BUFSIZ]; ssize_t bytes; int pid_fd; int pid = 0; /* Check argument */ if (!name) return set_errno(EINVAL); /* Build the pidfile path */ if (daemon_construct_pidfile(name, &pidfile) == -1) return -1; /* Open the pidfile */ pid_fd = open(pidfile, O_RDONLY); mem_release(pidfile); if (pid_fd == -1) return -1; /* Read it */ bytes = read(pid_fd, buf, BUFSIZ); close(pid_fd); if (bytes == -1) return -1; if (sscanf(buf, "%d", &pid) != 1) return -1; return (pid_t)pid; } /* =item C Checks whether or not a daemon with the given C is running. If the daemon in question is owned by I, then this function must be invoked by I. Similarly, if the daemon in question is owned by an ordinary user, then this function must be invoked by an ordinary user. However, if C is the absolute path to the pidfile (rather than just the daemon name), then any user may call this function. On success, returns C<1> if the daemon is running or C<0> if it is not. On error, returns C<-1> with C set appropriately. =cut */ int daemon_is_running(const char *name) { char *pidfile = NULL; int pid_fd; /* Check argument */ if (!name) return set_errno(EINVAL); /* Build the pidfile path */ if (daemon_construct_pidfile(name, &pidfile) == -1) return -1; /* Open the pidfile to see if it exists */ if ((pid_fd = open(pidfile, O_RDONLY)) == -1) { mem_release(pidfile); if (errno != ENOENT) return -1; /* The pidfile doesn't exist, so the daemon probably isn't running */ return 0; } /* Is the pidfile write-locked? If so, the following will fail */ if (fcntl_lock(pid_fd, F_SETLK, F_RDLCK, SEEK_SET, 0, 0) == -1) { mem_release(pidfile); close(pid_fd); if (errno != EACCES && errno != EAGAIN) return -1; return 1; } mem_release(pidfile); close(pid_fd); /* Not write-locked - daemon is not running */ return 0; } /* =item C Stops a daemon process with the given C by sending it a C signal. If the daemon in question is owned by I, then this function must be invoked by I. Similarly, if the daemon in question is owned by an ordinary user, then this function must be invoked by that user. Note that I can't use this function to stop a daemon started by another user just by passing the name of the daemon (because the pidfiles for I daemons and user daemons are stored in different directories). In order for I to stop an ordinary user's daemon process, C has to be the absolute path to the daemon's pidfile. On success, returns C<0>. On error, returns C<-1> with C set appropriately. =cut */ int daemon_stop(const char *name) { char *pidfile = NULL; char pidbuf[32]; ssize_t bytes; int pid_fd; int pid = -1; /* Check argument */ if (!name) return set_errno(EINVAL); /* Build the pidfile path */ if (daemon_construct_pidfile(name, &pidfile) == -1) return -1; /* Open it and lock it (if possible) */ if ((pid_fd = daemon_lock_pidfile(pidfile)) == -1) { /* Already locked - daemon is running */ if (errno == EACCES || errno == EAGAIN) { /* Read the process id */ if ((pid_fd = open(pidfile, O_RDONLY)) == -1) { mem_release(pidfile); return -1; } mem_release(pidfile); if ((bytes = read(pid_fd, pidbuf, 32)) <= 0) { close(pid_fd); return -1; } close(pid_fd); if (sscanf(pidbuf, "%d", &pid) != 1 || pid <= 0) return set_errno(EINVAL); /* Stop the daemon */ return kill((pid_t)pid, SIGTERM); } mem_release(pidfile); return -1; } /* Not locked - daemon is not running */ close(pid_fd); unlink(pidfile); mem_release(pidfile); return set_errno(ESRCH); } /* =back =head1 ERRORS Additional errors may be generated and returned from the underlying system calls. See their manual pages for details. =over 4 =item C An argument was invalid (e.g. C). =item C The C passed to I or I resulted in a path name that is too long for the intended filesystem. =item C I recursed too deeply (16 levels). =item C I found that there was no daemon running with the given name. =back =head1 MT-Level I =head1 EXAMPLE This example reads and prints C with I, becomes a daemon and then sends a I message and then terminates. #include const char * const config_fname = "/etc/fstab"; List *config = NULL; void fstab_parser(void *obj, const char *path, char *line, size_t lineno) { char device[64], mount[64], fstype[64], opts[64]; int freq, passno; if (sscanf(line, "%63s %63s %63s %63s %d %d", device, mount, fstype, opts, &freq, &passno) != 6) fprintf(stderr, "Syntax Error in %s (line %d): %s\n", path, lineno, line); else { char *copy; printf("%s %s %s %s %d %d\n", device, mount, fstype, opts, freq, passno); if (!(copy = mem_strdup(line))) fprintf(stderr, "out of memory\n"); else if (!list_append(config, copy)) fprintf(stderr, "failed to add line %d to config\n", lineno); } } void hup(int signo) { list_remove_range(config, 0, -1); daemon_parse_config(config_fname, config, fstab_parser); } void term(int signo) { daemon_close(); exit(EXIT_SUCCESS); } void do_stuff() { // do stuff... syslog(LOG_DAEMON | LOG_DEBUG, "Here we are"); kill(getpid(), SIGTERM); signal_handle_all(); } int main(int ac, char **av) { if (daemon_revoke_privileges() == -1 || daemon_prevent_core() == -1 || daemon_path_is_safe(config_fname, NULL, 0) != 1 || (config = list_create(free)) == NULL || daemon_parse_config(config_fname, config, fstab_parser) == NULL || daemon_init(prog_basename(*av)) == -1 || signal_set_handler(SIGHUP, 0, hup) == -1 || signal_set_handler(SIGTERM, 0, term) == -1) return EXIT_FAILURE; do_stuff(); return EXIT_SUCCESS; // unreached } =head1 CAVEAT Because I's pidfiles are created in a different directory (C) to those of ordinary users (C), it is possible for I and another user to use the same name for a daemon client. This shouldn't be a problem. It's probably desirable. But if it is a problem, recompile I and relink I so that all pidfiles are created in C by defining C and C to both be C. The exclusive creation and locking of the pidfile doesn't work correctly over I on I so pidfiles must reside locally. I ignores ACLs (so does I). It should probably treat a path as unsafe if there are any ACLs (allowing extra access) along the path. The functions I, I, I, I, I and I should probably all have the I prefix removed from their names. Their use is more general than just in daemons. If you use "exec daemon" to run a I application you may find that the I application sometimes doesn't run. This problem has only been seen with I but it may happen with other I applications as well. Capturing the standard error of the I application might show something like: unnamed app(9697): KUniqueApplication: Registering failed! unnamed app(9697): Communication problem with "konsole" , it probably crashed. Error message was: "org.freedesktop.DBus.Error.ServiceUnknown" : " "The name org.kde.konsole was not provided by any .service files" A workaround seems to be to delay the termination of the initial I process by at least 0.4 seconds. To make this happen, set the environment variable C to the number of milliseconds by which to delay. For example: C. =head1 SEE ALSO I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I =head1 AUTHOR 20210220 raf =cut */ #endif #ifdef TEST #include #include #include "msg.h" #include "prog.h" #include "sig.h" typedef struct Pair1 Pair1; typedef struct Data1 Data1; typedef struct Data2 Data2; struct Data1 { int test; int i; Pair1 *pair; }; struct Pair1 { const char *service; const char *port; }; static Pair1 pairs[] = { { "echo", "7/tcp" }, { "echo", "7/udp" }, { "ftp", "21/tcp" }, { "ssh", "22/tcp" }, { "smtp", "25/tcp" }, { NULL, NULL } }; static const int final_pair = 5; static Data1 data1[1] = {{ 0, 0, pairs }}; struct Data2 { int test; int i; int j; const char *text; const char *results[3][8]; }; static Data2 data2[1] = { { 0, 0, 0, "\n" "# This is a comment\n" "\n" "line1 = word1 word2\n" "line2 = word3 \\\n" "\tword4 word5 \\ # a comment in a funny place\n" "\tword6 word7\n" "\n" "line3 = \\\n" "\tword8\n" "\n", { { "line1", "=", "word1", "word2", NULL, NULL, NULL, NULL }, { "line2", "=", "word3", "word4", "word5", "word6", "word7", NULL }, { "line3", "=", "word8", NULL, NULL, NULL, NULL, NULL } } } }; static const int final_line = 3; static const int final_word = 3; static int errors = 0; static int config_test1(int test, const char *name) { FILE *out = fopen(name, "w"); int i; if (!out) { ++errors, printf("Test%d: failed to create file: '%s'\n", test, name); return 0; } for (i = 0; data1->pair[i].service; ++i) fprintf(out, "%s %s\n", data1->pair[i].service, data1->pair[i].port); fclose(out); return 1; } static void parse_test1(void *obj, const char *path, char *line, size_t lineno) { Data1 *data1 = (Data1 *)obj; char service[1024]; char port[1024]; if (sscanf(line, "%1023s %1023s", service, port) != 2) ++errors, printf("Test%d: syntax error: '%s' (file %s line %d)\n", data1->test, line, path, (int)lineno); else if (strcmp(service, data1->pair[data1->i].service)) ++errors, printf("Test%d: expected service '%s', received '%s' (file %s line %d)\n", data1->test, data1->pair[data1->i].service, service, path, (int)lineno); else if (strcmp(port, data1->pair[data1->i].port)) ++errors, printf("Test%d: expected port '%s', received '%s' (file %s line %d)\n", data1->test, data1->pair[data1->i].port, port, path, (int)lineno); ++data1->i; } static int config_test2(int test, const char *name) { FILE *out = fopen(name, "w"); if (!out) { ++errors, printf("Test%d: failed to create file: '%s'\n", test, name); return 0; } fprintf(out, "%s", data2->text); fclose(out); return 1; } static void parse_test2(void *obj, const char *path, char *line, size_t lineno) { Data2 *data2 = (Data2 *)obj; char word[8][1024]; int words; words = sscanf(line, "%1023s %1023s %1023s %1023s %1023s %1023s %1023s %1023s", word[0], word[1], word[2], word[3], word[4], word[5], word[6], word[7]); for (data2->j = 0; data2->j < words; ++data2->j) { if (!data2->results[data2->i][data2->j]) { ++errors, printf("Test%d: too many words: '%s' (file %s line %d)\n", data2->test, line, path, (int)lineno); break; } if (strcmp(word[data2->j], data2->results[data2->i][data2->j])) { ++errors; printf("Test%d: expected '%s', received '%s' (file %s line %d)\n", data2->test, data2->results[data2->i][data2->j], word[data2->j - 1], path, (int)lineno); break; } } ++data2->i; } void term(int signo) { daemon_close(); exit(EXIT_SUCCESS); } int main(int ac, char **av) { const char *config_name; char *cwd; char *core = "core"; char *core2 = "daemon.core"; /* OpenBSD, FreeBSD */ int facility = LOG_DAEMON | LOG_ERR; pid_t pid; int rc; uid_t uid, euid; gid_t gid, egid; int no_privileges = 0; int not_safe = 0; int not_root = 0; if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s\n", *av); return EXIT_SUCCESS; } printf("Testing: %s\n", "daemon"); /* Test (a bit) daemon_started_by_init() and daemon_started_by_inetd() */ if ((rc = daemon_started_by_init()) != 0) ++errors, printf("Test1: daemon_started_by_init() failed (ret %d, not %d)\n", rc, 0); if ((rc = daemon_started_by_inetd()) != 0) ++errors, printf("Test2: daemon_started_by_inetd() failed (ret %d, not %d)\n", rc, 0); /* Test daemon_prevent_core() */ unlink(core); unlink(core2); switch (pid = fork()) { case -1: { ++errors, printf("Test3: Failed to run test: fork: %s\n", strerror(errno)); break; } case 0: { if (daemon_prevent_core() == -1) { printf("Test3: daemon_prevent_core() failed: %s\n", strerror(errno)); return 1; } dump(""); } default: { struct stat statbuf[1]; int status; if (waitpid(pid, &status, 0) == -1) { printf("Test3: Failed to evaluate test: waitpid: %s\n", strerror(errno)); break; } #ifndef WCOREDUMP #define WCOREDUMP(status) 0 #endif if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) ++errors; else if (WCOREDUMP(status) && (stat(core, statbuf) == 0 || stat(core2, statbuf)) == 0) ++errors, printf("Test3: child dumped core\n"); unlink(core); unlink(core2); } } /* Test daemon_revoke_privileges() if possible */ uid = getuid(); gid = getgid(); euid = geteuid(); egid = getegid(); if (euid == uid && egid == gid) no_privileges = 1; else if (daemon_revoke_privileges() == -1 || geteuid() != getuid() || getegid() != getgid()) ++errors, printf("Test4: daemon_revoke_privileges() failed: %s\n", strerror(errno)); /* Test daemon_become_user() if possible */ if (uid) not_root = 1; else { switch (pid = fork()) { case -1: { ++errors, printf("Test5: Failed to run test: fork: %s\n", strerror(errno)); break; } case 0: { gid_t gids[10]; errno = 0; if (daemon_become_user(1, 1, NULL) == -1) { printf("Test5: daemon_become_user(1, 1, NULL) failed: %s\n", strerror(errno)); return 1; } if (geteuid() != 1 || getuid() != 1 || getegid() != 1 || getgid() != 1) { printf("Test5: daemon_become_user(1, 1, NULL) failed: euid/egid = %d/%d, uid/gid = %d/%d\n", (int)geteuid(), (int)getegid(), (int)getuid(), (int)getgid()); return 1; } if (getgroups(0, NULL) != 0 && (getgroups(10, gids) != 1 || gids[0] != getuid())) { printf("Test5: daemon_become_user(1, 1, NULL) failed: getgroups() = %d (not 0 or 1)\n", getgroups(0, NULL)); return 1; } return 0; } default: { int status; if (waitpid(pid, &status, 0) == -1) { printf("Test5: Failed to evaluate test: waitpid: %s\n", strerror(errno)); break; } if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) ++errors; } } } /* Test daemon_absolute_path() */ #define TEST_ABSOLUTE_PATH(i, path, abs_path) \ { \ char *result = daemon_absolute_path(path); \ if (!result) \ ++errors, printf("Test%d: daemon_absolute_path(%s) failed (%s)\n", (i), (path), strerror(errno)); \ else if (strcmp(result, (abs_path))) \ { \ struct stat result_status[1], abs_status[1]; \ ++errors, printf("Test%d: daemon_absolute_path(%s) failed (was %s, not %s)\n", (i), (path), result, (abs_path)); \ printf("\n"); \ if (stat(result, result_status) != -1 && stat(abs_path, abs_status) != -1 && result_status->st_ino == abs_status->st_ino) \ printf(" But they have the same inode (%d)\n", (int)abs_status->st_ino); \ printf(" Does your pwd return canonical paths?\n\n"); \ free(result); \ } \ } /* We must be in a safe, writable directory to test relative paths */ if (!(cwd = mem_create(limit_path(), char))) ++errors, printf("Test6: Failed to run test: mem_create: %s\n", strerror(errno)); else if (!getcwd(cwd, limit_path())) ++errors, printf("Test6: Failed to run test: getcwd: %s\n", strerror(errno)); else if (chdir("/etc") == -1) ++errors, printf("Test6: Failed to run test: chdir: %s\n", strerror(errno)); else { TEST_ABSOLUTE_PATH(6, ".", "/etc") TEST_ABSOLUTE_PATH(7, "..", "/") TEST_ABSOLUTE_PATH(8, "/", "/") TEST_ABSOLUTE_PATH(9, "/etc/passwd", "/etc/passwd") TEST_ABSOLUTE_PATH(10, "/.", "/") TEST_ABSOLUTE_PATH(11, "/..", "/") TEST_ABSOLUTE_PATH(12, "/./etc", "/etc") TEST_ABSOLUTE_PATH(13, "/../etc", "/etc") TEST_ABSOLUTE_PATH(14, "/etc/.././.././../usr", "/usr") TEST_ABSOLUTE_PATH(15, "../../../../../etc/././../etc/./.././etc", "/etc") TEST_ABSOLUTE_PATH(16, "././../../../../../etc/././.", "/etc") TEST_ABSOLUTE_PATH(17, "/etc/./sysconfig/./network-scripts/../blog/..", "/etc/sysconfig") TEST_ABSOLUTE_PATH(18, "/etc/./sysconfig/./network-scripts/../blog/../..", "/etc") TEST_ABSOLUTE_PATH(19, "passwd", "/etc/passwd") TEST_ABSOLUTE_PATH(20, "passwd/", "/etc/passwd") TEST_ABSOLUTE_PATH(21, "passwd////", "/etc/passwd") TEST_ABSOLUTE_PATH(22, "///////////////", "/") TEST_ABSOLUTE_PATH(23, "///////etc////////", "/etc") TEST_ABSOLUTE_PATH(24, "//////./.././..////..//", "/") chdir(cwd); } /* Test daemon_path_is_safe() */ #define TEST_PATH_IS_SAFE(i, path, safe, err, explanation) \ { \ int rc; \ char buf[1024]; \ errno = 0; \ if ((rc = daemon_path_is_safe(path, buf, sizeof(buf))) != (safe)) \ { \ struct stat status[1]; \ ++errors, printf("Test%d: daemon_path_is_safe(%s) failed (ret %d, not %d) %s\n", (i), (path), rc, (safe), errno ? strerror(errno) : ""); \ if (stat(ROOT_DIR, status) != -1 && status->st_mode & (S_IWGRP | S_IWOTH)) \ printf("\n No Wonder! Your %s directory is %s-writable!!!\n\n", ROOT_DIR, (status->st_mode & S_IWOTH) ? "world" : "group"); \ } \ else if (rc == -1 && errno != (err)) \ ++errors, printf("Test%d: daemon_path_is_safe(%s) failed (errno was %d, not %d)\n", (i), (path), errno, (err)); \ else if (rc == 0 && strcmp(buf + strlen(buf) - strlen(explanation), explanation)) \ ++errors, printf("Test%d: daemon_path_is_safe(%s) failed (explanation was \"%s\", not \"%s\")\n", (i), (path), buf, (explanation)); \ } TEST_PATH_IS_SAFE(25, "/etc/passwd", 1, 0, "") TEST_PATH_IS_SAFE(26, "/tmp", 0, 0, "/tmp is group- and world-writable") TEST_PATH_IS_SAFE(27, "/nonexistent-path", -1, ENOENT, "") if (daemon_path_is_safe(".", NULL, 0) != 1) not_safe = 1; else { const char *sym_link = "daemon_path_is_safe.test"; const char *sym_linked = "/tmp/daemon_path_is_safe.test"; mode_t mask; int fd; /* Test absolute link from safe directory to unsafe directory */ if ((fd = open(sym_linked, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1) ++errors, printf("Test28: Failed to run test: open(%s) failed %s\n", sym_linked, strerror(errno)); else { close(fd); TEST_PATH_IS_SAFE(28, sym_linked, 0, 0, "/tmp is group- and world-writable") if (symlink(sym_linked, sym_link) == -1) ++errors, printf("Test28: Failed to run test: symlink(%s, %s) failed %s\n", sym_linked, sym_link, strerror(errno)); else { TEST_PATH_IS_SAFE(28, sym_link, 0, 0, "/tmp is group- and world-writable") if (unlink(sym_link) == -1) ++errors, printf("Test28: Failed to unlink(%s): %s\n", sym_link, strerror(errno)); } if (unlink(sym_linked) == -1) ++errors, printf("Test28: Failed to unlink(%s): %s\n", sym_linked, strerror(errno)); } /* Test relative symbolic link from safe directory to safe directory */ if (mkdir("safedir", S_IRUSR | S_IWUSR | S_IXUSR) == -1) ++errors, printf("Test29: Failed to run test: mkdir(%s) failed: %s\n", "safedir", strerror(errno)); else { if (symlink("..", "safedir/safelink") == -1) ++errors, printf("Test29: symlink(.., safedir/safelink) failed: %s\n", strerror(errno)); else { TEST_PATH_IS_SAFE(29, "safedir/safelink", 1, 0, "") if (unlink("safedir/safelink") == -1) ++errors, printf("Test29: Failed to unlink(safedir/safelink): %s\n", strerror(errno)); } if (rmdir("safedir") == -1) ++errors, printf("Test29: Failed to rmdir(safedir): %s\n", strerror(errno)); } /* Test relative symbolic link from safe directory to unsafe directory */ if (mkdir("safedir", S_IRUSR | S_IWUSR | S_IXUSR) == -1) ++errors, printf("Test30: Failed to run test: mkdir(safedir) failed: %s\n", strerror(errno)); else { mask = umask((mode_t)0); if (mkdir("unsafedir", S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP) == -1) ++errors, printf("Test30: Failed to run test: mkdir(unsafedir) failed: %s\n", strerror(errno)); else { if (symlink("../unsafedir", "safedir/unsafelink") == -1) ++errors, printf("Test30: symlink(../unsafedir, safedir/unsafelink) failed: %s\n", strerror(errno)); else { TEST_PATH_IS_SAFE(30, "safedir/unsafelink", 0, 0, "/unsafedir is group-writable") if (unlink("safedir/unsafelink") == -1) ++errors, printf("Test30: Failed to unlink(safedir/unsafelink): %s\n", strerror(errno)); } if (rmdir("unsafedir") == -1) ++errors, printf("Test30: Failed to rmdir(unsafedir): %s\n", strerror(errno)); } if (rmdir("safedir") == -1) ++errors, printf("Test30: Failed to rmdir(safedir): %s\n", strerror(errno)); umask(mask); } /* Test relative symbolic link from unsafe directory to safe directory */ mask = umask((mode_t)0); if (mkdir("unsafedir", S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP) == -1) ++errors, printf("Test31: Failed to run test: mkdir(unsafedir) failed: %s\n", strerror(errno)); else { if (symlink("unsafedir", "unsafelink") == -1) ++errors, printf("Test31: symlink(../unsafedir, unsafelink) failed: %s\n", strerror(errno)); else { if (mkdir("unsafelink/unsafedir", S_IRUSR | S_IWUSR | S_IXUSR) == -1) ++errors, printf("Test31: Failed to run test: mkdir(unsafelink/unsafedir) failed: %s\n", strerror(errno)); else { TEST_PATH_IS_SAFE(31, "unsafelink/unsafedir", 0, 0, "/unsafedir is group-writable") if (rmdir("unsafelink/unsafedir") == -1) ++errors, printf("Test31: Failed to rmdir(unsafelink/unsafedir): %s\n", strerror(errno)); } if (unlink("unsafelink") == -1) ++errors, printf("Test31: Failed to unlink(unsafelink): %s\n", strerror(errno)); } if (rmdir("unsafedir") == -1) ++errors, printf("Test31: Failed to rmdir(unsafedir): %s\n", strerror(errno)); } umask(mask); } /* Test daemon_parse_config() */ config_name = "daemon_parse_config.testfile"; if (config_test1(32, config_name)) { int errors_save = errors; data1->test = 32; daemon_parse_config(config_name, data1, parse_test1); if (errors == errors_save && data1->i != final_pair) ++errors, printf("Test32: failed to parse entire config file\n"); unlink(config_name); } if (config_test2(33, config_name)) { int errors_save = errors; data2->test = 33; daemon_parse_config(config_name, data2, parse_test2); if (errors == errors_save && (data2->i != final_line || data2->j != final_word)) ++errors, printf("Test33: failed to parse entire config file\n"); unlink(config_name); } /* Test daemon_init() and daemon_close() */ switch (pid = fork()) { case -1: { ++errors, printf("Test34: Failed to run test: fork: %s\n", strerror(errno)); break; } case 0: { if (signal_set_handler(SIGTERM, 0, term) == -1) { syslog(facility, "%s: Test34: signal_set_handler(SIGTERM) failed: %s", *av, strerror(errno)); _exit(EXIT_FAILURE); } if (daemon_init(prog_basename(*av)) == -1) { syslog(facility, "%s: Test34: daemon_init(\"%s\") failed: %s", *av, prog_basename(*av), strerror(errno)); _exit(EXIT_FAILURE); } syslog(facility, "%s succeeded", *av); if (kill(getpid(), SIGTERM) == -1) syslog(facility, "%s: Test34: kill(%d, SIGTERM) failed: %s", *av, pid, strerror(errno)); signal_handle_all(); /* ** We can only get here if the signal hasn't arrived yet. ** If so, exit anyway. */ syslog(facility, "%s: Test34: signal_handle_all() failed", *av); _exit(EXIT_SUCCESS); } default: { int status; if (waitpid(pid, &status, 0) == -1) { printf("Test34: Failed to evaluate test: waitpid: %s\n", strerror(errno)); break; } if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) ++errors, printf("Test34: Failed to run test: signal_set_handler() failed\n"); } } if (errors) printf("%d/34 tests failed\n", errors); else printf("All tests passed\n"); printf("\n"); printf(" Note: Can't verify syslog daemon.err output (don't know where it goes).\n"); printf(" Look for \"%s succeeded\" (not \"%s failed\").\n", *av, *av); if (no_privileges) { printf("\n"); printf(" Note: Can't test daemon_revoke_privileges().\n"); printf(" Rerun test suid and/or sgid as someone other than the tester.\n"); } if (not_safe) { printf("\n"); printf(" Note: Can't perform all tests on daemon_path_is_safe().\n"); printf(" Rerun test from a safe directory (writable by the tester).\n"); } if (not_root) { printf("\n"); printf(" Note: Can't test daemon_become_user().\n"); printf(" Audit the code and rerun the test as root.\n"); } return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/daemon.h0000644000175000017500000000447114014141213014123 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_DAEMON_H #define LIBSLACK_DAEMON_H #include /* Define the standard pidfile directory for the root user */ #ifndef ROOT_PID_DIR #define ROOT_PID_DIR "/var/run" #endif /* Define the standard pidfile directory for normal users */ #ifndef USER_PID_DIR #define USER_PID_DIR "/tmp" #endif /* Define the root directory */ #ifndef ROOT_DIR #define ROOT_DIR "/" #endif /* Define the /etc directory */ #ifndef ETC_DIR #define ETC_DIR "/etc" #endif /* Define the path directory separator as a character */ #ifndef PATH_SEP #define PATH_SEP '/' #endif /* Define the path directory separator as a string */ #ifndef PATH_SEP_STR #define PATH_SEP_STR "/" #endif /* Define the $PATH environment variable directory separator */ #ifndef PATH_LIST_SEP #define PATH_LIST_SEP ':' #endif typedef void daemon_config_parser_t(void *obj, const char *path, char *line, size_t lineno); _begin_decls int daemon_started_by_init(void); int daemon_started_by_inetd(void); int daemon_prevent_core(void); int daemon_revoke_privileges(void); int daemon_become_user(uid_t uid, gid_t gid, char *user); char *daemon_absolute_path(const char *path); int daemon_path_is_safe(const char *path, char *explanation, size_t explanation_size); void *daemon_parse_config(const char *path, void *obj, daemon_config_parser_t *parser); int daemon_pidfile(const char *name); int daemon_init(const char *name); int daemon_close(void); pid_t daemon_getpid(const char *name); int daemon_is_running(const char *name); int daemon_stop(const char *name); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/err.h0000644000175000017500000000575414014141213013455 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_ERR_H #define LIBSLACK_ERR_H #include #include #include #if __cplusplus #define void_cast static_cast #else #define void_cast (void) #endif #undef debug #undef vdebug #undef debugsys #undef vdebugsys #undef check #ifdef NDEBUG #define debug(args) #define vdebug(args) #define debugsys(args) #define vdebugsys(args) #define check(cond, mesg) (void_cast(0)) #else #define debug(args) debugf args; #define vdebug(args) vdebugf args; #define debugsys(args) debugsysf args; #define vdebugsys(args) vdebugsysf args; #define check(cond, mesg) ((cond) ? void_cast(0) : (dump("Internal Error: %s: %s [%s:%d]", (#cond), (mesg), __FILE__, __LINE__))) #endif _begin_decls void msg(const char *format, ...); void vmsg(const char *format, va_list args); void verbose(size_t level, const char *format, ...); void vverbose(size_t level, const char *format, va_list args); void debugf(size_t level, const char *format, ...); void vdebugf(size_t level, const char *format, va_list args); int error(const char *format, ...); int verror(const char *format, va_list args); void fatal(const char *format, ...); void vfatal(const char *format, va_list args); void dump(const char *format, ...); void vdump(const char *format, va_list args); void alert(int priority, const char *format, ...); void valert(int priority, const char *format, va_list args); void debugsysf(size_t level, const char *format, ...); void vdebugsysf(size_t level, const char *format, va_list args); int errorsys(const char *format, ...); int verrorsys(const char *format, va_list args); void fatalsys(const char *format, ...); void vfatalsys(const char *format, va_list args); void dumpsys(const char *format, ...); void vdumpsys(const char *format, va_list args); void alertsys(int priority, const char *format, ...); void valertsys(int priority, const char *format, va_list args); int set_errno(int errnum); void *set_errnull(int errnum); void (*set_errnullf(int errnum))(); _end_decls /* Don't look below here - optimisations only */ /* And they produce lots of warnings with gcc-4.1 */ /* #define set_errno(errnum) (errno = (errnum), -1) */ /* #define set_errnull(errnum) ((void *)((void *)(errno = (errnum)), NULL)) */ #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/fio.c0000644000175000017500000007004714014141213013432 0ustar rafraf/* # libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ /* =head1 NAME I - fifo and file control module and some I/O =head1 SYNOPSIS #include #include char *fgetline(char *line, size_t size, FILE *stream); char *fgetline_unlocked(char *line, size_t size, FILE *stream); int read_timeout(int fd, long sec, long usec); int write_timeout(int fd, long sec, long usec); int rw_timeout(int fd, long sec, long usec); int nap(long sec, long usec); int fcntl_set_flag(int fd, int flag); int fcntl_clear_flag(int fd, int flag); int fcntl_set_fdflag(int fd, int flag); int fcntl_clear_fdflag(int fd, int flag); int fcntl_lock(int fd, int cmd, int type, int whence, int start, int len); int nonblock_set(int fd, int arg); int nonblock_on(int fd); int nonblock_off(int fd); int fifo_exists(const char *path, int prepare); int fifo_has_reader(const char *path, int prepare); int fifo_open(const char *path, mode_t mode, int lock, int *writefd); =head1 DESCRIPTION This module provides various I/O related functions: reading a line of text no matter what line endings are used; timeouts for read/write operations without signals; exclusively opening a fifo for reading; and some random shorthand functions for manipulating file flags and locks. =over 4 =cut */ #include "config.h" #ifndef NO_POSIX_SOURCE #define NO_POSIX_SOURCE /* For ETIMEDOUT, EADDRINUSE, EOPNOTSUPP on FreeBSD-8.0 */ #endif #include "std.h" #include #include #if HAVE_SYS_SELECT_H #include #endif #include #include #include "err.h" #include "fio.h" #ifndef TEST void (flockfile)(FILE *stream); /* Missing from old glibc headers */ void (funlockfile)(FILE *stream); #ifndef HAVE_FLOCKFILE #define flockfile(stream) #define funlockfile(stream) #define getc_unlocked(stream) getc(stream) #endif /* =item C Similar to I except that it recognises UNIX (C<"\n">), DOS/Windows (C<"\r\n">) and old Macintosh (C<"\r">) line endings (even different line endings in the same file). Reads bytes from C and stores them in the buffer pointed to by C. Reading stops after an C, or the end of the line is reached, or when C bytes have been stored. If the end of the line was reached, it is stored as a C<"\n"> byte. A C byte is stored after the last byte in the buffer. On success, returns C. On error, or when the end of file occurs while no bytes have been read, returns C. Note that even when C is returned, C is modified and will always be C-terminated. So it is safe to examine C even when this function returns C. Calls to this function can be mixed with calls to other input functions from the I library for the same input stream. This is a drop-in replacement for I. char line[BUFSIZ]; while (fgetline(line, BUFSIZ, stdin)) printf("%s", line); =cut */ char *fgetline(char *line, size_t size, FILE *stream) { char *ret; flockfile(stream); ret = fgetline_unlocked(line, size, stream); funlockfile(stream); return ret; } /* =item C Equivalent to I except that C is not locked. =cut */ char *fgetline_unlocked(char *line, size_t size, FILE *stream) { char *s = line; char *end = line + size - 1; int c = '\0', c2; if (!s) return NULL; while (s < end && (c = getc_unlocked(stream)) != EOF) { if (c == '\n') { *s++ = c; break; } else if (c == '\r') { *s++ = '\n'; if ((c2 = getc_unlocked(stream)) == '\n') break; ungetc(c2, stream); break; } else *s++ = c; } *s = '\0'; if (c == EOF && (s == line || ferror(stream))) return NULL; return line; } /* =item C Performs a I on a single file descriptor, C, for reading and exceptions (i.e. arrival of urgent data), that times out after C seconds and C microseconds. This is just a shorthand function to provide a simple timed I (or I or I or I or I or I without resorting to I and C signals (best avoided). On success, returns C<0>. On error, returns C<-1> with C set appropriately (C if it timed out, otherwise set by I). Usage: if (read_timeout(fd, 5, 0) == -1 || (bytes = read(fd, buf, count)) == -1) return -1; =cut */ int read_timeout(int fd, long sec, long usec) { fd_set readfds[1]; fd_set exceptfds[1]; struct timeval timeout[1]; if (fd < 0 || sec < 0 || usec < 0) return set_errno(EINVAL); FD_ZERO(readfds); FD_SET(fd, readfds); *exceptfds = *readfds; timeout->tv_sec = sec; timeout->tv_usec = usec; switch (select(fd + 1, readfds, NULL, exceptfds, timeout)) { case -1: return -1; case 0: return set_errno(ETIMEDOUT); } return 0; } /* =item C Performs a I on a single file descriptor, C, for writing, that times out after C seconds and C microseconds. This is just a shorthand function to provide a simple timed I (or I or I or I or I) without resorting to I and C signals (best avoided). On success, returns C<0>. On error, returns C<-1> with C set appropriately (C if it timed out, otherwise set by I). Usage: if (write_timeout(fd, 5, 0) == -1 || (bytes = write(fd, buf, count)) == -1) return -1; =cut */ int write_timeout(int fd, long sec, long usec) { fd_set writefds[1]; struct timeval timeout[1]; if (fd < 0 || sec < 0 || usec < 0) return set_errno(EINVAL); FD_ZERO(writefds); FD_SET(fd, writefds); timeout->tv_sec = sec; timeout->tv_usec = usec; switch (select(fd + 1, NULL, writefds, NULL, timeout)) { case -1: return -1; case 0: return set_errno(ETIMEDOUT); } return 0; } /* =item C Performs a I on a single file descriptor, C, for reading, writing and exceptions (i.e. arrival of urgent data), that times out after C seconds and C microseconds. This is just a shorthand function to provide a simple timed I or I without resorting to I and C signals (best avoided). On success, returns a bit mask indicating whether C is readable (C), writable (C) and/or has urgent data available (C). On error, returns C<-1> with C set appropriately (C if it timed out, otherwise set by I). if ((mask = rw_timeout(fd, 5, 0)) == -1) return -1; if ((mask & W_OK) && (bytes = write(fd, buf, count)) == -1) return -1; if ((mask & R_OK) && (bytes = read(fd, buf, count)) == -1) return -1; =cut */ int rw_timeout(int fd, long sec, long usec) { fd_set readfds[1]; fd_set writefds[1]; fd_set exceptfds[1]; struct timeval timeout[1]; int rc = 0; if (fd < 0 || sec < 0 || usec < 0) return set_errno(EINVAL); FD_ZERO(readfds); FD_SET(fd, readfds); *writefds = *readfds; *exceptfds = *readfds; timeout->tv_sec = sec; timeout->tv_usec = usec; switch (select(fd + 1, readfds, writefds, exceptfds, timeout)) { case -1: return -1; case 0: return set_errno(ETIMEDOUT); } if (FD_ISSET(fd, readfds)) rc |= R_OK; if (FD_ISSET(fd, writefds)) rc |= W_OK; if (FD_ISSET(fd, exceptfds)) rc |= X_OK; return rc; } /* =item C Puts the process to sleep for C seconds and C microseconds. Note, however, that many systems' timers only have 10ms resolution. This uses I to ensure that I and C signals are not used (best avoided). On success, returns C<0>. On error, returns C<-1> with C set appropriately. nap(1, 500000); // Sleep for 1.5 seconds nap(0, 100000); // Sleep for 0.1 seconds =cut */ int nap(long sec, long usec) { struct timeval tv[1]; if (sec < 0 || usec < 0) return set_errno(EINVAL); tv->tv_sec = sec; tv->tv_usec = usec; return select(0, NULL, NULL, NULL, tv); } /* =item C Shorthand for setting the file status flag, C, on the file descriptor, C, using I. All other file status flags are unaffected. On success, returns C<0>. On error, returns C<-1> with C set by I with C or C as the command. Example file status flags are C, C, C, C, and C depending on the system. =cut */ int fcntl_set_flag(int fd, int flag) { int flags; if ((flags = fcntl(fd, F_GETFL, 0)) == -1) return -1; return fcntl(fd, F_SETFL, flags | flag); } /* =item C Shorthand for clearing the file status flag, C, from the file descriptor, C, using I. All other file status flags are unaffected. On success, returns C<0>. On error, returns C<-1> with C set by I with C or C as the command. Example file status flags are C, C, C, C, and C depending on the system. =cut */ int fcntl_clear_flag(int fd, int flag) { int flags; if ((flags = fcntl(fd, F_GETFL, 0)) == -1) return -1; return fcntl(fd, F_SETFL, flags & ~flag); } /* =item C Shorthand for setting the file descriptor flag, C, on the file descriptor, C, using I. All other file descriptor flags are unaffected. On success, returns C<0>. On error, returns C<-1> with C set by I with C or C as the command. The only file descriptor flag at time of writing is C. =cut */ int fcntl_set_fdflag(int fd, int flag) { int flags; if ((flags = fcntl(fd, F_GETFD, 0)) == -1) return -1; return fcntl(fd, F_SETFD, flags | flag); } /* =item C Shorthand for clearing the file descriptor flag, C, from the file descriptor, C, using I. All other file descriptor flags are unaffected. On success, returns C<0>. On error, returns C<-1> with C set by I with C or C as the command. The only file descriptor flag at time of writing is C. =cut */ int fcntl_clear_fdflag(int fd, int flag) { int flags; if ((flags = fcntl(fd, F_GETFL, 0)) == -1) return -1; return fcntl(fd, F_SETFL, flags & ~flag); } /* =item C Shorthand for performing discretionary file locking operations on the file descriptor, C. C is the locking command and is passed to I. C, C, C and C are used to fill a I structure which is passed to I. Returns the same as I with C as the command. if (fcntl_lock(fd, F_SETLK, F_WRLCK, SEEK_SET, 0, 0) == -1) return -1; =cut */ int fcntl_lock(int fd, int cmd, int type, int whence, int start, int len) { struct flock lock[1]; lock->l_type = type; lock->l_whence = whence; lock->l_start = start; lock->l_len = len; return fcntl(fd, cmd, lock); } /* =item C Sets non-blocking mode for the file descriptor, C, if C is non-zero. Sets blocking mode if C is zero. On success, returns C<0>. On error, returns C<-1> with C set by I with C or C as the command. =cut */ int nonblock_set(int fd, int arg) { return (arg) ? nonblock_on(fd) : nonblock_off(fd); } /* =item C Sets non-blocking mode for the file descriptor, C. On success, returns C<0>. On error, returns C<-1> with C set by I with C or C as the command. =cut */ int nonblock_on(int fd) { return fcntl_set_flag(fd, O_NONBLOCK); } /* =item C Sets blocking mode for the file descriptor, C. On success, returns C<0>. On error, returns C<-1> with C set by I with C or C as the command. =cut */ int nonblock_off(int fd) { return fcntl_clear_flag(fd, O_NONBLOCK); } /* =item C Determines whether or not C refers to a fifo. Returns C<0> if C doesn't exist or doesn't refer to a fifo. If C refers to a fifo, returns 1. If C is non-zero, and C refers to a non-fifo, it will be unlinked. On error, returns C<-1> with C set by I. =cut */ int fifo_exists(const char *path, int prepare) { struct stat status[1]; if (stat(path, status) == -1) return (errno == ENOENT) ? 0 : -1; if (S_ISFIFO(status->st_mode) == 0) { if (prepare) unlink(path); return 0; } return 1; } /* =item C Determines whether or not C refers to a fifo that is being read by another process. If C does not exist, or does not refer to a fifo, or if the fifo can't be opened for non-blocking I, returns C<0>. If C is non-zero, and path refers to a non-fifo, it will be unlinked. On error, returns C<-1> with C set by I or I. =cut */ int fifo_has_reader(const char *path, int prepare) { int fd; /* ** Check that fifo exists and is a fifo. ** If not, there can be no reader process. */ switch (fifo_exists(path, prepare)) { case 0: return 0; case -1: return -1; } /* ** Open the fifo for non-blocking write. ** If there is no reader process, open() ** will fail with errno == ENXIO. */ if ((fd = open(path, O_WRONLY | O_NONBLOCK)) == -1) return (errno == ENXIO) ? 0 : -1; if (close(fd) == -1) return -1; return 1; } /* =item C Creates a fifo named C with creation mode C for reading. If C already exists, is a fifo, and has a reader process, returns C<-1> with C set to C. If the fifo is created (or an existing one can be reused), two file descriptors are opened to the fifo. A read descriptor and a write descriptor. On success, returns the read descriptor. The write descriptor only exists to ensure that there is always at least one writer process for the fifo. This allows a I on the read descriptor to block until another process writes to the fifo rather than returning an C condition. This is done in a I-compliant way. If C is non-zero, the fifo is exclusively locked. If C is not C, the write descriptor is stored there. On error, returns C<-1> with C set by I, I, I, I or I. char *fifopath = "/tmp/fifo"; int fd, wfd; if ((fd = fifo_open(fifopath, S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH, 1, &wfd)) == -1) return -1; // Read from fd... close(fd); close(wfd); unlink(fifopath); =cut */ int fifo_open(const char *path, mode_t mode, int lock, int *writefd) { struct stat status[1]; int rfd, wfd, mine = 0; /* Don't open the fifo for reading twice. */ switch (fifo_has_reader(path, 1)) { case 1: return set_errno(EADDRINUSE); case -1: return -1; } /* Create the fifo. */ if (mkfifo(path, mode) != -1) mine = 1; else if (errno != EEXIST) return -1; /* ** Open the fifo for non-blocking read only. ** This prevents blocking while waiting for a ** writer process. We are about to supply our ** own writer. */ if ((rfd = open(path, O_RDONLY | O_NONBLOCK)) == -1) { if (mine) unlink(path); return -1; } /* ** A sanity check to make sure that what we have just ** opened is really a fifo. Someone may have just replaced ** the fifo with a file between fifo_has_reader and here. */ if (fstat(rfd, status) == -1 || S_ISFIFO(status->st_mode) == 0) { if (mine) unlink(path); close(rfd); return -1; } /* ** Open the fifo for write only and leave this fd open. ** This guarantees that there is always at least one ** writer process. This prevents EOF indications being ** returned from read() when there are no other writer ** processes. ** ** Just opening the fifo "rw" should work but it's undefined ** by POSIX. */ if ((wfd = open(path, O_WRONLY)) == -1) { if (mine) unlink(path); close(rfd); return -1; } /* ** Exclusively lock the fifo to prevent two invocations ** deciding that there's no reader and opening this fifo ** at the same time. ** ** Note: some systems (e.g. FreeBSD, Mac OS X) can't lock fifos :( */ /* On MacOSX-10.6 these are different numbers */ #ifndef ENOTSUP #define ENOTSUP EOPNOTSUPP #endif if (lock && fcntl_lock(wfd, F_SETLK, F_WRLCK, SEEK_SET, 0, 0) == -1 && errno != EOPNOTSUPP && errno != ENOTSUP && errno != EBADF) { if (mine) unlink(path); close(rfd); close(wfd); return (errno == EACCES) ? set_errno(EADDRINUSE) : -1; } /* A sanity test on the write descriptor we have just opened and locked. */ if (fstat(wfd, status) == -1 || S_ISFIFO(status->st_mode) == 0) { if (mine) unlink(path); close(rfd); close(wfd); return -1; } /* Now put the reader into blocking mode. */ if (nonblock_off(rfd) == -1) { if (mine) unlink(path); close(rfd); close(wfd); return -1; } /* ** Flaw: If someone unceremoniously unlinks our fifo, we won't know ** about it and nothing will stop another invocation from creating a new ** fifo and handling it. This process would sleep forever in select(). */ if (writefd) *writefd = wfd; return rfd; } /* =back =head1 ERRORS These functions set C to the following values. C may also be set by the underlying system calls. See their manpages for details. =over 4 =item C The I, I and I functions set this when a timeout occurs. =item C I sets this when the path refers to a fifo that already has another process reading from it. =back =head1 MT-Level I I doesn't have I, I or I so I is not I on such platforms. You must guard all I calls in multi-threaded programs with explicit synchronisation variables. =head1 EXAMPLES A paranoid I example: #include #include int main() { char line[BUFSIZ]; while (fgetline(line, BUFSIZ, stdin)) printf("%s", line); if (ferror(stdin)) { if (!*line) printf("%s\n", line); return EXIT_FAILURE; } return EXIT_SUCCESS; } Read from stdin but give up after 5 seconds: #include #include int main() { char buf[BUFSIZ]; ssize_t bytes; if (read_timeout(STDIN_FILENO, 5, 0) == -1 || (bytes = read(STDIN_FILENO, buf, BUFSIZ)) == -1 || write(STDOUT_FILENO, buf, bytes) != bytes) return EXIT_FAILURE; return EXIT_SUCCESS; } A command line sub-second sleep command: #include #include int main(int ac, char **av) { if (ac != 3) return EXIT_FAILURE; nap(atoi(av[1]), atoi(av[2])); return EXIT_SUCCESS; } Setting file flags: #include #include int main() { if (fcntl_set_flag(STDIN_FILENO, O_NONBLOCK | O_ASYNC) == -1) return EXIT_FAILURE; if (fcntl_set_flag(STDOUT_FILENO, O_APPEND) == -1) return EXIT_FAILURE; if (fcntl_set_fdflag(STDOUT_FILENO, FD_CLOEXEC) == -1) return EXIT_FAILURE; if (nonblock_on(STDOUT_FILENO) == -1) return EXIT_FAILURE; if (fcntl_clear_flag(STDIN_FILENO, O_NONBLOCK | O_ASYNC) == -1) return EXIT_FAILURE; if (fcntl_clear_flag(STDOUT_FILENO, O_APPEND) == -1) return EXIT_FAILURE; if (fcntl_clear_fdflag(STDOUT_FILENO, FD_CLOEXEC) == -1) return EXIT_FAILURE; if (nonblock_off(STDOUT_FILENO) == -1) return EXIT_FAILURE; return EXIT_SUCCESS; } File locking: #include #include int main(int ac, char **av) { int fd; if ((fd = open(av[1], O_RDWR)) == -1) return EXIT_FAILURE; if (fcntl_lock(fd, F_SETLK, F_WRLCK, SEEK_SET, 0, 0) == -1) return close(fd), EXIT_FAILURE; // Write to the file... if (fcntl_lock(fd, F_SETLK, F_UNLCK, SEEK_SET, 0, 0) == -1) return close(fd), EXIT_FAILURE; close(fd); return EXIT_SUCCESS; } Turn a logfile into a fifo that sends log messages to syslog instead: #include #include #include int main() { char *fifopath = "/tmp/log2syslog"; char buf[BUFSIZ]; ssize_t bytes; int fd, wfd; if ((fd = fifo_open(fifopath, S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH, 1, &wfd)) == -1) return EXIT_FAILURE; while ((bytes = read(fd, buf, BUFSIZ)) > 0) { buf[bytes] = '\0'; syslog(LOG_DAEMON | LOG_ERR, "%s", buf); } close(fd); close(wfd); unlink(fifopath); } =head1 BUGS Some systems, such as I, can't lock fifos. On these systems, I ignores the locking failure and returns successfully. This means that there is no guarantee of a unique reader process on these systems. You will need to lock an ordinary file yourself to provide this guarantee. =head1 SEE ALSO I, I, I, I, I, I, I, I =head1 AUTHOR 20210220 raf =cut */ #endif #ifdef TEST #include int main(int ac, char **av) { const char * const fifoname = "./fio.fifo"; const char * const filename = "./fio.file"; const mode_t mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH; FILE *file; char line[BUFSIZ]; const int lock = 1; int errors = 0; int fd, wfd; if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s\n", *av); return EXIT_SUCCESS; } printf("Testing: %s\n", "fio"); umask(0); if ((fd = fifo_open(fifoname, mode, lock, &wfd)) == -1) { ++errors, printf("Test1: fifo_open(\"%s\", %d, %d) failed (%s)\n", fifoname, (int)mode, lock, strerror(errno)); #ifndef HAVE_FCNTL_THAT_CAN_LOCK_FIFOS printf("\n Can your system lock fifos?\n\n"); #endif } else { if ((fcntl_lock(fd, F_SETLK, F_WRLCK, SEEK_SET, 0, 0)) != -1) ++errors, printf("Test2: fcntl_lock(wrlock) failed\n"); /* Should really test that the following non-blocking changes do occur */ if (nonblock_on(fd) == -1) ++errors, printf("Test3: nonblock_on() failed (%s)\n", strerror(errno)); if (nonblock_off(fd) == -1) ++errors, printf("Test4: nonblock_off() failed (%s)\n", strerror(errno)); if (fcntl_set_flag(fd, O_NONBLOCK) == -1) ++errors, printf("Test5: fcntl_set_flag() failed (%s)\n", strerror(errno)); if (fcntl_clear_flag(fd, O_NONBLOCK) == -1) ++errors, printf("Test6: fcntl_clear_flag() failed (%s)\n", strerror(errno)); if (fcntl_set_fdflag(fd, FD_CLOEXEC) == -1) ++errors, printf("Test7: fcntl_set_fdflag() failed (%s)\n", strerror(errno)); if (fcntl_clear_fdflag(fd, FD_CLOEXEC) == -1) ++errors, printf("Test8: fcntl_clear_fdflag() failed (%s)\n", strerror(errno)); close(fd); close(wfd); unlink(fifoname); } #define CHECK_FGETLINE(i, size, expected) \ if ((expected) && !fgetline(line, (size), file)) \ ++errors, printf("Test%d: fgetline() failed\n", (i)); \ else if ((expected) && strcmp(line, ((expected) ? (expected) : ""))) \ ++errors, printf("Test%d: fgetline() read \"%s\", not \"%s\"\n", (i), line, (expected ? expected : "(null)")); #define TEST_FGETLINE(i, buf, size, contents, line1, line2, line3) \ if (!(file = fopen(filename, "wb"))) \ ++errors, printf("Test%d: failed to run test: failed to create test file\n", (i)); \ else \ { \ if (fwrite((contents), 1, strlen(contents), file) != strlen(contents)) \ ++errors, printf("Test%d: failed to run test: failed to write to test file\n", (i)); \ else \ { \ fclose(file); \ if (!(file = fopen(filename, "r"))) \ ++errors, printf("Test%d: failed to run test: failed to open test file for reading\n", (i)); \ else \ { \ CHECK_FGETLINE((i), (size), (line1)) \ CHECK_FGETLINE((i), (size), (line2)) \ CHECK_FGETLINE((i), (size), (line3)) \ if (fgetline(buf, BUFSIZ, file)) \ ++errors, printf("Test%d: fgetline() failed to return NULL at end of file\n", (i)); \ } \ } \ fclose(file); \ unlink(filename); \ } TEST_FGETLINE(9, line, BUFSIZ, "abc\ndef\r\nghi\r", "abc\n", "def\n", "ghi\n") TEST_FGETLINE(10, line, BUFSIZ, "abc\rdef\nghi\r\n", "abc\n", "def\n", "ghi\n") TEST_FGETLINE(11, line, BUFSIZ, "abc\r\ndef\rghi\n", "abc\n", "def\n", "ghi\n") TEST_FGETLINE(12, line, BUFSIZ, "abc\ndef\rghi", "abc\n", "def\n", "ghi") TEST_FGETLINE(13, line, BUFSIZ, "", (char *)NULL, (char *)NULL, (char *)NULL) TEST_FGETLINE(14, line, 5, "abc", "abc", (char *)NULL, (char *)NULL) TEST_FGETLINE(15, line, 5, "abc\n", "abc\n", (char *)NULL, (char *)NULL) TEST_FGETLINE(16, line, 5, "abc\r\n", "abc\n", (char *)NULL, (char *)NULL) TEST_FGETLINE(17, line, 5, "abc\r", "abc\n", (char *)NULL, (char *)NULL) TEST_FGETLINE(18, line, 3, "abc\r", "ab", "c\n", (char *)NULL) TEST_FGETLINE(19, NULL, 0, "abc\r", (char *)NULL, (char *)NULL, (char *)NULL) /* Test read_timeout() and write_timeout() */ if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, S_IRUSR | S_IWUSR)) == -1) ++errors, printf("Test20: failed to create %s (%s)\n", filename, strerror(errno)); else { char buf[12] = "0123456789\n"; if (write_timeout(fd, 1, 0) == -1) ++errors, printf("Test21: write_timeout(fd, 1, 0) failed (%s)\n", strerror(errno)); else if (write(fd, buf, 11) != 11) ++errors, printf("Test22: write(fd, \"0123456789\\n\", 11) failed (%s)\n", strerror(errno)); else { close(fd); if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) ++errors, printf("Test23: failed to open %s for reading (%s)\n", filename, strerror(errno)); else if (read_timeout(fd, 1, 0) == -1) ++errors, printf("Test24: read_timeout(fd, 1, 0) failed (%s)\n", strerror(errno)); else if (read(fd, buf, 11) != 11) ++errors, printf("Test25: read(fd) failed (%s)\n", strerror(errno)); } close(fd); } unlink(filename); /* Test error handling */ #define TEST_ERR(i, func) \ if ((func) != -1) \ ++errors, printf("Test%d: %s failed to return -1\n", (i), (#func)); \ else if (errno != EINVAL) \ ++errors, printf("Test%d: %s failed (errno = %s, not %s)\n", (i), (#func), strerror(errno), strerror(EINVAL)); TEST_ERR(26, read_timeout(-1, 0, 0)) TEST_ERR(27, read_timeout(0, -1, 0)) TEST_ERR(28, read_timeout(0, 0, -1)) TEST_ERR(29, write_timeout(-1, 0, 0)) TEST_ERR(30, write_timeout(0, -1, 0)) TEST_ERR(31, write_timeout(0, 0, -1)) TEST_ERR(32, rw_timeout(-1, 0, 0)) TEST_ERR(33, rw_timeout(0, -1, 0)) TEST_ERR(34, rw_timeout(0, 0, -1)) TEST_ERR(35, nap(-1, 0)) TEST_ERR(36, nap(0, -1)) if (errors) printf("%d/36 tests failed\n", errors); else printf("All tests passed\n"); #ifndef HAVE_FCNTL_THAT_CAN_LOCK_FIFOS printf("\n"); printf(" Note: Some systems (e.g. FreeBSD) can't lock fifos so fifo_open()\n"); printf(" can't guarantee a unique reader.\n"); #endif return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/fio.h0000644000175000017500000000330014014141213013423 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_FIO_H #define LIBSLACK_FIO_H #include #include #include _begin_decls char *fgetline(char *line, size_t size, FILE *stream); char *fgetline_unlocked(char *line, size_t size, FILE *stream); int read_timeout(int fd, long sec, long usec); int write_timeout(int fd, long sec, long usec); int rw_timeout(int fd, long sec, long usec); int nap(long sec, long usec); int fcntl_set_flag(int fd, int flag); int fcntl_clear_flag(int fd, int flag); int fcntl_set_fdflag(int fd, int flag); int fcntl_clear_fdflag(int fd, int flag); int fcntl_lock(int fd, int cmd, int type, int whence, int start, int len); int nonblock_set(int fd, int arg); int nonblock_on(int fd); int nonblock_off(int fd); int fifo_exists(const char *path, int prepare); int fifo_has_reader(const char *path, int prepare); int fifo_open(const char *path, mode_t mode, int lock, int *writefd); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/getopt.c0000644000175000017500000013505414014141213014157 0ustar rafraf/* Perform additional initialization for getopt functions in GNU libc. Copyright (C) 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1997. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Attention: this file is *not* necessary when the GNU getopt functions are used outside the GNU libc. Some additional functionality of the getopt functions in GNU libc require this additional work. */ /* (c) 1993 by Thomas Koenig (ig25@rz.uni-karlsruhe.de) Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one Since the Linux kernel and libraries are constantly changing, this manual page may be incorrect or out-of-date. The author(s) assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein. The author(s) may not have taken the same level of care in the production of this manual, which is licensed free of charge, as they might when working professionally. Formatted or processed versions of this manual, if unaccompanied by the source, must acknowledge the copyright and authors of this work. License. Modified Sat Jul 24 19:27:50 1993 by Rik Faith (faith@cs.unc.edu) Modified Mon Aug 30 22:02:34 1995 by Jim Van Zandt longindex is a pointer, has_arg can take 3 values, using consistent names for optstring and longindex, \n in formats fixed. Documenting opterr and getopt_long_only. Clarified explanations (borrowing heavily from the source code). Modified 8 May 1998 by Joseph S. Myers (jsm28@cam.ac.uk) =head1 NAME I - Parse command line options =head1 SYNOPSIS #include int getopt(int argc, char * const argv[], const char *optstring); extern char *optarg; extern int optind, opterr, optopt; #include int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex); int getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex); =head1 DESCRIPTION The I function parses the command line arguments. Its arguments C and C are the argument count and array as passed to the I function on program invocation. An element of C that starts with `-' (and is not exactly "-" or "--") is an option element. The characters of this element (aside from the initial `-') are option characters. If I is called repeatedly, it returns successively each of the option characters from each of the option elements. If I finds another option character, it returns that character, updating the external variable C and a static variable C so that the next call to I can resume the scan with the following option character or C-element. If there are no more option characters, I returns C. Then C is the index in C of the first C-element that is not an option. C is a string containing the legitimate option characters. If such a character is followed by a colon, the option requires an argument, so I places a pointer to the following text in the same C-element, or the text of the following C-element, in C. Two colons mean an option takes an optional arg; if there is text in the current C-element, it is returned in C, otherwise C is set to zero. This is a GNU extension. If C contains C followed by a semicolon, then C<-W foo> is treated as the long option C<--foo>. (The C<-W> option is reserved by POSIX.2 for implementation extensions.) This behaviour is a GNU extension, not available with libraries before GNU libc 2. By default, I permutes the contents of C as it scans, so that eventually all the non-options are at the end. Two other modes are also implemented. If the first character of C is `+' or the environment variable POSIXLY_CORRECT is set, then option processing stops as soon as a non-option argument is encountered. If the first character of C is `-', then each non-option C-element is handled as if it were the argument of an option with character code 1. (This is used by programs that were written to expect options and other C-elements in any order and that care about the ordering of the two.) The special argument `--' forces an end of option-scanning regardless of the scanning mode. If I does not recognize an option character, it prints an error message to stderr, stores the character in C, and returns `?'. The calling program may prevent the error message by setting C to 0. The I function works like I except that it also accepts long options, started out by two dashes. Long option names may be abbreviated if the abbreviation is unique or is an exact match for some defined option. A long option may take a parameter, of the form C<--arg=param> or C<--arg param>. C is a pointer to the first element of an array of C declared in C as struct option { const char *name; int has_arg; int *flag; int val; }; The meanings of the different fields are: =over 4 =item C is the name of the long option. =item C is: C (or 0) if the option does not take an argument, C (or 1) if the option requires an argument, or C (or 2) if the option takes an optional argument. =item C specifies how results are returned for a long option. If C is C, then I returns C. (For example, the calling program may set C to the equivalent short option character.) Otherwise, I returns 0, and C points to a variable which is set to C if the option is found, but left unchanged if the option is not found. =item C is the value to return, or to load into the variable pointed to by C. =back The last element of the array has to be filled with zeroes. If C is not C, it points to a variable which is set to the index of the long option relative to C. I is like I, but `-' as well as `--' can indicate a long option. If an option that starts with `-' (not `--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. =head1 RETURN VALUE The I function returns the option character if the option was found successfully, `:' if there was a missing parameter for one of the options, `?' for an unknown option character, or C for the end of the option list. I and I also return the option character when a short option is recognized. For a long option, they return C if C is C, and 0 otherwise. Error and C returns are the same as for I, plus `?' for an ambiguous match or an extraneous parameter. =head1 ENVIRONMENT VARIABLES =over 4 =item C If this is set, then option processing stops as soon as a non-option argument is encountered. =item C<_>IC<_GNU_nonoption_argv_flags_> This variable was used by I 2.0 to communicate to GNU libc which arguments are the results of wildcard expansion and so should not be considered as options. This behaviour was removed in I version 2.01, but the support remains in GNU libc. =back =head1 EXAMPLE The following example program, from the source code, illustrates the use of I with most of its features. #include #ifndef HAVE_GETOPT_LONG #include #else #include #endif int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 1, 0, 'c'}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:012", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } =head1 BUGS This manpage is confusing. The POSIX.2 specification of I has a technical error described in POSIX.2 Interpretation 150. The GNU implementation (and probably all other implementations) implements the correct behaviour rather than that speci- fied. =head1 CONFORMING TO =over 4 =item I: POSIX.2, provided the environment variable POSIXLY_CORRECT is set. Otherwise, the elements of C aren't really const, because we permute them. We pretend they're const in the prototype to be compatible with other systems. =back =cut */ #include "getopt.h" #include #include #if 0 #include #endif pid_t getpid(); /* Variable to synchronize work. */ char *__getopt_nonoption_flags; /* Lower-case digits. */ const char _itoa_lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; /* Upper-case digits. */ const char _itoa_upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /* Convert VALUE into ASCII in base BASE (2..36). Write backwards starting the character just before BUFLIM. Return the address of the first (left-to-right) character in the number. Use upper case letters iff UPPER_CASE is nonzero. */ extern char *_itoa (unsigned long int value, char *buflim, unsigned int base, int upper_case); static char * _itoa_word (unsigned long value, char *buflim, unsigned int base, int upper_case) { extern const char _itoa_upper_digits[], _itoa_lower_digits[]; const char *digits = upper_case ? _itoa_upper_digits : _itoa_lower_digits; char *bp = buflim; switch (base) { #define SPECIAL(Base) \ case Base: \ do \ *--bp = digits[value % Base]; \ while ((value /= Base) != 0); \ break SPECIAL (10); SPECIAL (16); SPECIAL (8); default: do *--bp = digits[value % base]; while ((value /= base) != 0); } return bp; } /* Remove the environment variable "__GNU_nonoption_argv_flags_" if it is still available. If the getopt functions are also used in the application it does not exist anymore since it was saved for the use in getopt. */ void __getopt_clean_environment (char **env) { /* Bash 2.0 puts a special variable in the environment for each command it runs, specifying which ARGV elements are the results of file name wildcard expansion and therefore should not be considered as options. */ static const char envvar_tail[] = "_GNU_nonoption_argv_flags_="; char var[100]; char *cp, **ep; size_t len; /* Construct the "__GNU_nonoption_argv_flags_=" string. We must not use `sprintf'. */ cp = memcpy (&var[sizeof (var) - sizeof (envvar_tail)], envvar_tail, sizeof (envvar_tail)); cp = _itoa_word (getpid (), cp, 10, 0); *--cp = '_'; len = (var + sizeof (var) - 1) - cp; for (ep = env; *ep != NULL; ++ep) if (!strncmp (*ep, cp, len)) { /* Found it. Store this pointer and move later ones back. */ char **dp = ep; __getopt_nonoption_flags = &(*ep)[len]; do dp[0] = dp[1]; while (*dp++); /* Continue the loop in case the name appears again. */ } } /* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ # ifdef HAVE_LIBINTL_H # include # define _(msgid) gettext (msgid) # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a NULL string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; static int original_argc; static char *const *original_argv; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ static void __attribute__ ((unused)) store_args_and_env (int argc, char *const *argv) { /* XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ original_argc = argc; original_argv = argv; } # ifdef text_set_element text_set_element (__libc_subinit, store_args_and_env); # endif /* text_set_element */ # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #ifdef _LIBC /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #ifdef _LIBC if (posixly_correct == NULL && argc == original_argc && argv == original_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #ifdef _LIBC # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a NULL option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ /* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "getopt.h" #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* Not ELIDE_CODE. */ #ifdef TEST #include #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ /* vi:set ts=8 sw=2 sts=2: */ daemon-0.8/libslack/getopt.h0000644000175000017500000001340314014141213014155 0ustar rafraf/* Declarations for getopt. Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if defined __STDC__ && __STDC__ const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #if defined __STDC__ && __STDC__ # ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int __argc, char *const *__argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ extern int getopt (); # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not __STDC__ */ extern int getopt (); # ifndef __need_getopt extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); # endif #endif /* __STDC__ */ #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ /* vi:set ts=8 sw=2 sts=2: */ daemon-0.8/libslack/hdr.h0000644000175000017500000000177714014141213013443 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_HDR_H #define LIBSLACK_HDR_H #undef _begin_decls #undef _end_decls #ifdef __cplusplus #define _begin_decls extern "C" { #define _end_decls } #else #define _begin_decls #define _end_decls #endif #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/hsort.c0000644000175000017500000003002114014141213014000 0ustar rafraf/* # libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ /* * Generic Heapsort. * * Synopsis: * hsort(void *base, size_t n, size_t size, int (*fn)(void *, void *)) * Description: * Hsort sorts the array of `n' items which starts at address `base'. * The size of each item is as given. Items are compared by the function * `fn', which is passed pointers to two items as arguments. The function * should return < 0 if item1 < item2, == 0 if item1 == item2, and > 0 * if item1 > item2. * Version: * 1988 April 28 * Author: * Stephen Russell, Department of Computer Science, * University of Sydney, 2006 * Australia. */ /* =head1 NAME I - generic heap sort =head1 SYNOPSIS #include #include typedef int hsort_cmp_t(const void *a, const void *b); typedef int hsort_closure_cmp_t(const void *a, const void *b, const void *data); void hsort(void *base, size_t n, size_t size, hsort_cmp_t *cmp); void hsort_closure(void *base, size_t n, size_t size, hsort_closure_cmp_t *cmp, const void *data); =head1 DESCRIPTION I is an implementation of the heap sort algorithm. It sorts a table of data in place. C points to the element at the base of the table. C is the number of elements in the table. C is the size of the elements in bytes. C is the comparison function, which is called with two arguments that point to the elements being compared. As the function must return an integer less than, equal to, or greater than zero, so must the first argument to be considered be less than, equal to, or greater than the second. This is a drop-in replacement for I. I is the same but it supports passing arbitrary data to the comparison function. =head1 NOTES The comparison function need not compare every byte, so arbitrary data may be contained in the elements in addition to the values being compared. The order in the output of two items which compare as equal is unpredictable. =head1 MT-Level I Note that the array being sorted will still have to be write-locked during I if it is accessed by other threads. =head1 EXAMPLE This examples sorts and prints an array of strings. #include #include int cmp(const char **p1, const char **p2) { return strcmp(*p1, *p2); } int main(int ac, char **av) { char *string[4] = { "jkl", "ghi", "def", "abc" }; int i; hsort(string, 4, sizeof string[0], (hsort_cmp_t *)cmp); for (i = 0; i < 4; ++i) printf("%s\n", string[i]); return EXIT_SUCCESS; } =head1 SEE ALSO I =head1 AUTHOR Stephen Russell, Department of Computer Science, University of Sydney, 2006. Australia 1988 April 28 Header file, test code and manpage by raf =cut */ #include "std.h" #include "hsort.h" #ifndef TEST #ifdef INLINE #define swap(p1, p2, n) \ {\ register char *_p1, *_p2;\ register size_t _n;\ register char _tmp;\ \ for (_p1 = p1, _p2 = p2, _n = n; _n-- > 0; )\ {\ _tmp = *_p1; *_p1++ = *_p2; *_p2++ = _tmp;\ }\ }\ #else /* * Support routine for swapping elements of the array. */ static void swap ( register char *p1, register char *p2, register size_t n ) { register char ctmp; /* * On machines with no alignment restrictions for ints, * the following loop may improve performance if moving lots * of data. It has been commented out for portability. register int itmp; for ( ; n > sizeof(int); n -= sizeof(int)) { itmp = *(int *)p1; *(int *)p1 = *(int *)p2; p1 += sizeof(int); *(int *)p2 = itmp; p2 += sizeof(int); } */ while (n-- != 0) { ctmp = *p1; *p1++ = *p2; *p2++ = ctmp; } } #endif /* * To avoid function calls in the inner loops, the code responsible for * constructing a heap from (part of) the array has been expanded inline. * It is possible to convert this common code to a function. The three * parameters base0, cmp and size are invariant - only the size of the * gap and the high bound of the array change. In phase 1, gap decreases * while hi is fixed. In phase 2, gap == size, and hi decreases. The * variables p, q, and g are only used in this common code. */ void hsort(void *base, size_t n, size_t size, hsort_cmp_t *cmp) { register char *p, *q, *base0, *hi; register unsigned int gap, g; if (n < 2) return; base0 = (char *)base - size; /* set up address of h[0] */ /* * The gap is the distance, in bytes, between h[0] and h[i], * for some i. It is also the distance between h[i] and h[2*i]; * that is, the distance between a node and its left child. * The initial node of interest is h[n/2] (the rightmost * interior node), so gap is set accordingly. The following is * the only multiplication needed. */ gap = (n >> 1) * size; /* initial gap is n/2*size */ hi = base0 + gap + gap; /* calculate address of h[n] */ if (n & 1) hi += size; /* watch out for odd arrays */ /* * Phase 1: Construct heap from random data. * * For i = n/2 downto 2, ensure h[i] is greater than its * children h[2*i] and h[2*i+1]. By decreasing 'gap' at each * iteration, we move down the heap towards h[2]. The final step * of making h[1] the maximum value is done in the next phase. */ for ( ; gap != size; gap -= size) { /* fixheap(base0, size, cmp, gap, hi) */ for (p = base0 + (g = gap); (q = p + g) <= hi; p = q) { g += g; /* double gap for next level */ /* * Find greater of left and right children. */ if (q != hi && (*cmp)(q + size, q) > 0) { q += size; /* choose right child */ g += size; /* follow right subtree */ } /* * Compare with parent. */ if ((*cmp)(p, q) >= 0) break; /* order is correct */ swap(p, q, size); /* swap parent and child */ } } /* * Phase 2: Each iteration makes the first item in the * array the maximum, then swaps it with the last item, which * is its correct position. The size of the heap is decreased * each iteration. The gap is always "size", as we are interested * in the heap starting at h[1]. */ for ( ; hi != base; hi -= size) { /* fixheap(base0, size, cmp, gap (== size), hi) */ p = (char *)base; /* == base0 + size */ for (g = size; (q = p + g) <= hi; p = q) { g += g; if (q != hi && (*cmp)(q + size, q) > 0) { q += size; g += size; } if ((*cmp)(p, q) >= 0) break; swap(p, q, size); } swap((char *)base, hi, size); /* move largest item to end */ } } void hsort_closure(void *base, size_t n, size_t size, hsort_closure_cmp_t *cmp, const void *data) { register char *p, *q, *base0, *hi; register unsigned int gap, g; if (n < 2) return; base0 = (char *)base - size; /* set up address of h[0] */ /* * The gap is the distance, in bytes, between h[0] and h[i], * for some i. It is also the distance between h[i] and h[2*i]; * that is, the distance between a node and its left child. * The initial node of interest is h[n/2] (the rightmost * interior node), so gap is set accordingly. The following is * the only multiplication needed. */ gap = (n >> 1) * size; /* initial gap is n/2*size */ hi = base0 + gap + gap; /* calculate address of h[n] */ if (n & 1) hi += size; /* watch out for odd arrays */ /* * Phase 1: Construct heap from random data. * * For i = n/2 downto 2, ensure h[i] is greater than its * children h[2*i] and h[2*i+1]. By decreasing 'gap' at each * iteration, we move down the heap towards h[2]. The final step * of making h[1] the maximum value is done in the next phase. */ for ( ; gap != size; gap -= size) { /* fixheap(base0, size, cmp, gap, hi) */ for (p = base0 + (g = gap); (q = p + g) <= hi; p = q) { g += g; /* double gap for next level */ /* * Find greater of left and right children. */ if (q != hi && (*cmp)(q + size, q, data) > 0) { q += size; /* choose right child */ g += size; /* follow right subtree */ } /* * Compare with parent. */ if ((*cmp)(p, q, data) >= 0) break; /* order is correct */ swap(p, q, size); /* swap parent and child */ } } /* * Phase 2: Each iteration makes the first item in the * array the maximum, then swaps it with the last item, which * is its correct position. The size of the heap is decreased * each iteration. The gap is always "size", as we are interested * in the heap starting at h[1]. */ for ( ; hi != base; hi -= size) { /* fixheap(base0, size, cmp, gap (== size), hi) */ p = (char *)base; /* == base0 + size */ for (g = size; (q = p + g) <= hi; p = q) { g += g; if (q != hi && (*cmp)(q + size, q, data) > 0) { q += size; g += size; } if ((*cmp)(p, q, data) >= 0) break; swap(p, q, size); } swap((char *)base, hi, size); /* move largest item to end */ } } #endif #ifdef TEST int errors = 0; char *string[4]; char *data = "arbitrary"; int testno = 0; static int cmp(const char **a, const char **b) { return strcmp(*a, *b); } static int cmp_closure(const char **a, const char **b, const char *data) { if (!data || strcmp(data, "arbitrary")) /* may crash here if buggy */ ++errors, printf("Test%d: hsort_closure() failed: data not supplied\n", testno); return strcmp(*a, *b); } static void verify(int test) { if (strcmp(string[0], "abc")) ++errors, printf("Test%d: 1st item is '%s' (not 'abc')\n", test, string[0]); else if (strcmp(string[1], "def")) ++errors, printf("Test%d: 2nd item is '%s' (not 'def')\n", test, string[1]); else if (strcmp(string[2], "ghi")) ++errors, printf("Test%d: 3rd item is '%s' (not 'ghi')\n", test, string[2]); else if (strcmp(string[3], "jkl")) ++errors, printf("Test%d: 4th item is '%s' (not 'jkl')\n", test, string[3]); } int main(int ac, char **av) { if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s\n", *av); return EXIT_SUCCESS; } printf("Testing: %s\n", "hsort"); string[0] = "abc"; string[1] = "def"; string[2] = "ghi"; string[3] = "jkl"; hsort(string, 4, sizeof string[0], (hsort_cmp_t *)cmp); verify(1); string[0] = "jkl"; string[1] = "ghi"; string[2] = "def"; string[3] = "abc"; hsort(string, 4, sizeof string[0], (hsort_cmp_t *)cmp); verify(2); string[0] = "def"; string[1] = "abc"; string[2] = "jkl"; string[3] = "ghi"; hsort(string, 4, sizeof string[0], (hsort_cmp_t *)cmp); verify(3); string[0] = "abc"; string[1] = "def"; string[2] = "ghi"; string[3] = "jkl"; testno = 5; hsort_closure(string, 4, sizeof string[0], (hsort_closure_cmp_t *)cmp_closure, data); verify(testno); string[0] = "jkl"; string[1] = "ghi"; string[2] = "def"; string[3] = "abc"; testno = 6; hsort_closure(string, 4, sizeof string[0], (hsort_closure_cmp_t *)cmp_closure, data); verify(testno); string[0] = "def"; string[1] = "abc"; string[2] = "jkl"; string[3] = "ghi"; testno = 7; hsort_closure(string, 4, sizeof string[0], (hsort_closure_cmp_t *)cmp_closure, data); verify(testno); if (errors) printf("%d/6 tests failed\n", errors); else printf("All tests passed\n"); return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/hsort.h0000644000175000017500000000231714014141213014014 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_HSORT_H #define LIBSLACK_HSORT_H #include #include typedef int hsort_cmp_t(const void *a, const void *b); typedef int hsort_closure_cmp_t(const void *a, const void *b, const void *data); _begin_decls void hsort(void *base, size_t n, size_t size, hsort_cmp_t *cmp); void hsort_closure(void *base, size_t n, size_t size, hsort_closure_cmp_t *cmp, const void *data); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/lib.h0000644000175000017500000000265314014141213013426 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_LIB_H #define LIBSLACK_LIB_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef HAVE_SNPRINTF #include #endif #ifndef HAVE_VSSCANF #include #endif #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/libslack-config.pod0000644000175000017500000000705214014141213016240 0ustar rafraf# # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 20210220 raf =head1 NAME I - administrative tool for libslack =head1 SYNOPSIS libslack-config [options] options: -h, --help - Print this help and exit -v, --version - Print the version of the currently installed libslack -L, --latest - Print the latest version of libslack (uses wget) -D, --download - Download the latest version of libslack (uses wget) -U, --upgrade - Upgrade to the latest version of libslack (uses wget) -p, --prefix - Print the prefix directory of the libslack installation -c, --cflags - Print CFLAGS needed to compile clients of libslack -l, --libs - Print LDFLAGS needed to link against libslack -l, --ldflags - Identical to --libs -u, --uninstall - Uninstall libslack Note: The dashes are optional for long option names Command line example: gcc -o app app.c `libslack-config --cflags --libs` Makefile example: APP_CFLAGS += $(shell libslack-config --cflags) APP_LDFLAGS += $(shell libslack-config --libs) =head1 DESCRIPTION I is an administrative tool for I. It can print the compiler and linker flags that are needed to compile and link programs that use I. It can also print the version of the currently installed I or print the latest version available at C. It can also download the latest version. It can also upgrade libslack. It can also uninstall libslack. =head1 OPTIONS =over 4 =item C<-h>, C<--help> Print a help message and exit. =item C<-v>, C<--version> Print the version of the currently installed I. =item C<-L>, C<--latest> Print the latest version of I available at C. =item C<-D>, C<--download> Download the latest version of I from C. =item C<-U>, C<--upgrade> Upgrade to the latest version of I from C. This downloads the latest version, configures it, compiles it, uninstalls the currently installed version and then installs the new version wherever the current version was installed. =item C<-p>, C<--prefix> Print the prefix directory under which I was installed. =item C<-c>, C<--cflags> Print the compiler flags needed to compile code that uses I. =item C<-l>, C<--libs>, C<--ldflags> Print the linker flags needed to link code against I. =item C<-u>, C<--uninstall> Uninstall I. =back =head1 SEE ALSO C, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I =head1 AUTHOR 20210220 raf =cut daemon-0.8/libslack/libslack-config.t0000644000175000017500000001014214014141213015713 0ustar rafraf#!/bin/bash # # libslack - http://libslack.org/ # # Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 20210220 raf var() { eval $1='$2'; export $1; } die() { echo "$@" >&2; exit 1; } var url "@@URL@@" var name "@@NAME@@" var version "@@VERSION@@" var prefix "@@PREFIX@@" var cflags "@@CFLAGS@@" var libs "@@LIBS@@" if test "$prefix" != "/usr" -a "$prefix" != "/usr/local" then cflags="-I$prefix/include $cflags" libs="-L$prefix/lib $libs" fi usage() { cat <) { $version{$1} = 1 if /[Hh][Rr][Ee][Ff]=".*$ENV{name}-([\d.]+)\.tar\.gz"/; } sub version_sort { my @anum = split /\./, $a; my @bnum = split /\./, $b; while ($#anum != -1 && $#bnum != -1) { return $x if $x = $bnum[0] - $anum[0]; shift @anum; shift @bnum; } return -1 if $#anum != -1; return 1 if $#bnum != -1; return 0; } @version = sort { version_sort } keys %version; die "No versions found at $ENV{url}download/\n" if $#version == -1; print "$ENV{url}download/$ENV{name}-$version[0].tar.gz\n"; exit 0; ' } download() { latest="`latest 2>&1`" test "$latest" = "No versions found at ${url}download" && die "$latest" file="`echo $latest | sed 's/^.*\///'`" test -f "$file" && die "The file $file already exists" wget "$latest" } upgrade() { latest="`latest 2>&1`" test "$latest" = "No versions found at ${url}/download" && die "$latest" file="`echo $latest | sed 's/^.*\///'`" dir="`echo $file | sed 's/\.tar\.gz$//'`" test -f "$file" || wget "$latest" test -s "$file" || die "Failed to download $latest" tar xzf "$file" || die "Failed to untar $file" cd "$dir" || die "Failed to cd $dir" ./configure || die "Failed to configure $dir" make || die "Failed to make $dir" uninstall || die "Failed to uninstall current version" make PREFIX="$prefix" install || die "Failed to install $dir into $prefix" cd .. && rm -rf "$dir" } uninstall() { @@UNINSTALL@@ } test $# -eq 0 && usage 1 1>&2 while test $# -gt 0 do case "$1" in -h|--help|help) usage 0;; -v|--version|version) echo "$version";; -L|--latest|latest) latest;; -D|--download|download) download;; -U|--upgrade|upgrade) upgrade;; -p|--prefix|prefix) echo "$prefix";; -c|--cflags|cflags) echo "$cflags";; -l|--libs|libs) echo "$libs";; -l|--ldflags|ldflags) echo "$libs";; -u|--uninstall|uninstall) uninstall;; *) usage 1 >&2;; esac shift done exit 0 # vim:set ts=4 sw=4: daemon-0.8/libslack/lim.c0000644000175000017500000004527214014141213013440 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ /* =head1 NAME I - I limits module =head1 SYNOPSIS #include #include long limit_arg(void); long limit_child(void); long limit_tick(void); long limit_group(void); long limit_open(void); long limit_stream(void); long limit_tzname(void); long limit_job(void); long limit_save_ids(void); long limit_version(void); long limit_pcanon(const char *path); long limit_fcanon(int fd); long limit_canon(void); long limit_pinput(const char *path); long limit_finput(int fd); long limit_input(void); long limit_pvdisable(const char *path); long limit_fvdisable(int fd); long limit_vdisable(void); long limit_plink(const char *path); long limit_flink(int fd); long limit_link(void); long limit_pname(const char *path); long limit_fname(int fd); long limit_name(void); long limit_ppath(const char *path); long limit_fpath(int fd); long limit_path(void); long limit_ppipe(const char *path); long limit_fpipe(int fd); long limit_pnotrunc(const char *path); long limit_fnotrunc(int fd); long limit_notrunc(void); long limit_pchown(const char *path); long limit_fchown(int fd); long limit_chown(void); =head1 DESCRIPTION This module provides functions for simply and reliably obtaining a I limit for the current system or a usable default when a particular facility is unlimited on the current system. These functions always return a usable value. =over 4 =cut */ #include "config.h" #include "std.h" #include #include #include "lim.h" #include "err.h" enum name_t { LIMIT_ARG, LIMIT_CHILD, LIMIT_TICK, LIMIT_GROUP, LIMIT_OPEN, LIMIT_STREAM, LIMIT_TZNAME, LIMIT_JOB, LIMIT_SAVE_IDS, LIMIT_VERSION, LIMIT_CANON, LIMIT_INPUT, LIMIT_VDISABLE, LIMIT_LINK, LIMIT_NAME, LIMIT_PATH, LIMIT_PIPE, LIMIT_NOTRUNC, LIMIT_CHOWN, LIMIT_COUNT }; typedef struct conf_t conf_t; struct conf_t { const int name; /* name argument for sysconf, [f]pathconf */ const long value; /* limit to use when indeterminate */ const off_t offset; /* offset to apply to value when not indeterminate */ }; #ifndef TEST static const struct { conf_t conf[LIMIT_COUNT]; } g = { { { _SC_ARG_MAX, 131072, 0 }, { _SC_CHILD_MAX, 1024, 0 }, { _SC_CLK_TCK, -1, 0 }, { _SC_NGROUPS_MAX, 32, 0 }, { _SC_OPEN_MAX, 1024, 0 }, { _SC_STREAM_MAX, 1024, 0 }, { _SC_TZNAME_MAX, 3, 0 }, { _SC_JOB_CONTROL, 0, 0 }, { _SC_SAVED_IDS, 0, 0 }, { _SC_VERSION, 0, 0 }, { _PC_MAX_CANON, 255, 0 }, { _PC_MAX_INPUT, 255, 0 }, { _PC_VDISABLE, 0, 0 }, { _PC_LINK_MAX, 32768, 0 }, { _PC_NAME_MAX, 1024, 0 }, { _PC_PATH_MAX, 4096, 2 }, { _PC_PIPE_BUF, 4096, 0 }, { _PC_NO_TRUNC, 0, 0 }, { _PC_CHOWN_RESTRICTED, 0, 0 } } }; /* C Returns system limits using I. If the limit is indeterminate, a predetermined default value is returned. Whatever happens, a usable value is returned. */ static long limit_sysconf(int limit) { long value; if ((value = sysconf(g.conf[limit].name)) == -1) return g.conf[limit].value; return value; } /* C Returns system limits using I. If the limit is indeterminate, a predetermined default value is returned. If the limit is determinate, a predetermined amount may be added to its value. This is only needed for C<_PC_PATH_MAX> which is the maximum length of a relative path. To be more useful, C<2> is added to this limit to account for the C<'/'> and C<'\0'> that will be needed to form an absolute path. Whatever happens, a usable value is returned. */ static long limit_pathconf(int limit, const char *path) { long value; if ((value = pathconf(path, g.conf[limit].name)) == -1) return g.conf[limit].value; return value + g.conf[limit].offset; } /* C Returns system limits using I. If the limit is indeterminate, a predetermined default value is returned. If the limit is determinate, a predetermined amount may be added to its value. This is only needed for C<_PC_PATH_MAX> which is the maximum length of a relative path. To be more useful, C<2> is added to this limit to account for the C<'/'> and C<'\0'> that will be needed to form an absolute path. Whatever happens, a usable value is returned. */ static long limit_fpathconf(int limit, int fd) { long value; if ((value = fpathconf(fd, g.conf[limit].name)) == -1) return g.conf[limit].value; return value + g.conf[limit].offset; } /* =item C Returns the maximum length of arguments to the I family of functions. If indeterminate, a usable value (131072) is returned. =cut */ long limit_arg(void) { return limit_sysconf(LIMIT_ARG); } /* =item C Returns the maximum number of simultaneous processes per user id. If indeterminate, a usable value (1024) is returned. =cut */ long limit_child(void) { return limit_sysconf(LIMIT_CHILD); } /* =item C Returns the number of clock ticks per second. If indeterminate (which makes no sense), -1 is returned. This should never happen. =cut */ long limit_tick(void) { return limit_sysconf(LIMIT_TICK); } /* =item C Returns the maximum number of groups that a user may belong to. If indeterminate, a usable value (32) is returned. =cut */ long limit_group(void) { return limit_sysconf(LIMIT_GROUP); } /* =item C Returns the maximum number of files that a process can have open at any time. If indeterminate, a usable value (1024) is returned. =cut */ long limit_open(void) { return limit_sysconf(LIMIT_OPEN); } /* =item C Returns the maximum number of streams that a process can have open at any time. If indeterminate, a usable value (1024) is returned. =cut */ long limit_stream(void) { return limit_sysconf(LIMIT_STREAM); } /* =item C Returns the maximum number of bytes in a time zone name. If indeterminate, a usable value (3) is returned. =cut */ long limit_tzname(void) { return limit_sysconf(LIMIT_TZNAME); } /* =item C Returns whether or not job control is supported. =cut */ long limit_job(void) { return limit_sysconf(LIMIT_JOB); } /* =item C Returns whether or not a process has a saved set-user-id and a saved set-group-id. =cut */ long limit_save_ids(void) { return limit_sysconf(LIMIT_SAVE_IDS); } /* =item C Returns the year and month the I standard was approved in the format I. =cut */ long limit_version(void) { return limit_sysconf(LIMIT_VERSION); } /* =item C Returns the maximum length of a formatted input line for the terminal referred to by C. If indeterminate, a usable value (255) is returned. =cut */ long limit_pcanon(const char *path) { return limit_pathconf(LIMIT_CANON, path); } /* =item C Returns the maximum length of a formatted input line for the terminal referred to by C. If indeterminate, a usable value (255) is returned. =cut */ long limit_fcanon(int fd) { return limit_fpathconf(LIMIT_CANON, fd); } /* =item C Returns the maximum length of a formatted input line for the controlling terminal (C). If indeterminate, a usable value (255) is returned. =cut */ long limit_canon(void) { return limit_pcanon("/dev/tty"); } /* =item C Returns the maximum length of an input line for the terminal referred to by C. If indeterminate, a usable value (255) is returned. =cut */ long limit_pinput(const char *path) { return limit_pathconf(LIMIT_INPUT, path); } /* =item C Returns the maximum length of an input line for the terminal referred to by C. If indeterminate, a usable value (255) is returned. =cut */ long limit_finput(int fd) { return limit_fpathconf(LIMIT_INPUT, fd); } /* =item C Returns the maximum length of an input line for the controlling terminal (C). If indeterminate, a usable value (255) is returned. =cut */ long limit_input(void) { return limit_pinput("/dev/tty"); } /* =item C Returns whether or not special character processing can be disabled for the terminal referred to by C. =cut */ long limit_pvdisable(const char *path) { return limit_pathconf(LIMIT_VDISABLE, path); } /* =item C Returns whether or not special character processing can be disabled for the terminal referred to by C. =cut */ long limit_fvdisable(int fd) { return limit_fpathconf(LIMIT_VDISABLE, fd); } /* =item C Returns whether or not special character processing can be disabled for the controlling terminal (C). =cut */ long limit_vdisable(void) { return limit_pvdisable("/dev/tty"); } /* =item C Returns the maximum number of links to the file represented by C. If indeterminate, a usable value (32768) is returned. =cut */ long limit_plink(const char *path) { return limit_pathconf(LIMIT_LINK, path); } /* =item C Returns the maximum number of links to the file represented by C. If indeterminate, a usable value (32768) is returned. =cut */ long limit_flink(int fd) { return limit_fpathconf(LIMIT_LINK, fd); } /* =item C Returns the maximum number of links to the root directory (C). If indeterminate, a usable value (32768) is returned. =cut */ long limit_link(void) { return limit_plink("/"); } /* =item C Returns the maximum length of a filename in the directory referred to by C that the process can create. If indeterminate, a usable value (1024) is returned. =cut */ long limit_pname(const char *path) { return limit_pathconf(LIMIT_NAME, path); } /* =item C Returns the maximum length of a filename in the directory referred to by C that the process can create. If indeterminate, a usable value (1024) is returned. =cut */ long limit_fname(int fd) { return limit_fpathconf(LIMIT_NAME, fd); } /* =item C Returns the maximum length of a filename in the root directory (C) that the process can create. If indeterminate, a usable value (1024) is returned. =cut */ long limit_name(void) { return limit_pname("/"); } /* =item C Returns the maximum length of an absolute pathname (including the C character) when C is the current directory. If indeterminate, a usable value (4096) is returned. =cut */ long limit_ppath(const char *path) { return limit_pathconf(LIMIT_PATH, path); } /* =item C Returns the maximum length of an absolute pathname (including the C character) when C refers to the current directory. If indeterminate, a usable value (4096) is returned. =cut */ long limit_fpath(int fd) { return limit_fpathconf(LIMIT_PATH, fd); } /* =item C Returns the maximum length of an absolute pathname (including the C character). If indeterminate, a usable value (4096) is returned. =cut */ long limit_path(void) { return limit_ppath("/"); } /* =item C Returns the size of the pipe buffer for the fifo referred to by C. If indeterminate, a usable value (4096) is returned. =cut */ long limit_ppipe(const char *path) { return limit_pathconf(LIMIT_PIPE, path); } /* =item C Returns the size of the pipe buffer for the pipe or fifo referred to by C. If indeterminate, a usable value (4096) is returned. =cut */ long limit_fpipe(int fd) { return limit_fpathconf(LIMIT_PIPE, fd); } /* =item C Returns whether or not an error is generated when accessing filenames longer than the maximum filename length for the filesystem referred to by C. =cut */ long limit_pnotrunc(const char *path) { return limit_pathconf(LIMIT_NOTRUNC, path); } /* =item C Returns whether or not an error is generated when accessing filenames longer than the maximum filename length for the filesystem referred to by C. =cut */ long limit_fnotrunc(int fd) { return limit_fpathconf(LIMIT_NOTRUNC, fd); } /* =item C Returns whether or not an error is generated when accessing filenames longer than the maximum filename length for the root filesystem. =cut */ long limit_notrunc(void) { return limit_pnotrunc("/"); } /* =item C Returns whether or not I may be called on the file referred to by C or the files contained in the directory referred to by C. =cut */ long limit_pchown(const char *path) { return limit_pathconf(LIMIT_CHOWN, path); } /* =item C Returns whether or not I may be called on the file referred to by C or the files contained in the directory referred to by C. =cut */ long limit_fchown(int fd) { return limit_fpathconf(LIMIT_CHOWN, fd); } /* =item C Returns whether or not I may be called on the files contained in the root filesystem. =cut */ long limit_chown(void) { return limit_pchown("/"); } /* =back =head1 RETURNS The functions that return a condition return C<1> when the condition is true or C<0> when it is false. All of the others either return the system limit indicated, or a predetermined, usable value when the indicated limit is indeterminate. These functions never return C<-1>. =head1 MT-Level I =head1 EXAMPLES Store the current directory into allocated memory: #include #include int main() { long path_size = limit_path(); char *buf = malloc(path_size * sizeof(char)); if (!buf) return EXIT_FAILURE; printf("%s\n", getcwd(buf, path_size)); return EXIT_SUCCESS; } Close all file descriptors: #include #include int main() { int fd_limit = limit_open(); int fd; for (fd = 0; fd < fd_limit; ++fd) close(fd); return EXIT_SUCCESS; } =head1 SEE ALSO I, I, I, I, I =head1 AUTHOR 20210220 raf =cut */ #endif #ifdef TEST int main(int ac, char **av) { int fds[2]; long limit; int errors = 0; int verbose = (ac >= 2 && !strcmp(av[1], "-v")); if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s [-v]\n", *av); return EXIT_SUCCESS; } printf("Testing: %s\n", "lim"); if ((limit = limit_arg()) == -1) ++errors, printf("Test1: limit_arg() failed\n"); else if (verbose) printf("arg = %ld\n", limit); if ((limit = limit_child()) == -1) ++errors, printf("Test2: limit_child() failed\n"); else if (verbose) printf("child = %ld\n", limit); if ((limit = limit_tick()) == -1) ++errors, printf("Test3: limit_tick() failed\n"); else if (verbose) printf("tick = %ld\n", limit); if ((limit = limit_group()) == -1) ++errors, printf("Test4: limit_group() failed\n"); else if (verbose) printf("group = %ld\n", limit); if ((limit = limit_open()) == -1) ++errors, printf("Test5: limit_open() failed\n"); else if (verbose) printf("open = %ld\n", limit); if ((limit = limit_stream()) == -1) ++errors, printf("Test6: limit_stream() failed\n"); else if (verbose) printf("stream = %ld\n", limit); if ((limit = limit_tzname()) == -1) ++errors, printf("Test7: limit_tzname() failed\n"); else if (verbose) printf("tzname = %ld\n", limit); if ((limit = limit_job()) == -1) ++errors, printf("Test8: limit_job() failed\n"); else if (verbose) printf("job = %ld\n", limit); if ((limit = limit_save_ids()) == -1) ++errors, printf("Test9: limit_save_ids() failed\n"); else if (verbose) printf("save_ids = %ld\n", limit); if ((limit = limit_version()) == -1) ++errors, printf("Test10: limit_version() failed\n"); else if (verbose) printf("version = %ld\n", limit); if ((limit = limit_canon()) == -1) ++errors, printf("Test11: limit_canon() failed\n"); else if (verbose) printf("canon = %ld\n", limit); if ((limit = limit_input()) == -1) ++errors, printf("Test12: limit_input() failed\n"); else if (verbose) printf("input = %ld\n", limit); if ((limit = limit_vdisable()) == -1) ++errors, printf("Test13: limit_vdisable() failed\n"); else if (verbose) printf("vdisable = %ld\n", limit); if ((limit = limit_link()) == -1) ++errors, printf("Test14: limit_link() failed\n"); else if (verbose) printf("link = %ld\n", limit); if ((limit = limit_name()) == -1) ++errors, printf("Test15: limit_name() failed\n"); else if (verbose) printf("name = %ld\n", limit); if ((limit = limit_path()) == -1) ++errors, printf("Test16: limit_path() failed\n"); else if (verbose) printf("path = %ld\n", limit); if (pipe(fds) == -1) { ++errors, printf("Test17: failed to test limit_fpipe() - pipe() failed (%s)\n", strerror(errno)); } else { if ((limit = limit_fpipe(fds[0])) == -1) ++errors, printf("Test17: limit_fpipe() failed\n"); else if (verbose) printf("pipe = %ld\n", limit); close(fds[0]); close(fds[1]); } if ((limit = limit_notrunc()) == -1) ++errors, printf("Test18: limit_notrunc() failed\n"); else if (verbose) printf("notrunc = %ld\n", limit); if ((limit = limit_chown()) == -1) ++errors, printf("Test19: limit_chown() failed\n"); else if (verbose) printf("chown = %ld\n", limit); if (errors) printf("%d/19 tests failed\n", errors); else printf("All tests passed\n"); return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/lim.h0000644000175000017500000000357614014141213013446 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_LIM_H #define LIBSLACK_LIM_H #include _begin_decls long limit_arg(void); long limit_child(void); long limit_tick(void); long limit_group(void); long limit_open(void); long limit_stream(void); long limit_tzname(void); long limit_job(void); long limit_save_ids(void); long limit_version(void); long limit_pcanon(const char *path); long limit_fcanon(int fd); long limit_canon(void); long limit_pinput(const char *path); long limit_finput(int fd); long limit_input(void); long limit_pvdisable(const char *path); long limit_fvdisable(int fd); long limit_vdisable(void); long limit_plink(const char *path); long limit_flink(int fd); long limit_link(void); long limit_pname(const char *path); long limit_fname(int fd); long limit_name(void); long limit_ppath(const char *path); long limit_fpath(int fd); long limit_path(void); long limit_ppipe(const char *path); long limit_fpipe(int fd); long limit_pnotrunc(const char *path); long limit_fnotrunc(int fd); long limit_notrunc(void); long limit_pchown(const char *path); long limit_fchown(int fd); long limit_chown(void); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/link.h0000644000175000017500000000343714014141213013616 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_LINK_H #define LIBSLACK_LINK_H #include typedef struct slink_t slink_t; typedef struct dlink_t dlink_t; struct slink_t { void *next; }; struct dlink_t { void *next; void *prev; }; _begin_decls int slink_has_next(void *link); void *slink_next(void *link); int dlink_has_next(void *link); void *dlink_next(void *link); int dlink_has_prev(void *link); void *dlink_prev(void *link); void *slink_insert(void *link, void *item); void *dlink_insert(void *link, void *item); void *slink_remove(void *link); void *dlink_remove(void *link); void *slink_freelist_init(void *freelist, size_t nelem, size_t size); void *dlink_freelist_init(void *freelist, size_t nelem, size_t size); void *slink_freelist_attach(void *freelist1, void *freelist2); void *dlink_freelist_attach(void *freelist1, void *freelist2); void *slink_alloc(void **freelist); void *dlink_alloc(void **freelist); void *slink_free(void **freelist, void *item); void *dlink_free(void **freelist, void *item); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/list.c0000644000175000017500000033203614014141213013627 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ /* =head1 NAME I - list module =head1 SYNOPSIS #include #include typedef struct List List; typedef struct Lister Lister; typedef void list_release_t(void *item); typedef void *list_copy_t(const void *item); typedef int list_cmp_t(const void *a, const void *b); typedef void list_action_t(void *item, size_t *index, void *data); typedef void *list_map_t(void *item, size_t *index, void *data); typedef int list_query_t(void *item, size_t *index, void *data); List *list_create(list_release_t *destroy); List *list_make(list_release_t *destroy, ...); List *list_vmake(list_release_t *destroy, va_list args); List *list_copy(const List *src, list_copy_t *copy); List *list_create_with_locker(Locker *locker, list_release_t *destroy); List *list_make_with_locker(Locker *locker, list_release_t *destroy, ...); List *list_vmake_with_locker(Locker *locker, list_release_t *destroy, va_list args); List *list_copy_with_locker(Locker *locker, const List *src, list_copy_t *copy); int list_rdlock(const List *list); int list_wrlock(const List *list); int list_unlock(const List *list); void list_release(List *list); void *list_destroy(List **list); int list_own(List *list, list_release_t *destroy); int list_own_unlocked(List *list, list_release_t *destroy); list_release_t *list_disown(List *list); list_release_t *list_disown_unlocked(List *list); void *list_item(const List *list, ssize_t index); void *list_item_unlocked(const List *list, ssize_t index); int list_item_int(const List *list, ssize_t index); int list_item_int_unlocked(const List *list, ssize_t index); int list_empty(const List *list); int list_empty_unlocked(const List *list); ssize_t list_length(const List *list); ssize_t list_length_unlocked(const List *list); ssize_t list_last(const List *list); ssize_t list_last_unlocked(const List *list); List *list_remove(List *list, ssize_t index); List *list_remove_unlocked(List *list, ssize_t index); List *list_remove_range(List *list, ssize_t index, ssize_t range); List *list_remove_range_unlocked(List *list, ssize_t index, ssize_t range); List *list_insert(List *list, ssize_t index, void *item); List *list_insert_unlocked(List *list, ssize_t index, void *item); List *list_insert_int(List *list, ssize_t index, int item); List *list_insert_int_unlocked(List *list, ssize_t index, int item); List *list_insert_list(List *list, ssize_t index, const List *src, list_copy_t *copy); List *list_insert_list_unlocked(List *list, ssize_t index, const List *src, list_copy_t *copy); List *list_append(List *list, void *item); List *list_append_unlocked(List *list, void *item); List *list_append_int(List *list, int item); List *list_append_int_unlocked(List *list, int item); List *list_append_list(List *list, const List *src, list_copy_t *copy); List *list_append_list_unlocked(List *list, const List *src, list_copy_t *copy); List *list_prepend(List *list, void *item); List *list_prepend_unlocked(List *list, void *item); List *list_prepend_int(List *list, int item); List *list_prepend_int_unlocked(List *list, int item); List *list_prepend_list(List *list, const List *src, list_copy_t *copy); List *list_prepend_list_unlocked(List *list, const List *src, list_copy_t *copy); List *list_replace(List *list, ssize_t index, ssize_t range, void *item); List *list_replace_unlocked(List *list, ssize_t index, ssize_t range, void *item); List *list_replace_int(List *list, ssize_t index, ssize_t range, int item); List *list_replace_int_unlocked(List *list, ssize_t index, ssize_t range, int item); List *list_replace_list(List *list, ssize_t index, ssize_t range, const List *src, list_copy_t *copy); List *list_replace_list_unlocked(List *list, ssize_t index, ssize_t range, const List *src, list_copy_t *copy); List *list_extract(const List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_extract_unlocked(const List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_extract_with_locker(Locker *locker, const List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_extract_with_locker_unlocked(Locker *locker, const List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_push(List *list, void *item); List *list_push_unlocked(List *list, void *item); List *list_push_int(List *list, int item); List *list_push_int_unlocked(List *list, int item); void *list_pop(List *list); void *list_pop_unlocked(List *list); int list_pop_int(List *list); int list_pop_int_unlocked(List *list); void *list_shift(List *list); void *list_shift_unlocked(List *list); int list_shift_int(List *list); int list_shift_int_unlocked(List *list); List *list_unshift(List *list, void *item); List *list_unshift_unlocked(List *list, void *item); List *list_unshift_int(List *list, int item); List *list_unshift_int_unlocked(List *list, int item); List *list_splice(List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_splice_unlocked(List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_splice_with_locker(Locker *locker, List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_splice_with_locker_unlocked(Locker *locker, List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_sort(List *list, list_cmp_t *cmp); List *list_sort_unlocked(List *list, list_cmp_t *cmp); void list_apply(List *list, list_action_t *action, void *data); void list_apply_rdlocked(List *list, list_action_t *action, void *data); void list_apply_wrlocked(List *list, list_action_t *action, void *data); void list_apply_unlocked(List *list, list_action_t *action, void *data); List *list_map(List *list, list_release_t *destroy, list_map_t *map, void *data); List *list_map_unlocked(List *list, list_release_t *destroy, list_map_t *map, void *data); List *list_map_with_locker(Locker *locker, List *list, list_release_t *destroy, list_map_t *map, void *data); List *list_map_with_locker_unlocked(Locker *locker, List *list, list_release_t *destroy, list_map_t *map, void *data); List *list_grep(List *list, list_query_t *grep, void *data); List *list_grep_unlocked(List *list, list_query_t *grep, void *data); List *list_grep_with_locker(Locker *locker, List *list, list_query_t *grep, void *data); List *list_grep_with_locker_unlocked(Locker *locker, List *list, list_query_t *grep, void *data); ssize_t list_query(List *list, ssize_t *index, list_query_t *query, void *data); ssize_t list_query_unlocked(List *list, ssize_t *index, list_query_t *query, void *data); Lister *lister_create(List *list); Lister *lister_create_rdlocked(List *list); Lister *lister_create_wrlocked(List *list); Lister *lister_create_unlocked(const List *list); void lister_release(Lister *lister); void lister_release_unlocked(Lister *lister); void *lister_destroy(Lister **lister); void *lister_destroy_unlocked(Lister **lister); int lister_has_next(Lister *lister); void *lister_next(Lister *lister); int lister_next_int(Lister *lister); void lister_remove(Lister *lister); int list_has_next(List *list); void list_break(List *list); void *list_next(List *list); int list_next_int(List *list); void list_remove_current(List *list); =head1 DESCRIPTION This module provides functions for manipulating and iterating over lists of homogeneous data (or heterogeneous data if it's polymorphic). Is may own their items. Is created with a non-C destroy function use that function to destroy an item when it is removed from the list, and to destroy each item when the list itself is destroyed. Be careful not to insert items owned by one list into a list that doesn't own its own items unless you know that the source list (and all of the shared items) will outlive the destination list. =over 4 =cut */ #include "config.h" #include "std.h" #include "list.h" #include "mem.h" #include "err.h" #include "hsort.h" #include "locker.h" #define xor(a, b) (!(a) ^ !(b)) #define iff(a, b) !xor(a, b) #define implies(a, b) (!(a) || (b)) struct List { size_t size; /* number of item slots allocated */ size_t length; /* number of items used */ void **list; /* vector of items (void *) */ list_release_t *destroy; /* item destructor, if any */ Lister *lister; /* built-in iterator */ Locker *locker; /* locking strategy for this object */ }; struct Lister { List *list; /* the list being iterated over */ ssize_t index; /* the index of the current item */ }; #ifndef TEST /* Minimum list length: must be a power of 2 */ static const size_t MIN_LIST_SIZE = 4; /* C Allocates enough memory to add C extra items to C if necessary. On success, returns C<0>. On error, returns C<-1>. */ static int grow(List *list, size_t items) { int grown = 0; while (list->length + items > list->size) { if (list->size) list->size <<= 1; else list->size = MIN_LIST_SIZE; grown = 1; } if (grown) return mem_resize(&list->list, list->size) ? 0 : -1; return 0; } /* C Allocates less memory for removing C items from C if necessary. On success, returns C<0>. On error, returns C<-1>. */ static int shrink(List *list, size_t items) { int shrunk = 0; while (list->length - items < list->size >> 1) { if (list->size == MIN_LIST_SIZE) break; list->size >>= 1; shrunk = 1; } if (shrunk) return mem_resize(&list->list, list->size) ? 0 : -1; return 0; } /* C Slides C's items, starting at C, C slots to the right to make room for more. On success, returns C<0>. On error, returns C<-1>. */ static int expand(List *list, ssize_t index, size_t range) { if (grow(list, range) == -1) return -1; memmove(list->list + index + range, list->list + index, (list->length - index) * sizeof(*list->list)); list->length += range; return 0; } /* C Slides C's items, starting at C + C, C slots to the left to close a gap starting at C. On success, returns C<0>. On error, returns C<-1>. */ static int contract(List *list, ssize_t index, size_t range) { memmove(list->list + index, list->list + index + range, (list->length - index - range) * sizeof(*list->list)); if (shrink(list, range) == -1) return -1; list->length -= range; return 0; } /* C Expands or contracts C as required so that C occupies C. On success, returns C<0>. On error, returns C<-1>. */ static int adjust(List *list, ssize_t index, size_t range, size_t length) { if (range < length) return expand(list, index + range, length - range); if (range > length) return contract(list, index + length, range - length); return 0; } /* C Destroys the items in C ranging from C to C. */ static void killitems(List *list, size_t index, size_t range) { while (range--) { if (list->destroy) list->destroy(list->list[index]); list->list[index++] = NULL; } } /* =item C Creates a I with C as its item destructor. It is the caller's responsibility to deallocate the new list with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new list. On error, returns C with C set appropriately. =cut */ List *list_create(list_release_t *destroy) { return list_create_with_locker(NULL, destroy); } /* =item C Creates a I with C as its item destructor and the remaining arguments as its initial items. It is the caller's responsibility to deallocate the new list with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new list. On error, return C with C set appropriately. =cut */ List *list_make(list_release_t *destroy, ...) { List *list; va_list args; va_start(args, destroy); list = list_vmake_with_locker(NULL, destroy, args); va_end(args); return list; } /* =item C Equivalent to I with the variable argument list specified directly as for I. =cut */ List *list_vmake(list_release_t *destroy, va_list args) { return list_vmake_with_locker(NULL, destroy, args); } /* =item C Creates a copy of C using C as the copy constructor (if not C). It is the caller's responsibility to deallocate the new list with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new copy. On error, returns C with C set appropriately. =cut */ List *list_copy(const List *src, list_copy_t *copy) { return list_copy_with_locker(NULL, src, copy); } /* =item C Equivalent to I except that multiple threads accessing the new list will be synchronised by C. =cut */ List *list_create_with_locker(Locker *locker, list_release_t *destroy) { List *list; if (!(list = mem_new(List))) /* XXX decouple */ return NULL; list->size = list->length = 0; list->list = NULL; list->destroy = destroy; list->lister = NULL; list->locker = locker; return list; } /* =item C Equivalent to I except that multiple threads accessing the new list will be synchronised by C. =cut */ List *list_make_with_locker(Locker *locker, list_release_t *destroy, ...) { List *list; va_list args; va_start(args, destroy); list = list_vmake_with_locker(locker, destroy, args); va_end(args); return list; } /* =item C Equivalent to I except that multiple threads accessing the new list will be synchronised by C. =cut */ List *list_vmake_with_locker(Locker *locker, list_release_t *destroy, va_list args) { List *list; void *item; if (!(list = list_create_with_locker(locker, destroy))) return NULL; while ((item = va_arg(args, void *)) != NULL) { if (!list_append(list, item)) { list_release(list); return NULL; } } return list; } /* =item C Equivalent to I except that multiple threads accessing the new list will be synchronised by C. =cut */ List *list_copy_with_locker(Locker *locker, const List *src, list_copy_t *copy) { List *list; if (!src) return set_errnull(EINVAL); if (!(list = list_extract(src, 0, src->length, copy))) return NULL; list->locker = locker; return list; } /* =item C Claims a read lock on C (if C was created with a I). This is needed when multiple read-only I module functions need to be called atomically. It is the client's responsibility to call I after the atomic operation. The only functions that may be called on C between calls to I and I are any read-only I module functions whose name ends with C<_unlocked>. On success, returns C<0>. On error, returns an error code. =cut */ #define list_rdlock(list) ((list) ? locker_rdlock((list)->locker) : EINVAL) #define list_wrlock(list) ((list) ? locker_wrlock((list)->locker) : EINVAL) #define list_unlock(list) ((list) ? locker_unlock((list)->locker) : EINVAL) int (list_rdlock)(const List *list) { return list_rdlock(list); } /* =item C Claims a write lock on C (if C was created with a I). This is needed when multiple read/write I module functions need to be called atomically. It is the client's responsibility to call I after the atomic operation. The only functions that may be called on C between calls to I and I are any I module functions whose name ends with C<_unlocked>. On success, returns C<0>. On error, returns an error code. =cut */ int (list_wrlock)(const List *list) { return list_wrlock(list); } /* =item C Unlocks a read or write lock on C obtained with I or I (if C was created with a C). On success, returns C<0>. On error, returns an error code. =cut */ int (list_unlock)(const List *list) { return list_unlock(list); } /* =item C Releases (deallocates) C, destroying its items if necessary. On error, sets C appropriately. =cut */ void list_release(List *list) { if (!list) return; if (list->list) { killitems(list, 0, list->length); mem_release(list->list); } mem_release(list); } /* =item C Destroys (deallocates and sets to C) C<*list>. Returns C. B Lists shared by multiple threads must not be destroyed until after all threads have finished with it. =cut */ void *list_destroy(List **list) { if (list && *list) { list_release(*list); *list = NULL; } return NULL; } /* =item C Causes C to take ownership of its items. The items will be destroyed using C when they are removed or when C is destroyed. On success, returns C<0>. On error, returns C<-1> with C set appropriately. =cut */ int list_own(List *list, list_release_t *destroy) { int err; if (!list || !destroy) return set_errno(EINVAL); if ((err = list_wrlock(list))) return set_errno(err); list->destroy = destroy; if ((err = list_unlock(list))) return set_errno(err); return 0; } /* =item C Equivalent to I except that C is not write-locked. =cut */ int list_own_unlocked(List *list, list_release_t *destroy) { if (!list || !destroy) return set_errno(EINVAL); list->destroy = destroy; return 0; } /* =item C Causes C to relinquish ownership of its items. The items will not be destroyed when they are removed from C or when C is destroyed. On success, returns the previous destroy function, if any. On error, returns C with C set appropriately. =cut */ list_release_t *list_disown(List *list) { list_release_t *destroy; int err; if (!list) return (list_release_t *)set_errnullf(EINVAL); if ((err = list_wrlock(list))) return (list_release_t *)set_errnullf(err); destroy = list_disown_unlocked(list); if ((err = list_unlock(list))) return (list_release_t *)set_errnullf(err); return destroy; } /* =item C Equivalent to I except that C is not write-locked. =cut */ list_release_t *list_disown_unlocked(List *list) { list_release_t *destroy; if (!list) return (list_release_t *)set_errnullf(EINVAL); destroy = list->destroy; list->destroy = NULL; return destroy; } /* =item C Returns the C'th item in C. If C is negative, it refers to an item position relative to the end of the list (C<-1> is the position after the last item, C<-2> is the position of the last item, and so on). On error, returns C with C set appropriately. =cut */ void *list_item(const List *list, ssize_t index) { void *item; int err; if (!list) return set_errnull(EINVAL); if ((err = list_rdlock(list))) return set_errnull(err); item = list_item_unlocked(list, index); if ((err = list_unlock(list))) return set_errnull(err); return item; } /* =item C Equivalent to I except that C is not read-locked. =cut */ void *list_item_unlocked(const List *list, ssize_t index) { if (!list) return set_errnull(EINVAL); if (index < 0) index = list->length + 1 + index; if (index < 0) return set_errnull(EINVAL); if (index >= list->length) return set_errnull(EINVAL); return list->list[index]; } /* =item C Equivalent to I except that the item is cast to an integer type. =cut */ int list_item_int(const List *list, ssize_t index) { return (int)(long)list_item(list, index); } /* =item C Equivalent to I except that C is not read-locked. =cut */ int list_item_int_unlocked(const List *list, ssize_t index) { return (int)(long)list_item_unlocked(list, index); } /* =item C Returns whether or not C is empty. On error, returns C<-1> with C set appropriately. =cut */ int list_empty(const List *list) { int empty; int err; if (!list) return set_errno(EINVAL); if ((err = list_rdlock(list))) return set_errno(err); empty = (list->length == 0); if ((err = list_unlock(list))) return set_errno(err); return empty; } /* =item C Equivalent to I except that C is not read-locked. =cut */ int list_empty_unlocked(const List *list) { if (!list) return set_errno(EINVAL); return (list->length == 0); } /* =item C Returns the length of C. On error, returns C<-1> with C set appropriately. =cut */ ssize_t list_length(const List *list) { size_t length; int err; if (!list) return set_errno(EINVAL); if ((err = list_rdlock(list))) return set_errno(err); length = list->length; if ((err = list_unlock(list))) return set_errno(err); return length; } /* =item C Equivalent to I except that C is not read-locked. =cut */ ssize_t list_length_unlocked(const List *list) { if (!list) return set_errno(EINVAL); return list->length; } /* =item C Returns the index of the last item in C, or C<-1> if there are no items. On error, returns C<-1> with C set appropriately. =cut */ ssize_t list_last(const List *list) { ssize_t last; int err; if (!list) return set_errno(EINVAL); if ((err = list_rdlock(list))) return set_errno(err); last = list->length - 1; if ((err = list_unlock(list))) return set_errno(err); return last; } /* =item C Equivalent to I except that C is not read-locked. =cut */ ssize_t list_last_unlocked(const List *list) { if (!list) return set_errno(EINVAL); return list->length - 1; } /* =item C Removes the C'th item from C. If C is negative, it refers to an item position relative to the end of the list (C<-1> is the position after the last item, C<-2> is the position of the last item and so on). On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_remove(List *list, ssize_t index) { return list_remove_range(list, index, 1); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_remove_unlocked(List *list, ssize_t index) { return list_remove_range_unlocked(list, index, 1); } /* =item C Removes C items from C starting at C. If C or C are negative, they refer to item positions relative to the end of the list (C<-1> is the position after the last item, C<-2> is the position of the last item and so on). On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_remove_range(List *list, ssize_t index, ssize_t range) { List *ret; int err; if (!list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); ret = list_remove_range_unlocked(list, index, range); if ((err = list_unlock(list))) return set_errnull(err); return ret; } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_remove_range_unlocked(List *list, ssize_t index, ssize_t range) { if (!list) return set_errnull(EINVAL); if (index < 0) index = list->length + 1 + index; if (index < 0) return set_errnull(EINVAL); if (range < 0) range = list->length + 1 + range - index; if (range < 0) return set_errnull(EINVAL); if (list->length < index + range) return set_errnull(EINVAL); killitems(list, index, range); if (contract(list, index, range) == -1) return NULL; return list; } /* =item C Adds C to C at position C. If C is negative, it refers to an item position relative to the end of the list (C<-1> is the position after the last item, C<-2> is the position of the last item and so on). On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_insert(List *list, ssize_t index, void *item) { List *ret; int err; if (!list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); ret = list_insert_unlocked(list, index, item); if ((err = list_unlock(list))) return set_errnull(err); return ret; } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_insert_unlocked(List *list, ssize_t index, void *item) { if (!list) return set_errnull(EINVAL); if (index < 0) index = list->length + 1 + index; if (index < 0) return set_errnull(EINVAL); if (list->length < index) return set_errnull(EINVAL); if (expand(list, index, 1) == -1) return NULL; list->list[index] = item; return list; } /* =item C Equivalent to I except that C is an integer type. =cut */ List *list_insert_int(List *list, ssize_t index, int item) { return list_insert(list, index, (void *)(long)item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_insert_int_unlocked(List *list, ssize_t index, int item) { return list_insert_unlocked(list, index, (void *)(long)item); } /* =item C Inserts the items from C into C, starting at position C, using C as the copy constructor (if not C). If C is negative, it refers to an item position relative to the end of the list (C<-1> is the position after the last item, C<-2> is the position of the last item and so on). On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_insert_list(List *list, ssize_t index, const List *src, list_copy_t *copy) { List *ret; int err; if (!src || !list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); if ((err = list_rdlock(src))) { list_unlock(list); return set_errnull(err); } ret = list_insert_list_unlocked(list, index, src, copy); if ((err = list_unlock(src))) { list_unlock(list); return set_errnull(err); } if ((err = list_unlock(list))) return set_errnull(err); return ret; } /* =item C Equivalent to I except that C is not write-locked and C is not read-locked. Note: If C needs to be read-locked, it is the caller's responsibility to lock and unlock it explicitly with I and I. =cut */ #define enlist(item, copy) ((copy) ? (copy)(item) : (item)) List *list_insert_list_unlocked(List *list, ssize_t index, const List *src, list_copy_t *copy) { size_t i; if (!src || !list) return set_errnull(EINVAL); if (index < 0) index = list->length + 1 + index; if (index < 0) return set_errnull(EINVAL); if (list->length < index || xor(list->destroy, copy)) return set_errnull(EINVAL); if (expand(list, index, src->length) == -1) return NULL; for (i = 0; i < src->length; ++i) list->list[index + i] = enlist(src->list[i], copy); return list; } /* =item C Appends C to C. On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_append(List *list, void *item) { return list_insert(list, -1, item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_append_unlocked(List *list, void *item) { return list_insert_unlocked(list, -1, item); } /* =item C Equivalent to I except that C is an integer. =cut */ List *list_append_int(List *list, int item) { return list_insert_int(list, -1, item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_append_int_unlocked(List *list, int item) { return list_insert_int_unlocked(list, -1, item); } /* =item C Appends the items in C to C, using C as the copy constructor (if not C). On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_append_list(List *list, const List *src, list_copy_t *copy) { return list_insert_list(list, -1, src, copy); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_append_list_unlocked(List *list, const List *src, list_copy_t *copy) { return list_insert_list_unlocked(list, -1, src, copy); } /* =item C Prepends C to C. On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_prepend(List *list, void *item) { return list_insert(list, 0, item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_prepend_unlocked(List *list, void *item) { return list_insert_unlocked(list, 0, item); } /* =item C Equivalent to I except that C is an integer. =cut */ List *list_prepend_int(List *list, int item) { return list_insert_int(list, 0, item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_prepend_int_unlocked(List *list, int item) { return list_insert_int_unlocked(list, 0, item); } /* =item C Prepends the items in C to C, using C as the copy constructor (if not C). On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_prepend_list(List *list, const List *src, list_copy_t *copy) { return list_insert_list(list, 0, src, copy); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_prepend_list_unlocked(List *list, const List *src, list_copy_t *copy) { return list_insert_list_unlocked(list, 0, src, copy); } /* =item C Replaces C items in C, starting at C, with C. If C or C are negative, they refer to item positions relative to the end of the list (C<-1> is the position after the last item, C<-2> is the position of the last item and so on). On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_replace(List *list, ssize_t index, ssize_t range, void *item) { List *ret; int err; if (!list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); ret = list_replace_unlocked(list, index, range, item); if ((err = list_unlock(list))) return set_errnull(err); return ret; } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_replace_unlocked(List *list, ssize_t index, ssize_t range, void *item) { if (!list) return set_errnull(EINVAL); if (index < 0) index = list->length + 1 + index; if (index < 0) return set_errnull(EINVAL); if (range < 0) range = list->length + 1 + range - index; if (range < 0) return set_errnull(EINVAL); if (list->length < index + range) return set_errnull(EINVAL); killitems(list, index, range); if (adjust(list, index, range, 1) == -1) return NULL; list->list[index] = item; return list; } /* =item C Equivalent to I except that C is an integer type. =cut */ List *list_replace_int(List *list, ssize_t index, ssize_t range, int item) { return list_replace(list, index, range, (void *)(long)item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_replace_int_unlocked(List *list, ssize_t index, ssize_t range, int item) { return list_replace_unlocked(list, index, range, (void *)(long)item); } /* =item C Replaces C items in C, starting at C, with the items in C, using C as the copy constructor (if not C). If C or C are negative, they refer to item positions relative to the end of the list (C<-1> is the position after the last item, C<-2> is the position of the last item and so on). On success, return C. On error, returns C with C set appropriately. =cut */ List *list_replace_list(List *list, ssize_t index, ssize_t range, const List *src, list_copy_t *copy) { List *ret; int err; if (!src || !list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); if ((err = list_rdlock(src))) { list_unlock(list); return set_errnull(err); } ret = list_replace_list_unlocked(list, index, range, src, copy); if ((err = list_unlock(src))) { list_unlock(list); return set_errnull(err); } if ((err = list_unlock(list))) return set_errnull(err); return ret; } /* =item C Equivalent to I except that C is not write-locked and C is not read-locked. Note: If C needs to be read-locked, it is the caller's responsibility to lock and unlock it explicitly with I and I. =cut */ List *list_replace_list_unlocked(List *list, ssize_t index, ssize_t range, const List *src, list_copy_t *copy) { ssize_t length; if (!src || !list) return set_errnull(EINVAL); if (index < 0) index = list->length + 1 + index; if (index < 0) return set_errnull(EINVAL); if (range < 0) range = list->length + 1 + range - index; if (range < 0) return set_errnull(EINVAL); if (list->length < index + range || xor(list->destroy, copy)) return set_errnull(EINVAL); killitems(list, index, range); length = src->length; if (adjust(list, index, range, length) == -1) return NULL; while (length--) list->list[index + length] = enlist(src->list[length], copy); return list; } /* =item C Creates a new list consisting of C items from C, starting at C, using C as the copy constructor (if not C). If C or C are negative, they refer to item positions relative to the end of the list (C<-1> is the position after the last item, C<-2> is the position of the last item and so on). It is the caller's responsibility to deallocate the new list with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new list. On error, returns C with C set appropriately. =cut */ List *list_extract(const List *list, ssize_t index, ssize_t range, list_copy_t *copy) { return list_extract_with_locker(NULL, list, index, range, copy); } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *list_extract_unlocked(const List *list, ssize_t index, ssize_t range, list_copy_t *copy) { return list_extract_with_locker_unlocked(NULL, list, index, range, copy); } /* =item C Equivalent to I except that multiple threads accessing the new list will be synchronised by C. =cut */ List *list_extract_with_locker(Locker *locker, const List *list, ssize_t index, ssize_t range, list_copy_t *copy) { List *ret; int err; if (!list) return set_errnull(EINVAL); if ((err = list_rdlock(list))) return set_errnull(err); ret = list_extract_with_locker_unlocked(locker, list, index, range, copy); if ((err = list_unlock(list))) return set_errnull(err); return ret; } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *list_extract_with_locker_unlocked(Locker *locker, const List *list, ssize_t index, ssize_t range, list_copy_t *copy) { List *ret; if (!list) return set_errnull(EINVAL); if (index < 0) index = list->length + 1 + index; if (index < 0) return set_errnull(EINVAL); if (range < 0) range = list->length + 1 + range - index; if (range < 0) return set_errnull(EINVAL); if (list->length < index + range || xor(list->destroy, copy)) return set_errnull(EINVAL); if (!(ret = list_create_with_locker(locker, copy ? list->destroy : NULL))) return NULL; while (range--) { if (!list_append(ret, enlist(list->list[index++], copy))) { list_release(ret); return NULL; } } return ret; } #undef enlist /* =item C Pushes C onto the end of C. On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_push(List *list, void *item) { return list_append(list, item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_push_unlocked(List *list, void *item) { return list_append_unlocked(list, item); } /* =item C Equivalent to I except that C is an integer. =cut */ List *list_push_int(List *list, int item) { return list_append_int(list, item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_push_int_unlocked(List *list, int item) { return list_append_int_unlocked(list, item); } /* =item C Pops the last item off C. On success, returns the item popped. On error, returns C with C set appropriately. =cut */ void *list_pop(List *list) { void *item; int err; if (!list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); item = list_pop_unlocked(list); if ((err = list_unlock(list))) return set_errnull(err); return item; } /* =item C Equivalent to I except that C is not write-locked. =cut */ void *list_pop_unlocked(List *list) { void *item; if (!list) return set_errnull(EINVAL); if (!list->length) return set_errnull(EINVAL); item = list->list[list->length - 1]; list->list[list->length - 1] = NULL; if (!list_remove_unlocked(list, list->length - 1)) { list->list[list->length - 1] = item; return NULL; } return item; } /* =item C Equivalent to I except that the item popped has an integer type. =cut */ int list_pop_int(List *list) { return (int)(long)list_pop(list); } /* =item C Equivalent to I except that C is not write-locked. =cut */ int list_pop_int_unlocked(List *list) { return (int)(long)list_pop_unlocked(list); } /* =item C Removes and returns the first item in C. On success, returns the item shifted. On error, returns C with C set appropriately. =cut */ void *list_shift(List *list) { void *item; int err; if (!list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); item = list_shift_unlocked(list); if ((err = list_unlock(list))) return set_errnull(err); return item; } /* =item C Equivalent to I except that C is not write-locked. =cut */ void *list_shift_unlocked(List *list) { void *item; if (!list) return set_errnull(EINVAL); if (!list->length) return set_errnull(EINVAL); item = list->list[0]; list->list[0] = NULL; if (!list_remove_unlocked(list, 0)) { list->list[0] = item; return NULL; } return item; } /* =item C Equivalent to I except that the item shifted has an integer type. =cut */ int list_shift_int(List *list) { return (int)(long)list_shift(list); } /* =item C Equivalent to I except that C is not write-locked. =cut */ int list_shift_int_unlocked(List *list) { return (int)(long)list_shift_unlocked(list); } /* =item C Inserts C at the start of C. On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_unshift(List *list, void *item) { return list_prepend(list, item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_unshift_unlocked(List *list, void *item) { return list_prepend_unlocked(list, item); } /* =item C Equivalent to I except that C is an integer. =cut */ List *list_unshift_int(List *list, int item) { return list_prepend_int(list, item); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_unshift_int_unlocked(List *list, int item) { return list_prepend_int_unlocked(list, item); } /* =item C Removes a sublist from C starting at C, with length C, after copying the items with C (if not C). If C or C are negative, they refer to item positions relative to the end of the list (C<-1> is the position after the last item, C<-2> is the position of the last item and so on). On success, returns the sublist. It is the caller's responsibility to deallocate the new list with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On error, returns C with C set appropriately. =cut */ List *list_splice(List *list, ssize_t index, ssize_t range, list_copy_t *copy) { return list_splice_with_locker(NULL, list, index, range, copy); } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_splice_unlocked(List *list, ssize_t index, ssize_t range, list_copy_t *copy) { return list_splice_with_locker_unlocked(NULL, list, index, range, copy); } /* =item C Equivalent to I except that multiple threads accessing the new list will be synchronised by C. =cut */ List *list_splice_with_locker(Locker *locker, List *list, ssize_t index, ssize_t range, list_copy_t *copy) { List *ret; int err; if (!list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); ret = list_splice_with_locker_unlocked(locker, list, index, range, copy); if ((err = list_unlock(list))) { list_release(ret); return set_errnull(err); } return ret; } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_splice_with_locker_unlocked(Locker *locker, List *list, ssize_t index, ssize_t range, list_copy_t *copy) { List *ret; if (!list) return set_errnull(EINVAL); if (!(ret = list_extract_with_locker_unlocked(locker, list, index, range, copy))) return NULL; if (!list_remove_range_unlocked(list, index, range)) { list_release(ret); return NULL; } return ret; } /* =item C Sorts the items in C, using the item comparison function C, and I for lists of fewer than 10000 items, and I for larger lists. On success, returns C. On error, returns C with C set appropriately. =cut */ List *list_sort(List *list, list_cmp_t *cmp) { List *ret; int err; if (!list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); ret = list_sort_unlocked(list, cmp); if ((err = list_unlock(list))) return set_errnull(err); return ret; } /* =item C Equivalent to I except that C is not write-locked. =cut */ List *list_sort_unlocked(List *list, list_cmp_t *cmp) { if (!list) return set_errnull(EINVAL); if (!list->list || !list->length) return set_errnull(EINVAL); ((list->length >= 10000) ? hsort : qsort)(list->list, list->length, sizeof list->list[0], cmp); return list; } /* =item C Invokes C for each of C's items. The arguments passed to C are the item, a pointer to the loop variable containing the item's position within C, and C. On error, sets C appropriately. =cut */ void list_apply(List *list, list_action_t *action, void *data) { list_apply_wrlocked(list, action, data); } /* =item C Equivalent to I except that C is read-locked rather than write-locked. Use this in preference to I when C and its items will not be modified during the iteration. =cut */ void list_apply_rdlocked(List *list, list_action_t *action, void *data) { int err; if (!list || !action) { set_errno(EINVAL); return; } if ((err = list_rdlock(list))) { set_errno(err); return; } list_apply_unlocked(list, action, data); if ((err = list_unlock(list))) set_errno(err); } /* =item C Equivalent to I except that this function name makes the fact that C is write-locked explicit. =cut */ void list_apply_wrlocked(List *list, list_action_t *action, void *data) { int err; if (!list || !action) { set_errno(EINVAL); return; } if ((err = list_wrlock(list))) { set_errno(err); return; } list_apply_unlocked(list, action, data); if ((err = list_unlock(list))) set_errno(err); } /* =item C Equivalent to I except that C is not write-locked. =cut */ void list_apply_unlocked(List *list, list_action_t *action, void *data) { size_t i; if (!list || !action) { set_errno(EINVAL); return; } for (i = 0; i < list->length; ++i) action(list->list[i], &i, data); } /* =item C Creates and returns a new list containing the return values of C, invoked once for each item in C. The arguments passed to C are the item, a pointer to the loop variable containing the item's position within C, and C. C will be the item destructor for the new list. It is the caller's responsibility to deallocate the new list with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new list. On error, returns C with C set appropriately. =cut */ List *list_map(List *list, list_release_t *destroy, list_map_t *map, void *data) { return list_map_with_locker(NULL, list, destroy, map, data); } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *list_map_unlocked(List *list, list_release_t *destroy, list_map_t *map, void *data) { return list_map_with_locker_unlocked(NULL, list, destroy, map, data); } /* =item C Equivalent to I except that multiple threads accessing the new list will be synchronised by C. =cut */ List *list_map_with_locker(Locker *locker, List *list, list_release_t *destroy, list_map_t *map, void *data) { List *mapping; int err; if (!list || !map) return set_errnull(EINVAL); if ((err = list_rdlock(list))) return set_errnull(err); mapping = list_map_with_locker_unlocked(locker, list, destroy, map, data); if ((err = list_unlock(list))) { list_release(mapping); return set_errnull(err); } return mapping; } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *list_map_with_locker_unlocked(Locker *locker, List *list, list_release_t *destroy, list_map_t *map, void *data) { List *mapping; size_t i; if (!list || !map) return set_errnull(EINVAL); if (!(mapping = list_create_with_locker(locker, destroy))) return NULL; for (i = 0; i < list->length; ++i) { if (!list_append(mapping, map(list->list[i], &i, data))) { list_release(mapping); return NULL; } } return mapping; } /* =item C Creates and returns a new list by invoking C for each item in C, and appending the items for which C returned a non-zero value. The arguments passed to C are the item, a pointer to the loop variable containing the item's position within C, and C. It is the caller's responsibility to deallocate the new list with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. Note that the new list does not own its items, because it does not copy them. On success, returns the new list. On error, returns C with C set appropriately. =cut */ List *list_grep(List *list, list_query_t *grep, void *data) { return list_grep_with_locker(NULL, list, grep, data); } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *list_grep_unlocked(List *list, list_query_t *grep, void *data) { return list_grep_with_locker_unlocked(NULL, list, grep, data); } /* =item C Equivalent to I except that multiple threads accessing the new list will be synchronised by C. =cut */ List *list_grep_with_locker(Locker *locker, List *list, list_query_t *grep, void *data) { List *grepping; int err; if (!list || !list) return set_errnull(EINVAL); if ((err = list_rdlock(list))) return set_errnull(err); grepping = list_grep_with_locker_unlocked(locker, list, grep, data); if ((err = list_unlock(list))) { list_release(grepping); return set_errnull(err); } return grepping; } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *list_grep_with_locker_unlocked(Locker *locker, List *list, list_query_t *grep, void *data) { List *grepping; size_t i; if (!list || !list) return set_errnull(EINVAL); if (!(grepping = list_create(NULL))) return NULL; for (i = 0; i < list->length; ++i) { if (grep(list->list[i], &i, data)) { if (!list_append(grepping, list->list[i])) { list_release(grepping); return NULL; } } } return grepping; } /* =item C Invokes C on each item in C, starting at C<*index>, until C returns a non-zero value. The arguments passed to C are the item, C, and C. Returns the index of the item that satisfied C, or C<-1> when C is not satisfied by any remaining items. The value pointed to by C is set to the return value. On error, sets C appropriately. =cut */ ssize_t list_query(List *list, ssize_t *index, list_query_t *query, void *data) { ssize_t ret; int err; if (!list || !index || !query) return set_errno(EINVAL); if ((err = list_rdlock(list))) return set_errno(err); ret = list_query_unlocked(list, index, query, data); if ((err = list_unlock(list))) return set_errno(err); return ret; } /* =item C Equivalent to I except that C is not read-locked. =cut */ ssize_t list_query_unlocked(List *list, ssize_t *index, list_query_t *query, void *data) { size_t i; if (!list || !index || !query) return set_errno(EINVAL); if (*index >= list->length) return set_errno(EINVAL); for (i = *index; i < list->length; ++i) { if (query(list->list[i], (size_t *)index, data)) return *index = i; } return *index = -1; } /* =item C Creates an iterator for C. It is the caller's responsibility to deallocate the iterator with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. The iterator keeps C write-locked until it is released with I or I. Note that the iterator itself is not locked so it must not be shared between threads. On success, returns the iterator. On error, returns C with C set appropriately. =cut */ Lister *lister_create(List *list) { return lister_create_wrlocked(list); } /* =item C Equivalent to I except that C is read-locked rather than write-locked. Use this in preference to I when no calls to I will be made during the iteration. =cut */ Lister *lister_create_rdlocked(List *list) { int err; if (!list) return set_errnull(EINVAL); if ((err = list_rdlock(list))) return set_errnull(err); return lister_create_unlocked(list); } /* =item C Equivalent to I except that this function name makes the fact that C is write-locked explicit. =cut */ Lister *lister_create_wrlocked(List *list) { int err; if (!list) return set_errnull(EINVAL); if ((err = list_wrlock(list))) return set_errnull(err); return lister_create_unlocked(list); } /* =item C Equivalent to I except that C is not write-locked. =cut */ Lister *lister_create_unlocked(const List *list) { Lister *lister; if (!list) return set_errnull(EINVAL); if (!(lister = mem_new(Lister))) /* XXX decouple */ return NULL; lister->list = (List *)list; lister->index = -1; return lister; } /* =item C Releases (deallocates) C and unlocks the associated list. =cut */ void lister_release(Lister *lister) { int err; if (!lister) return; if ((err = list_unlock(lister->list))) { set_errno(err); return; } mem_release(lister); } /* =item C Equivalent to I except that the associated list is not unlocked. =cut */ void lister_release_unlocked(Lister *lister) { if (!lister) return; mem_release(lister); } /* =item C Destroys (deallocates and sets to C) C<*lister> and unlocks the associated list. Returns C. On error, sets C appropriately. =cut */ void *lister_destroy(Lister **lister) { if (lister && *lister) { lister_release(*lister); *lister = NULL; } return NULL; } /* =item C Equivalent to I except that the associated list is not unlocked. =cut */ void *lister_destroy_unlocked(Lister **lister) { if (lister && *lister) { lister_release_unlocked(*lister); *lister = NULL; } return NULL; } /* =item C Returns whether or not there is another item in the list over which C is iterating. On error, returns C<-1> with C set appropriately. =cut */ int lister_has_next(Lister *lister) { if (!lister) return set_errno(EINVAL); return lister->index + 1 < lister->list->length; } /* =item C Returns the next item in the iteration, C. On error, returns C with C set appropriately. =cut */ void *lister_next(Lister *lister) { if (!lister) return set_errnull(EINVAL); return list_item_unlocked(lister->list, (size_t)++lister->index); } /* =item C Equivalent to I except that the item returned is an integer. =cut */ int lister_next_int(Lister *lister) { if (!lister) return set_errno(EINVAL); return list_item_int_unlocked(lister->list, (size_t)++lister->index); } /* =item C Removes the current item in the iteration, C. The next item in the iteration is the item following the removed item, if any. This must be called after I or I. On error, sets C appropriately. =cut */ void lister_remove(Lister *lister) { if (!lister) { set_errno(EINVAL); return; } if (lister->index == -1) { set_errno(EINVAL); return; } list_remove_unlocked(lister->list, (size_t)lister->index--); } /* =item C Returns whether or not there is another item in C using an internal iterator. The first time this is called, a new internal I will be created (Note: There can be only one at any time for a given list). When there are no more items, returns C<0> and destroys the internal iterator. When it returns C<1>, use I or I to retrieve the next item. On error, returns C<-1> with C set appropriately. Note: If an iteration using an internal iterator terminates before the end of the list, it is the caller's responsibility to call I. Failure to do so will cause the internal iterator to leak. It will also break the next call to I which will continue where the current iteration stopped rather than starting at the beginning again. I assumes that there is no internal iterator, so it is the caller's responsibility to complete the iteration, or call I before releasing C with I or I. Note: The internal I does not lock C so this function is not threadsafe. It can only be used with lists created in the current function (to guarantee that no other thread can access it). This practice should be observed even in single-threaded applications to avoid breaking iterator semantics (possible with nested function calls). If C is a parameter or a variable declared outside the function, it is best to create an explicit I instead. If this function is used on such lists instead, it is the caller's responsibility to explicitly lock C first with I and explicitly unlock it with I. Do this even if you are writing single-threaded code, in case your function may one day be used in a multi-threaded application. =cut */ int list_has_next(List *list) { int has; if (!list) return set_errno(EINVAL); if (!list->lister && !(list->lister = lister_create_unlocked(list))) return -1; if ((has = lister_has_next(list->lister)) != 1) list_break(list); return has; } /* =item C Unlocks C and destroys its internal iterator. Must be used only when an iteration using an internal iterator has terminated before reaching the end of C. On error, returns C with C set appropriately. =cut */ void list_break(List *list) { if (!list) { set_errno(EINVAL); return; } lister_destroy_unlocked(&list->lister); } /* =item C Returns the next item in C using its internal iterator. On error, returns C with C set appropriately. =cut */ void *list_next(List *list) { if (!list || !list->lister) return set_errnull(EINVAL); return lister_next(list->lister); } /* =item C Equivalent to I except that the item returned is an integer. =cut */ int list_next_int(List *list) { if (!list || !list->lister) return set_errno(EINVAL); return lister_next_int(list->lister); } /* =item C Removes the current item in C using its internal iterator. The next item in the iteration is the item following the removed item, if any. This must be called after I. On error, sets C appropriately. =cut */ void list_remove_current(List *list) { if (!list || !list->lister) { set_errno(EINVAL); return; } lister_remove(list->lister); } /* =back =head1 ERRORS On error, C is set either by an underlying function, or as follows: =over 4 =item C When arguments are C or out of range. =back =head1 MT-Level I By default, Is are not I because most programs are single-threaded, and synchronisation doesn't come for free. Even in multi-threaded programs, not all Is are necessarily shared between multiple threads. When a I is shared between multiple threads which need to be synchronised, the method of synchronisation must be carefully selected by the client code. There are tradeoffs between concurrency and overhead. The greater the concurrency, the greater the overhead. More locks give greater concurrency, but have greater overhead. Readers/Writer locks can give greater concurrency than mutex locks, but have greater overhead. One lock for each I may be required, or one lock for all (or a set of) Is may be more appropriate. Generally, the best synchronisation strategy for a given application can only be determined by testing/benchmarking the written application. It is important to be able to experiment with the synchronisation strategy at this stage of development without pain. To facilitate this, Is can be created with I, which takes a I argument. The I specifies a lock and a set of functions for manipulating the lock. Each I can have its own lock, by creating a separate I for each I. Multiple Is can share the same lock, by sharing the same I. Only the application developer can determine what is appropriate for each application, on a case by case basis. I means that the application developer has a mechanism for specifying the synchronisation requirements to be applied to library code. =head1 EXAMPLES Create a list that doesn't own its items, populate it, and then iterate over its values with the internal iterator to print the values: #include #include int main() { List *list; if (!(list = list_create(NULL))) return EXIT_FAILURE; list_append(list, "123"); list_append(list, "456"); list_append(list, "789"); while (list_has_next(list) == 1) printf("%s\n", (char *)list_next(list)); list_destroy(&list); return EXIT_SUCCESS; } The same, but create the list and populate it at the same time: #include #include int main() { List *list; if (!(list = list_make(NULL, "123", "456", "789", NULL))) return EXIT_FAILURE; while (list_has_next(list) == 1) printf("%s\n", (char *)list_next(list)); list_destroy(&list); return EXIT_SUCCESS; } Create a list that does own its items, populate it, and then iterator over it with an external iterator to print its items. #include #include int main() { List *list; Lister *lister; if (!(list = list_create(NULL))) return EXIT_FAILURE; list_append(list, "123"); list_append(list, "456"); list_append(list, "789"); if (!(lister = lister_create(list))) { list_destroy(&list); return EXIT_FAILURE; } while (lister_has_next(lister) == 1) printf("%s\n", (char *)lister_next(lister)); lister_destroy(&lister); list_destroy(&list); return EXIT_SUCCESS; } The same, but with an apply function: #include #include void action(void *item, size_t *index, void *data) { printf("%s\n", (char *)item); } int main() { List *list; if (!(list = list_create(free))) return EXIT_FAILURE; list_append(list, strdup("123")); list_append(list, strdup("456")); list_append(list, strdup("789")); list_apply(list, action, NULL); list_destroy(&list); return EXIT_SUCCESS; } The same, but with a list of integers: #include #include int main() { List *list; if (!(list = list_create(NULL))) return EXIT_FAILURE; list_append(list, (void *)123); list_append(list, (void *)456); list_append(list, (void *)789); while (list_has_next(list) == 1) printf("%d\n", list_next_int(list)); list_destroy(&list); return EXIT_SUCCESS; } Create a copy of a list: #include #include int main() { List *orig; List *copy; if (!(orig = list_make(free, strdup("123"), strdup("456"), strdup("789"), NULL))) return EXIT_FAILURE; if (!(copy = list_copy(orig, (list_copy_t *)strdup))) { list_destroy(&orig); return EXIT_FAILURE; } list_destroy(&orig); while (list_has_next(copy) == 1) printf("%s\n", (char *)list_next(copy)); list_destroy(©); return EXIT_SUCCESS; } Transfer ownership from one list to another: #include #include int main() { List *donor; List *recipient; if (!(donor = list_make(free, strdup("123"), strdup("456"), strdup("789"), NULL))) return EXIT_FAILURE; if (!(recipient = list_create(NULL))) { list_destroy(&donor); return EXIT_FAILURE; } while (list_has_next(donor) == 1) list_append(recipient, list_next(donor)); list_own(recipient, list_disown(donor)); list_destroy(&donor); while (list_has_next(recipient) == 1) printf("%s\n", (char *)list_next(recipient)); list_destroy(&recipient); return EXIT_SUCCESS; } Manipulate a list, examine it, use apply, map, grep, and query, remove items while iterating: #include #include int cmp(const void *a, const void *b) { return strcmp(*(char **)a, *(char **)b); } void action(void *item, size_t *index, void *data) { printf("%s\n", (char *)item); } void *upper(void *item, size_t *index, void *data) { char *uc = strdup(item); if (uc) *uc = toupper(*uc); return uc; } int even(void *item, size_t *index, void *data) { return item && (*(char *)item & 1) == 0; } int main() { Lister *lister; List *list; void *item; List *res; ssize_t i; if (!(list = list_create(NULL))) return EXIT_FAILURE; // Manipulate a list printf("length %d empty %d\n", list_length(list), list_empty(list)); list_append(list, "a"); list_append(list, "b"); list_append(list, "c"); list_remove(list, 0); list_insert(list, 1, "d"); list_prepend(list, "e"); list_replace(list, 1, 2, "f"); list_push(list, "g"); list_push(list, "h"); list_push(list, "i"); item = list_pop(list); list_unshift(list, list_shift(list)); list_release(list_splice(list, 0, 1, NULL)); list_sort(list, cmp); printf("last %s\n", (char *)list_item(list, list_last(list))); // Apply an action to a list list_apply(list, action, NULL); // Map a list into another list res = list_map(list, free, upper, NULL); list_apply(res, action, NULL); list_destroy(&res); // Grep a list for items that match some criteria res = list_grep(list, even, NULL); list_apply(res, action, NULL); list_destroy(&res); // Locate a list's items that match some criteria for (i = 0; list_query(list, &i, even, NULL) != -1; ++i) printf("%d %s even\n", i, (char *)list_item(list, i)); // Remove elements via the internal iterator and break out of loop while (list_has_next(list) == 1) { item = list_next(list); list_remove_current(list); if (!strcmp(item, "f")) { list_break(list); break; } } // Remove elements via an external iterator for (lister = lister_create(list); lister_has_next(lister) == 1; ) { item = lister_next(lister); lister_remove(lister); } lister_destroy(&lister); list_destroy(&list); return EXIT_SUCCESS; } Manipulate a list of integers: #include #include int main() { Lister *lister; List *list; int item; int i; if (!(list = list_create(NULL))) return EXIT_FAILURE; // Manipulate a list list_append_int(list, 1); list_append_int(list, 2); list_append_int(list, 3); list_remove(list, 0); list_insert_int(list, 1, 4); list_prepend_int(list, 5); list_replace_int(list, 1, 2, 6); list_push_int(list, 7); list_push_int(list, 8); list_push_int(list, 9); item = list_pop_int(list); list_unshift_int(list, list_shift_int(list)); list_release(list_splice(list, 0, 1, NULL)); // Get items as integers for (i = 0; i < list_length(list); ++i) printf("%d\n", list_item_int(list, i)); // Remove elements via the internal iterator while (list_has_next(list) == 1) { item = list_next_int(list); list_remove_current(list); } // Remove elements via an external iterator for (lister = lister_create(list); lister_has_next(lister) == 1; ) { item = lister_next_int(lister); lister_remove(lister); } list_destroy(&list); return EXIT_SUCCESS; } Append, insert, prepend, and replace using another list, not just one item: #include #include int main() { List *list; List *src; int i; if (!(list = list_create(NULL))) return EXIT_FAILURE; if (!(src = list_make(NULL, "a", "b", "c", NULL))) { list_destroy(&list); return EXIT_FAILURE; } list_append_list(list, src, NULL); list_insert_list(list, 1, src, NULL); list_prepend_list(list, src, NULL); list_replace_list(list, 1, 2, src, NULL); for (i = 0; i < list_length(list); ++i) printf("%s\n", (char *)list_item(list, i)); list_destroy(&list); return EXIT_SUCCESS; } The same as the previous example but with a list that owns its items: #include #include int main() { List *list; List *src; int i; if (!(list = list_create(free))) return EXIT_FAILURE; if (!(src = list_make(NULL, "a", "b", "c", NULL))) { list_destroy(&list); return EXIT_FAILURE; } list_append_list(list, src, (list_copy_t *)strdup); list_insert_list(list, 1, src, (list_copy_t *)strdup); list_prepend_list(list, src, (list_copy_t *)strdup); list_replace_list(list, 1, 2, src, (list_copy_t *)strdup); for (i = 0; i < list_length(list); ++i) printf("%s\n", (char *)list_item(list, i)); list_destroy(&list); return EXIT_SUCCESS; } =head1 CAVEAT Little attempt is made to protect the client from sharing items between lists with differing ownership policies and getting it wrong. When copying items from any list to an owning list, a copy function must be supplied. When adding a single item to an owning list, it is assumed that the list may take over ownership of the item. When an owning list is destroyed, all of its items are destroyed. If any of these items had been shared with a non-owning list that outlived the owning list, then the non-owning list will contain items that point to deallocated memory. This must be avoided. If you use an internal iterator in a loop that terminates before the end of the list, and fail to call I, the internal iterator will leak. This must be avoided. =head1 BUGS Uses I directly. The type of memory used and the allocation strategy should be decoupled from this code. =head1 SEE ALSO I, I, I, I, I, I =head1 AUTHOR 20210220 raf =cut */ #endif #ifdef TEST #include char action_data[1024]; void action(void *item, size_t *index) { strlcat(action_data, item, 1024); } int query_data[] = { 2, 6, 8 , -1 }; int query(void *item, size_t *index) { return !strcmp((const char *)item, "def"); } int sort_cmp(const char **a, const char **b) { return strcmp(*a, *b); } int mapf(int item, size_t *index, int *sum) { return (sum) ? *sum += item : item; } int grepf(int item, size_t *index, int *data) { return !(item & 1); } #define RD 0 #define WR 1 List *mtlist = NULL; Locker *locker = NULL; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #ifdef PTHREAD_RWLOCK_INITIALIZER pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; #else pthread_rwlock_t rwlock; #endif int barrier[2]; int length[2]; const int lim = 1000; int debug = 0; int errors = 0; void *produce(void *arg) { int i; int test = *(int *)arg; for (i = 0; i <= lim; ++i) { if (debug) printf("p: prepend %d\n", i); if (!list_prepend_int(mtlist, i)) ++errors, printf("Test%d: list_prepend_int(mtlist, %d), failed\n", test, i); write(length[WR], "", 1); } write(barrier[WR], "", 1); return NULL; } void *consume(void *arg) { int i, v; int test = *(int *)arg; char ack; for (i = 0; i < lim * 2; ++i) { if (debug) printf("c: pop\n"); while (read(length[RD], &ack, 1) == -1 && errno == EINTR) {} v = list_pop_int(mtlist); if (debug) printf("c: pop %d\n", v); if (v == lim) break; } if (i != lim) ++errors, printf("Test%d: consumer read %d items, not %d\n", test, i, lim); write(barrier[WR], "", 1); return NULL; } void *iterate_builtin(void *arg) { int i; int t = *(int *)arg; int broken = 0; if (debug) printf("i%d: loop\n", t); for (i = 0; i < lim / 10; ++i) { list_wrlock(mtlist); while (list_has_next(mtlist) == 1) { int val = list_next_int(mtlist); if (debug) printf("i%d: loop %d/%d val %d\n", t, i, lim / 10, val); if (!broken) { list_break(mtlist); broken = 1; break; } } list_unlock(mtlist); } write(barrier[WR], "", 1); return NULL; } void *iterate_rdlocked(void *arg) { int i; int t = *(int *)arg; if (debug) printf("j%d: loop\n", t); for (i = 0; i < lim / 10; ++i) { Lister *lister = lister_create_rdlocked(mtlist); while (lister_has_next(lister) == 1) { int val = (int)(long)lister_next(lister); if (debug) printf("j%d: loop %d/%d val %d\n", t, i, lim / 10, val); } lister_release(lister); } write(barrier[WR], "", 1); return NULL; } void *iterate_wrlocked(void *arg) { int i; int t = *(int *)arg; if (debug) printf("k%d: loop\n", t); for (i = 0; i < lim / 10; ++i) { Lister *lister = lister_create_wrlocked(mtlist); while (lister_has_next(lister) == 1) { int val = (int)(long)lister_next(lister); if (debug) printf("k%d: loop %d/%d val %d\n", t, i, lim / 10, val); } lister_release(lister); } write(barrier[WR], "", 1); return NULL; } void mt_test(int test, Locker *locker) { if (!(mtlist = list_create_with_locker(locker, NULL))) ++errors, printf("Test%d: list_create_with_locker(NULL) failed\n", test); else { static int iid[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; pthread_attr_t attr; pthread_t id; int i; char ack; if (pipe(length) == -1 || pipe(barrier) == -1) { ++errors, printf("Test%d: failed to perform test: pipe() failed\n", test); return; } pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&id, &attr, produce, &test); pthread_create(&id, &attr, consume, &test); pthread_create(&id, &attr, iterate_builtin, iid + 0); pthread_create(&id, &attr, iterate_builtin, iid + 1); pthread_create(&id, &attr, iterate_builtin, iid + 2); pthread_create(&id, &attr, iterate_builtin, iid + 3); pthread_create(&id, &attr, iterate_rdlocked, iid + 4); pthread_create(&id, &attr, iterate_rdlocked, iid + 5); pthread_create(&id, &attr, iterate_rdlocked, iid + 6); pthread_create(&id, &attr, iterate_wrlocked, iid + 7); pthread_create(&id, &attr, iterate_wrlocked, iid + 8); pthread_create(&id, &attr, iterate_wrlocked, iid + 9); pthread_attr_destroy(&attr); for (i = 0; i < 12; ++i) while (read(barrier[RD], &ack, 1) == -1 && errno == EINTR) {} list_destroy(&mtlist); if (mtlist) ++errors, printf("Test%d: list_destroy(&mtlist) failed\n", test); close(length[RD]); close(length[WR]); close(barrier[RD]); close(barrier[WR]); } } #define TEST_ACT(i, action) \ if (!(action)) \ ++errors, printf("Test%d: %s failed\n", (i), (#action)); #define TEST_EQ(i, action, value) \ if ((val = (action)) != (value)) \ ++errors, printf("Test%d: %s failed (returned %d, not %d)\n", (i), (#action), val, (value)); #define CHECK_LENGTH(i, action, list, length) \ if (list_length(list) != (length)) \ ++errors, printf("Test%d: %s failed: list_length(%s) = %d, not %d\n", (i), (#action), (#list), (int)list_length(list), (length)); #define CHECK_ITEM(i, action, list, item, value) \ if (!list_item((list), (item)) || strcmp(list_item((list), (item)), (value))) \ ++errors, printf("Test%d: %s failed (item %d is \"%s\", not \"%s\")\n", (i), (#action), (item), (char *)list_item(list, (item)), (value)); #define CHECK_INT_ITEM(i, action, list, item, value) \ if (list_item_int((list), (item)) != (value)) \ ++errors, printf("Test%d: %s failed (item %d is %d, not %d)\n", (i), (#action), (item), list_item_int(list, (item)), (value)); int main(int ac, char **av) { int errors = 0; List *a, *b, *c, *d; Lister *lister; ssize_t index = 0; int i, val; if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s [debug]\n", *av); return EXIT_SUCCESS; } printf("Testing: %s\n", "list"); /* Test list_make, list_length, list_item */ TEST_ACT(1, a = list_make(NULL, "abc", "def", "ghi", "jkl", NULL)) else CHECK_LENGTH(1, list_make(), a, 4) else CHECK_ITEM(1, list_make(), a, 0, "abc") else CHECK_ITEM(1, list_make(), a, 1, "def") else CHECK_ITEM(1, list_make(), a, 2, "ghi") else CHECK_ITEM(1, list_make(), a, 3, "jkl") /* Test list_create(NULL), list_empty, list_append, list_prepend, list_insert, list_last */ TEST_ACT(2, b = list_create(NULL)) TEST_ACT(3, list_empty(b)) TEST_ACT(4, list_append(b, "abc")) else CHECK_LENGTH(4, list_append(b, "abc"), b, 1) else CHECK_ITEM(4, list_append(b, "abc"), b, 0, "abc") TEST_ACT(5, !list_empty(b)) TEST_ACT(6, list_prepend(b, "def")) else CHECK_LENGTH(6, list_prepend(b, "def"), b, 2) else CHECK_ITEM(6, list_prepend(b, "def"), b, 0, "def") else CHECK_ITEM(6, list_prepend(b, "def"), b, 1, "abc") TEST_ACT(7, list_insert(b, 1, "ghi")) else CHECK_LENGTH(7, list_insert(b, "ghi"), b, 3) else CHECK_ITEM(7, list_insert(b, "ghi"), b, 0, "def") else CHECK_ITEM(7, list_insert(b, "ghi"), b, 1, "ghi") else CHECK_ITEM(7, list_insert(b, "ghi"), b, 2, "abc") TEST_EQ(8, list_last(b), 2) TEST_EQ(9, list_length(NULL), -1) else if (errno != EINVAL) ++errors, printf("Test9: list_length(NULL) failed (errno = %d, not EINVAL)\n", errno); TEST_EQ(10, list_empty(NULL), -1) else if (errno != EINVAL) ++errors, printf("Test10: list_empty(NULL) failed (errno = %d, not EINVAL)\n", errno); /* Test list_copy, list_destroy */ if ((c = list_copy(a, (list_copy_t *)free))) ++errors, printf("Test11: list_copy() with copy() but no destroy() failed\n"); if (!(c = list_copy(a, NULL))) ++errors, printf("Test12: list_copy() without copy() or destroy() failed\n"); else CHECK_LENGTH(12, list_copy(a, NULL), c, 4) else CHECK_ITEM(12, list_copy(a, NULL), c, 0, "abc") else CHECK_ITEM(12, list_copy(a, NULL), c, 1, "def") else CHECK_ITEM(12, list_copy(a, NULL), c, 2, "ghi") else CHECK_ITEM(12, list_copy(a, NULL), c, 3, "jkl") list_destroy(&c); if (c) ++errors, printf("Test13: list_destroy(&c) failed\n"); /* Test list_create(free), list_append, list_copy */ if (!(c = list_create((list_release_t *)free))) ++errors, printf("Test14: list_create(free) failed\n"); else { TEST_ACT(15, list_append(c, mem_strdup("abc"))) TEST_ACT(16, list_append(c, mem_strdup("def"))) TEST_ACT(17, list_append(c, mem_strdup("ghi"))) TEST_ACT(18, list_append(c, mem_strdup("jkl"))) if ((d = list_copy(c, NULL))) ++errors, printf("Test19: list_copy() with destroy() but no copy() failed\n"); if (!(d = list_copy(c, (list_copy_t *)mem_strdup))) ++errors, printf("Test20: list_copy() with copy() and destroy() failed\n"); } /* Test list_remove, list_replace */ TEST_ACT(21, list_remove(a, 3)) else CHECK_LENGTH(21, list_remove(a, 3), a, 3) else CHECK_ITEM(21, list_remove(a, 3), a, 0, "abc") else CHECK_ITEM(21, list_remove(a, 3), a, 1, "def") else CHECK_ITEM(21, list_remove(a, 3), a, 2, "ghi") TEST_ACT(22, list_remove(a, 0)) else CHECK_LENGTH(22, list_remove(a, 0), a, 2) else CHECK_ITEM(22, list_remove(a, 0), a, 0, "def") else CHECK_ITEM(22, list_remove(a, 0), a, 1, "ghi") TEST_ACT(23, list_replace(a, 1, 1, "123")) else CHECK_LENGTH(23, list_replace(a, 1, 1, "123"), a, 2) else CHECK_ITEM(23, list_replace(a, 1, 1, "123"), a, 0, "def") else CHECK_ITEM(23, list_replace(a, 1, 1, "123"), a, 1, "123") /* Test list_append_list, list_prepend_list, list_insert_list */ TEST_ACT(24, list_append_list(a, b, NULL)) else CHECK_LENGTH(24, list_append_list(a, b, NULL), a, 5) else CHECK_ITEM(24, list_append_list(a, b, NULL), a, 0, "def") else CHECK_ITEM(24, list_append_list(a, b, NULL), a, 1, "123") else CHECK_ITEM(24, list_append_list(a, b, NULL), a, 2, "def") else CHECK_ITEM(24, list_append_list(a, b, NULL), a, 3, "ghi") else CHECK_ITEM(24, list_append_list(a, b, NULL), a, 4, "abc") TEST_ACT(25, list_prepend_list(a, c, NULL)) else CHECK_LENGTH(25, list_prepend_list(a, c, NULL), a, 9) else CHECK_ITEM(25, list_prepend_list(a, c, NULL), a, 0, "abc") else CHECK_ITEM(25, list_prepend_list(a, c, NULL), a, 1, "def") else CHECK_ITEM(25, list_prepend_list(a, c, NULL), a, 2, "ghi") else CHECK_ITEM(25, list_prepend_list(a, c, NULL), a, 3, "jkl") else CHECK_ITEM(25, list_prepend_list(a, c, NULL), a, 4, "def") else CHECK_ITEM(25, list_prepend_list(a, c, NULL), a, 5, "123") else CHECK_ITEM(25, list_prepend_list(a, c, NULL), a, 6, "def") else CHECK_ITEM(25, list_prepend_list(a, c, NULL), a, 7, "ghi") else CHECK_ITEM(25, list_prepend_list(a, c, NULL), a, 8, "abc") TEST_ACT(26, list_insert_list(b, 1, c, NULL)) else CHECK_LENGTH(26, list_insert_list(b, 1, c, NULL), b, 7) else CHECK_ITEM(26, list_insert_list(b, 1, c, NULL), b, 0, "def") else CHECK_ITEM(26, list_insert_list(b, 1, c, NULL), b, 1, "abc") else CHECK_ITEM(26, list_insert_list(b, 1, c, NULL), b, 2, "def") else CHECK_ITEM(26, list_insert_list(b, 1, c, NULL), b, 3, "ghi") else CHECK_ITEM(26, list_insert_list(b, 1, c, NULL), b, 4, "jkl") else CHECK_ITEM(26, list_insert_list(b, 1, c, NULL), b, 5, "ghi") else CHECK_ITEM(26, list_insert_list(b, 1, c, NULL), b, 6, "abc") /* Test list_replace_list, list_remove_range */ if (list_replace_list(c, 1, 2, d, NULL)) ++errors, printf("Test27: list_replace_list() with destroy() but not copy() failed\n"); if (list_replace_list(a, 1, 2, d, (list_copy_t *)mem_strdup)) ++errors, printf("Test28: list_replace_list() with copy() but not destroy() failed\n"); TEST_ACT(29, list_replace_list(a, 1, 2, d, NULL)) else CHECK_LENGTH(29, list_replace_list(a, 1, 2, d, NULL), a, 11) else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 0, "abc") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 1, "abc") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 2, "def") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 3, "ghi") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 4, "jkl") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 5, "jkl") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 6, "def") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 7, "123") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 8, "def") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 9, "ghi") else CHECK_ITEM(29, list_replace_list(a, 1, 2, d, NULL), a, 10, "abc") TEST_ACT(30, list_remove_range(b, 1, 3)) else CHECK_LENGTH(30, list_remove_range(b, 1, 3), b, 4) else CHECK_ITEM(30, list_remove_range(b, 1, 3), b, 0, "def") else CHECK_ITEM(30, list_remove_range(b, 1, 3), b, 1, "jkl") else CHECK_ITEM(30, list_remove_range(b, 1, 3), b, 2, "ghi") else CHECK_ITEM(30, list_remove_range(b, 1, 3), b, 3, "abc") /* Test list_apply, list_query, list_sort */ list_apply(a, (list_action_t *)action, NULL); if (strcmp(action_data, "abcabcdefghijkljkldef123defghiabc")) ++errors, printf("Test31: list_apply() failed\n"); for (i = 0; list_query(a, &index, (list_query_t *)query, NULL) != -1; ++i, ++index) { if (index != query_data[i]) { ++errors, printf("Test32: list_query returned %d (not %d)\n", (int)index, query_data[i]); break; } } TEST_ACT(33, list_sort(a, (list_cmp_t *)sort_cmp)) else CHECK_LENGTH(33, list_sort(a, sort_cmp), a, 11) else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 0, "123") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 1, "abc") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 2, "abc") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 3, "abc") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 4, "def") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 5, "def") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 6, "def") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 7, "ghi") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 8, "ghi") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 9, "jkl") else CHECK_ITEM(33, list_sort(a, sort_cmp), a, 10, "jkl") /* Test lister_create, lister_has_next, lister_next, lister_destroy */ TEST_ACT(34, lister = lister_create(a)) for (i = 0; lister_has_next(lister) == 1; ++i) { void *item = lister_next(lister); if (item != a->list[i]) /* white box */ { ++errors, printf("Test35: iteration %d is '%s' not '%s'\n", i, (char *)item, (char *)list_item(a, i)); break; } } lister_destroy(&lister); if (lister) ++errors, printf("Test36: lister_destroy(&lister) failed, lister is %p not NULL\n", (void *)lister); /* Test list_has_next, list_next, list_break */ for (i = 0; list_has_next(a) == 1; ++i) { void *item = list_next(a); if (item != a->list[i]) /* white box */ { ++errors, printf("Test37: internal iteration %d is '%s' not '%s'\n", i, (char *)item, (char *)list_item(a, i)); list_break(a); break; } } for (i = 0; list_has_next(a) == 1; ++i) { void *item = list_next(a); if (item != a->list[i]) /* white box */ { ++errors, printf("Test38: internal iteration %d is '%s' not '%s'\n", i, (char *)item, (char *)list_item(a, i)); list_break(a); break; } if (i == 2) { list_break(a); break; } } if (a->lister) ++errors, printf("Test38: list_break() failed\n"); /* Test lister_remove */ if (!(lister = lister_create(a))) ++errors, printf("Test39: lister_create() failed\n"); for (i = 0; lister_has_next(lister) == 1; ++i) { lister_next(lister); if (i == 4) lister_remove(lister); } lister_destroy(&lister); if (lister) ++errors, printf("Test40: lister_destroy(&lister) failed, lister is %p not NULL\n", (void *)lister); CHECK_LENGTH(41, list_remove(lister), a, 10) else CHECK_ITEM(41, lister_remove(lister), a, 0, "123") else CHECK_ITEM(41, lister_remove(lister), a, 1, "abc") else CHECK_ITEM(41, lister_remove(lister), a, 2, "abc") else CHECK_ITEM(41, lister_remove(lister), a, 3, "abc") else CHECK_ITEM(41, lister_remove(lister), a, 4, "def") else CHECK_ITEM(41, lister_remove(lister), a, 5, "def") else CHECK_ITEM(41, lister_remove(lister), a, 6, "ghi") else CHECK_ITEM(41, lister_remove(lister), a, 7, "ghi") else CHECK_ITEM(41, lister_remove(lister), a, 8, "jkl") else CHECK_ITEM(41, lister_remove(lister), a, 9, "jkl") list_destroy(&a); if (a) ++errors, printf("Test42: list_destroy(&a) failed, a is %p not NULL\n", (void *)a); list_destroy(&b); if (b) ++errors, printf("Test43: list_destroy(&b) failed, b is %p not NULL\n", (void *)b); list_destroy(&c); if (c) ++errors, printf("Test44: list_destroy(&c) failed, c is %p not NULL\n", (void *)c); list_destroy(&d); if (d) ++errors, printf("Test45: list_destroy(&d) failed, d is %p not NULL\n", (void *)d); /* Test relative index/range */ TEST_ACT(46, a = list_make(NULL, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL)) else { void *item; TEST_ACT(47, list_item(a, -1) == NULL) TEST_ACT(47, item = list_item(a, -2)) TEST_ACT(47, !strcmp(item, "9")) TEST_ACT(47, item = list_item(a, -3)) TEST_ACT(47, !strcmp(item, "8")) TEST_ACT(47, item = list_item(a, -4)) TEST_ACT(47, !strcmp(item, "7")) TEST_ACT(47, item = list_item(a, -5)) TEST_ACT(47, !strcmp(item, "6")) TEST_ACT(47, item = list_item(a, -6)) TEST_ACT(47, !strcmp(item, "5")) TEST_ACT(47, item = list_item(a, -7)) TEST_ACT(47, !strcmp(item, "4")) TEST_ACT(47, item = list_item(a, -8)) TEST_ACT(47, !strcmp(item, "3")) TEST_ACT(47, item = list_item(a, -9)) TEST_ACT(47, !strcmp(item, "2")) TEST_ACT(47, item = list_item(a, -10)) TEST_ACT(47, !strcmp(item, "1")) TEST_ACT(47, item = list_item(a, -11)) TEST_ACT(47, !strcmp(item, "0")) TEST_ACT(47, list_item(a, -12) == NULL) TEST_ACT(47, list_item(a, -1000) == NULL) TEST_ACT(48, list_remove_range(a, -5, -1)) else CHECK_LENGTH(48, list_remove_range(a, -5, -1), a, 6) else CHECK_ITEM(48, list_remove_range(a, -5, -1), a, 0, "0") else CHECK_ITEM(48, list_remove_range(a, -5, -1), a, 1, "1") else CHECK_ITEM(48, list_remove_range(a, -5, -1), a, 2, "2") else CHECK_ITEM(48, list_remove_range(a, -5, -1), a, 3, "3") else CHECK_ITEM(48, list_remove_range(a, -5, -1), a, 4, "4") else CHECK_ITEM(48, list_remove_range(a, -5, -1), a, 5, "5") TEST_ACT(49, list_remove_range(a, -1, -1)) else CHECK_LENGTH(49, list_remove_range(a, -1, -1), a, 6) else CHECK_ITEM(49, list_remove_range(a, -1, -1), a, 0, "0") else CHECK_ITEM(49, list_remove_range(a, -1, -1), a, 1, "1") else CHECK_ITEM(49, list_remove_range(a, -1, -1), a, 2, "2") else CHECK_ITEM(49, list_remove_range(a, -1, -1), a, 3, "3") else CHECK_ITEM(49, list_remove_range(a, -1, -1), a, 4, "4") else CHECK_ITEM(49, list_remove_range(a, -1, -1), a, 5, "5") TEST_ACT(50, list_remove_range(a, -3, -2)) else CHECK_LENGTH(50, list_remove_range(a, -3, -2), a, 5) else CHECK_ITEM(50, list_remove_range(a, -3, -2), a, 0, "0") else CHECK_ITEM(50, list_remove_range(a, -3, -2), a, 1, "1") else CHECK_ITEM(50, list_remove_range(a, -3, -2), a, 2, "2") else CHECK_ITEM(50, list_remove_range(a, -3, -2), a, 3, "3") else CHECK_ITEM(50, list_remove_range(a, -3, -2), a, 4, "5") TEST_ACT(51, list_insert(a, -1, "X")) else CHECK_LENGTH(51, list_insert(a, -1, "X"), a, 6) else CHECK_ITEM(51, list_insert(a, -1, "X"), a, 0, "0") else CHECK_ITEM(51, list_insert(a, -1, "X"), a, 1, "1") else CHECK_ITEM(51, list_insert(a, -1, "X"), a, 2, "2") else CHECK_ITEM(51, list_insert(a, -1, "X"), a, 3, "3") else CHECK_ITEM(51, list_insert(a, -1, "X"), a, 4, "5") else CHECK_ITEM(51, list_insert(a, -1, "X"), a, 5, "X") TEST_ACT(52, b = list_make(NULL, "a", "b", "c", NULL)) else TEST_ACT(52, list_insert_list(a, -1, b, NULL)) else CHECK_LENGTH(52, list_insert_list(a, -1, b, NULL), a, 9) else CHECK_ITEM(52, list_insert_list(a, -1, b, NULL), a, 0, "0") else CHECK_ITEM(52, list_insert_list(a, -1, b, NULL), a, 1, "1") else CHECK_ITEM(52, list_insert_list(a, -1, b, NULL), a, 2, "2") else CHECK_ITEM(52, list_insert_list(a, -1, b, NULL), a, 3, "3") else CHECK_ITEM(52, list_insert_list(a, -1, b, NULL), a, 4, "5") else CHECK_ITEM(52, list_insert_list(a, -1, b, NULL), a, 5, "X") else CHECK_ITEM(52, list_insert_list(a, -1, b, NULL), a, 6, "a") else CHECK_ITEM(52, list_insert_list(a, -1, b, NULL), a, 7, "b") else CHECK_ITEM(52, list_insert_list(a, -1, b, NULL), a, 8, "c") list_destroy(&b); TEST_ACT(53, b = list_make(NULL, "x", "y", "z", NULL)) else TEST_ACT(53, list_insert_list(a, -10, b, NULL)) else CHECK_LENGTH(53, list_insert_list(a, -10, b, NULL), a, 12) else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 0, "x") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 1, "y") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 2, "z") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 3, "0") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 4, "1") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 5, "2") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 6, "3") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 7, "5") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 8, "X") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 9, "a") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 10, "b") else CHECK_ITEM(53, list_insert_list(a, -10, b, NULL), a, 11, "c") list_destroy(&b); TEST_ACT(54, b = list_make(NULL, "0", NULL)) else TEST_ACT(54, list_replace_list(a, -13, -9, b, NULL)) else CHECK_LENGTH(54, list_replace_list(a, -13, -9, b, NULL), a, 9) else CHECK_ITEM(54, list_replace_list(a, -13, -9, b, NULL), a, 0, "0") else CHECK_ITEM(54, list_replace_list(a, -13, -9, b, NULL), a, 1, "1") else CHECK_ITEM(54, list_replace_list(a, -13, -9, b, NULL), a, 2, "2") else CHECK_ITEM(54, list_replace_list(a, -13, -9, b, NULL), a, 3, "3") else CHECK_ITEM(54, list_replace_list(a, -13, -9, b, NULL), a, 4, "5") else CHECK_ITEM(54, list_replace_list(a, -13, -9, b, NULL), a, 5, "X") else CHECK_ITEM(54, list_replace_list(a, -13, -9, b, NULL), a, 6, "a") else CHECK_ITEM(54, list_replace_list(a, -13, -9, b, NULL), a, 7, "b") else CHECK_ITEM(54, list_replace_list(a, -13, -9, b, NULL), a, 8, "c") list_destroy(&b); TEST_ACT(55, b = list_make(NULL, "X", NULL)) else TEST_ACT(55, list_replace_list(a, -5, -1, b, NULL)) else CHECK_LENGTH(55, list_replace_list(a, -5, -1, b, NULL), a, 6) else CHECK_ITEM(55, list_replace_list(a, -5, -1, b, NULL), a, 0, "0") else CHECK_ITEM(55, list_replace_list(a, -5, -1, b, NULL), a, 1, "1") else CHECK_ITEM(55, list_replace_list(a, -5, -1, b, NULL), a, 2, "2") else CHECK_ITEM(55, list_replace_list(a, -5, -1, b, NULL), a, 3, "3") else CHECK_ITEM(55, list_replace_list(a, -5, -1, b, NULL), a, 4, "5") else CHECK_ITEM(55, list_replace_list(a, -5, -1, b, NULL), a, 5, "X") list_destroy(&b); TEST_ACT(56, list_replace(a, -5, -2, "Y")) else CHECK_LENGTH(56, list_replace(a, -5, -2, "Y"), a, 4) else CHECK_ITEM(56, list_replace(a, -5, -2, "Y"), a, 0, "0") else CHECK_ITEM(56, list_replace(a, -5, -2, "Y"), a, 1, "1") else CHECK_ITEM(56, list_replace(a, -5, -2, "Y"), a, 2, "Y") else CHECK_ITEM(56, list_replace(a, -5, -2, "Y"), a, 3, "X") TEST_ACT(57, b = list_extract(a, -4, -2, NULL)) else CHECK_LENGTH(57, b = list_extract(a, -4, -2, NULL), b, 2) else CHECK_ITEM(57, b = list_extract(a, -4, -2, NULL), b, 0, "1") else CHECK_ITEM(57, b = list_extract(a, -4, -2, NULL), b, 1, "Y") list_destroy(&b); /* Test relative error checking */ TEST_ACT(58, list_remove_range(a, -2, -1000) == NULL) TEST_ACT(59, list_remove_range(a, -1000, -2) == NULL) TEST_ACT(60, list_remove_range(a, -1000, -1000) == NULL) TEST_ACT(61, list_insert(a, -1000, "?") == NULL) TEST_ACT(62, b = list_make(NULL, "?", NULL)) else { TEST_ACT(63, list_insert_list(a, -1000, b, NULL) == NULL) TEST_ACT(64, list_replace_list(a, -2, -1000, b, NULL) == NULL) TEST_ACT(65, list_replace_list(a, -1000, -2, b, NULL) == NULL) TEST_ACT(66, list_replace_list(a, -1000, -1000, b, NULL) == NULL) list_destroy(&b); } TEST_ACT(67, list_replace(a, -2, -1000, "?") == NULL) TEST_ACT(68, list_replace(a, -1000, -2, "?") == NULL) TEST_ACT(69, list_replace(a, -1000, -1000, "?") == NULL) TEST_ACT(70, list_extract(a, -2, -1000, NULL) == NULL) TEST_ACT(71, list_extract(a, -1000, -2, NULL) == NULL) TEST_ACT(72, list_extract(a, -1000, -1000, NULL) == NULL) list_destroy(&a); } /* Test lists with int items, list_map, list_grep */ TEST_ACT(73, a = list_create(NULL)) else { TEST_ACT(74, list_append_int(a, 2)) else CHECK_LENGTH(74, list_append_int(a, 2), a, 1) else CHECK_INT_ITEM(74, list_append_int(a, 2), a, 0, 2) TEST_ACT(75, list_prepend_int(a, 0)) else CHECK_LENGTH(75, list_prepend_int(a, 0), a, 2) else CHECK_INT_ITEM(75, list_prepend_int(a, 0), a, 0, 0) else CHECK_INT_ITEM(75, list_prepend_int(a, 0), a, 1, 2) TEST_ACT(76, list_insert_int(a, 1, 1)) else CHECK_LENGTH(76, list_insert_int(a, 1, 1), a, 3) else CHECK_INT_ITEM(76, list_insert_int(a, 1, 1), a, 0, 0) else CHECK_INT_ITEM(76, list_insert_int(a, 1, 1), a, 1, 1) else CHECK_INT_ITEM(76, list_insert_int(a, 1, 1), a, 2, 2) for (i = 0; list_has_next(a) == 1; ++i) { int item = list_next_int(a); if (item != (int)(long)a->list[i]) /* white box */ ++errors, printf("Test77: int list test failed (item %d = %d, not %d)\n", i, item, list_item_int(a, i)); } if (i != 3) ++errors, printf("Test78: list_has_next() failed (only %d items, not %d)\n", i, 3); if (!(lister = lister_create(a))) ++errors, printf("Test79: lister_create(a) failed\n"); else { for (i = 0; lister_has_next(lister) == 1; ++i) { int item = lister_next_int(lister); if (item != (int)(long)a->list[i]) /* white box */ ++errors, printf("Test80: int list test failed (item %d = %d, not %d)\n", i, item, i); } if (i != 3) ++errors, printf("Test81: lister_has_next() failed (only %d items, not %d)\n", i, 3); lister_destroy(&lister); } TEST_ACT(82, list_replace_int(a, 2, 1, 4)) else CHECK_LENGTH(82, list_replace_int(a, 2, 1, 4), a, 3) else CHECK_INT_ITEM(82, list_replace_int(a, 2, 1, 4), a, 0, 0) else CHECK_INT_ITEM(82, list_replace_int(a, 2, 1, 4), a, 1, 1) else CHECK_INT_ITEM(82, list_replace_int(a, 2, 1, 4), a, 2, 4) i = 0; TEST_ACT(83, b = list_map(a, NULL, (list_map_t *)mapf, &i)) else { CHECK_LENGTH(83, b = list_map(), b, 3) CHECK_INT_ITEM(83, b = list_map(), b, 0, 0) CHECK_INT_ITEM(83, b = list_map(), b, 1, 1) CHECK_INT_ITEM(83, b = list_map(), b, 2, 5) list_destroy(&b); } TEST_ACT(84, b = list_grep(a, (list_query_t *)grepf, NULL)) else { CHECK_LENGTH(84, b = list_grep(), b, 2) CHECK_INT_ITEM(84, b = list_grep(), b, 0, 0) CHECK_INT_ITEM(84, b = list_grep(), b, 1, 4) list_destroy(&b); } list_destroy(&a); } /* Test list_push_int, list_pop_int, list_unshift_int, list_shift_int */ TEST_ACT(85, a = list_create(NULL)) else { TEST_ACT(86, list_push_int(a, 1)) TEST_ACT(87, list_push_int(a, 2)) TEST_ACT(88, list_push_int(a, 3)) TEST_ACT(89, list_push_int(a, 0)) TEST_ACT(90, list_push_int(a, 5)) TEST_ACT(91, list_push_int(a, 6)) TEST_ACT(92, list_push_int(a, 7)) TEST_EQ(93, list_pop_int(a), 7) TEST_EQ(94, list_pop_int(a), 6) TEST_EQ(95, list_pop_int(a), 5) TEST_EQ(96, list_pop_int(a), 0) TEST_EQ(97, list_pop_int(a), 3) TEST_EQ(98, list_pop_int(a), 2) TEST_EQ(99, list_pop_int(a), 1) TEST_EQ(100, list_pop_int(a), 0) TEST_ACT(101, list_unshift_int(a, 1)) TEST_ACT(102, list_unshift_int(a, 2)) TEST_ACT(103, list_unshift_int(a, 3)) TEST_ACT(104, list_unshift_int(a, 0)) TEST_ACT(105, list_unshift_int(a, 5)) TEST_ACT(106, list_unshift_int(a, 6)) TEST_ACT(107, list_unshift_int(a, 7)) TEST_EQ(108, list_shift_int(a), 7) TEST_EQ(109, list_shift_int(a), 6) TEST_EQ(110, list_shift_int(a), 5) TEST_EQ(111, list_shift_int(a), 0) TEST_EQ(112, list_shift_int(a), 3) TEST_EQ(113, list_shift_int(a), 2) TEST_EQ(114, list_shift_int(a), 1) TEST_EQ(115, list_shift_int(a), 0) list_destroy(&a); } /* Test list_push, list_pop, list_unshift, list_shift */ TEST_ACT(116, a = list_create(free)) else { char *item; TEST_ACT(117, list_push(a, mem_strdup("1"))) TEST_ACT(118, list_push(a, mem_strdup("2"))) TEST_ACT(119, list_push(a, mem_strdup("3"))) TEST_ACT(120, list_push(a, mem_strdup("4"))) TEST_ACT(121, list_push(a, mem_strdup("5"))) TEST_ACT(122, list_push(a, mem_strdup("6"))) TEST_ACT(123, list_push(a, mem_strdup("7"))) #define CHECK_POP(i, action, value) \ if (!(item = (action)) || strcmp(item, (value))) \ ++errors, printf("Test%d: %s failed (\"%s\", not \"%s\")\n", (i), (#action), (item) ? item : "NULL", (value) ? (value) : NULL); \ free(item); CHECK_POP(124, list_pop(a), "7") CHECK_POP(125, list_pop(a), "6") CHECK_POP(126, list_pop(a), "5") CHECK_POP(127, list_pop(a), "4") CHECK_POP(128, list_pop(a), "3") CHECK_POP(129, list_pop(a), "2") CHECK_POP(130, list_pop(a), "1") TEST_ACT(131, !list_pop(a)) TEST_ACT(132, list_unshift(a, mem_strdup("1"))) TEST_ACT(133, list_unshift(a, mem_strdup("2"))) TEST_ACT(134, list_unshift(a, mem_strdup("3"))) TEST_ACT(135, list_unshift(a, mem_strdup("4"))) TEST_ACT(136, list_unshift(a, mem_strdup("5"))) TEST_ACT(137, list_unshift(a, mem_strdup("6"))) TEST_ACT(138, list_unshift(a, mem_strdup("7"))) CHECK_POP(139, list_shift(a), "7") CHECK_POP(140, list_shift(a), "6") CHECK_POP(141, list_shift(a), "5") CHECK_POP(142, list_shift(a), "4") CHECK_POP(143, list_shift(a), "3") CHECK_POP(144, list_shift(a), "2") CHECK_POP(145, list_shift(a), "1") TEST_ACT(146, !list_shift(a)) list_destroy(&a); } /* Test list_make, list_splice */ TEST_ACT(147, a = list_make(NULL, "a", "b", "c", "d", "e", "f", NULL)) else { List *splice; TEST_ACT(148, splice = list_splice(a, 0, 1, NULL)) else { CHECK_LENGTH(149, splice = list_splice(a, 0, 1, NULL), splice, 1) CHECK_ITEM(150, splice = list_splice(a, 0, 1, NULL), splice, 0, "a") CHECK_LENGTH(151, splice = list_splice(a, 0, 1, NULL), a, 5) CHECK_ITEM(152, splice = list_splice(a, 0, 1, NULL), a, 0, "b") CHECK_ITEM(153, splice = list_splice(a, 0, 1, NULL), a, 1, "c") CHECK_ITEM(154, splice = list_splice(a, 0, 1, NULL), a, 2, "d") CHECK_ITEM(155, splice = list_splice(a, 0, 1, NULL), a, 3, "e") CHECK_ITEM(156, splice = list_splice(a, 0, 1, NULL), a, 4, "f") list_destroy(&splice); } TEST_ACT(157, splice = list_splice(a, 4, 1, NULL)) else { CHECK_LENGTH(158, splice = list_splice(a, 4, 1, NULL), splice, 1) CHECK_ITEM(159, splice = list_splice(a, 4, 1, NULL), splice, 0, "f") CHECK_LENGTH(160, splice = list_splice(a, 4, 1, NULL), a, 4) CHECK_ITEM(161, splice = list_splice(a, 4, 1, NULL), a, 0, "b") CHECK_ITEM(162, splice = list_splice(a, 4, 1, NULL), a, 1, "c") CHECK_ITEM(163, splice = list_splice(a, 4, 1, NULL), a, 2, "d") CHECK_ITEM(164, splice = list_splice(a, 4, 1, NULL), a, 3, "e") list_destroy(&splice); } TEST_ACT(165, splice = list_splice(a, 1, 2, NULL)) else { CHECK_LENGTH(166, splice = list_splice(a, 1, 2, NULL), splice, 2) CHECK_ITEM(167, splice = list_splice(a, 1, 2, NULL), splice, 0, "c") CHECK_ITEM(168, splice = list_splice(a, 1, 2, NULL), splice, 1, "d") CHECK_LENGTH(169, splice = list_splice(a, 1, 2, NULL), a, 2) CHECK_ITEM(170, splice = list_splice(a, 1, 2, NULL), a, 0, "b") CHECK_ITEM(171, splice = list_splice(a, 1, 2, NULL), a, 1, "e") list_destroy(&splice); } list_destroy(&a); } /* Test MT Safety */ debug = av[1] && !strcmp(av[1], "debug"); if (debug) setbuf(stdout, NULL); #ifndef PTHREAD_RWLOCK_INITIALIZER pthread_rwlock_init(&rwlock, NULL); #endif if (debug) locker = locker_create_debug_rwlock(&rwlock); else locker = locker_create_rwlock(&rwlock); if (!locker) ++errors, printf("Test172: locker_create_rwlock() failed\n"); else { mt_test(173, locker); locker_destroy(&locker); } if (debug) locker = locker_create_debug_mutex(&mutex); else locker = locker_create_mutex(&mutex); if (!locker) ++errors, printf("Test174: locker_create_mutex() failed\n"); else { mt_test(175, locker); locker_destroy(&locker); } /* Test assumption: sizeof(int) <= sizeof(void *) */ if (sizeof(int) > sizeof(void *)) ++errors, printf("Test176: assumption failed: sizeof(int) > sizeof(void *): int lists are limited to %d bytes\n", (int)sizeof(void *)); if (errors) printf("%d/176 tests failed\n", errors); else printf("All tests passed\n"); return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/list.h0000644000175000017500000001754514014141213013641 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_LIST_H #define LIBSLACK_LIST_H #include #include #include #include typedef struct List List; typedef struct Lister Lister; typedef void list_release_t(void *item); typedef void *list_copy_t(const void *item); typedef int list_cmp_t(const void *a, const void *b); typedef void list_action_t(void *item, size_t *index, void *data); typedef void *list_map_t(void *item, size_t *index, void *data); typedef int list_query_t(void *item, size_t *index, void *data); _begin_decls List *list_create(list_release_t *destroy); List *list_make(list_release_t *destroy, ...); List *list_vmake(list_release_t *destroy, va_list args); List *list_copy(const List *src, list_copy_t *copy); List *list_create_with_locker(Locker *locker, list_release_t *destroy); List *list_make_with_locker(Locker *locker, list_release_t *destroy, ...); List *list_vmake_with_locker(Locker *locker, list_release_t *destroy, va_list args); List *list_copy_with_locker(Locker *locker, const List *src, list_copy_t *copy); int list_rdlock(const List *list); int list_wrlock(const List *list); int list_unlock(const List *list); void list_release(List *list); void *list_destroy(List **list); int list_own(List *list, list_release_t *destroy); int list_own_unlocked(List *list, list_release_t *destroy); list_release_t *list_disown(List *list); list_release_t *list_disown_unlocked(List *list); void *list_item(const List *list, ssize_t index); void *list_item_unlocked(const List *list, ssize_t index); int list_item_int(const List *list, ssize_t index); int list_item_int_unlocked(const List *list, ssize_t index); int list_empty(const List *list); int list_empty_unlocked(const List *list); ssize_t list_length(const List *list); ssize_t list_length_unlocked(const List *list); ssize_t list_last(const List *list); ssize_t list_last_unlocked(const List *list); List *list_remove(List *list, ssize_t index); List *list_remove_unlocked(List *list, ssize_t index); List *list_remove_range(List *list, ssize_t index, ssize_t range); List *list_remove_range_unlocked(List *list, ssize_t index, ssize_t range); List *list_insert(List *list, ssize_t index, void *item); List *list_insert_unlocked(List *list, ssize_t index, void *item); List *list_insert_int(List *list, ssize_t index, int item); List *list_insert_int_unlocked(List *list, ssize_t index, int item); List *list_insert_list(List *list, ssize_t index, const List *src, list_copy_t *copy); List *list_insert_list_unlocked(List *list, ssize_t index, const List *src, list_copy_t *copy); List *list_append(List *list, void *item); List *list_append_unlocked(List *list, void *item); List *list_append_int(List *list, int item); List *list_append_int_unlocked(List *list, int item); List *list_append_list(List *list, const List *src, list_copy_t *copy); List *list_append_list_unlocked(List *list, const List *src, list_copy_t *copy); List *list_prepend(List *list, void *item); List *list_prepend_unlocked(List *list, void *item); List *list_prepend_int(List *list, int item); List *list_prepend_int_unlocked(List *list, int item); List *list_prepend_list(List *list, const List *src, list_copy_t *copy); List *list_prepend_list_unlocked(List *list, const List *src, list_copy_t *copy); List *list_replace(List *list, ssize_t index, ssize_t range, void *item); List *list_replace_unlocked(List *list, ssize_t index, ssize_t range, void *item); List *list_replace_int(List *list, ssize_t index, ssize_t range, int item); List *list_replace_int_unlocked(List *list, ssize_t index, ssize_t range, int item); List *list_replace_list(List *list, ssize_t index, ssize_t range, const List *src, list_copy_t *copy); List *list_replace_list_unlocked(List *list, ssize_t index, ssize_t range, const List *src, list_copy_t *copy); List *list_extract(const List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_extract_unlocked(const List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_extract_with_locker(Locker *locker, const List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_extract_with_locker_unlocked(Locker *locker, const List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_push(List *list, void *item); List *list_push_unlocked(List *list, void *item); List *list_push_int(List *list, int item); List *list_push_int_unlocked(List *list, int item); void *list_pop(List *list); void *list_pop_unlocked(List *list); int list_pop_int(List *list); int list_pop_int_unlocked(List *list); void *list_shift(List *list); void *list_shift_unlocked(List *list); int list_shift_int(List *list); int list_shift_int_unlocked(List *list); List *list_unshift(List *list, void *item); List *list_unshift_unlocked(List *list, void *item); List *list_unshift_int(List *list, int item); List *list_unshift_int_unlocked(List *list, int item); List *list_splice(List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_splice_unlocked(List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_splice_with_locker(Locker *locker, List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_splice_with_locker_unlocked(Locker *locker, List *list, ssize_t index, ssize_t range, list_copy_t *copy); List *list_sort(List *list, list_cmp_t *cmp); List *list_sort_unlocked(List *list, list_cmp_t *cmp); void list_apply(List *list, list_action_t *action, void *data); void list_apply_rdlocked(List *list, list_action_t *action, void *data); void list_apply_wrlocked(List *list, list_action_t *action, void *data); void list_apply_unlocked(List *list, list_action_t *action, void *data); List *list_map(List *list, list_release_t *destroy, list_map_t *map, void *data); List *list_map_unlocked(List *list, list_release_t *destroy, list_map_t *map, void *data); List *list_map_with_locker(Locker *locker, List *list, list_release_t *destroy, list_map_t *map, void *data); List *list_map_with_locker_unlocked(Locker *locker, List *list, list_release_t *destroy, list_map_t *map, void *data); List *list_grep(List *list, list_query_t *grep, void *data); List *list_grep_unlocked(List *list, list_query_t *grep, void *data); List *list_grep_with_locker(Locker *locker, List *list, list_query_t *grep, void *data); List *list_grep_with_locker_unlocked(Locker *locker, List *list, list_query_t *grep, void *data); ssize_t list_query(List *list, ssize_t *index, list_query_t *query, void *data); ssize_t list_query_unlocked(List *list, ssize_t *index, list_query_t *query, void *data); Lister *lister_create(List *list); Lister *lister_create_rdlocked(List *list); Lister *lister_create_wrlocked(List *list); Lister *lister_create_unlocked(const List *list); void lister_release(Lister *lister); void lister_release_unlocked(Lister *lister); void *lister_destroy(Lister **lister); void *lister_destroy_unlocked(Lister **lister); int lister_has_next(Lister *lister); void *lister_next(Lister *lister); int lister_next_int(Lister *lister); void lister_remove(Lister *lister); int list_has_next(List *list); void list_break(List *list); void *list_next(List *list); int list_next_int(List *list); void list_remove_current(List *list); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/locker.c0000644000175000017500000011325614014141213014134 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ /* =head1 NAME I - abstract locking, rwlocks =head1 SYNOPSIS #include #include typedef struct Locker Locker; typedef int lockerf_t(void *lock); Locker *locker_create_mutex(pthread_mutex_t *mutex); Locker *locker_create_rwlock(pthread_rwlock_t *rwlock); Locker *locker_create_debug_mutex(pthread_mutex_t *mutex); Locker *locker_create_debug_rwlock(pthread_rwlock_t *rwlock); Locker *locker_create(void *lock, lockerf_t *tryrdlock, lockerf_t *rdlock, lockerf_t *trywrlock, lockerf_t *wrlock, lockerf_t *unlock); void locker_release(Locker *locker); void *locker_destroy(Locker **locker); int locker_tryrdlock(Locker *locker); int locker_rdlock(Locker *locker); int locker_trywrlock(Locker *locker); int locker_wrlock(Locker *locker); int locker_unlock(Locker *locker); int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); int pthread_rwlockattr_init(pthread_rwlockattr_t *attr); int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr); int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared); =head1 DESCRIPTION This module provides an abstraction of thread synchronisation that facilitates the implementation of I libraries. I'll explain what this means. Libraries need to be I when used in a multi-threaded program. However, most programs are single-threaded, and synchronisation doesn't come for free, so libraries should be I when used in a single-threaded program. Even in multi-threaded programs, some functions or objects may only be accessed by a single thread, and so they should not incur the expense of synchronisation. When an object is shared between multiple threads which need to be synchronised, the method of synchronisation must be carefully selected by the client code. There are tradeoffs between concurrency and overhead. The greater the concurrency, the greater the overhead. More locks give greater concurrency, but have greater overhead. Readers/Writer locks can give greater concurrency than Mutex locks, but have greater overhead. One lock for each object may be required, or one lock for all (or a set of) objects may be more appropriate. Generally, the best synchronisation strategy for a given application can only be determined by testing/benchmarking the written application. It is important to be able to experiment with the synchronisation strategy at this stage of development without pain. The solution, of course, is to decouple the synchronisation strategy from the library code. To facilitate this, the I type and associated functions can be incorporated into library code to provide the necessary flexibility. The I type specifies a lock and a set of functions for manipulating the lock. Arbitrary objects can include a pointer to a I object to use for thread synchronisation. Such objects may each have their own lock, by having separate I objects, or they may share the same lock by sharing the same I object. Only the application developer can determine what is appropriate for each application, on a case by case basis. I means that the application developer has a mechanism for specifying the synchronisation requirements to be applied to library code. For more details, see I (C). This module also provides an implementation of readers/writer locks which are defined in recent standards but may not be on your system yet. The readers/writer lock implementation originally came from code by Bil Lewis and was then completed and made robust. =over 4 =cut */ #include "config.h" #include "std.h" #include "locker.h" #include "mem.h" #include "err.h" #ifndef HAVE_PTHREAD_PROCESS_PRIVATE #define PTHREAD_PROCESS_PRIVATE 0 #endif #ifndef HAVE_PTHREAD_PROCESS_SHARED #define PTHREAD_PROCESS_SHARED 0 #endif #ifndef HAVE_PTHREAD_CONDATTR_INIT #define pthread_condattr_init(condattr) 0 #endif #ifndef HAVE_PTHREAD_CONDATTR_SETPSHARED #define pthread_condattr_setpshared(condattr, pshared) 0 #endif #ifndef HAVE_PTHREAD_MUTEXATTR_SETPSHARED #define pthread_mutexattr_setpshared(mutexattr, pshared) 0 #endif #if 0 struct Locker { void *lock; lockerf_t *tryrdlock; lockerf_t *rdlock; lockerf_t *trywrlock; lockerf_t *wrlock; lockerf_t *unlock; }; #endif #ifndef TEST #define try(action) { int rc = (action); if (rc != 0) return rc; } #define try_catch(action, catch) { int rc = (action); if (rc != 0) return (catch), rc; } /* =item C Creates a I object that will operate on the mutex lock, C. I and I will call I. I and I will call I. I will call I. It is the caller's responsibility to initialise C if necessary before use, and to destroy C if necessary after use. On success, returns the new I object. On error, returns C with C set appropriately. =cut */ Locker *locker_create_mutex(pthread_mutex_t *mutex) { return locker_create ( mutex, (lockerf_t *)pthread_mutex_trylock, (lockerf_t *)pthread_mutex_lock, (lockerf_t *)pthread_mutex_trylock, (lockerf_t *)pthread_mutex_lock, (lockerf_t *)pthread_mutex_unlock ); } /* =item C Creates a I object that will operate on the readers/writer lock, C. I will call I. I will call I. I will call I. I will call I. I will call I. It is the caller's responsibility to initialise C if necessary before use, and to destroy C if necessary after use. On success, returns the new I object. On error, returns C with C set appropriately. =cut */ Locker *locker_create_rwlock(pthread_rwlock_t *rwlock) { return locker_create ( rwlock, (lockerf_t *)pthread_rwlock_tryrdlock, (lockerf_t *)pthread_rwlock_rdlock, (lockerf_t *)pthread_rwlock_trywrlock, (lockerf_t *)pthread_rwlock_wrlock, (lockerf_t *)pthread_rwlock_unlock ); } #ifndef NO_DEBUG_LOCKERS /* =item C Equivalent to I except that debug messages are printed to standard output before and after each locking function is called to help locate deadlocks. The debug messages look like: [thread id] funcname(mutex address) ... [thread id] funcname(mutex address) done On success, returns the new I. On error, returns C with C set appropriately. =cut */ static int debug_invoke(const char *name, lockerf_t *action, void *lock) { int err; printf("[%lu] %s(%p) ...\n", (unsigned long)pthread_self(), name, lock); err = action(lock); if (err) printf("[%lu] %s(%p) done (%s)\n", (unsigned long)pthread_self(), name, lock, strerror(err)); else printf("[%lu] %s(%p) done\n", (unsigned long)pthread_self(), name, lock); return err; } static int debug_pthread_mutex_trylock(pthread_mutex_t *mutex) { return debug_invoke("pthread_mutex_trylock", (lockerf_t *)pthread_mutex_trylock, mutex); } static int debug_pthread_mutex_lock(pthread_mutex_t *mutex) { return debug_invoke("pthread_mutex_lock", (lockerf_t *)pthread_mutex_lock, mutex); } static int debug_pthread_mutex_unlock(pthread_mutex_t *mutex) { return debug_invoke("pthread_mutex_unlock", (lockerf_t *)pthread_mutex_unlock, mutex); } Locker *locker_create_debug_mutex(pthread_mutex_t *mutex) { return locker_create ( mutex, (lockerf_t *)debug_pthread_mutex_trylock, (lockerf_t *)debug_pthread_mutex_lock, (lockerf_t *)debug_pthread_mutex_trylock, (lockerf_t *)debug_pthread_mutex_lock, (lockerf_t *)debug_pthread_mutex_unlock ); } /* =item C Equivalent to I except that debug messages are printed to standard output before and after each locking function is called to help locate deadlocks. The debug messages look like: [thread id] funcname(rwlock address) ... [thread id] funcname(rwlock address) done On success, returns the new I. On error, returns C with C set appropriately. =cut */ static int debug_pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) { return debug_invoke("pthread_rwlock_tryrdlock", (lockerf_t *)pthread_rwlock_tryrdlock, rwlock); } static int debug_pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) { return debug_invoke("pthread_rwlock_rdlock", (lockerf_t *)pthread_rwlock_rdlock, rwlock); } static int debug_pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) { return debug_invoke("pthread_rwlock_trywrlock", (lockerf_t *)pthread_rwlock_trywrlock, rwlock); } static int debug_pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) { return debug_invoke("pthread_rwlock_wrlock", (lockerf_t *)pthread_rwlock_wrlock, rwlock); } static int debug_pthread_rwlock_unlock(pthread_rwlock_t *rwlock) { return debug_invoke("pthread_rwlock_unlock", (lockerf_t *)pthread_rwlock_unlock, rwlock); } Locker *locker_create_debug_rwlock(pthread_rwlock_t *rwlock) { return locker_create ( rwlock, (lockerf_t *)debug_pthread_rwlock_tryrdlock, (lockerf_t *)debug_pthread_rwlock_rdlock, (lockerf_t *)debug_pthread_rwlock_trywrlock, (lockerf_t *)debug_pthread_rwlock_wrlock, (lockerf_t *)debug_pthread_rwlock_unlock ); } #endif /* =item C Creates a I object that will operate on the synchronisation variable, C. I will call C. I will call C. I will call C. I will call C. I will call C. It is the caller's responsibility to initialise C if necessary before use, and to destroy C if necessary after use. None of the arguments may be C. On success, returns the new I object. On error, returns C with C set appropriately. =cut */ Locker *locker_create(void *lock, lockerf_t *tryrdlock, lockerf_t *rdlock, lockerf_t *trywrlock, lockerf_t *wrlock, lockerf_t *unlock) { Locker *locker; if (!lock || !tryrdlock || !rdlock || !trywrlock || !wrlock || !unlock) return set_errnull(EINVAL); if (!(locker = mem_new(Locker))) /* XXX decouple */ return NULL; locker->lock = lock; locker->tryrdlock = tryrdlock; locker->rdlock = rdlock; locker->trywrlock = trywrlock; locker->wrlock = wrlock; locker->unlock = unlock; return locker; } /* =item C Releases (deallocates) C. It is the caller's responsibility to destroy the synchronisation variable used by C if necessary. =cut */ void locker_release(Locker *locker) { if (!locker) return; mem_release(locker); } /* =item C Destroys (deallocates and sets to C) C<*locker>. Returns C. It is the caller's responsibility to destroy the synchronisation variable used by C if necessary. =cut */ void *locker_destroy(Locker **locker) { if (locker && *locker) { locker_release(*locker); *locker = NULL; } return NULL; } /* =item C Tries to claim a read lock on the synchronisation variable managed by C. See I and I for details. On success, returns C<0>. On error, returns the error code from the underlying I library function. =cut */ int (locker_tryrdlock)(Locker *locker) { return locker ? locker->tryrdlock(locker->lock) : 0; } /* =item C Claims a read lock on the synchronisation variable managed by C. See I and I for details. On success, returns C<0>. On error, returns the error code from the underlying I library function. =cut */ int (locker_rdlock)(Locker *locker) { return locker ? locker->rdlock(locker->lock) : 0; } /* =item C Tries to claim a write lock on the synchronisation variable managed by C. See I and I for details. On success, returns C<0>. On error, returns the error code from the underlying I library function. =cut */ int (locker_trywrlock)(Locker *locker) { return locker ? locker->trywrlock(locker->lock) : 0; } /* =item C Claims a write lock on the synchronisation variable managed by C. See I and I for details. On success, returns C<0>. On error, returns the error code from the underlying I library function. =cut */ int (locker_wrlock)(Locker *locker) { return locker ? locker->wrlock(locker->lock) : 0; } /* =item C Unlocks the synchronisation variable managed by C. See I and I for details. On success, returns C<0>. On error, returns the error code from the underlying I library function. =cut */ int (locker_unlock)(Locker *locker) { return locker ? locker->unlock(locker->lock) : 0; } #ifndef HAVE_PTHREAD_RWLOCK /* =item I Initialises the readers/writer lock, C, with the attributes in C. If C is C, C is initialised as a process private lock. Note that this is the only option under I. On success, returns C<0>. On error, returns an error code. =cut */ int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) { #define DMA pthread_mutexattr_destroy(&mutexattr) #define DCA pthread_condattr_destroy(&condattr) #define DL pthread_mutex_destroy(&rwlock->lock) #define DR pthread_cond_destroy(&rwlock->readers) #define DW pthread_cond_destroy(&rwlock->writers) pthread_mutexattr_t mutexattr; pthread_condattr_t condattr; int pshared; if (!rwlock) return EINVAL; try(pthread_mutexattr_init(&mutexattr)) try_catch(pthread_condattr_init(&condattr), DMA) if (attr) try_catch(pthread_rwlockattr_getpshared(attr, &pshared), (DCA, DMA)) else pshared = PTHREAD_PROCESS_PRIVATE; try_catch(pthread_mutexattr_setpshared(&mutexattr, pshared), (DCA, DMA)) try_catch(pthread_condattr_setpshared(&condattr, pshared), (DCA, DMA)) try_catch(pthread_mutex_init(&rwlock->lock, &mutexattr), (DCA, DMA)) try_catch(pthread_cond_init(&rwlock->readers, &condattr), (DL, DCA, DMA)) try_catch(pthread_cond_init(&rwlock->writers, &condattr), (DR, DL, DCA, DMA)) rwlock->waiters = 0; rwlock->state = 0; return 0; #undef DMA #undef DCA #undef DL #undef DR #undef DW } /* =item I Destroys the readers/writer lock, C, that was initialised by I. It is the caller's responsibility to deallocate the memory pointed to by C if necessary. On success, returns C<0>. On error, returns an error code. =cut */ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) { if (!rwlock) return EINVAL; pthread_mutex_destroy(&rwlock->lock); pthread_cond_destroy(&rwlock->readers); pthread_cond_destroy(&rwlock->writers); return 0; } /* =item I Claims a read lock on C. Multiple threads may hold a read lock at the same time, but only if no thread holds a write lock. On success, returns C<0>. On error, returns an error code. =cut */ static void rdlock_cleanup(void *arg) { pthread_rwlock_t *rwlock = (pthread_rwlock_t *)arg; pthread_mutex_unlock(&rwlock->lock); } int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) { if (!rwlock) return EINVAL; try(pthread_mutex_lock(&rwlock->lock)) pthread_cleanup_push(rdlock_cleanup, rwlock); /* Wait until there are no active or queued writers */ while (rwlock->state == -1 || rwlock->waiters) try(pthread_cond_wait(&rwlock->readers, &rwlock->lock)) ++rwlock->state; pthread_cleanup_pop(1); return 0; } /* =item I Attempts to claim a read lock on C. On success, returns C<0>. On error, returns an error code. If C is already locked, returns C. =cut */ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) { if (!rwlock) return EINVAL; /* Are there no active or waiting writers? */ try(pthread_mutex_lock(&rwlock->lock)) if (rwlock->state != -1 && !rwlock->waiters) { ++rwlock->state; try(pthread_mutex_unlock(&rwlock->lock)) return 0; } try(pthread_mutex_unlock(&rwlock->lock)) return EBUSY; } /* =item I Claims a write lock on C. Only a single thread may hold a write lock at any point in time. On success, returns C<0>. On error, returns an error code. =cut */ static void wrlock_cleanup(void *arg) { pthread_rwlock_t *rwlock = (pthread_rwlock_t *)arg; /* ** Was the only queued writer and lock is available for readers. ** Called through cancellation clean-up so lock is held at entry. */ if (--rwlock->waiters == 0 && rwlock->state != -1) pthread_cond_broadcast(&rwlock->readers); pthread_mutex_unlock(&rwlock->lock); } int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) { if (!rwlock) return EINVAL; try(pthread_mutex_lock(&rwlock->lock)) /* Queue this writer */ ++rwlock->waiters; pthread_cleanup_push(wrlock_cleanup, rwlock); /* Wait until readers have finished */ while (rwlock->state != 0) try(pthread_cond_wait(&rwlock->writers, &rwlock->lock)) rwlock->state = -1; pthread_cleanup_pop(1); return 0; } /* =item I Attempts to claim a write lock on C. On success, returns C<0>. On error, returns an error code. If C is already locked, returns C. =cut */ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) { if (!rwlock) return EINVAL; try(pthread_mutex_lock(&rwlock->lock)) /* Are there no readers and no active or queued writers? */ if (rwlock->state == 0 && rwlock->waiters == 0) { rwlock->state = -1; try(pthread_mutex_unlock(&rwlock->lock)) return 0; } try(pthread_mutex_unlock(&rwlock->lock)) return EBUSY; } /* =item I Unlocks C. On success, returns C<0>. On error, returns an error code. =cut */ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) { if (!rwlock) return EINVAL; /* Writer releasing lock */ if (rwlock->state == -1) { /* Mark as available */ rwlock->state = 0; /* Signal queued writers if any, or broadcast to readers */ if (rwlock->waiters) try(pthread_cond_signal(&rwlock->writers)) else try(pthread_cond_broadcast(&rwlock->readers)) } else { /* Reader releasing lock */ if (--rwlock->state == 0) try(pthread_cond_signal(&rwlock->writers)) } try(pthread_mutex_unlock(&rwlock->lock)) return 0; } /* =item I Initialises the readers/writer lock attribute object, C. On success, returns C<0>. On error, returns an error code. =cut */ int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) { if (!attr) return EINVAL; attr->pshared = PTHREAD_PROCESS_PRIVATE; return 0; } /* =item I Destroys the readers/writer lock attribute object, C, that was initialised by I. Note that the memory pointed to by C may also need to be deallocated separately. On success, returns C<0>. On error, returns an error code. =cut */ int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) { if (!attr) return EINVAL; return 0; } /* =item I Stores the C attribute of C into C<*pshared>. On success, returns C<0>. On error, returns an error code. =cut */ int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared) { if (!attr || !pshared) return EINVAL; *pshared = attr->pshared; return 0; } /* =item I Sets the C attribute of C to C. On success, returns C<0>. On error, returns an error code. Note that under I, C must be C or I will subsequently fail. =cut */ int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) { if (!attr) return EINVAL; if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) return EINVAL; attr->pshared = pshared; return 0; } #endif /* =back =head1 ERRORS On error, C is set, either by an underlying function, or as follows: =over 4 =item C Arguments are C or invalid. =back =head1 MT-Level I =head1 EXAMPLES A mutex example: #include #include int main(int ac, char **av) { pthread_mutex_t mutex[1]; Locker *locker; errno = pthread_mutex_init(mutex, NULL); locker = locker_create_mutex(mutex); errno = locker_rdlock(locker); errno = locker_unlock(locker); errno = locker_wrlock(locker); errno = locker_unlock(locker); locker_destroy(&locker); pthread_mutex_destroy(mutex); return EXIT_SUCCESS; } A rwlock example: #include #include int main(int ac, char **av) { pthread_rwlock_t rwlock[1]; Locker *locker; errno = pthread_rwlock_init(rwlock, NULL); locker = locker_create_rwlock(rwlock); errno = locker_rdlock(locker); errno = locker_unlock(locker); errno = locker_wrlock(locker); errno = locker_unlock(locker); locker_destroy(&locker); pthread_rwlock_destroy(rwlock); return EXIT_SUCCESS; } A debug mutex example: #include #include int main(int ac, char **av) { pthread_mutex_t mutex[1]; Locker *locker; errno = pthread_mutex_init(mutex, NULL); locker = locker_create_debug_mutex(mutex); errno = locker_rdlock(locker); errno = locker_unlock(locker); errno = locker_wrlock(locker); errno = locker_unlock(locker); locker_destroy(&locker); pthread_mutex_destroy(mutex); return EXIT_SUCCESS; } A debug rwlock example: #include #include int main(int ac, char **av) { pthread_rwlock_t rwlock[1]; Locker *locker; errno = pthread_rwlock_init(rwlock, NULL); locker = locker_create_debug_rwlock(rwlock); errno = locker_rdlock(locker); errno = locker_unlock(locker); errno = locker_wrlock(locker); errno = locker_unlock(locker); locker_destroy(&locker); pthread_rwlock_destroy(rwlock); return EXIT_SUCCESS; } A non-locking example: #include #include int main(int ac, char **av) { Locker *locker = NULL; errno = locker_rdlock(locker); errno = locker_unlock(locker); errno = locker_wrlock(locker); errno = locker_unlock(locker); return EXIT_SUCCESS; } =head1 SEE ALSO I, C =head1 AUTHOR 20210220 raf =cut */ #endif #ifdef TEST #include #include struct List /* identical to list.c */ { size_t size; /* number of item slots allocated */ size_t length; /* number of items used */ void **list; /* vector of items (void *) */ list_release_t *destroy; /* item destructor, if any */ Lister *lister; /* built-in iterator */ Locker *locker; /* locking strategy for this object */ }; /* Unsafe */ #define list_length_test_nolock_macro(list) ((list) ? (list)->length : -1) ssize_t list_length_test_nolock_func(const List *list) { if (!list) return -1; return list->length; } /* MT-Safe */ ssize_t list_length_test_direct_mutex(const List *list, pthread_mutex_t *mutex) { size_t length; if (!list) return -1; if (pthread_mutex_lock(mutex)) return -1; length = list->length; if (pthread_mutex_unlock(mutex)) return -1; return length; } ssize_t list_length_test_direct_rwlock(const List *list, pthread_rwlock_t *rwlock) { size_t length; if (!list) return -1; if (pthread_rwlock_rdlock(rwlock)) return -1; length = list->length; if (pthread_rwlock_unlock(rwlock)) return -1; return length; } /* MT-Disciplined */ ssize_t list_length_test_lock_funcptr(const List *list, lockerf_t *lockf, lockerf_t *unlockf, void *lock) { size_t length; if (!list) return -1; if (lock && lockf(lock)) return -1; length = list->length; if (lock && unlockf(lock)) return -1; return length; } ssize_t list_length_test_lock_funcptr_1test(const List *list, lockerf_t *lockf, lockerf_t *unlockf, void *lock) { size_t length; if (!list) return -1; if (!lock) return list->length; if (lockf(lock)) return -1; length = list->length; if (unlockf(lock)) return -1; return length; } ssize_t list_length_test_separate_locker(const List *list, Locker *locker) { size_t length; if (!list) return -1; if (locker_rdlock(locker)) return -1; length = list->length; if (locker_unlock(locker)) return -1; return length; } ssize_t list_length_test_separate_locker_1test(const List *list, Locker *locker) { size_t length; if (!list) return -1; if (!locker) return list->length; if (locker->rdlock(locker->lock)) return -1; length = list->length; if (locker->unlock(locker->lock)) return -1; return length; } ssize_t list_length_test_builtin_locker(const List *list) { size_t length; if (!list) return -1; if (locker_rdlock(list->locker)) return -1; length = list->length; if (locker_unlock(list->locker)) return -1; return length; } ssize_t list_length_test_builtin_locker_cacheaddr(const List *list) { size_t length; Locker *locker; if (!list) return -1; locker = list->locker; if (locker_rdlock(locker)) return -1; length = list->length; if (locker_unlock(locker)) return -1; return length; } ssize_t list_length_test_builtin_locker_1test(const List *list) { size_t length; if (!list) return -1; if (!list->locker) return list->length; if (list->locker->rdlock(list->locker->lock)) return -1; length = list->length; if (list->locker->unlock(list->locker->lock)) return -1; return length; } ssize_t list_length_test_builtin_locker_1test_cacheaddr(const List *list) { size_t length; Locker *locker; lockerf_t *rdlock; lockerf_t *unlock; void *lock; if (!list) return -1; if (!list->locker) return list->length; locker = list->locker; rdlock = locker->rdlock; unlock = locker->unlock; lock = locker->lock; if (rdlock(lock)) return -1; length = list->length; if (unlock(lock)) return -1; return length; } int main(int ac, char **av) { int errors = 0; int debug; Locker *locker; pthread_mutex_t mutex[1]; pthread_rwlock_t rwlock[1]; if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s [debug]\n", *av); return EXIT_SUCCESS; } printf("Testing: %s\n", "locker"); /* ** Note: Debug lockers are not tested by default. Invoke the test with ** av[1] == "debug" to use debug lockers instead of ordinary lockers. ** Local implementation of rwlocks are not tested unless your system ** requires them. */ debug = (av[1] && !strcmp(av[1], "debug")); if (debug) setbuf(stdout, NULL); /* Test mutex lockers */ if ((errno = pthread_mutex_init(mutex, NULL))) ++errors, printf("Test1: failed to perform test: pthread_mutex_init() failed: err = %d\n", errno); else if (!(locker = (debug ? locker_create_debug_mutex : locker_create_mutex)(mutex))) ++errors, printf("Test1: %s() failed (%s)\n", debug ? "locker_create_debug_mutex" : "locker_create_mutex", strerror(errno)); else { if ((errno = locker_tryrdlock(locker))) ++errors, printf("Test2: locker_tryrdlock(mutex_locker) failed (%s)\n", strerror(errno)); else if ((errno = locker_unlock(locker))) ++errors, printf("Test3: locker_unlock(mutex_locker) failed (%s)\n", strerror(errno)); if ((errno = locker_rdlock(locker))) ++errors, printf("Test4: locker_rdlock(mutex_locker) failed (%s)\n", strerror(errno)); else if ((errno = locker_unlock(locker))) ++errors, printf("Test5: locker_unlock(mutex_locker) failed (%s)\n", strerror(errno)); if ((errno = locker_trywrlock(locker))) ++errors, printf("Test6: locker_trywrlock(mutex_locker) failed (%s)\n", strerror(errno)); else if ((errno = locker_unlock(locker))) ++errors, printf("Test7: locker_unlock(mutex_locker) failed (%s)\n", strerror(errno)); if ((errno = locker_wrlock(locker))) ++errors, printf("Test8: locker_wrlock(mutex_locker) failed (%s)\n", strerror(errno)); else if ((errno = locker_unlock(locker))) ++errors, printf("Test9: locker_unlock(mutex_locker) failed (%s)\n", strerror(errno)); locker_destroy(&locker); if (locker) ++errors, printf("Test10: locker_destroy(mutex_locker) failed (%s)\n", strerror(errno)); } pthread_mutex_destroy(mutex); /* Test rwlock lockers */ if ((errno = pthread_rwlock_init(rwlock, NULL))) ++errors, printf("Test11: failed to perform test: pthread_rwlock_init() failed: err = %d\n", errno); else if (!(locker = (debug ? locker_create_debug_rwlock : locker_create_rwlock)(rwlock))) ++errors, printf("Test11: %s() failed (%s)\n", debug ? "locker_create_debug_rwlock" : "locker_create_rwlock", strerror(errno)); else { if ((errno = locker_tryrdlock(locker))) ++errors, printf("Test12: locker_tryrdlock(rwlock_locker) failed (%s)\n", strerror(errno)); else if ((errno = locker_unlock(locker))) ++errors, printf("Test13: locker_unlock(rwlock_locker) failed (%s)\n", strerror(errno)); if ((errno = locker_rdlock(locker))) ++errors, printf("Test14: locker_rdlock(rwlock_locker) failed (%s)\n", strerror(errno)); else if ((errno = locker_unlock(locker))) ++errors, printf("Test15: locker_unlock(rwlock_locker) failed (%s)\n", strerror(errno)); if ((errno = locker_trywrlock(locker))) ++errors, printf("Test16: locker_trywrlock(rwlock_locker) failed (%s)\n", strerror(errno)); else if ((errno = locker_unlock(locker))) ++errors, printf("Test17: locker_unlock(rwlock_locker) failed (%s)\n", strerror(errno)); if ((errno = locker_wrlock(locker))) ++errors, printf("Test18: locker_wrlock(rwlock_locker) failed (%s)\n", strerror(errno)); else if ((errno = locker_unlock(locker))) ++errors, printf("Test19: locker_unlock(rwlock_locker) failed (%s)\n", strerror(errno)); locker_destroy(&locker); if (locker) ++errors, printf("Test20: locker_destroy(rwlock_locker) failed (%s)\n", strerror(errno)); } pthread_rwlock_destroy(rwlock); /* Timing tests */ if (av[1] && !strcmp(av[1], "time")) { List *list, *mutex_list, *rwlock_list; clock_t start, end; size_t i, length; pthread_mutex_t mutex; Locker *mutex_locker; pthread_rwlock_t rwlock; Locker *rwlock_locker; double nm, nf; double dm, dr; double np, mp, rp, np1, mp1, rp1; double nsl, msl, rsl, nsl1, msl1, rsl1; double nbl, mbl, rbl, nblc, mblc, rblc; double nbl1, mbl1, rbl1, nbl1c, mbl1c, rbl1c; printf("Timing: struct attribute accesses with differing MT safety\n"); list = list_make(NULL, "...", NULL); pthread_mutex_init(&mutex, NULL); mutex_locker = locker_create_mutex(&mutex); mutex_list = list_create_with_locker(mutex_locker, NULL); pthread_rwlock_init(&rwlock, NULL); rwlock_locker = locker_create_rwlock(&rwlock); rwlock_list = list_create_with_locker(rwlock_locker, NULL); #define ITERATIONS 10000000 #define TIME_TEST(label, base, basetime, timevar, action) \ start = clock(); \ for (i = 0; i < ITERATIONS; ++i) \ action; \ end = clock(); \ timevar = ((double)(end - start) / (double)CLOCKS_PER_SEC) / ITERATIONS * 1000000000; \ printf(" %-39s %g ns", (label), (timevar)); \ if (!base) \ { \ printf(" (overhead = %g ns", (timevar) - (basetime)); \ if ((basetime) != 0.0) \ printf(" = %g%%", (((timevar) / (basetime)) - 1.0) * 100); \ printf(")"); \ } \ printf("\n"); printf(" Unsafe:\n"); TIME_TEST("nolock/macro", 1, 0.0, nm, length = list_length_test_nolock_macro(list)) TIME_TEST("nolock/func", 1, 0.0, nf, length = list_length_test_nolock_func(list)) printf("\n"); printf(" MT-Safe:\n"); TIME_TEST("direct mutex", 1, 0.0, dm, length = list_length_test_direct_mutex(list, &mutex)) TIME_TEST("direct rwlock", 1, 0.0, dr, length = list_length_test_direct_rwlock(list, &rwlock)) printf("\n"); printf(" MT-Disciplined:\n"); TIME_TEST("null pointers", 0, nf, np, length = list_length_test_lock_funcptr(list, NULL, NULL, NULL)) TIME_TEST("null pointers (1test)", 0, nf, np1, length = list_length_test_lock_funcptr_1test(list, NULL, NULL, NULL)) TIME_TEST("null separate locker", 0, nf, nsl, length = list_length_test_separate_locker(list, NULL)) TIME_TEST("null separate locker (1test)", 0, nf, nsl1, length = list_length_test_separate_locker_1test(list, NULL)) TIME_TEST("null builtin locker", 0, nf, nbl, length = list_length_test_builtin_locker(list)) TIME_TEST("null builtin locker (1test)", 0, nf, nbl1, length = list_length_test_builtin_locker_1test(list)) TIME_TEST("null builtin locker (cacheaddr)", 0, nf, nblc, length = list_length_test_builtin_locker_cacheaddr(list)) TIME_TEST("null builtin locker (1test/cacheaddr)", 0, nf, nbl1c, length = list_length_test_builtin_locker_1test_cacheaddr(list)) printf("\n"); TIME_TEST("mutex pointers", 0, dm, mp, length = list_length_test_lock_funcptr(mutex_list, (lockerf_t *)pthread_mutex_lock, (lockerf_t *)pthread_mutex_unlock, &mutex)) TIME_TEST("mutex pointers (1test)", 0, dm, mp1, length = list_length_test_lock_funcptr_1test(mutex_list, (lockerf_t *)pthread_mutex_lock, (lockerf_t *)pthread_mutex_unlock, &mutex)) TIME_TEST("mutex separate locker", 0, dm, msl, length = list_length_test_separate_locker(mutex_list, mutex_locker)) TIME_TEST("mutex separate locker (1test)", 0, dm, msl1, length = list_length_test_separate_locker_1test(mutex_list, mutex_locker)) TIME_TEST("mutex builtin locker", 0, dm, mbl, length = list_length_test_builtin_locker(mutex_list)) TIME_TEST("mutex builtin locker (1test)", 0, dm, mbl1, length = list_length_test_builtin_locker_1test(mutex_list)) TIME_TEST("mutex builtin locker (cacheaddr)", 0, dm, mblc, length = list_length_test_builtin_locker_cacheaddr(mutex_list)) TIME_TEST("mutex builtin locker (1test/cacheaddr)", 0, dm, mbl1c, length = list_length_test_builtin_locker_1test_cacheaddr(mutex_list)) printf("\n"); TIME_TEST("rwlock pointers", 0, dr, rp, length = list_length_test_lock_funcptr(rwlock_list, (lockerf_t *)pthread_rwlock_rdlock, (lockerf_t *)pthread_rwlock_unlock, &rwlock)) TIME_TEST("rwlock pointers (1test)", 0, dr, rp1, length = list_length_test_lock_funcptr_1test(rwlock_list, (lockerf_t *)pthread_rwlock_rdlock, (lockerf_t *)pthread_rwlock_unlock, &rwlock)) TIME_TEST("rwlock separate locker", 0, dr, rsl, length = list_length_test_separate_locker(rwlock_list, rwlock_locker)) TIME_TEST("rwlock separate locker (1test)", 0, dr, rsl1, length = list_length_test_separate_locker_1test(rwlock_list, rwlock_locker)) TIME_TEST("rwlock builtin locker", 0, dr, rbl, length = list_length_test_builtin_locker(rwlock_list)) TIME_TEST("rwlock builtin locker (1test)", 0, dr, rbl1, length = list_length_test_builtin_locker_1test(rwlock_list)) TIME_TEST("rwlock builtin locker (cacheaddr)", 0, dr, rblc, length = list_length_test_builtin_locker_cacheaddr(rwlock_list)) TIME_TEST("rwlock builtin locker (1test/cacheaddr)", 0, dr, rbl1c, length = list_length_test_builtin_locker_1test_cacheaddr(rwlock_list)) printf("\n"); /* Suppress compiler warning */ if (length) length = 0; list_release(list); list_release(mutex_list); locker_release(mutex_locker); pthread_mutex_destroy(&mutex); list_release(rwlock_list); locker_release(rwlock_locker); pthread_rwlock_destroy(&rwlock); } if (errors) printf("%d/20 tests failed\n", errors); else printf("All tests passed\n"); return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/locker.h0000644000175000017500000000713214014141213014134 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_LOCKER_H #define LIBSLACK_LOCKER_H #include #include typedef struct Locker Locker; typedef int lockerf_t(void *lock); #ifndef HAVE_PTHREAD_RWLOCK typedef struct pthread_rwlock_t pthread_rwlock_t; typedef struct pthread_rwlockattr_t pthread_rwlockattr_t; struct pthread_rwlock_t { pthread_mutex_t lock; /* Lock for structure */ pthread_cond_t readers; /* Are there readers waiting? */ pthread_cond_t writers; /* Are there writers waiting? */ int waiters; /* Number of writers waiting */ int state; /* State: -1 -> writer, 0 -> idle, +ve -> readers */ }; struct pthread_rwlockattr_t { int pshared; /* Shared between processes or not */ }; #define PTHREAD_RWLOCK_INITIALIZER \ { \ PTHREAD_MUTEX_INITIALIZER, \ PTHREAD_COND_INITIALIZER, \ PTHREAD_COND_INITIALIZER, \ 0, 0 \ } #endif _begin_decls Locker *locker_create_mutex(pthread_mutex_t *mutex); Locker *locker_create_rwlock(pthread_rwlock_t *rwlock); Locker *locker_create_debug_mutex(pthread_mutex_t *mutex); Locker *locker_create_debug_rwlock(pthread_rwlock_t *rwlock); Locker *locker_create(void *lock, lockerf_t *tryrdlock, lockerf_t *rdlock, lockerf_t *trywrlock, lockerf_t *wrlock, lockerf_t *unlock); void locker_release(Locker *locker); void *locker_destroy(Locker **locker); int locker_tryrdlock(Locker *locker); int locker_rdlock(Locker *locker); int locker_trywrlock(Locker *locker); int locker_wrlock(Locker *locker); int locker_unlock(Locker *locker); #ifndef HAVE_PTHREAD_RWLOCK int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); int pthread_rwlockattr_init(pthread_rwlockattr_t *attr); int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr); int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared); #endif _end_decls /* Don't look below here - optimisations only */ struct Locker { void *lock; lockerf_t *tryrdlock; lockerf_t *rdlock; lockerf_t *trywrlock; lockerf_t *wrlock; lockerf_t *unlock; }; #define locker_tryrdlock(locker) ((locker) ? (locker)->tryrdlock((locker)->lock) : 0) #define locker_rdlock(locker) ((locker) ? (locker)->rdlock((locker)->lock) : 0) #define locker_trywrlock(locker) ((locker) ? (locker)->trywrlock((locker)->lock) : 0) #define locker_wrlock(locker) ((locker) ? (locker)->wrlock((locker)->lock) : 0) #define locker_unlock(locker) ((locker) ? (locker)->unlock((locker)->lock) : 0) #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/map.c0000644000175000017500000022121214014141213013422 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ /* =head1 NAME I - map module =head1 SYNOPSIS #include #include typedef struct Map Map; typedef struct Mapper Mapper; typedef struct Mapping Mapping; typedef list_release_t map_release_t; typedef list_copy_t map_copy_t; typedef list_cmp_t map_cmp_t; typedef size_t map_hash_t(size_t table_size, const void *key); typedef void map_action_t(void *key, void *item, void *data); Map *map_create(map_release_t *destroy); Map *map_create_sized(size_t size, map_release_t *destroy); Map *map_create_with_hash(map_hash_t *hash, map_release_t *destroy); Map *map_create_sized_with_hash(size_t size, map_hash_t *hash, map_release_t *destroy); Map *map_create_with_locker(Locker *locker, map_release_t *destroy); Map *map_create_with_locker_sized(Locker *locker, size_t size, map_release_t *destroy); Map *map_create_with_locker_with_hash(Locker *locker, map_hash_t *hash, map_release_t *destroy); Map *map_create_with_locker_sized_with_hash(Locker *locker, size_t size, map_hash_t *hash, map_release_t *destroy); Map *map_create_generic(map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy); Map *map_create_generic_sized(size_t size, map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy); Map *map_create_generic_with_locker(Locker *locker, map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy); Map *map_create_generic_with_locker_sized(Locker *locker, size_t size, map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy); int map_rdlock(const Map *map); int map_wrlock(const Map *map); int map_unlock(const Map *map); void map_release(Map *map); void *map_destroy(Map **map); int map_own(Map *map, map_release_t *destroy); int map_own_unlocked(Map *map, map_release_t *destroy); map_release_t *map_disown(Map *map); map_release_t *map_disown_unlocked(Map *map); int map_add(Map *map, const void *key, void *value); int map_add_unlocked(Map *map, const void *key, void *value); int map_put(Map *map, const void *key, void *value); int map_put_unlocked(Map *map, const void *key, void *value); int map_insert(Map *map, const void *key, void *value, int replace); int map_insert_unlocked(Map *map, const void *key, void *value, int replace); int map_remove(Map *map, const void *key); int map_remove_unlocked(Map *map, const void *key); void *map_get(Map *map, const void *key); void *map_get_unlocked(const Map *map, const void *key); Mapper *mapper_create(Map *map); Mapper *mapper_create_rdlocked(Map *map); Mapper *mapper_create_wrlocked(Map *map); Mapper *mapper_create_unlocked(Map *map); void mapper_release(Mapper *mapper); void mapper_release_unlocked(Mapper *mapper); void *mapper_destroy(Mapper **mapper); void *mapper_destroy_unlocked(Mapper **mapper); int mapper_has_next(Mapper *mapper); void *mapper_next(Mapper *mapper); const Mapping *mapper_next_mapping(Mapper *mapper); void mapper_remove(Mapper *mapper); int map_has_next(Map *map); void map_break(Map *map); void *map_next(Map *map); const Mapping *map_next_mapping(Map *map); void map_remove_current(Map *map); const void *mapping_key(const Mapping *mapping); const void *mapping_value(const Mapping *mapping); List *map_keys(Map *map); List *map_keys_unlocked(Map *map); List *map_keys_with_locker(Locker *locker, Map *map); List *map_keys_with_locker_unlocked(Locker *locker, Map *map); List *map_values(Map *map); List *map_values_unlocked(Map *map); List *map_values_with_locker(Locker *locker, Map *map); List *map_values_with_locker_unlocked(Locker *locker, Map *map); void map_apply(Map *map, map_action_t *action, void *data); void map_apply_rdlocked(Map *map, map_action_t *action, void *data); void map_apply_wrlocked(Map *map, map_action_t *action, void *data); void map_apply_unlocked(Map *map, map_action_t *action, void *data); ssize_t map_size(Map *map); ssize_t map_size_unlocked(const Map *map); =head1 DESCRIPTION This module provides functions for manipulating and iterating over a set of mappings from one object to another object, also known as hashes or associative arrays. Is may own their items. Is created with a non-C destroy function use that function to destroy an item when it is removed from the map and to destroy each item when the map itself it destroyed. Is are hash tables with C<11> buckets by default. They grow when necessary, approximately doubling in size each time up to a maximum size of C<26,214,401> buckets. =over 4 =cut */ #ifndef _BSD_SOURCE #define _BSD_SOURCE /* For snprintf() on OpenBSD-4.7 */ #endif #ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE /* New name for _BSD_SOURCE */ #endif #include "config.h" #include "std.h" #include "map.h" #include "mem.h" #include "err.h" #include "locker.h" struct Map { size_t size; /* number of buckets */ size_t items; /* number of items */ List **chain; /* array of hash buckets */ map_hash_t *hash; /* hash function */ map_copy_t *copy; /* key copy function */ map_cmp_t *cmp; /* key comparison function */ map_release_t *key_destroy; /* destructor function for keys */ map_release_t *value_destroy; /* destructor function for items */ Mapper *mapper; /* built-in iterator */ Locker *locker; /* locking strategy for this object */ }; struct Mapping { void *key; /* a map key */ void *value; /* a map value */ map_release_t *key_destroy; /* destructor function for key */ map_release_t *value_destroy; /* destructor function for value */ }; struct Mapper { Map *map; /* the map being iterated over */ ssize_t chain_index; /* the index of the chain of the current item */ ssize_t item_index; /* the index of the current item */ ssize_t next_chain_index; /* the index of the chain of the next item */ ssize_t next_item_index; /* the index of the next item */ }; #ifndef TEST /* Increasing sequence of valid (i.e. prime) table sizes to choose from. */ static const size_t table_sizes[] = { 11, 23, 47, 101, 199, 401, 797, 1601, 3203, 6397, 12799, 25601, 51199, 102397, 204803, 409597, 819187, 1638431, 3276799, 6553621, 13107197, 26214401 }; static const size_t num_table_sizes = sizeof(table_sizes) / sizeof(table_sizes[0]); /* Average bucket length threshold that must be reached before a map grows */ static const double table_resize_factor = 2.0; #if 0 /* C JPW hash function. Returns a hash value (in the range 0..size-1) for C. */ static size_t hash(size_t size, const void *key) { unsigned char *k = key; size_t g, h = 0; while (*k) if ((g = (h <<= 4, h += *k++) & 0xf0000000)) h ^= (g >> 24) ^ g; return h % size; } #endif /* C Hash function from The Practice of Programming by Kernighan and Pike (p57). Returns a hash value (in the range 0..size-1) for C. */ static size_t hash(size_t size, const void *key) { const unsigned char *k = key; size_t h = 0; while (*k) h *= 31, h += *k++; return h % size; } /* C Creates a new mapping from C to C. C is the destructor function for C. On success, returns the new mapping. On error, returns C with C set appropriately. */ static Mapping *mapping_create(void *key, void *value, map_release_t *key_destroy, map_release_t *value_destroy) { Mapping *mapping; if (!(mapping = mem_new(Mapping))) /* XXX decouple */ return NULL; mapping->key = key; mapping->value = value; mapping->key_destroy = key_destroy; mapping->value_destroy = value_destroy; return mapping; } /* C Releases (deallocates) C, destroying its value if necessary. */ static void mapping_release(Mapping *mapping) { if (!mapping) return; if (mapping->key_destroy) mapping->key_destroy(mapping->key); if (mapping->value_destroy) mapping->value_destroy(mapping->value); mem_release(mapping); } /* =item C Creates a small I with string keys and C as its item destructor. It is the caller's responsibility to deallocate the new map with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new map. On error, returns C with C set appropriately. =cut */ Map *map_create(map_release_t *destroy) { return map_create_sized_with_hash(table_sizes[0], (map_hash_t *)hash, destroy); } /* =item C Equivalent to I except that the initial number of buckets is approximately C. The actual size will be the first prime greater than or equal to C in a prebuilt sequence of primes between C<11> and C<26,214,401> that double at each step. =cut */ Map *map_create_sized(size_t size, map_release_t *destroy) { return map_create_sized_with_hash(size, (map_hash_t *)hash, destroy); } /* =item C Equivalent to I except that C is used as the hash function. The arguments to C are a I specifying the number of buckets, and a I specifying the key to hash. It must return a I between zero and the table size - 1. =cut */ Map *map_create_with_hash(map_hash_t *hash, map_release_t *destroy) { return map_create_sized_with_hash(table_sizes[0], hash, destroy); } /* =item C Equivalent to I except that C is used as the hash function. The arguments to C are a I specifying the number of buckets, and a I specifying the key to hash. It must return a I between zero and the table size - 1. =cut */ Map *map_create_sized_with_hash(size_t size, map_hash_t *hash, map_release_t *destroy) { return map_create_generic_sized(size, (map_copy_t *)mem_strdup, (map_cmp_t *)strcmp, hash, (map_release_t *)free, destroy); } /* =item C Equivalent to I except that multiple threads accessing the new map will be synchronised by C. =cut */ Map *map_create_with_locker(Locker *locker, map_release_t *destroy) { return map_create_with_locker_sized_with_hash(locker, table_sizes[0], (map_hash_t *)hash, destroy); } /* =item C Equivalent to I except that multiple threads accessing the new map will be synchronised by C. =cut */ Map *map_create_with_locker_sized(Locker *locker, size_t size, map_release_t *destroy) { return map_create_with_locker_sized_with_hash(locker, size, (map_hash_t *)hash, destroy); } /* =item C Equivalent to I except that multiple threads accessing the new map will be synchronised by C. =cut */ Map *map_create_with_locker_with_hash(Locker *locker, map_hash_t *hash, map_release_t *destroy) { return map_create_with_locker_sized_with_hash(locker, table_sizes[0], hash, destroy); } /* =item C Equivalent to I except that multiple threads accessing the new map will be synchronised by C. =cut */ Map *map_create_with_locker_sized_with_hash(Locker *locker, size_t size, map_hash_t *hash, map_release_t *destroy) { return map_create_generic_with_locker_sized(locker, size, (map_copy_t *)mem_strdup, (map_cmp_t *)strcmp, hash, (map_release_t *)free, destroy); } /* =item C Equivalent to I except that the mapping keys can be of any type. C is used to copy mapping keys. The argument to C is the key to be copied. It must return a copy of its argument. C is used to compare mapping keys. The arguments to C are two keys to be compared. It must return < 0 if the first compares less than the second, 0 if they compare equal and > 0 if the first compares greater than the second. C is the hash function. The arguments to C are a I specifying the number of buckets, and a I specifying the key to hash. It must return a I between zero and the table size - 1. C is the destructor for mapping keys. C is the destructor for mapping values. On success, returns the new map. On error, returns C with C set appropriately. =cut */ Map *map_create_generic(map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy) { return map_create_generic_with_locker_sized(NULL, table_sizes[0], copy, cmp, hash, key_destroy, value_destroy); } /* =item C Equivalent to I except that the initial number of buckets is approximately C. The actual size will be the first prime greater than or equal to C in a prebuilt sequence of primes between C<11> and C<26,214,401> that double at each step. =cut */ Map *map_create_generic_sized(size_t size, map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy) { return map_create_generic_with_locker_sized(NULL, size, copy, cmp, hash, key_destroy, value_destroy); } /* =item C Equivalent to I except that multiple threads accessing the new map will be synchronised by C. =cut */ Map *map_create_generic_with_locker(Locker *locker, map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy) { return map_create_generic_with_locker_sized(locker, table_sizes[0], copy, cmp, hash, key_destroy, value_destroy); } /* =item C Equivalent to I except that multiple threads accessing the new map will be synchronised by C. =cut */ Map *map_create_generic_with_locker_sized(Locker *locker, size_t size, map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy) { Map *map; size_t i; for (i = 0; i < num_table_sizes; ++i) { if (table_sizes[i] >= size) { size = table_sizes[i]; break; } } if (i == num_table_sizes) return set_errnull(EINVAL); if (!(map = mem_new(Map))) /* XXX decouple */ return NULL; if (!(map->chain = mem_create(size, List *))) { mem_release(map); return NULL; } map->size = size; map->items = 0; memset(map->chain, 0, map->size * sizeof(List *)); map->hash = hash; map->copy = copy; map->cmp = cmp; map->key_destroy = key_destroy; map->value_destroy = value_destroy; map->mapper = NULL; map->locker = locker; return map; } /* =item C Claims a read lock on C (if C was created with a I). This is needed when multiple read-only I module functions need to be called atomically. It is the client's responsibility to call I after the atomic operation. The only functions that may be called on C between calls to I and I are any read-only I module functions whose name ends with C<_unlocked>. On success, returns C<0>. On error, returns an error code. =cut */ #define map_rdlock(map) ((map) ? locker_rdlock((map)->locker) : EINVAL) #define map_wrlock(map) ((map) ? locker_wrlock((map)->locker) : EINVAL) #define map_unlock(map) ((map) ? locker_unlock((map)->locker) : EINVAL) int (map_rdlock)(const Map *map) { return map_rdlock(map); } /* =item C Claims a write lock on C (if C was created with a I). This is needed when multiple read/write I module functions need to be called atomically. It is the client's responsibility to subsequently call I. The only functions that may be called on C between calls to I and I are any I module functions whose name ends with C<_unlocked>. On success, returns C<0>. On error, returns an error code. =cut */ int (map_wrlock)(const Map *map) { return map_wrlock(map); } /* =item C Unlocks a read or write lock on C obtained with I or I (if C was created with a C). On success, returns C<0>. On error, returns an error code. =cut */ int (map_unlock)(const Map *map) { return map_unlock(map); } /* =item C Releases (deallocates) C, destroying its items if necessary. On error, sets C appropriately. =cut */ void map_release(Map *map) { size_t i; if (!map) return; for (i = 0; i < map->size; ++i) list_release(map->chain[i]); mem_release(map->chain); mem_release(map); } /* =item C Destroys (deallocates and sets to C) C<*map>. Returns C. B maps shared by multiple threads must not be destroyed until after all threads have finished with it. =cut */ void *map_destroy(Map **map) { if (map && *map) { map_release(*map); *map = NULL; } return NULL; } /* =item C Causes C to take ownership of its items. The items will be destroyed using C when their mappings are removed from C or when C is destroyed. On success, returns C<0>. On error, returns C<-1> with C set appropriately. =cut */ int map_own(Map *map, map_release_t *destroy) { int ret; int err; if (!map || !destroy) return set_errno(EINVAL); if ((err = map_wrlock(map))) return set_errno(err); ret = map_own_unlocked(map, destroy); if ((err = map_unlock(map))) return set_errno(err); return ret; } /* =item C Equivalent to I except that C is not write-locked. =cut */ int map_own_unlocked(Map *map, map_release_t *destroy) { ssize_t length; size_t c, i; if (!map || !destroy) return set_errno(EINVAL); if (destroy == map->value_destroy) return 0; map->value_destroy = destroy; for (c = 0; c < map->size; ++c) { List *chain = map->chain[c]; if (!chain) continue; if ((length = list_length_unlocked(chain)) == -1) return -1; for (i = 0; i < length; ++i) { Mapping *mapping = (Mapping *)list_item_unlocked(chain, i); mapping->value_destroy = destroy; } } return 0; } /* =item C Causes C to relinquish ownership of its items. The items will not be destroyed when their mappings are removed from C or when C is destroyed. On success, returns the previous destroy function, if any. On error, returns C with C set appropriately. =cut */ map_release_t *map_disown(Map *map) { map_release_t *ret; int err; if (!map) return (map_release_t *)set_errnullf(EINVAL); if ((err = map_wrlock(map))) return (map_release_t *)set_errnullf(err); ret = map_disown_unlocked(map); if ((err = map_unlock(map))) return (map_release_t *)set_errnullf(err); return ret; } /* =item C Equivalent to I except that C is not write-locked. =cut */ map_release_t *map_disown_unlocked(Map *map) { ssize_t length; size_t c, i; map_release_t *destroy; if (!map) return (map_release_t *)set_errnullf(EINVAL); if (!map->value_destroy) return NULL; destroy = map->value_destroy; map->value_destroy = NULL; for (c = 0; c < map->size; ++c) { List *chain = map->chain[c]; if (!chain) continue; if ((length = list_length_unlocked(chain)) == -1) return NULL; for (i = 0; i < length; ++i) { Mapping *mapping = (Mapping *)list_item_unlocked(chain, i); mapping->value_destroy = NULL; } } return destroy; } /* C Resizes C to use the next prime in a prebuilt sequence of primes between C<11> and C<26,214,401> that is greater than the current size. On success, returns C<0>. On error, returns C<-1> with C set appropriately. */ static int map_resize(Map *map) { size_t size = 0; size_t i; Mapper *mapper; Map *new_map; if (!map) return set_errno(EINVAL); for (i = 1; i < num_table_sizes; ++i) { if (table_sizes[i] > map->size) { size = table_sizes[i]; break; } } if (i == num_table_sizes || size == 0) return set_errno(EINVAL); if (!(new_map = map_create_generic_sized(size, map->copy, map->cmp, map->hash, map->key_destroy, map->value_destroy))) return -1; if (!(mapper = mapper_create_unlocked(map))) { map_release(new_map); return -1; } while (mapper_has_next(mapper) == 1) { const Mapping *mapping = mapper_next_mapping(mapper); if (map_add_unlocked(new_map, mapping->key, mapping->value) == -1) { mapper_release_unlocked(mapper); map_release(new_map); return -1; } } mapper_release_unlocked(mapper); errno = 0; if (map_disown_unlocked(map) == NULL && errno) { map_release(new_map); return -1; } for (i = 0; i < map->size; ++i) list_release(map->chain[i]); mem_release(map->chain); map->size = new_map->size; map->items = new_map->items; map->chain = new_map->chain; map->value_destroy = new_map->value_destroy; mem_release(new_map); return 0; } /* =item C Adds the C<(key, value)> mapping to C, if C is not already present. Note that C is copied but C is not. On success, returns C<0>. On error, returns C<-1> with C set appropriately. =cut */ int map_add(Map *map, const void *key, void *value) { return map_insert(map, key, value, 0); } /* =item C Equivalent to I except that C is not write-locked. =cut */ int map_add_unlocked(Map *map, const void *key, void *value) { return map_insert_unlocked(map, key, value, 0); } /* =item C Adds the C<(key, value)> mapping to C, replacing any existing C<(key, value)> mapping. Note that C is copied but C is not. On success, returns C<0>. On error, returns C<-1> with C set appropriately. =cut */ int map_put(Map *map, const void *key, void *value) { return map_insert(map, key, value, 1); } /* =item C Equivalent to I except that C is not write-locked. =cut */ int map_put_unlocked(Map *map, const void *key, void *value) { return map_insert_unlocked(map, key, value, 1); } /* =item C Adds the C<(key, value)> mapping to C, replacing any existing C<(key, value)> mapping, if C is non-zero. Note that C is copied but C is not. On success, returns C<0>. On error, or if C is already present and C is zero, returns C<-1> with C set appropriately. =cut */ int map_insert(Map *map, const void *key, void *value, int replace) { int ret; int err; if (!map || !key) return set_errno(EINVAL); if ((err = map_wrlock(map))) return set_errno(err); ret = map_insert_unlocked(map, key, value, replace); if ((err = map_unlock(map))) return set_errno(err); return ret; } /* =item C Equivalent to I except that C is not write-locked. =cut */ int map_insert_unlocked(Map *map, const void *key, void *value, int replace) { Mapping *mapping; List *chain; ssize_t length; size_t h, c; if (!map || !key) return set_errno(EINVAL); if ((double)map->items / (double)map->size >= (double)table_resize_factor) if (map_resize(map) == -1) return -1; if ((h = map->hash(map->size, key)) >= map->size) return set_errno(EINVAL); if (!map->chain[h] && !(map->chain[h] = list_create((map_release_t *)mapping_release))) return -1; chain = map->chain[h]; if ((length = list_length_unlocked(chain)) == -1) return -1; for (c = 0; c < length; ++c) { mapping = (Mapping *)list_item_unlocked(chain, c); if (!map->cmp(mapping->key, key)) { if (replace && list_remove_unlocked(chain, c)) break; return -1; } } if (!(mapping = mapping_create(map->copy(key), value, map->key_destroy, map->value_destroy))) return -1; if (!list_append_unlocked(chain, mapping)) { mapping_release(mapping); return -1; } ++map->items; return 0; } /* =item C Removes C<(key, value)> mapping from C if it is present. If C was created with a destroy function, then the value will be destroyed. On success, returns C<0>. On error, returns C<-1> with C set appropriately. =cut */ int map_remove(Map *map, const void *key) { int ret; int err; if (!map || !key) return set_errno(EINVAL); if ((err = map_wrlock(map))) return set_errno(err); ret = map_remove_unlocked(map, key); if ((err = map_unlock(map))) return set_errno(err); return ret; } /* =item C Equivalent to I except that C is not write-locked. =cut */ int map_remove_unlocked(Map *map, const void *key) { List *chain; ssize_t length; size_t h, c; if (!map || !key) return set_errno(EINVAL); if ((h = map->hash(map->size, key)) >= map->size) return set_errno(EINVAL); if (!(chain = map->chain[h])) return set_errno(ENOENT); if ((length = list_length_unlocked(chain)) == -1) return -1; for (c = 0; c < length; ++c) { Mapping *mapping = (Mapping *)list_item_unlocked(chain, c); if (!map->cmp(mapping->key, key)) { if (!list_remove_unlocked(chain, c)) return -1; --map->items; return 0; } } return set_errno(ENOENT); } /* =item C Returns the value associated with C in C, or C if there is none. On error, returns C with C set appropriately. =cut */ void *map_get(Map *map, const void *key) { void *ret; int err; if (!map || !key) return set_errnull(EINVAL); if ((err = map_rdlock(map))) return set_errnull(err); ret = map_get_unlocked(map, key); if ((err = map_unlock(map))) return set_errnull(err); return ret; } /* =item C Equivalent to I except that C is not read-locked. =cut */ void *map_get_unlocked(const Map *map, const void *key) { List *chain; ssize_t length; size_t h, c; if (!map || !key) return set_errnull(EINVAL); if ((h = map->hash(map->size, key)) >= map->size) return set_errnull(EINVAL); if (!(chain = map->chain[h])) return set_errnull(ENOENT); if ((length = list_length_unlocked(chain)) == -1) return NULL; for (c = 0; c < length; ++c) { Mapping *mapping = (Mapping *)list_item_unlocked(chain, c); if (!map->cmp(mapping->key, key)) return mapping->value; } return set_errnull(ENOENT); } /* =item C Creates an iterator for C. The iterator keeps C write-locked until it is released with I or I. Note that the iterator itself is not locked, so it must not be shared between threads. On success, returns the iterator. On error, returns C with C set appropriately. =cut */ Mapper *mapper_create(Map *map) { return mapper_create_wrlocked(map); } /* =item C Equivalent to I except that C is read-locked rather than write-locked. Use this in preference to I when no calls to I will be made during the iteration. =cut */ Mapper *mapper_create_rdlocked(Map *map) { int err; if (!map) return set_errnull(EINVAL); if ((err = map_rdlock(map))) return set_errnull(err); return mapper_create_unlocked(map); } /* =item C Equivalent to I except that this function name makes the fact that C is write-locked explicit. =cut */ Mapper *mapper_create_wrlocked(Map *map) { int err; if (!map) return set_errnull(EINVAL); if ((err = map_wrlock(map))) return set_errnull(err); return mapper_create_unlocked(map); } /* =item C Equivalent to I except that C is not write-locked. =cut */ Mapper *mapper_create_unlocked(Map *map) { Mapper *mapper; if (!map) return set_errnull(EINVAL); if (!(mapper = mem_new(Mapper))) /* XXX decouple */ return NULL; mapper->map = map; mapper->chain_index = -1; mapper->item_index = -1; mapper->next_chain_index = -1; mapper->next_item_index = -1; return mapper; } /* =item C Releases (deallocates) C and unlocks the associated map. =cut */ void mapper_release(Mapper *mapper) { int err; if (!mapper) return; if ((err = map_unlock(mapper->map))) { set_errno(err); return; } mem_release(mapper); } /* =item C Equivalent to I except that the associated map is not unlocked. =cut */ void mapper_release_unlocked(Mapper *mapper) { if (!mapper) return; mem_release(mapper); } /* =item C Destroys (deallocates and sets to C) C<*mapper> and unlocks the associated map. Returns C. On error, sets C appropriately. =cut */ void *mapper_destroy(Mapper **mapper) { if (mapper && *mapper) { mapper_release(*mapper); *mapper = NULL; } return NULL; } /* =item C Equivalent to I except that the associated map is not unlocked. =cut */ void *mapper_destroy_unlocked(Mapper **mapper) { if (mapper && *mapper) { mapper_release_unlocked(*mapper); *mapper = NULL; } return NULL; } /* =item C Returns whether or not there is another item in the map over which C is iterating. On error, returns C<-1> with C set appropriately. =cut */ int mapper_has_next(Mapper *mapper) { List *chain; ssize_t length; if (!mapper) return set_errno(EINVAL); /* Find the current/first chain */ mapper->next_chain_index = mapper->chain_index; mapper->next_item_index = mapper->item_index; if (mapper->next_chain_index == -1) ++mapper->next_chain_index; while (mapper->next_chain_index < mapper->map->size && !mapper->map->chain[mapper->next_chain_index]) ++mapper->next_chain_index; if (mapper->next_chain_index == mapper->map->size) return 0; chain = mapper->map->chain[mapper->next_chain_index]; /* Find the next item */ if ((length = list_length_unlocked(chain)) == -1) return -1; if (++mapper->next_item_index < length) return 1; do { ++mapper->next_chain_index; while (mapper->next_chain_index < mapper->map->size && !mapper->map->chain[mapper->next_chain_index]) ++mapper->next_chain_index; if (mapper->next_chain_index == mapper->map->size) return 0; chain = mapper->map->chain[mapper->next_chain_index]; if ((length = list_length_unlocked(chain)) == -1) return -1; } while (length == 0); mapper->next_item_index = 0; return 1; } /* =item C Returns the next item in the map over which C is iterating. On error, returns C with C set appropriately. =cut */ void *mapper_next(Mapper *mapper) { if (!mapper) return set_errnull(EINVAL); return mapper_next_mapping(mapper)->value; } /* =item C Returns the next mapping (key, value) pair in the map over which C is iterating. On error, returns C with C set appropriately. =cut */ const Mapping *mapper_next_mapping(Mapper *mapper) { if (!mapper) return set_errnull(EINVAL); mapper->chain_index = mapper->next_chain_index; mapper->item_index = mapper->next_item_index; return (Mapping *)list_item_unlocked(mapper->map->chain[mapper->chain_index], mapper->item_index); } /* =item C Removes the current item in the iteration C. The next item in the iteration is the item following the removed item, if any. This must be called after I. On error, sets C appropriately. =cut */ void mapper_remove(Mapper *mapper) { if (!mapper) { set_errno(EINVAL); return; } if (mapper->item_index == -1) { set_errno(EINVAL); return; } list_remove_unlocked(mapper->map->chain[mapper->chain_index], (size_t)mapper->item_index--); --mapper->map->items; } /* =item C Returns whether or not there is another item in C using an internal iterator. The first time this is called, a new internal I will be created (Note: There can be only one at any time for a given map). When there are no more items, returns C<0> and destroys the internal iterator. When it returns C<1>, use I to retrieve the next item. On error, returns C<-1> with C set appropriately. Note: If an iteration using an internal iterator terminates before the end of the map, it is the caller's responsibility to call I. Failure to do so will cause the internal iterator to leak. It will also break the next call to I which will continue where the current iteration stopped rather than starting at the beginning again. I assumes that there is no internal iterator, so it is the caller's responsibility to complete the iteration, or call I before releasing C with I or I. Note: The internal I does not lock C so this function is not threadsafe. It can only be used with maps created in the current function (to guarantee that no other thread can access it). This practice should be observed even in single-threaded applications to avoid breaking iterator semantics (possible with nested function calls). If C is a parameter or a variable declared outside the function, it is best to create an explicit I instead. If this function is used on such maps instead, it is the caller's responsibility to explicitly lock C first with I and explicitly unlock it with I. Do this even if you are writing single-threaded code, in case your function may one day be used in a multi-threaded application. =cut */ int map_has_next(Map *map) { int has; if (!map) return set_errno(EINVAL); if (!map->mapper && !(map->mapper = mapper_create_unlocked(map))) return -1; if ((has = mapper_has_next(map->mapper)) != 1) map_break(map); return has; } /* =item C Unlocks C and destroys its internal iterator. Must be used only when an iteration using an internal iterator has terminated before reaching the end of C. On error, returns C with C set appropriately. =cut */ void map_break(Map *map) { if (!map) { set_errno(EINVAL); return; } mapper_destroy_unlocked(&map->mapper); } /* =item C Returns the next item in C using its internal iterator. On error, returns C with C set appropriately. =cut */ void *map_next(Map *map) { if (!map || !map->mapper) return set_errnull(EINVAL); return mapper_next(map->mapper); } /* =item C Returns the next mapping (key, value) pair in C using its internal iterator. On error, returns C<-1> with C set appropriately. =cut */ const Mapping *map_next_mapping(Map *map) { if (!map || !map->mapper) return set_errnull(EINVAL); return mapper_next_mapping(map->mapper); } /* =item C Removes the current item in C using its internal iterator. The next item in the iteration is the item following the removed item, if any. This must be called after I. =cut */ void map_remove_current(Map *map) { if (!map || !map->mapper) { set_errno(EINVAL); return; } mapper_remove(map->mapper); } /* =item C Returns the key in C. On error, returns C with C set appropriately. =cut */ const void *mapping_key(const Mapping *mapping) { if (!mapping) return set_errnull(EINVAL); return mapping->key; } /* =item C Returns the value in C. On error, returns C with C set appropriately. =cut */ const void *mapping_value(const Mapping *mapping) { if (!mapping) return set_errnull(EINVAL); return mapping->value; } /* =item C Creates and returns a list of all of the keys contained in C. It is the caller's responsibility to deallocate the new list with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. The keys in the new list are owned by C, so the list returned must not outlive C. On error, returns C with C set appropriately. =cut */ List *map_keys(Map *map) { return map_keys_with_locker(NULL, map); } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *map_keys_unlocked(Map *map) { return map_keys_with_locker_unlocked(NULL, map); } /* =item C Equivalent to I except that multiple threads accessing the list returned will be synchronised by C. =cut */ List *map_keys_with_locker(Locker *locker, Map *map) { List *keys; int err; if (!map) return set_errnull(EINVAL); if ((err = map_rdlock(map))) return set_errnull(err); keys = map_keys_with_locker_unlocked(locker, map); if ((err = map_unlock(map))) return set_errnull(err); return keys; } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *map_keys_with_locker_unlocked(Locker *locker, Map *map) { Mapper *mapper; List *keys; if (!map) return set_errnull(EINVAL); if (!(keys = list_create_with_locker(locker, NULL))) return NULL; if (!(mapper = mapper_create_unlocked(map))) { list_release(keys); return NULL; } while (mapper_has_next(mapper) == 1) { const Mapping *mapping = mapper_next_mapping(mapper); if (!list_append(keys, mapping->key)) { list_destroy(&keys); break; } } mapper_release_unlocked(mapper); return keys; } /* =item C Creates and returns a list of all of the values contained in C. It is the caller's responsibility to deallocate the new list with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. The values in the list are not owned by the list, so it must not outlive the owner of the items in C. On error, returns C with C set appropriately. =cut */ List *map_values(Map *map) { return map_values_with_locker(NULL, map); } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *map_values_unlocked(Map *map) { return map_values_with_locker_unlocked(NULL, map); } /* =item C Equivalent to I except that multiple threads accessing the list returned will be synchronised by C. =cut */ List *map_values_with_locker(Locker *locker, Map *map) { List *values; int err; if (!map) return set_errnull(EINVAL); if ((err = map_rdlock(map))) return set_errnull(err); values = map_values_with_locker_unlocked(locker, map); if ((err = map_unlock(map))) return set_errnull(err); return values; } /* =item C Equivalent to I except that C is not read-locked. =cut */ List *map_values_with_locker_unlocked(Locker *locker, Map *map) { Mapper *mapper; List *values; if (!map) return set_errnull(EINVAL); if (!(values = list_create_with_locker(locker, NULL))) return NULL; if (!(mapper = mapper_create_unlocked(map))) { list_release(values); return NULL; } while (mapper_has_next(mapper) == 1) { const Mapping *mapping = mapper_next_mapping(mapper); if (!list_append(values, mapping->value)) { list_destroy(&values); break; } } mapper_release_unlocked(mapper); return values; } /* =item C Invokes C for each of C's items. The arguments passed to C are the key, the item, and C. On error, sets C appropriately. =cut */ void map_apply(Map *map, map_action_t *action, void *data) { map_apply_wrlocked(map, action, data); } /* =item C Equivalent to I except that C is read-locked rather than write-locked. Use this in preference to I when C and its items will not be modified during the iteration. =cut */ void map_apply_rdlocked(Map *map, map_action_t *action, void *data) { int err; if (!map || !action) { set_errno(EINVAL); return; } if ((err = map_rdlock(map))) { set_errno(err); return; } map_apply_unlocked(map, action, data); if ((err = map_unlock(map))) { set_errno(err); return; } } /* =item C Equivalent to I except that this function name makes the fact that C is write-locked explicit. =cut */ void map_apply_wrlocked(Map *map, map_action_t *action, void *data) { int err; if (!map || !action) { set_errno(EINVAL); return; } if ((err = map_wrlock(map))) { set_errno(err); return; } map_apply_unlocked(map, action, data); if ((err = map_unlock(map))) { set_errno(err); return; } } /* =item C Equivalent to I except that C is not write-locked. =cut */ void map_apply_unlocked(Map *map, map_action_t *action, void *data) { Mapper *mapper; if (!map || !action) { set_errno(EINVAL); return; } if (!(mapper = mapper_create_unlocked(map))) return; while (mapper_has_next(mapper) == 1) { const Mapping *mapping = mapper_next_mapping(mapper); action(mapping->key, mapping->value, data); } mapper_release_unlocked(mapper); } /* =item C Returns the number of mappings in C. On error, returns C<-1> with C set appropriately. =cut */ ssize_t map_size(Map *map) { size_t size; int err; if (!map) return set_errno(EINVAL); if ((err = map_rdlock(map))) return set_errno(err); size = map->items; if ((err = map_unlock(map))) return set_errno(err); return size; } /* =item C Equivalent to I except that C is not read-locked. =cut */ ssize_t map_size_unlocked(const Map *map) { if (!map) return set_errno(EINVAL); return map->items; } /* =back =head1 ERRORS On error, C is set either by an underlying function, or as follows: =over 4 =item C When arguments are C or out of range. =item C When I tries to get, or I tries to remove, a non-existent mapping. =back =head1 MT-Level I By default, Is are not I because most programs are single-threaded, and synchronisation doesn't come for free. Even in multi-threaded programs, not all Is are necessarily shared between multiple threads. When a I is shared between multiple threads which need to be synchronised, the method of synchronisation must be carefully selected by the client code. There are tradeoffs between concurrency and overhead. The greater the concurrency, the greater the overhead. More locks give greater concurrency, but have greater overhead. Readers/Writer locks can give greater concurrency than Mutex, locks but have greater overhead. One lock for each I may be required, or one lock for all (or a set of) Is may be more appropriate. Generally, the best synchronisation strategy for a given application can only be determined by testing/benchmarking the written application. It is important to be able to experiment with the synchronisation strategy at this stage of development without pain. To facilitate this, Is can be created with I, which takes a I argument. The I specifies a lock and a set of functions for manipulating the lock. Each I can have its own lock by creating a separate I for each I. Multiple Is can share the same lock by sharing the same I. Only the application developer can determine what is appropriate for each application on a case by case basis. I means that the application developer has a mechanism for specifying the synchronisation requirements to be applied to library code. =head1 EXAMPLES Create a map that doesn't own its items, populate it, and then iterate over its values with the internal iterator to print the values: #include #include int main() { Map *map; if (!(map = map_create(NULL))) return EXIT_FAILURE; map_add(map, "abc", "123"); map_add(map, "def", "456"); map_add(map, "ghi", "789"); while (map_has_next(map) == 1) printf("%s\n", (char *)map_next(map)); map_destroy(&map); return EXIT_SUCCESS; } Create a map that does own its items, populate it, and then iterate over its items with an external iterator to print its keys and values: #include #include int main() { Map *map; Mapper *mapper; if (!(map = map_create(free))) return EXIT_FAILURE; map_add(map, "abc", strdup("123")); map_add(map, "def", strdup("456")); map_add(map, "ghi", strdup("789")); if (!(mapper = mapper_create(map))) { map_destroy(&map); return EXIT_FAILURE; } while (mapper_has_next(mapper) == 1) { const Mapping *mapping = mapper_next_mapping(mapper); printf("%s -> %s\n", (char *)mapping_key(mapping), (char *)mapping_value(mapping)); } mapper_destroy(&mapper); map_destroy(&map); return EXIT_SUCCESS; } The same, but with an apply function: #include #include void action(void *key, void *item, void *data) { printf("%s -> %s\n", (char *)key, (char *)item); } int main() { Map *map; if (!(map = map_create(free))) return EXIT_FAILURE; map_add(map, "abc", strdup("123")); map_add(map, "def", strdup("456")); map_add(map, "ghi", strdup("789")); map_apply(map, action, NULL); map_destroy(&map); return EXIT_SUCCESS; } The same, but with integer keys: #include #include static void *int_copy(const void *key) { return (void *)key; } static int int_cmp(const void *a, const void *b) { return (int)a - (int)b; } static size_t int_hash(size_t size, const void *key) { return (int)key % size; } void action(void *key, void *item, void *data) { printf("%d -> %s\n", (int)key, (char *)item); } int main(int ac, char **av) { Map *map; if (!(map = map_create_generic(int_copy, int_cmp, int_hash, NULL, free))) return EXIT_FAILURE; map_add(map, (void *)123, strdup("abc")); map_add(map, (void *)456, strdup("def")); map_add(map, (void *)789, strdup("ghi")); map_apply(map, action, NULL); map_destroy(&map); return EXIT_SUCCESS; } =head1 CAVEAT A C pointer can't be a key. Neither can zero when using integers as keys. If you use an internal iterator in a loop that terminates before the end of the map, and fail to call I, the internal iterator will leak. =head1 BUGS Uses I directly. The type of memory used and the allocation strategy should be decoupled from this code. =head1 SEE ALSO I, I, I, I =head1 AUTHOR 20210220 raf =cut */ #endif #ifdef TEST #ifndef HAVE_SNPRINTF #include #endif #if 0 static void map_print(const char *name, Map *map) { size_t i, j; if (!map) { printf("%s = nil\n", name); return; } printf("%s =\n{\n", name); for (i = 0; i < map->size; ++i) { if (map->chain[i]) { List *chain = map->chain[i]; ssize_t length = list_length(chain); if (length == -1) printf(" !!! length == -1 !!!\n"); for (j = 0; j < length; ++j) { Mapping *mapping = (Mapping *)list_item(chain, j); printf(" [%d/%d] \"%s\" -> \"%s\"\n", i, j, (char *)mapping->key, (char *)mapping->value); } } } printf("}\n"); } #endif static void map_histogram(const char *name, Map *map) { size_t i; int *histogram; if (!map) { printf("%s = nil\n", name); return; } if (!(histogram = mem_create(map->items, int))) { printf("Failed to allocate histogram for map %s\n", name); return; } memset(histogram, 0, map->items * sizeof(int)); for (i = 0; i < map->size; ++i) { size_t length = list_length(map->chain[i]); if (length == -1) { printf(" length[%d] = -1\n", (int)i); continue; } ++histogram[length]; } printf("\nhistogram %s =\n{\n", name); for (i = 0; i < map->items; ++i) if (histogram[i]) printf(" %d chain%s of length %d\n", histogram[i], (histogram[i] == 1) ? "" : "s", (int)i); printf("}\n"); } static void test_hash(void) { FILE *words = fopen("/usr/dict/words", "r"); char word[BUFSIZ]; Map *map; size_t c; size_t min = 0xffffffff; size_t max = 0x00000000; int sum = 0; if (!words) { printf("Failed to open /usr/dict/words\n"); exit(EXIT_FAILURE); } if (!(map = map_create(free))) { printf("Failed to create map\n"); exit(EXIT_FAILURE); } while (fgets(word, BUFSIZ, words)) { char *eow = strchr(word, '\n'); if (eow) *eow = nul; map_add(map, word, mem_strdup(word)); } fclose(words); printf("%d entries into %d buckets:\n\n", (int)map->items, (int)map->size); for (c = 0; c < map->size; ++c) { size_t length; if (!map->chain[c]) continue; if ((length = list_length(map->chain[c])) == -1) { printf(" length[%d] == -1\n", (int)c); continue; } if (length > max) max = length; if (length < min) min = length; sum += length; } printf("avg = %g\n", (double)sum / (double)map->size); printf("min = %d\n", (int)min); printf("max = %d\n", (int)max); map_histogram("dict", map); map_release(map); exit(EXIT_SUCCESS); } static int sort_cmp(const char **a, const char **b) { return strcmp(*a, *b); } static void test_action(char *key, char *value, char *cat) { size_t len = strlen(cat); snprintf(cat + len, BUFSIZ, "%s%s=%s", (len) ? ", " : "", key, value); } typedef struct Point Point; struct Point { int x; int y; }; static Point *point_create(int x, int y) { Point *point = mem_create(1, Point); if (!point) return NULL; point->x = x; point->y = y; return point; } static Point *point_copy(Point *point) { return point_create(point->x, point->y); } static int point_cmp(Point *a, Point *b) { if (a->x > b->x) return 1; if (a->y > b->y) return 1; if (a->x == b->x && a->y == b->y) return 0; return -1; } static size_t point_hash(size_t size, Point *point) { return (point->x * 31 + point->y * 37) % size; } static void point_release(Point *point) { mem_release(point); } static int direct_copy(int key) { return key; } static int direct_cmp(int a, int b) { return a - b; } static size_t direct_hash(size_t size, int key) { return key % size; } #define RD 0 #define WR 1 Map *mtmap = NULL; Locker *locker = NULL; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #ifdef PTHREAD_RWLOCK_INITIALIZER pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; #else pthread_rwlock_t rwlock; #endif int barrier[2]; int size[2]; const int lim = 1000; int debug = 0; int errors = 0; void *produce(void *arg) { int i; int test = *(int *)arg; for (i = 1; i <= lim; ++i) { if (debug) printf("p: add %d\n", i); if (map_add(mtmap, (void *)(long)i, (void *)(long)i) == -1) ++errors, printf("Test%d: map_add(mtmap, %d), failed (%s)\n", test, i, strerror(errno)); write(size[WR], "", 1); } write(barrier[WR], "", 1); return NULL; } void *consume(void *arg) { int i; int test = *(int *)arg; char ack; for (i = 1; i <= lim; ++i) { if (debug) printf("c: pop\n"); while (read(size[RD], &ack, 1) == -1 && errno == EINTR) {} if (map_remove(mtmap, (void *)(long)i) == -1) { ++errors, printf("Test%d: map_remove(mtmap, %d), failed\n", test, i); break; } if (debug) printf("c: remove %d\n", i); } if (i != lim + 1) ++errors, printf("Test%d: consumer read %d items, not %d\n", test, i - 1, lim); write(barrier[WR], "", 1); return NULL; } void *iterate_builtin(void *arg) { int i; int t = *(int *)arg; int broken = 0; if (debug) printf("i%d: loop\n", t); for (i = 0; i < lim / 10; ++i) { map_wrlock(mtmap); while (map_has_next(mtmap) == 1) { int val = (int)(long)map_next(mtmap); if (debug) printf("i%d: loop %d/%d val %d\n", t, i, lim / 10, val); if (!broken) { map_break(mtmap); broken = 1; break; } } map_unlock(mtmap); } write(barrier[WR], "", 1); return NULL; } void *iterate_rdlocked(void *arg) { int i; int t = *(int *)arg; if (debug) printf("j%d: loop\n", t); for (i = 0; i < lim / 10; ++i) { Mapper *mapper = mapper_create_rdlocked(mtmap); while (mapper_has_next(mapper) == 1) { int val = (int)(long)mapper_next(mapper); if (debug) printf("j%d: loop %d/%d val %d\n", t, i, lim / 10, val); } mapper_release(mapper); } write(barrier[WR], "", 1); return NULL; } void *iterate_wrlocked(void *arg) { int i; int t = *(int *)arg; if (debug) printf("k%d: loop\n", t); for (i = 0; i < lim / 10; ++i) { Mapper *mapper = mapper_create_wrlocked(mtmap); while (mapper_has_next(mapper) == 1) { int val = (int)(long)mapper_next(mapper); if (debug) printf("k%d: loop %d/%d val %d\n", t, i, lim / 10, val); } mapper_release(mapper); } write(barrier[WR], "", 1); return NULL; } pthread_mutex_t rand_mutex[1] = { PTHREAD_MUTEX_INITIALIZER }; void *reader(void *arg) { int i; int t = *(int *)arg; if (debug) printf("r%d: loop\n", t); for (i = 0; i < lim / 10; ++i) { int key, value, r; List *keys, *values; pthread_mutex_lock(rand_mutex); r = rand(); pthread_mutex_unlock(rand_mutex); map_rdlock(mtmap); key = 1 + (int)((double)(map_size_unlocked(mtmap) - 1) * r / (RAND_MAX + 1.0)); value = (int)(long)map_get_unlocked(mtmap, (void *)(long)key); map_unlock(mtmap); keys = map_keys(mtmap); values = map_values(mtmap); if (debug) printf("r%d: loop %d/%d key/val %d/%d, #keys %d, #values %d\n", t, i, lim / 10, key, value, (int)list_length(keys), (int)list_length(values)); list_destroy(&keys); list_destroy(&values); } write(barrier[WR], "", 1); return NULL; } void mt_test(int test, Locker *locker) { mtmap = map_create_generic_with_locker(locker, (map_copy_t *)direct_copy, (map_cmp_t *)direct_cmp, (map_hash_t *)direct_hash, NULL, NULL); if (!mtmap) ++errors, printf("Test%d: map_create_generic_with_locker(NULL) failed\n", test); else { static int iid[13] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; pthread_attr_t attr; pthread_t id; int i; char ack; if (pipe(size) == -1 || pipe(barrier) == -1) { ++errors, printf("Test%d: failed to perform test: pipe() failed\n", test); return; } srand(getpid() ^ time(NULL)); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&id, &attr, produce, &test); pthread_create(&id, &attr, consume, &test); pthread_create(&id, &attr, iterate_builtin, iid + 0); pthread_create(&id, &attr, iterate_builtin, iid + 1); pthread_create(&id, &attr, iterate_builtin, iid + 2); pthread_create(&id, &attr, iterate_builtin, iid + 3); pthread_create(&id, &attr, iterate_rdlocked, iid + 4); pthread_create(&id, &attr, iterate_rdlocked, iid + 5); pthread_create(&id, &attr, iterate_rdlocked, iid + 6); pthread_create(&id, &attr, iterate_wrlocked, iid + 7); pthread_create(&id, &attr, iterate_wrlocked, iid + 8); pthread_create(&id, &attr, iterate_wrlocked, iid + 9); pthread_create(&id, &attr, reader, iid + 10); pthread_create(&id, &attr, reader, iid + 11); pthread_create(&id, &attr, reader, iid + 12); pthread_attr_destroy(&attr); for (i = 0; i < 15; ++i) while (read(barrier[RD], &ack, 1) == -1 && errno == EINTR) {} map_destroy(&mtmap); if (mtmap) ++errors, printf("Test%d: map_destroy(&mtmap) failed\n", test); close(size[RD]); close(size[WR]); close(barrier[RD]); close(barrier[WR]); } } #define TEST_ACT(i, action) \ if (!(action)) \ ++errors, printf("Test%d: %s failed\n", (i), (#action)); #define TEST_INT_ACT(i, action) \ if ((action) == -1) \ ++errors, printf("Test%d: %s failed\n", (i), (#action)); #define TEST_EQ(i, action, value) \ if ((val = (action)) != (value)) \ ++errors, printf("Test%d: %s failed (returned %d, not %d)\n", (i), (#action), val, (value)); #define TEST_NEQ(i, action, value) \ if ((val = (action)) == (value)) \ ++errors, printf("Test%d: %s failed (returned %d)\n", (i), (#action), val); #define CHECK_ITEM(i, action, key, result) \ if (!(value = (char *)(action)) || strcmp(value, (result))) \ ++errors, printf("Test%d: %s failed (mapping \"%s\" is \"%s\", not \"%s\")\n", (i), (#action), (key), value, (result)); #define CHECK_LIST_ITEM(i, action, list, item, value) \ if (!list_item((list), (item)) || strcmp(list_item((list), (item)), (value))) \ ++errors, printf("Test%d: %s failed (item %d is \"%s\", not \"%s\")\n", (i), (#action), (item), (char *)list_item(list, (item)), (value)); #define CHECK_LIST(i, desc, list) \ if (list_length(list) != 4) \ ++errors, printf("Test%d: %s failed (%d items, not 4)\n", (i), (desc), (int)list_length(list)); \ else \ { \ TEST_ACT((i), list_sort((list), (list_cmp_t *)sort_cmp)); \ CHECK_LIST_ITEM((i), list_sort((list), sort_cmp), (list), 0, "abc") \ CHECK_LIST_ITEM((i), list_sort((list), sort_cmp), (list), 1, "def") \ CHECK_LIST_ITEM((i), list_sort((list), sort_cmp), (list), 2, "ghi") \ CHECK_LIST_ITEM((i), list_sort((list), sort_cmp), (list), 3, "jkl") \ } int main(int ac, char **av) { Map *map; Mapper *mapper; List *keys, *values; const void *ckey; const char *cvalue; char *value; char cat[BUFSIZ]; void *ptr; int val; if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s [debug|hash]\n", *av); return EXIT_SUCCESS; } if (ac == 2 && !strcmp(av[1], "hash")) test_hash(); printf("Testing: %s\n", "map"); /* Test map_create, map_add, map_get */ TEST_ACT(1, map = map_create(NULL)) else { TEST_INT_ACT(2, map_add(map, "abc", "abc")) TEST_INT_ACT(3, map_add(map, "def", "def")) TEST_INT_ACT(4, map_add(map, "ghi", "ghi")) TEST_INT_ACT(5, map_add(map, "jkl", "jkl")) CHECK_ITEM(6, map_get(map, "abc"), "abc", "abc") CHECK_ITEM(7, map_get(map, "def"), "def", "def") CHECK_ITEM(8, map_get(map, "ghi"), "ghi", "ghi") CHECK_ITEM(9, map_get(map, "jkl"), "jkl", "jkl") if ((value = (char *)map_get(map, "zzz"))) ++errors, printf("Test10: map_get(\"zzz\") failed\n"); /* Test mapper_create, mapper_has_next, mapper_next, map_destroy */ TEST_ACT(11, mapper = mapper_create(map)) else { TEST_ACT(12, keys = list_create(NULL)) while (mapper_has_next(mapper) == 1) { void *item = mapper_next(mapper); TEST_ACT(13, item) else TEST_ACT(13, list_append(keys, item)) } mapper_destroy(&mapper); if (mapper) ++errors, printf("Test14: mapper_destroy(&mapper) failed (%p, not NULL)", (void *)mapper); CHECK_LIST(15, "mapper_has_next/mapper_next", keys) list_destroy(&keys); } /* Test mapper_next_mapping, mapping_key, mapping_value */ TEST_ACT(16, mapper = mapper_create(map)) else { TEST_ACT(16, keys = list_create(NULL)) TEST_ACT(16, values = list_create(NULL)) while (mapper_has_next(mapper) == 1) { const Mapping *mapping = mapper_next_mapping(mapper); if (!mapping) ++errors, printf("Test17: mapper_next_mapping() failed\n"); else { TEST_ACT(17, ckey = mapping_key((void *)mapping)) else TEST_ACT(17, list_append(keys, (void *)ckey)) TEST_ACT(17, cvalue = mapping_value(mapping)) else TEST_ACT(17, list_append(values, (void *)cvalue)) } } mapper_destroy(&mapper); if (mapper) ++errors, printf("Test18: mapper_destroy(&mapper) failed (%p, not NULL)", (void *)mapper); CHECK_LIST(19, "mapper_has_next/mapper_next_mapping", keys) list_destroy(&keys); CHECK_LIST(20, "mapper_has_next/mapper_next_mapping", values) list_destroy(&values); } /* Test map_has_next, map_next */ TEST_ACT(21, keys = list_create(NULL)) while (map_has_next(map) == 1) { void *item; TEST_ACT(22, item = map_next(map)) else TEST_ACT(22, list_append(keys, item)) } CHECK_LIST(23, "map_has_next/map_next", keys) list_destroy(&keys); /* Test map_next_mapping */ TEST_ACT(24, keys = list_create(NULL)) TEST_ACT(24, values = list_create(NULL)) while (map_has_next(map) == 1) { const Mapping *mapping; TEST_ACT(25, mapping = map_next_mapping(map)) else { TEST_ACT(25, ckey = mapping_key(mapping)) else TEST_ACT(25, list_append(keys, (void *)ckey)) TEST_ACT(25, cvalue = mapping_value(mapping)) else TEST_ACT(25, list_append(values, (void *)cvalue)) } } CHECK_LIST(26, "map_has_next/map_next_mapping", keys) list_destroy(&keys); CHECK_LIST(27, "map_has_next/map_next_mapping", values) list_destroy(&values); /* Test map_keys */ TEST_ACT(28, keys = map_keys(map)) else { CHECK_LIST(29, "map_keys", keys) list_destroy(&keys); } /* Test map_values */ TEST_ACT(30, values = map_values(map)) else { CHECK_LIST(31, "map_values", values) list_destroy(&values); } /* Test map_remove */ TEST_ACT(32, map_remove(map, "zzz") == -1) TEST_ACT(33, map_remove(map, "abc") != -1) TEST_ACT(34, map_remove(map, "def") != -1) TEST_ACT(35, map_remove(map, "ghi") != -1) TEST_ACT(36, map_remove(map, "jkl") != -1) map_destroy(&map); if (map) ++errors, printf("Test37: map_destroy(&map) failed (%p, not NULL)\n", (void *)map); } /* Test map_apply */ TEST_ACT(38, map = map_create(NULL)) else { TEST_ACT(39, map_add(map, "1", "7") == 0) TEST_ACT(40, map_add(map, "2", "6") == 0) TEST_ACT(41, map_add(map, "3", "5") == 0) TEST_ACT(42, map_add(map, "4", "4") == 0) TEST_ACT(43, map_add(map, "5", "3") == 0) TEST_ACT(44, map_add(map, "6", "2") == 0) TEST_ACT(45, map_add(map, "7", "1") == 0) CHECK_ITEM(46, map_get(map, "1"), "1", "7") CHECK_ITEM(47, map_get(map, "2"), "2", "6") CHECK_ITEM(48, map_get(map, "3"), "3", "5") CHECK_ITEM(49, map_get(map, "4"), "4", "4") CHECK_ITEM(50, map_get(map, "5"), "5", "3") CHECK_ITEM(51, map_get(map, "6"), "6", "2") CHECK_ITEM(52, map_get(map, "7"), "7", "1") cat[0] = nul; map_apply(map, (map_action_t *)test_action, cat); if (strcmp(cat, "7=1, 1=7, 2=6, 3=5, 4=4, 5=3, 6=2")) ++errors, printf("Test53: map_apply(cat) failed (cat = \"%s\", not \"%s\")\n", cat, "7=1, 1=7, 2=6, 3=5, 4=4, 5=3, 6=2"); map_destroy(&map); if (map) ++errors, printf("Test54: map_destroy(&map) failed (%p, not NULL)\n", (void *)map); } /* Test mapper_remove, map_size */ TEST_ACT(55, map = map_create(NULL)) else { TEST_ACT(56, map_add(map, "1", "7") == 0) TEST_ACT(57, map_add(map, "2", "6") == 0) TEST_ACT(58, map_add(map, "3", "5") == 0) TEST_ACT(59, map_add(map, "4", "4") == 0) TEST_ACT(60, map_add(map, "5", "3") == 0) TEST_ACT(61, map_add(map, "6", "2") == 0) TEST_ACT(62, map_add(map, "7", "1") == 0) TEST_ACT(63, mapper = mapper_create(map)) else { while (mapper_has_next(mapper) == 1) { void *item; TEST_ACT(64, item = mapper_next(mapper)) mapper_remove(mapper); } mapper_destroy(&mapper); if (mapper) ++errors, printf("Test65: mapper_destroy(&mapper) failed (%p, not NULL)\n", (void *)mapper); TEST_EQ(66, map_size(map), 0) } map_destroy(&map); if (map) ++errors, printf("Test67: map_destroy(&map) failed (%p, not NULL)\n", (void *)map); } /* Test map_remove_current */ TEST_ACT(68, map = map_create(NULL)) else { TEST_ACT(69, map_add(map, "1", "1") == 0) TEST_ACT(70, map_add(map, "2", "2") == 0) TEST_ACT(71, map_add(map, "3", "3") == 0) TEST_ACT(72, map_add(map, "4", "4") == 0) while (map_has_next(map) == 1) { void *item; TEST_ACT(73, item = map_next(map)) map_remove_current(map); } TEST_EQ(74, map_size(map), 0) mapper_destroy(&mapper); map_destroy(&map); } /* Test map_create_generic (Point -> char *) */ #define ADD_POINT(i, xpos, ypos, value, rc) \ point->x = (xpos); \ point->y = (ypos); \ TEST_ACT((i), map_add(map, point, (value)) == (rc)) #define GET_POINT(i, xpos, ypos, str) \ point->x = (xpos); \ point->y = (ypos); \ if (!(value = map_get(map, point))) \ ++errors, printf("Test%d: map_get(generic) failed\n", (i)); \ else if (strcmp(value, (str))) \ ++errors, printf("Test%d: map_get(generic) failed (\"%s\", not \"%s\")\n", (i), value, (str)); TEST_ACT(75, map = map_create_generic((map_copy_t *)point_copy, (map_cmp_t *)point_cmp, (map_hash_t *)point_hash, (map_release_t *)point_release, NULL)) else { Point *point = point_create(0, 0); ADD_POINT(76, 0, 0, "(0, 0)", 0) ADD_POINT(77, 1, 0, "(1, 0)", 0) ADD_POINT(78, 0, 1, "(0, 1)", 0) ADD_POINT(79, 1, 1, "(1, 1)", 0) ADD_POINT(80, -1, 0, "(-1, 0)", 0) ADD_POINT(81, 0, -1, "(0, -1)", 0) ADD_POINT(82, -1, -1, "(-1, -1)", 0) ADD_POINT(83, 2, 0, "(2, 0)", 0) ADD_POINT(84, 0, 2, "(0, 2)", 0) ADD_POINT(85, 2, 2, "(2, 2)", 0) ADD_POINT(86, -2, 0, "(-2, 0)", 0) ADD_POINT(87, 0, -2, "(0, -2)", 0) ADD_POINT(88, -2, -2, "(-2, -2)", 0) ADD_POINT(89, 0, 0, "(0, 0)", -1) TEST_EQ(90, map_size(map), 13) GET_POINT(91, 0, 0, "(0, 0)") GET_POINT(92, 1, 0, "(1, 0)") GET_POINT(93, 0, 1, "(0, 1)") GET_POINT(94, 1, 1, "(1, 1)") GET_POINT(95, -1, 0, "(-1, 0)") GET_POINT(96, 0, -1, "(0, -1)") GET_POINT(97, -1, -1, "(-1, -1)") GET_POINT(98, 2, 0, "(2, 0)") GET_POINT(99, 0, 2, "(0, 2)") GET_POINT(100, 2, 2, "(2, 2)") GET_POINT(101, -2, 0, "(-2, 0)") GET_POINT(102, 0, -2, "(0, -2)") GET_POINT(103, -2, -2, "(-2, -2)") point_release(point); map_destroy(&map); } /* Test map_create_generic (int -> int) and map growth */ TEST_ACT(104, map = map_create_generic((map_copy_t *)direct_copy, (map_cmp_t *)direct_cmp, (map_hash_t *)direct_hash, NULL, NULL)) else { TEST_ACT(105, map_add(map, (void *)1, (void *)1) == 0) TEST_ACT(106, map_add(map, (void *)2, (void *)2) == 0) TEST_ACT(107, map_add(map, (void *)3, (void *)3) == 0) TEST_ACT(108, map_add(map, (void *)4, (void *)4) == 0) TEST_ACT(109, map_add(map, (void *)5, (void *)5) == 0) TEST_ACT(110, map_add(map, (void *)6, (void *)6) == 0) TEST_ACT(111, map_add(map, (void *)7, (void *)7) == 0) TEST_ACT(112, map_add(map, (void *)8, (void *)8) == 0) TEST_ACT(113, map_add(map, (void *)9, (void *)9) == 0) TEST_ACT(114, map_add(map, (void *)10, (void *)10) == 0) TEST_ACT(115, map_add(map, (void *)11, (void *)11) == 0) TEST_ACT(116, map_add(map, (void *)12, (void *)12) == 0) TEST_ACT(117, map_add(map, (void *)13, (void *)13) == 0) TEST_ACT(118, map_add(map, (void *)14, (void *)14) == 0) TEST_ACT(119, map_add(map, (void *)15, (void *)15) == 0) TEST_ACT(120, map_add(map, (void *)16, (void *)16) == 0) TEST_ACT(121, map_add(map, (void *)17, (void *)17) == 0) TEST_ACT(122, map_add(map, (void *)18, (void *)18) == 0) TEST_ACT(123, map_add(map, (void *)19, (void *)19) == 0) TEST_ACT(124, map_add(map, (void *)20, (void *)20) == 0) TEST_ACT(125, map_add(map, (void *)21, (void *)21) == 0) TEST_ACT(126, map_add(map, (void *)22, (void *)22) == 0) TEST_ACT(127, map_add(map, (void *)23, (void *)23) == 0) TEST_ACT(128, map_add(map, (void *)24, (void *)24) == 0) TEST_ACT(129, map_add(map, (void *)25, (void *)25) == 0) TEST_ACT(130, map_add(map, (void *)25, (void *)25) != 0) TEST_EQ(130, map_size(map), 25) TEST_EQ(131, (int)(long)map_get(map, (void *)1), 1) TEST_EQ(132, (int)(long)map_get(map, (void *)2), 2) TEST_EQ(133, (int)(long)map_get(map, (void *)3), 3) TEST_EQ(134, (int)(long)map_get(map, (void *)4), 4) TEST_EQ(135, (int)(long)map_get(map, (void *)5), 5) TEST_EQ(136, (int)(long)map_get(map, (void *)6), 6) TEST_EQ(137, (int)(long)map_get(map, (void *)7), 7) TEST_EQ(138, (int)(long)map_get(map, (void *)8), 8) TEST_EQ(139, (int)(long)map_get(map, (void *)9), 9) TEST_EQ(140, (int)(long)map_get(map, (void *)10), 10) TEST_EQ(141, (int)(long)map_get(map, (void *)11), 11) TEST_EQ(142, (int)(long)map_get(map, (void *)12), 12) TEST_EQ(143, (int)(long)map_get(map, (void *)13), 13) TEST_EQ(144, (int)(long)map_get(map, (void *)14), 14) TEST_EQ(145, (int)(long)map_get(map, (void *)15), 15) TEST_EQ(146, (int)(long)map_get(map, (void *)16), 16) TEST_EQ(147, (int)(long)map_get(map, (void *)17), 17) TEST_EQ(148, (int)(long)map_get(map, (void *)18), 18) TEST_EQ(149, (int)(long)map_get(map, (void *)19), 19) TEST_EQ(150, (int)(long)map_get(map, (void *)20), 20) TEST_EQ(151, (int)(long)map_get(map, (void *)21), 21) TEST_EQ(152, (int)(long)map_get(map, (void *)22), 22) TEST_EQ(153, (int)(long)map_get(map, (void *)23), 23) TEST_EQ(154, (int)(long)map_get(map, (void *)24), 24) TEST_EQ(155, (int)(long)map_get(map, (void *)25), 25) map_destroy(&map); } /* Test MT Safety */ debug = ac == 2 && !strcmp(av[1], "debug"); if (debug) setbuf(stdout, NULL); #ifndef PTHREAD_RWLOCK_INITIALIZER pthread_rwlock_init(&rwlock, NULL); #endif if (debug) locker = locker_create_debug_rwlock(&rwlock); else locker = locker_create_rwlock(&rwlock); if (!locker) ++errors, printf("Test220: locker_create_rwlock() failed\n"); else { mt_test(220, locker); locker_destroy(&locker); } if (debug) locker = locker_create_debug_mutex(&mutex); else locker = locker_create_mutex(&mutex); if (!locker) ++errors, printf("Test221: locker_create_mutex() failed\n"); else { mt_test(221, locker); locker_destroy(&locker); } /* Test assumption: sizeof(int) <= sizeof(void *) */ if (sizeof(int) > sizeof(void *)) ++errors, printf("Test 222: assumption failed: sizeof(int) > sizeof(void *): int maps are limited to %d bytes\n", (int)sizeof(void *)); /* Test assumption: memset(&ptr, 0, sizeof(void *)) same as NULL */ memset(&ptr, 0, sizeof(void *)); if (ptr != NULL) ++errors, printf("Test223: assumption failed: memset(&ptr, 0, sizeof(void *)) not same as NULL\n"); if (errors) printf("%d/223 tests failed\n", errors); else printf("All tests passed\n"); return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/map.h0000644000175000017500000001143114014141213013427 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_MAP_H #define LIBSLACK_MAP_H #include #include #include typedef struct Map Map; typedef struct Mapper Mapper; typedef struct Mapping Mapping; typedef list_release_t map_release_t; typedef list_copy_t map_copy_t; typedef list_cmp_t map_cmp_t; typedef size_t map_hash_t(size_t table_size, const void *key); typedef void map_action_t(void *key, void *item, void *data); _begin_decls Map *map_create(map_release_t *destroy); Map *map_create_sized(size_t size, map_release_t *destroy); Map *map_create_with_hash(map_hash_t *hash, map_release_t *destroy); Map *map_create_sized_with_hash(size_t size, map_hash_t *hash, map_release_t *destroy); Map *map_create_with_locker(Locker *locker, map_release_t *destroy); Map *map_create_with_locker_sized(Locker *locker, size_t size, map_release_t *destroy); Map *map_create_with_locker_with_hash(Locker *locker, map_hash_t *hash, map_release_t *destroy); Map *map_create_with_locker_sized_with_hash(Locker *locker, size_t size, map_hash_t *hash, map_release_t *destroy); Map *map_create_generic(map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy); Map *map_create_generic_sized(size_t size, map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy); Map *map_create_generic_with_locker(Locker *locker, map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy); Map *map_create_generic_with_locker_sized(Locker *locker, size_t size, map_copy_t *copy, map_cmp_t *cmp, map_hash_t *hash, map_release_t *key_destroy, map_release_t *value_destroy); int map_rdlock(const Map *map); int map_wrlock(const Map *map); int map_unlock(const Map *map); void map_release(Map *map); void *map_destroy(Map **map); int map_own(Map *map, map_release_t *destroy); int map_own_unlocked(Map *map, map_release_t *destroy); map_release_t *map_disown(Map *map); map_release_t *map_disown_unlocked(Map *map); int map_add(Map *map, const void *key, void *value); int map_add_unlocked(Map *map, const void *key, void *value); int map_put(Map *map, const void *key, void *value); int map_put_unlocked(Map *map, const void *key, void *value); int map_insert(Map *map, const void *key, void *value, int replace); int map_insert_unlocked(Map *map, const void *key, void *value, int replace); int map_remove(Map *map, const void *key); int map_remove_unlocked(Map *map, const void *key); void *map_get(Map *map, const void *key); void *map_get_unlocked(const Map *map, const void *key); Mapper *mapper_create(Map *map); Mapper *mapper_create_rdlocked(Map *map); Mapper *mapper_create_wrlocked(Map *map); Mapper *mapper_create_unlocked(Map *map); void mapper_release(Mapper *mapper); void mapper_release_unlocked(Mapper *mapper); void *mapper_destroy(Mapper **mapper); void *mapper_destroy_unlocked(Mapper **mapper); int mapper_has_next(Mapper *mapper); void *mapper_next(Mapper *mapper); const Mapping *mapper_next_mapping(Mapper *mapper); void mapper_remove(Mapper *mapper); int map_has_next(Map *map); void map_break(Map *map); void *map_next(Map *map); const Mapping *map_next_mapping(Map *map); void map_remove_current(Map *map); const void *mapping_key(const Mapping *mapping); const void *mapping_value(const Mapping *mapping); List *map_keys(Map *map); List *map_keys_unlocked(Map *map); List *map_keys_with_locker(Locker *locker, Map *map); List *map_keys_with_locker_unlocked(Locker *locker, Map *map); List *map_values(Map *map); List *map_values_unlocked(Map *map); List *map_values_with_locker(Locker *locker, Map *map); List *map_values_with_locker_unlocked(Locker *locker, Map *map); void map_apply(Map *map, map_action_t *action, void *data); void map_apply_rdlocked(Map *map, map_action_t *action, void *data); void map_apply_wrlocked(Map *map, map_action_t *action, void *data); void map_apply_unlocked(Map *map, map_action_t *action, void *data); ssize_t map_size(Map *map); ssize_t map_size_unlocked(const Map *map); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/mem.c0000644000175000017500000012732514014141213013435 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ /* =head1 NAME I - memory module =head1 SYNOPSIS #include #include typedef struct Pool Pool; #define null NULL #define nul '\0' #define mem_new(type) #define mem_create(size, type) #define mem_resize(mem, size) void *mem_resize_fn(void **mem, size_t size); #define mem_release(mem) void *mem_destroy(void **mem); void *mem_create_secure(size_t size); void mem_release_secure(void *mem); void *mem_destroy_secure(void **mem); char *mem_strdup(const char *str); #define mem_create2d(type, x, y) #define mem_create3d(type, x, y, z) #define mem_create4d(type, x, y, z, a) void *mem_create_space(size_t size, ...); size_t mem_space_start(size_t size, ...); #define mem_release2d(space) #define mem_release3d(space) #define mem_release4d(space) #define mem_release_space(space) #define mem_destroy2d(space) #define mem_destroy3d(space) #define mem_destroy4d(space) #define mem_destroy_space(space) Pool *pool_create(size_t size); Pool *pool_create_with_locker(Locker *locker, size_t size); void pool_release(Pool *pool); void *pool_destroy(Pool **pool); Pool *pool_create_secure(size_t size); Pool *pool_create_secure_with_locker(Locker *locker, size_t size); void pool_release_secure(Pool *pool); void *pool_destroy_secure(Pool **pool); void pool_clear_secure(Pool *pool); #define pool_new(pool, type) #define pool_newsz(pool, size, type) void *pool_alloc(Pool *pool, size_t size); void pool_clear(Pool *pool); =head1 DESCRIPTION This module is mostly just an interface to I, I and I that tries to ensure that pointers that don't point to anything get set to C. It also provides dynamically allocated multi-dimensional arrays, memory pools and secure memory for the more adventurous. =over 4 =cut */ #include "config.h" #include "std.h" #ifdef HAVE_MLOCK #include #endif #include "err.h" #include "mem.h" struct Pool { size_t size; /* number of bytes in the pool */ size_t used; /* number of bytes allocated from the pool */ char *pool; /* address of the pool */ Locker *locker; /* locking strategy for the pool */ }; #ifndef TEST /* =item C< #define null NULL> Easier to type. Easier to read. Feel free to keep using C if you prefer. =item C< #define nul '\0'> A name for the C character. =item C< #define mem_new(type)> Allocates enough memory (with I) to store an object of type C. It is the caller's responsibility to deallocate the allocated memory with I, I, or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the address of the allocated memory. On error, returns C. =item C< #define mem_create(size, type)> Allocates enough memory (with I) to store C objects of type C. It is the caller's responsibility to deallocate the allocated memory with I, I, or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the address of the allocated memory. On error, returns C. =item C< #define mem_resize(mem, num)> Alters the amount of memory pointed to by C<*mem>. If C<*mem> is C, new memory is allocated and assigned to C<*mem>. If size is zero, C<*mem> is deallocated and C is assigned to C<*mem>. Otherwise, C<*mem> is reallocated and assigned back to C<*mem>. On success, returns C<*mem> (which will be C if C is zero). On error, returns C with C set appropriately, and C<*mem> is not altered. =item C An interface to I that also assigns to a pointer variable unless an error occurred. C points to the pointer to be affected. C is the requested size in bytes. If C is zero, C<*mem> is deallocated and set to C. This function is exposed as an implementation side effect. Don't call it directly. Call I instead. On error, returns C with C set appropriately. =cut */ #ifdef HAVE_ISOC_REALLOC #define isoc_realloc realloc #else static void *isoc_realloc(void *ptr, size_t size) { void *p; if (size) { if (!(p = (ptr) ? realloc(ptr, size) : malloc(size))) errno = ENOMEM; /* Not required by ISO C but handy */ } else { free(ptr); p = NULL; } return p; } #endif void *mem_resize_fn(void **mem, size_t size) { void *ptr; if (!mem) return set_errnull(EINVAL); ptr = isoc_realloc(*mem, size); if (size && !ptr) return NULL; return *mem = ptr; } /* =item C< #define mem_release(mem)> Releases (deallocates) C. Same as I. Only to be used in destructor functions. In other cases, use I which also sets C to C. =item C Calls I on the pointer, C<*mem>. Then assigns C to this pointer. Returns C. =cut */ void *(mem_destroy)(void **mem) { if (mem && *mem) { free(*mem); *mem = NULL; } return NULL; } /* =item C Allocates C bytes of memory (with I), and then locks it into RAM with I so that it can't be paged to disk, where some nefarious local user with root access might read its contents. Note that additional operating system dependent measures might be required to prevent the I user from accessing the RAM of arbitrary processes (e.g. On I: C). It is the caller's responsibility to deallocate the secure memory with I or I which will clear the memory and unlock it before deallocating it. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the address of the secure allocated memory. On error, returns C with C set appropriately. Note that entire memory pages are locked by I, so don't create many, small pieces of secure memory or many entire pages will be locked. Use a secure memory pool instead. Also note that on old systems, secure memory requires root privileges. On some systems (e.g. I), memory locks must start on page boundaries. So we need to I enough memory to extend from whatever address I may return to the next page boundary (worst case: C) and then the actual number of bytes requested. We need an additional C bytes (e.g. C<8> or C<16>) to store the address returned by I (so we can I it later), and the size passed to I so we can pass it to I later. Unfortunately, we need to store the address and the size after the page boundary and not before it, because I might return a page boundary or an address less than C bytes to the left of a page boundary. It will look like: for free() +-------+ +- size+n for munlock() v | v +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |* * * *|# # # #| | | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ^ ^ ^ . . . size bytes . . . . . . | +- next page | +- malloc() +- address returned If your system doesn't require page boundaries (e.g. I), the address returned by I is locked, and only the size is stored. =cut */ void *mem_create_secure(size_t size) { #ifdef HAVE_MLOCK char *addr, *lock; #ifdef MLOCK_REQUIRES_PAGE_BOUNDARY long pagesize; if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) return set_errnull(EINVAL); size += sizeof(void *) + sizeof(size_t); addr = malloc(pagesize - sizeof(int) + size); #else size += sizeof(size_t); addr = malloc(size); #endif if (!addr) return NULL; #ifdef MLOCK_REQUIRES_PAGE_BOUNDARY if ((long)addr & (pagesize - 1)) /* addr not on page boundary */ lock = (void *)(((long)addr & ~(pagesize - 1)) + pagesize); else lock = addr; #else lock = addr; #endif if (mlock(lock, size) == -1) { free(addr); return NULL; } #ifdef MLOCK_REQUIRES_PAGE_BOUNDARY *(void **)lock = addr; lock += sizeof(void *); #endif *(size_t *)lock = size; lock += sizeof(size_t); return lock; #else errno = ENOSYS; return NULL; #endif } /* =item C Sets the memory pointed to by C to C<0xff> bytes, then to C<0xaa> bytes, then to C<0x55> bytes, then to C bytes, then unlocks and releases (deallocates) C. Only to be used on memory returned by I. Only to be used in destructor functions. In other cases, use I which also sets C to C. =cut */ void mem_release_secure(void *mem) { #ifdef HAVE_MLOCK char *addr, *lock; size_t size; if (!mem) return; lock = mem; lock -= sizeof(size_t); size = *(size_t *)lock; #ifdef MLOCK_REQUIRES_PAGE_BOUNDARY lock -= sizeof(void *); addr = *(void **)lock; #else addr = lock; #endif memset(lock, 0xff, size); memset(lock, 0xaa, size); memset(lock, 0x55, size); memset(lock, 0x00, size); munlock(lock, size); free(addr); #endif } /* =item C Sets the memory pointed to by C<*mem> to C<0xff> bytes, then to C<0xaa> bytes, then to C<0x55> bytes, then to C bytes, then unlocks and destroys (deallocates and sets to C) C<*mem>. Only to be used on memory returned by I. Returns C. =cut */ void *(mem_destroy_secure)(void **mem) { if (mem && *mem) { mem_release_secure(*mem); *mem = NULL; } return NULL; } /* =item C Returns a dynamically allocated copy of C. It is the caller's responsibility to deallocate the new string with I, I, or I. It is strongly recommended to use I, because it also sets the pointer variable to C. This function exists because I is not part of the I standard. On error, returns C with C set appropriately. =cut */ char *mem_strdup(const char *str) { size_t size; char *copy; if (!str) return set_errnull(EINVAL); if (!(copy = mem_create(size = strlen(str) + 1, char))) return NULL; return memcpy(copy, str, size); } /* =item C< #define mem_create2d(i, j, type)> Alias for allocating a 2-dimensional array. See I. =item C< #define mem_create3d(i, j, k, type)> Alias for allocating a 3-dimensional array. See I. =item C< #define mem_create4d(i, j, k, l, type)> Alias for allocating a 4-dimensional array. See I. =item C Allocates a multi-dimensional array of elements of size C and sets the memory to C bytes. The remaining arguments specify the sizes of each dimension. The last argument must be zero. There is an arbitrary limit of 32 dimensions. The memory returned is set to C bytes. The memory returned needs to be cast or assigned into the appropriate pointer type. You can then set and access elements exactly like a real multi-dimensional C array. Finally, it must be deallocated with I or I or I or I or I. It is strongly recommended to use I or I, because they also set the pointer variable to C. Note: You must not use I on all of the returned memory because the start of this memory contains pointers into the remainder. The exact amount of this overhead depends on the number and size of dimensions. The memory is allocated with I to reduce the need to I the elements, but if you need to know where the elements begin, use I. The memory returned looks like (e.g.): char ***a = mem_create3d(2, 2, 3, char); +-------------------------+ +-------|-------------------+ | a +-------|-------|-------------+ | | | +-------|-------|-------|-------+ | | | v | | | | V V V V +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | a[0] | a[1] |a[0][0]|a[0][1]|a[1][0]|a[1][1]| | | | | | | | | | | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ^ ^ a a a a a a a a a a a a +-------|-------+ | 0 0 0 0 0 0 1 1 1 1 1 1 +-----------------------+ 0 0 0 1 1 1 0 0 0 1 1 1 0 1 2 0 1 2 0 1 2 0 1 2 =cut */ #ifndef MEM_MAX_DIM #define MEM_MAX_DIM 32 #endif void *mem_create_space(size_t size, ...) { size_t dim[MEM_MAX_DIM], d, i, j; size_t lengths[MEM_MAX_DIM]; size_t starts[MEM_MAX_DIM]; size_t sizes[MEM_MAX_DIM]; char *space; size_t arg, length; va_list args; va_start(args, size); for (d = 0; d < MEM_MAX_DIM && (arg = va_arg(args, size_t)); ++d) dim[d] = arg; va_end(args); for (length = i = 0; i < d; ++i) { starts[i] = length; lengths[i] = sizes[i] = (i == d - 1) ? size : sizeof(void *); for (j = 0; j <= i; ++j) lengths[i] *= dim[j]; length += lengths[i]; } if (!(space = calloc(length, 1))) return NULL; for (i = 0; i < d - 1; ++i) { size_t num = dim[i]; for (j = 0; j < i; ++j) num *= dim[j]; for (j = 0; j < num; ++j) *(char **)(space + starts[i] + j * sizes[i]) = space + starts[i + 1] + j * dim[i + 1] * sizes[i + 1]; } return space; } /* =item C Calculates the amount of overhead required for a dynamically allocated multi-dimensional array created by a call to I with the same arguments. If you need to reset all elements in such an array to C bytes: int ****space = mem_create_space(sizeof(int), 2, 3, 4, 5, 0); size_t start = mem_space_start(sizeof(int), 2, 3, 4, 5, 0); memset((char *)space + start, '\0', sizeof(int) * 2 * 3 * 4 * 5); =cut */ size_t mem_space_start(size_t size, ...) { size_t dim[MEM_MAX_DIM], d, i, j; size_t lengths[MEM_MAX_DIM]; size_t arg, length; va_list args; va_start(args, size); for (d = 0; d < MEM_MAX_DIM && (arg = va_arg(args, size_t)); ++d) dim[d] = arg; va_end(args); for (length = i = 0; i < d; ++i) { lengths[i] = (i == d - 1) ? size : sizeof(void *); for (j = 0; j <= i; ++j) lengths[i] *= dim[j]; length += lengths[i]; } return length - lengths[d - 1]; } /* =item C< #define mem_release2d(space)> Alias for releasing (deallocating) a dynamically allocated 2-dimensional array. See I. =item C< #define mem_release3d(space)> Alias for releasing (deallocating) a dynamically allocated 3-dimensional array. See I. =item C< #define mem_release4d(space)> Alias for releasing (deallocating) a dynamically allocated 4-dimensional array. See I. =item C< #define mem_release_space(space)> Releases (deallocates) a multi-dimensional array, C, allocated with I. Same as I. Only to be used in destructor functions. In other cases, use I or I which also set C to C. =item C< #define mem_destroy2d(space)> Alias for destroying (deallocating and setting to C) a 2-dimensional array. See I. =item C< #define mem_destroy3d(space)> Alias for destroying (deallocating and setting to C) a 3-dimensional array. See I. =item C< #define mem_destroy4d(space)> Alias for destroying (deallocating and setting to C) a 4-dimensional array. See I. =item C< #define mem_destroy_space(mem)> Destroys (deallocates and sets to C) the multi-dimensional array pointed to by C. =cut */ /* =item C Creates a memory pool of size C from which smaller chunks of memory may be subsequently allocated (with I) without resorting to the use of I. Useful when you have many small objects to allocate, but I is slowing your program down too much. It is the caller's responsibility to deallocate the new pool with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the pool. On error, returns C. The size of a pool can't be changed after it is created, and the individual chunks of memory allocated from within a pool can't be separately deallocated. The entire pool can be emptied with I. =cut */ Pool *pool_create(size_t size) { return pool_create_with_locker(NULL, size); } /* =item C Equivalent to I except that multiple threads accessing the new pool will be synchronised by C. =cut */ Pool *pool_create_with_locker(Locker *locker, size_t size) { Pool *pool = mem_create(1, Pool); if (!pool) return NULL; if (!(pool->pool = malloc(size))) { mem_release(pool); return NULL; } pool->size = size; pool->used = 0; pool->locker = locker; return pool; } /* C Claims a write lock on C. On success, returns C<0>. On error, returns an error code. C Unlocks a write lock on C. On success, returns C<0>. On error, returns an error code. */ #define pool_lock(pool) locker_wrlock((pool)->locker) #define pool_unlock(pool) locker_unlock((pool)->locker) /* =item C Releases (deallocates) C. Only to be used in destructor functions. In other cases, use I which also sets C to C. =cut */ void pool_release(Pool *pool) { Locker *locker; int err; if (!pool) return; if ((err = pool_lock(pool))) { set_errno(err); return; } locker = pool->locker; mem_release(pool->pool); mem_release(pool); if ((err = locker_unlock(locker))) set_errno(err); } /* =item C Destroys (deallocates and sets to C) C<*pool>. Returns C. B pools shared by multiple threads must not be destroyed until after all threads have finished with it. =cut */ void *pool_destroy(Pool **pool) { if (pool && *pool) { pool_release(*pool); *pool = NULL; } return NULL; } /* =item C Creates a memory pool of size C just like I except that the memory pool is locked into RAM with I so that it can't be paged to disk where some nefarious local user with root access might read its contents. Note that additional operating system dependent measures might be required to prevent the I user from accessing the RAM of arbitrary processes (e.g. On I: C). It is the caller's responsibility to deallocate the new pool with I or I which will clear the memory pool and unlock it before deallocating it. In all other ways, the pool returned is exactly like a pool returned by I. On success, returns the pool. On error, returns C with C set appropriately. Note that on old systems, secure memory requires root privileges. =cut */ Pool *pool_create_secure(size_t size) { return pool_create_secure_with_locker(NULL, size); } /* =item C Equivalent to I except that multiple threads accessing the new pool will be synchronised by C. =cut */ Pool *pool_create_secure_with_locker(Locker *locker, size_t size) { #ifdef HAVE_MLOCK Pool *pool = mem_create(1, Pool); if (!pool) return NULL; if (!(pool->pool = mem_create_secure(size))) { mem_release(pool); return NULL; } pool->size = size; pool->used = 0; pool->locker = locker; return pool; #else errno = ENOSYS; return NULL; #endif } /* =item C Sets the contents of the memory pool to C<0xff> bytes, then to C<0xaa> bytes, then to C<0x55> bytes, then to C bytes, then unlocks and releases (deallocates) C. Only to be used on pools returned by I. Only to be used in destructor functions. In other cases, use I which also sets C to C. =cut */ void pool_release_secure(Pool *pool) { #ifdef HAVE_MLOCK Locker *locker; int err; if (!pool) return; if ((err = pool_lock(pool))) { set_errno(err); return; } locker = pool->locker; mem_release_secure(pool->pool); mem_release(pool); if ((err = locker_unlock(locker))) set_errno(err); #endif } /* =item C Sets the contents of the memory pool to C<0xff> bytes, then to C<0xaa> bytes, then to C<0x55> bytes, then to C bytes, then unlocks and destroys (deallocates and sets to C) C<*pool>. Returns C. B secure pools shared by multiple threads must not be destroyed until after all threads have finished with it. =cut */ void *pool_destroy_secure(Pool **pool) { if (pool && *pool) { pool_release_secure(*pool); *pool = NULL; } return NULL; } /* =item C Fills the secure C with C<0xff> bytes, then C<0xaa> bytes, then C<0x55> bytes, then C bytes, and deallocates all of the chunks of secure memory previously allocated from C so that it can be reused. Does not use I. =cut */ static void pool_clear_unlocked(Pool *pool); void pool_clear_secure(Pool *pool) { int err; if (!pool) return; if ((err = pool_lock(pool))) { set_errno(err); return; } pool_clear_unlocked(pool); memset(pool->pool, 0xff, pool->size); memset(pool->pool, 0xaa, pool->size); memset(pool->pool, 0x55, pool->size); memset(pool->pool, 0x00, pool->size); if ((err = pool_unlock(pool))) set_errno(err); } /* =item C< #define pool_new(pool, type)> Allocates enough memory from C to store an object of type C. On success, returns the address of the allocated memory. On error, returns C with C set appropriately. =item C< #define pool_newsz(pool, size, type)> Allocates enough memory from C to store C objects of type C. On success, returns the address of the allocated memory. On error, returns C with C set appropriately. =item C Allocates a chunk of memory of C bytes from C. Does not use I. The pointer returned must not be passed to I or I. Only the entire pool can be deallocated with I or I. All of the chunks can be deallocated in one go with I without deallocating the pool itself. On success, returns the pointer to the allocated pool memory. On error, returns C with C set appropriately (i.e. C if C is C, C if C does not have enough unused memory to allocate C bytes). It is the caller's responsibility to ensure the correct alignment if necessary by allocating the right numbers of bytes. The easiest way to do ensure is to use separate pools for each specific data type that requires specific alignment. =cut */ void *pool_alloc(Pool *pool, size_t size) { void *addr; int err; if (!pool) return set_errnull(EINVAL); if ((err = pool_lock(pool))) return set_errnull(err); if (pool->used + size > pool->size) { pool_unlock(pool); return set_errnull(ENOSPC); } addr = pool->pool + pool->used; pool->used += size; if ((err = pool_unlock(pool))) return set_errnull(err); return addr; } /* =item C Deallocates all of the chunks of memory previously allocated from C so that it can be reused. Does not use I. =cut */ static void pool_clear_with_locker(Pool *pool, int lock_pool) { int err; if (!pool) return; if (lock_pool && (err = pool_lock(pool))) { set_errno(err); return; } pool->used = 0; if (lock_pool && (err = pool_unlock(pool))) set_errno(err); } static void pool_clear_unlocked(Pool *pool) { pool_clear_with_locker(pool, 0); } void pool_clear(Pool *pool) { pool_clear_with_locker(pool, 1); } /* =back =head1 ERRORS On error, C is set by underlying functions or as follows: =over 4 =item C When arguments are invalid. =item C When there is insufficient available space in a pool for I to satisfy a request. =item C Returned by I and I when I is not supported (e.g. I). =back =head1 MT-Level I (mem) I (pool) man I for details. =head1 EXAMPLES 1D array of longs: long *mem = mem_create(100, long); mem_resize(&mem, 200); mem_destroy(&mem); 3D array of ints: int ***space = mem_create3d(10, 20, 30, int); int i, j, k; for (i = 0; i < 10; ++i) for (j = 0; j < 20; ++j) for (k = 0; k < 30; ++k) space[i][j][k] = i + j + j; mem_destroy3d(&space); A pool of a million integers: void pool() { Pool *pool; int i, *p; if (!(pool = pool_create(1024 * 1024 * sizeof(int)))) return; for (i = 0; i < 1024 * 1024; ++i) { if (!(p = pool_new(pool, int))) break; *p = i; } pool_destroy(&pool); } Secure memory: char *secure_passwd = mem_create_secure(32); if (!secure_passwd) exit(EXIT_FAILURE); get_passwd(secure_passwd, 32); use_passwd(secure_passwd); mem_destroy_secure(&secure_passwd); Secure memory pool: Pool *secure_pool; char *secure_passwd; if (!(secure_pool = pool_create_secure(1024 * 1024))) exit(EXIT_FAILURE); secure_passwd = pool_alloc(secure_pool, 32); get_passwd(secure_passwd, 32); use_passwd(secure_passwd); pool_destroy_secure(&secure_pool); =head1 SEE ALSO I, I, I, I, I, I, I, I =head1 AUTHOR 20210220 raf =cut */ #endif #ifdef TEST #include #include #include #include int main(int ac, char **av) { int *mem1 = NULL; char *mem2 = NULL; char *str = NULL; int **space2 = NULL; int ***space3 = NULL; int ****space4 = NULL; int *****space5 = NULL; char **space2d = NULL; double ***space3d = NULL; int i, j, k, l, m; Pool *pool; clock_t start_clock; clock_t end_clock; long malloc_time; long pool_time; int errors = 0; int no_secure_mem; pid_t pid; if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s [pool]\n", *av); return EXIT_SUCCESS; } printf("Testing: %s\n", "mem"); /* Test create, resize and destroy */ if (!(mem1 = mem_create(100, int))) ++errors, printf("Test1: mem_create(100, int) failed\n"); if (!(mem_resize(&mem1, 50))) ++errors, printf("Test2: mem_resize(100 -> 50) failed\n"); if (mem_resize(&mem1, 0)) ++errors, printf("Test3: mem_resize(50 -> 0) failed\n"); if (!(mem_resize(&mem1, 50))) ++errors, printf("Test4: mem_resize(0 -> 50) failed\n"); if (mem_destroy(&mem1)) ++errors, printf("Test5: mem_destroy() failed\n"); if (!(mem2 = mem_create(0, char))) ++errors, printf("Test6: mem_create(0, char) failed\n"); if (!(mem_resize(&mem2, 10))) ++errors, printf("Test7: mem_resize(0 -> 10) failed\n"); if (mem_resize(&mem2, 0)) ++errors, printf("Test8: mem_resize(10 -> 0) failed\n"); if (mem_destroy(&mem2)) ++errors, printf("Test9: mem_destroy() failed\n"); /* This used to segfault a broken version of mem_resize() */ switch (pid = fork()) { case -1: { fprintf(stderr, "Failed to perform test - fork() failed (%s)\n", strerror(errno)); break; } case 0: { size_t size = 16; sockopt_t *so = mem_create(size, sockopt_t); sockaddr_any_t *sa = mem_create(size, sockaddr_any_t); mem_resize(&so, size << 1); memset(so + size, 0, size * sizeof(sockopt_t)); mem_resize(&sa, size << 1); memset(sa + size, 0, size * sizeof(sockaddr_any_t)); mem_destroy(&so); mem_destroy(&sa); _exit(EXIT_SUCCESS); break; } default: { int status; if (waitpid(pid, &status, 0) == -1) { fprintf(stderr, "Failed to evaluate test - waitpid(%d) failed (%s)\n", (int)pid, strerror(errno)); break; } if (WIFSIGNALED(status) && WTERMSIG(status) != SIGABRT) ++errors, printf("Test10: mem_resize() failed - killed by signal %d\n", WTERMSIG(status)); else if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) ++errors, printf("Test10: mem_resize() failed - exit status %d\n", WEXITSTATUS(status)); break; } } /* Test strdup */ if (!(str = mem_strdup("test"))) ++errors, printf("Test11: mem_strdup() failed (returned NULL)\n"); else { if (strcmp(str, "test")) ++errors, printf("Test12: mem_strdup() failed (equals \"%s\", not \"test\")\n", str); mem_release(str); } /* Test 2D space allocation and deallocation */ if (!(space2 = mem_create_space(sizeof(int), (size_t)1, (size_t)1, (size_t)0))) ++errors, printf("Test13: mem_create_space(1, 1) failed (returned NULL)\n"); else { space2[0][0] = 37; if (space2[0][0] != 37) ++errors, printf("Test14: mem_create_space(1, 1) failed (space2[%d][%d] = %d, not %d)\n", 0, 0, space2[0][0], 37); mem_destroy_space(&space2); if (space2) ++errors, printf("Test15: mem_destroy_space(1, 1) failed\n"); } if (!(space2 = mem_create_space(sizeof(int), (size_t)10, (size_t)10, (size_t)0))) ++errors, printf("Test16: mem_create_space(10, 10) failed (returned NULL)\n"); else { int error = 0; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) space2[i][j] = i + j; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) if (space2[i][j] != i + j) ++error, printf("Test17: mem_create_space(10, 10) failed (space2[%d][%d] = %d, not %d)\n", i, j, space2[i][j], i + j); if (error) ++errors; mem_destroy_space(&space2); if (space2) ++errors, printf("Test18: mem_destroy_space(10, 10) failed\n"); } /* Test 3D space allocation and deallocation */ if (!(space3 = mem_create_space(sizeof(int), (size_t)1, (size_t)1, (size_t)1, (size_t)0))) ++errors, printf("Test19: mem_create_space(1, 1, 1) failed (returned NULL)\n"); else { space3[0][0][0] = 37; if (space3[0][0][0] != 37) ++errors, printf("Test20: mem_create_space(1, 1, 1) failed (space3[%d][%d][%d] = %d, not %d)\n", 0, 0, 0, space3[0][0][0], 37); mem_destroy_space(&space3); if (space3) ++errors, printf("Test21: mem_destroy_space(1, 1, 1) failed\n"); } if (!(space3 = mem_create_space(sizeof(int), (size_t)10, (size_t)10, (size_t)10, (size_t)0))) ++errors, printf("Test22: mem_create_space(10, 10, 10) failed (returned NULL)\n"); else { int error = 0; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) for (k = 0; k < 10; ++k) space3[i][j][k] = i + j + k; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) for (k = 0; k < 10; ++k) if (space3[i][j][k] != i + j + k) ++error, printf("Test23: mem_create_space(10, 10, 10) failed (space3[%d][%d][%d] = %d, not %d)\n", i, j, k, space3[i][j][k], i + j + k); if (error) ++errors; mem_destroy_space(&space3); if (space3) ++errors, printf("Test24: mem_destroy_space(10, 10, 10) failed\n"); } /* Test 4D space allocation and deallocation */ if (!(space4 = mem_create_space(sizeof(int), (size_t)1, (size_t)1, (size_t)1, (size_t)1, (size_t)0))) ++errors, printf("Test25: mem_create_space(1, 1, 1, 1) failed (returned NULL)\n"); else { space4[0][0][0][0] = 37; if (space4[0][0][0][0] != 37) ++errors, printf("Test26: mem_create_space(1, 1, 1, 1) failed (space4[%d][%d][%d][%d] = %d, not %d)\n", 0, 0, 0, 0, space4[0][0][0][0], 37); mem_destroy_space(&space4); if (space4) ++errors, printf("Test27: mem_destroy_space(1, 1, 1, 1) failed\n"); } if (!(space4 = mem_create_space(sizeof(int), (size_t)10, (size_t)10, (size_t)10, (size_t)10, (size_t)0))) ++errors, printf("Test28: mem_create_space(10, 10, 10, 10) failed (returned NULL)\n"); else { int error = 0; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) for (k = 0; k < 10; ++k) for (l = 0; l < 10; ++l) space4[i][j][k][l] = i + j + k + l; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) for (k = 0; k < 10; ++k) for (l = 0; l < 10; ++l) if (space4[i][j][k][l] != i + j + k + l) ++error, printf("Test29: mem_create_space(10, 10, 10, 10) failed (space4[%d][%d][%d][%d] = %d, not %d)\n", i, j, k, l, space4[i][j][k][l], i + j + k + l); if (error) ++errors; mem_destroy_space(&space4); if (space4) ++errors, printf("Test30: mem_destroy_space(10, 10, 10, 10) failed\n"); } /* Test 5D space allocation and deallocation */ if (!(space5 = mem_create_space(sizeof(int), (size_t)1, (size_t)1, (size_t)1, (size_t)1, (size_t)1, (size_t)0))) ++errors, printf("Test31: mem_create_space(1, 1, 1, 1, 1) failed (returned NULL)\n"); else { space5[0][0][0][0][0] = 37; if (space5[0][0][0][0][0] != 37) ++errors, printf("Test32: mem_create_space(1, 1, 1, 1, 1) failed (space5[%d][%d][%d][%d][%d] = %d, not %d)\n", 0, 0, 0, 0, 0, space5[0][0][0][0][0], 37); mem_destroy_space(&space5); if (space5) ++errors, printf("Test33: mem_destroy_space(1, 1, 1, 1, 1) failed\n"); } if (!(space5 = mem_create_space(sizeof(int), (size_t)10, (size_t)10, (size_t)10, (size_t)10, (size_t)10, (size_t)0))) ++errors, printf("Test34: mem_create_space(10, 10, 10, 10, 10) failed (returned NULL)\n"); else { int error = 0; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) for (k = 0; k < 10; ++k) for (l = 0; l < 10; ++l) for (m = 0; m < 10; ++m) space5[i][j][k][l][m] = i + j + k + l + m; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) for (k = 0; k < 10; ++k) for (l = 0; l < 10; ++l) for (m = 0; m < 10; ++m) if (space5[i][j][k][l][m] != i + j + k + l + m) ++error, printf("Test35: mem_create_space(10, 10, 10, 10, 10) failed (space5[%d][%d][%d][%d][%d] = %d, not %d)\n", i, j, k, l, m, space5[i][j][k][l][m], i + j + k + l + m); if (error) ++errors; mem_destroy_space(&space5); if (space5) ++errors, printf("Test36: mem_destroy_space(10, 10, 10, 10, 10) failed\n"); } /* Test element sizes smaller than sizeof(void *) */ if (!(space2d = mem_create_space(sizeof(char), (size_t)1, (size_t)1, (size_t)0))) ++errors, printf("Test37: mem_create_space(char, 1, 1) failed (returned NULL)\n"); else { space2d[0][0] = 'a'; if (space2d[0][0] != 'a') ++errors, printf("Test38: mem_create_space(char, 1, 1) failed (space2d[%d][%d] = '%c', not '%c')\n", 0, 0, space2d[0][0], 'a'); mem_destroy_space(&space2d); if (space2d) ++errors, printf("Test39: mem_destroy_space(char, 1, 1) failed\n"); } if (!(space2d = mem_create_space(sizeof(char), (size_t)10, (size_t)10, (size_t)0))) ++errors, printf("Test40: mem_create_space(char, 10, 10) failed (returned NULL)\n"); else { int error = 0; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) space2d[i][j] = 'a' + (i + j) % 26; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) if (space2d[i][j] != 'a' + (i + j) % 26) ++error, printf("Test41: mem_create_space(char, 10, 10) failed (space2d[%d][%d] = '%c', not '%c')\n", i, j, space2d[i][j], 'a' + (i + j) % 26); if (error) ++errors; mem_destroy_space(&space2d); if (space2d) ++errors, printf("Test42: mem_destroy_space(char, 10, 10) failed\n"); } /* Test element sizes larger than sizeof(void *) */ if (!(space3d = mem_create_space(sizeof(double), (size_t)1, (size_t)1, (size_t)1, (size_t)0))) ++errors, printf("Test43: mem_create_space(double, 1, 1, 1) failed (returned NULL)\n"); else { space3d[0][0][0] = 37.5; if (space3d[0][0][0] != 37.5) ++errors, printf("Test44: mem_create_space(double, 1, 1, 1) failed (space3d[%d][%d][%d] = %g, not %g)\n", 0, 0, 0, space3d[0][0][0], 37.5); mem_destroy_space(&space3d); if (space3d) ++errors, printf("Test45: mem_destroy_space(double, 1, 1, 1) failed\n"); } if (!(space3d = mem_create_space(sizeof(double), (size_t)10, (size_t)10, (size_t)10, (size_t)0))) ++errors, printf("Test46: mem_create_space(double, 10, 10, 10) failed (returned NULL)\n"); else { int error = 0; for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) for (k = 0; k < 10; ++k) space3d[i][j][k] = (double)(i + j + k); for (i = 0; i < 10; ++i) for (j = 0; j < 10; ++j) for (k = 0; k < 10; ++k) if (space3d[i][j][k] != (double)(i + j + k)) ++error, printf("Test47: mem_create_space(double, 10, 10, 10) failed (space3[%d][%d][%d] = %g, not %g)\n", i, j, k, space3d[i][j][k], (double)(i + j + k)); if (error) ++errors; mem_destroy_space(&space3d); if (space3d) ++errors, printf("Test48: mem_destroy_space(double, 10, 10, 10) failed\n"); } /* Test mem_space_start() */ if (!(space4 = mem_create_space(sizeof(int), (size_t)2, (size_t)3, (size_t)4, (size_t)5, (size_t)0))) ++errors, printf("Test49: mem_create_space(int, 2, 3, 4, 5) failed (returned NULL)\n"); else { int error = 0; size_t start; for (i = 0; i < 2; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 4; ++k) for (l = 0; l < 5; ++l) space4[i][j][k][l] = i + j + k + l; for (i = 0; i < 2; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 4; ++k) for (l = 0; l < 5; ++l) if (space4[i][j][k][l] != i + j + k + l) ++error, printf("Test50: mem_create_space(int, 2, 3, 4, 5) failed (space4[%d][%d][%d][%d] = %d, not %d)\n", i, j, k, l, space4[i][j][k][l], i + j + k + l); if (error) ++errors; start = mem_space_start(sizeof(int), (size_t)2, (size_t)3, (size_t)4, (size_t)5, (size_t)0); memset((char *)space4 + start, 0, sizeof(int) * 2 * 3 * 4 * 5); for (i = 0; i < 2; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 4; ++k) for (l = 0; l < 4; ++l) if (space4[i][j][k][l] != 0) ++error, printf("Test51: mem_space_start(int, 2, 3, 4, 5) failed (space4[%d][%d][%d][%d] = %d, not %d)\n", i, j, k, l, space4[i][j][k][l], 0); for (i = 0; i < 2; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 4; ++k) for (l = 0; l < 5; ++l) space4[i][j][k][l] = i + j + k + l; for (i = 0; i < 2; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 4; ++k) for (l = 0; l < 5; ++l) if (space4[i][j][k][l] != i + j + k + l) ++error, printf("Test52: mem_space_start(int, 2, 3, 4, 5) failed (space4[%d][%d][%d][%d] = %d, not %d)\n", i, j, k, l, space4[i][j][k][l], i + j + k + l); if (error) ++errors; mem_destroy_space(&space4); if (space4) ++errors, printf("Test53: mem_destroy_space(int, 2, 3, 4, 5) failed\n"); } /* Test pool functions */ start_clock = clock(); if (!(pool = pool_create(1024 * 1024))) ++errors, printf("Test54: pool_create(1024 * 1024) failed: %s\n", strerror(errno)); else { for (i = 0; i < 1024 * 1024; ++i) { if (!pool_new(pool, char)) { ++errors, printf("Test55: pool_alloc() failed: %s\n", strerror(errno)); break; } } errno = 0; if (pool_alloc(pool, 1) != NULL || errno != ENOSPC) ++errors, printf("Test56: pool_alloc(pool, 1) failed (errno %d, not %d)\n", errno, ENOSPC); errno = 0; if (pool_alloc(NULL, 1) != NULL || errno != EINVAL) ++errors, printf("Test57: pool_alloc(NULL, 1) failed (errno %d, not %d)\n", errno, EINVAL); pool_clear(pool); if (!pool_alloc(pool, 1)) ++errors, printf("Test58: pool_clear(), pool_alloc() failed: %s\n", strerror(errno)); pool_destroy(&pool); if (pool) ++errors, printf("Test59: pool_destroy() failed (%p, not NULL)\n", (void *)pool); } end_clock = clock(); pool_time = end_clock - start_clock; if (ac == 2 && !strcmp(av[1], "pool")) { start_clock = clock(); for (i = 0; i < 1024 * 1024; ++i) free(malloc(1)); end_clock = clock(); malloc_time = end_clock - start_clock; printf("malloc %ldus, pool %ldus (pool %g times faster than malloc)\n", malloc_time, pool_time, (double)malloc_time / (double)pool_time); } /* Test secure mem/pool functions */ no_secure_mem = 0; /* (getuid() != 0); */ if (!no_secure_mem) { #ifdef MLOCK_REQUIRES_PAGE_BOUNDARY /* Test that page boundary is a power of two */ long pagesize; if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) ++errors, printf("Test60: Failed to perform test: sysconf(_SC_PAGESIZE) failed\n"); else { long size = pagesize; int bits; for (bits = 0; size; size >>= 1) if (size & 1) ++bits; if (bits != 1) ++errors, printf("Test60: pagesize (%ld) is not a power of 2! Secure memory won't work\n", pagesize); } #endif if (!(mem1 = mem_create_secure(1024))) ++errors, printf("Test61: mem_create_secure(1024) failed: %s (Does mlock() require root privileges on this system? If so, audit this code and rerun it as root)\n", strerror(errno)); else { mem_destroy_secure(&mem1); if (mem1) ++errors, printf("Test62: mem_destroy_secure(1024) failed: mem == %p, not NULL\n", (void *)mem1); } if (!(pool = pool_create_secure(32))) ++errors, printf("Test63: pool_create_secure(32) failed: %s (Does mlock() require root privileges on this system? If so, audit this code and rerun it as root)\n", strerror(errno)); else { void *whitebox = pool->pool; if (!(mem1 = pool_alloc(pool, 32))) ++errors, printf("Test64: pool_alloc(pool, 32) failed: %s\n", strerror(errno)); memset(mem1, 0xff, 32); pool_destroy_secure(&pool); /* Note: This test may be invalid because the memory has already been deallocated */ if (memcmp(whitebox, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32)) { if (!memcmp(whitebox, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 32)) ++errors, printf("Test65: pool_destroy_secure(32) failed: memory not cleared\n"); else { ++errors, printf("Test65: pool_destroy_secure(32) failed: memory not cleared (possibly - or maybe the already-deallocated memory has just been reused by now)\n"); { int i; printf("content = \""); for (i = 0; i < 32; i++) printf("\\x%02x", ((unsigned char *)whitebox)[i]); printf("\" (should be all or mostly \\x00)\n"); } } } if (pool) ++errors, printf("Test66: pool_destroy_secure(32) failed: pool == %p, not NULL\n", (void *)pool); } } /* Test assumption: memory failure results in errno == ENOMEM */ errno = 0; str = NULL; if (!mem_resize(&str, UINT_MAX) && errno != ENOMEM) ++errors, printf("Test67: assumption failed: realloc failed but errno == \"%s\" (not \"%s\")\n", strerror(errno), strerror(ENOMEM)); if (errors) printf("%d/67 tests failed\n", errors); else printf("All tests passed\n"); if (no_secure_mem) { printf("\n"); printf(" Note: Can't perform secure memory tests.\n"); printf(" Audit the code and rerun the test as root.\n"); } return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/mem.h0000644000175000017500000000571414014141213013437 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ #ifndef LIBSLACK_MEM_H #define LIBSLACK_MEM_H #include #include #include #ifndef null #define null NULL #endif #ifndef nul #define nul '\0' #endif typedef struct Pool Pool; _begin_decls #define mem_new(type) malloc(sizeof(type)) #define mem_create(size, type) malloc((size) * sizeof(type)) #define mem_resize(mem, size) mem_resize_fn((void **)(mem), (size) * sizeof(**(mem))) void *mem_resize_fn(void **mem, size_t size); #define mem_release(mem) free(mem) void *mem_destroy(void **mem); #define mem_destroy(mem) (mem_destroy)((void **)(mem)) void *mem_create_secure(size_t size); void mem_release_secure(void *mem); void *mem_destroy_secure(void **mem); #define mem_destroy_secure(mem) (mem_destroy_secure)((void **)(mem)) char *mem_strdup(const char *str); #define mem_create2d(i, j, type) ((type **)mem_create_space(sizeof(type), (i), (j), 0)) #define mem_create3d(i, j, k, type) ((type ***)mem_create_space(sizeof(type), (i), (j), (k), 0)) #define mem_create4d(i, j, k, l, type) ((type ****)mem_create_space(sizeof(type), (i), (j), (k), (l), 0)) void *mem_create_space(size_t size, ...); size_t mem_space_start(size_t size, ...); #define mem_release2d(space) mem_release_space(space) #define mem_release3d(space) mem_release_space(space) #define mem_release4d(space) mem_release_space(space) #define mem_release_space(space) mem_release(space) #define mem_destroy2d(space) mem_destroy_space(space) #define mem_destroy3d(space) mem_destroy_space(space) #define mem_destroy4d(space) mem_destroy_space(space) #define mem_destroy_space(space) mem_destroy(space) Pool *pool_create(size_t size); Pool *pool_create_with_locker(Locker *locker, size_t size); void pool_release(Pool *pool); void *pool_destroy(Pool **pool); Pool *pool_create_secure(size_t size); Pool *pool_create_secure_with_locker(Locker *locker, size_t size); void pool_release_secure(Pool *pool); void *pool_destroy_secure(Pool **pool); void pool_clear_secure(Pool *pool); #define pool_new(pool, type) pool_alloc((pool), sizeof(type)) #define pool_newsz(pool, size, type) pool_alloc((pool), (size) * sizeof(type)) void *pool_alloc(Pool *pool, size_t size); void pool_clear(Pool *pool); _end_decls #endif /* vi:set ts=4 sw=4: */ daemon-0.8/libslack/msg.c0000644000175000017500000012512414014141213013440 0ustar rafraf/* * libslack - http://libslack.org/ * * Copyright (C) 1999-2002, 2004, 2010, 2020-2021 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20210220 raf */ /* =head1 NAME I - message module =head1 SYNOPSIS #include #include typedef struct Msg Msg; typedef void msg_out_t(void *data, const void *mesg, size_t mesglen); typedef int msg_filter_t(void **mesgp, const void *mesg, size_t mesglen); typedef void msg_release_t(void *data); Msg *msg_create(int type, msg_out_t *out, void *data, msg_release_t *destroy); Msg *msg_create_with_locker(Locker *locker, int type, msg_out_t *out, void *data, msg_release_t *destroy); int msg_rdlock(Msg *mesg); int msg_wrlock(Msg *mesg); int msg_unlock(Msg *mesg); void msg_release(Msg *mesg); void *msg_destroy(Msg **mesg); void msg_out(Msg *dst, const char *format, ...); void msg_out_unlocked(Msg *dst, const char *format, ...); void vmsg_out(Msg *dst, const char *format, va_list args); void vmsg_out_unlocked(Msg *dst, const char *format, va_list args); Msg *msg_create_fd(int fd); Msg *msg_create_fd_with_locker(Locker *locker, int fd); Msg *msg_create_stderr(void); Msg *msg_create_stderr_with_locker(Locker *locker); Msg *msg_create_stdout(void); Msg *msg_create_stdout_with_locker(Locker *locker); Msg *msg_create_file(const char *path); Msg *msg_create_file_with_locker(Locker *locker, const char *path); Msg *msg_create_syslog(const char *ident, int option, int facility, int priority); Msg *msg_create_syslog_with_locker(Locker *locker, const char *ident, int option, int facility, int priority); Msg *msg_syslog_set_facility(Msg *mesg, int facility); Msg *msg_syslog_set_facility_unlocked(Msg *mesg, int facility); Msg *msg_syslog_set_priority(Msg *mesg, int priority); Msg *msg_syslog_set_priority_unlocked(Msg *mesg, int priority); Msg *msg_create_plex(Msg *msg1, Msg *msg2); Msg *msg_create_plex_with_locker(Locker *locker, Msg *msg1, Msg *msg2); int msg_add_plex(Msg *mesg, Msg *item); int msg_add_plex_unlocked(Msg *mesg, Msg *item); Msg *msg_create_filter(msg_filter_t *filter, Msg *mesg); Msg *msg_create_filter_with_locker(Locker *locker, msg_filter_t *filter, Msg *mesg); const char *msg_set_timestamp_format(const char *format); int msg_set_timestamp_format_locker(Locker *locker); int syslog_lookup_facility(const char *facility); int syslog_lookup_priority(const char *priority); const char *syslog_facility_str(int spec); const char *syslog_priority_str(int spec); int syslog_parse(const char *spec, int *facility, int *priority); =head1 DESCRIPTION This module provides general messaging functions. Message channels can be created that send messages to a file descriptor, a file, I or a client defined message handler or that multiplexes messages to any combination of the above. Messages sent to files are timestamped using (by default) the I format: C<"%Y%m%d %H:%M:%S">. It also provides functions for parsing I targets, converting between I facility names and codes, and converting between I priority names and codes. =over 4 =cut */ #ifndef _BSD_SOURCE #define _BSD_SOURCE /* For snprintf() on OpenBSD-4.7 */ #endif #ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE /* New name for _BSD_SOURCE */ #endif #include "config.h" #include "std.h" #include #include #include #include #include "msg.h" #include "mem.h" #include "err.h" #include "str.h" #ifndef HAVE_SNPRINTF #include "snprintf.h" #endif typedef int MsgFDData; typedef struct MsgFileData MsgFileData; typedef struct MsgSyslogData MsgSyslogData; typedef struct MsgFilterData MsgFilterData; typedef struct MsgPlexData MsgPlexData; #define MSG_FD 1 #define MSG_FILE 2 #define MSG_SYSLOG 3 #define MSG_PLEX 4 #define MSG_FILTER 5 struct Msg { int type; /* subtype */ msg_out_t *out; /* message handling function */ void *data; /* subtype specific data */ msg_release_t *destroy; /* destructor function for data */ Locker *locker; /* locking strategy for this structure */ }; struct MsgFileData { int fd; /* file descriptor (-1 if open failed) */ }; struct MsgSyslogData { int facility; /* syslog(3) priority */ int priority; /* syslog(3) priority */ }; struct MsgPlexData { size_t size; /* elements allocated */ size_t length; /* length of Msg list */ Msg **list; /* list of Msg objects */ }; struct MsgFilterData { msg_filter_t *filter; /* filter function */ Msg *mesg; /* destination Msg */ }; typedef struct syslog_map_t syslog_map_t; struct syslog_map_t { char *name; int val; }; /* ** The following masks might be wrong on some systems. */ #ifndef LOG_PRIMASK #define LOG_PRIMASK 0x0007 #endif #ifndef LOG_FACMASK #define LOG_FACMASK 0x03f8 #endif static const syslog_map_t syslog_facility_map[] = { { "kern", LOG_KERN }, { "user", LOG_USER }, { "mail", LOG_MAIL }, { "daemon", LOG_DAEMON }, { "auth", LOG_AUTH }, { "syslog", LOG_SYSLOG }, { "lpr", LOG_LPR }, { "news", LOG_NEWS }, { "uucp", LOG_UUCP }, { "cron", LOG_CRON }, { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, { NULL, -1 } }; static const syslog_map_t syslog_priority_map[] = { { "emerg", LOG_EMERG }, { "alert", LOG_ALERT }, { "crit", LOG_CRIT }, { "err", LOG_ERR }, { "warning", LOG_WARNING }, #ifdef LOG_NOTICE { "notice", LOG_NOTICE }, #endif { "info", LOG_INFO }, { "debug", LOG_DEBUG }, { NULL, -1 } }; #ifndef TEST static const char *timestamp_format = "%Y%m%d %H:%M:%S "; static Locker *timestamp_format_locker = NULL; /* =item C Creates a I object initialised with C, C, C and C. Client-defined message handlers must specify a C greater than C<5>. It is the caller's responsibility to deallocate the new I with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new I object. On error, returns C. =cut */ Msg *msg_create(int type, msg_out_t *out, void *data, msg_release_t *destroy) { return msg_create_with_locker(NULL, type, out, data, destroy); } /* =item C Equivalent to I except that multiple threads accessing the new I will be synchronised by C. =cut */ Msg *msg_create_with_locker(Locker *locker, int type, msg_out_t *out, void *data, msg_release_t *destroy) { Msg *mesg; if (!(mesg = mem_new(Msg))) return NULL; mesg->type = type; mesg->out = out; mesg->data = data; mesg->destroy = destroy; mesg->locker = locker; return mesg; } /* =item C Claims a read lock on C (if C was created with a I). This is needed when multiple read-only I module functions need to be called atomically. It is the caller's responsibility to call I after the atomic operation. The only functions that may be called on C between calls to I and I are any read-only I module functions whose name ends with C<_unlocked>. On success, returns C<0>. On error, returns an error code. =cut */ #define msg_rdlock(mesg) ((mesg) ? locker_rdlock((mesg)->locker) : EINVAL) #define msg_wrlock(mesg) ((mesg) ? locker_wrlock((mesg)->locker) : EINVAL) #define msg_unlock(mesg) ((mesg) ? locker_unlock((mesg)->locker) : EINVAL) int (msg_rdlock)(Msg *mesg) { return msg_rdlock(mesg); } /* =item C Claims a write lock on C. Claims a write lock on C (if C was created with a I). This is needed when multiple read/write I module functions need to be called atomically. It is the caller's responsibility to call I after the atomic operation. The only functions that may be called on C between calls to I and I are any I module functions whose name ends with C<_unlocked>. On success, returns C<0>. On error, returns an error code. =cut */ int (msg_wrlock)(Msg *mesg) { return msg_wrlock(mesg); } /* =item C Unlocks a read or write lock on C obtained with I or I (if C was created with a I). On success, returns C<0>. On error, returns an error code. =cut */ int (msg_unlock)(Msg *mesg) { return msg_unlock(mesg); } /* =item C Releases (deallocates) C and its internal data. =cut */ void msg_release(Msg *mesg) { if (!mesg) return; if (mesg->destroy) mesg->destroy(mesg->data); mem_release(mesg); } /* =item C Destroys (deallocates and sets to C) C<*mesg>. Returns C. =cut */ void *msg_destroy(Msg **mesg) { if (mesg && *mesg) { msg_release(*mesg); *mesg = NULL; } return NULL; } /* =item C Sends a message to C. C is a I-like format string. Any remaining arguments are processed as in I. B msg_out(dst, buf); // EVIL msg_out(dst, "%s", buf); // GOOD =cut */ void msg_out(Msg *dst, const char *format, ...) { va_list args; va_start(args, format); vmsg_out(dst, format, args); va_end(args); } /* =item C Equivalent to I except that C is not read-locked. =cut */ void msg_out_unlocked(Msg *dst, const char *format, ...) { va_list args; va_start(args, format); vmsg_out_unlocked(dst, format, args); va_end(args); } /* =item C Sends a message to C. C is a I-like format string. C is processed as in I. =cut */ void vmsg_out(Msg *dst, const char *format, va_list args) { int err; if (!dst) return; if ((err = msg_rdlock(dst))) { set_errno(err); return; } vmsg_out_unlocked(dst, format, args); if ((err = msg_unlock(dst))) set_errno(err); } /* =item C Equivalent to I except that C is not read-locked. =cut */ void vmsg_out_unlocked(Msg *dst, const char *format, va_list args) { if (!dst) return; if (dst->out) { char mesg[MSG_SIZE]; vsnprintf(mesg, MSG_SIZE, format, args); dst->out(dst->data, mesg, strlen(mesg)); } } /* C Creates and initialises the internal data needed by a I object that sends messages to file descriptor C. On success, returns the data. On error, returns C. */ static MsgFDData *msg_fddata_create(int fd) { MsgFDData *data; if (!(data = mem_new(MsgFDData))) return NULL; *data = fd; return data; } /* C Releases (deallocates) the internal data needed by a I object that sends messages to a file descriptor. The file descriptor is not closed. */ static void msg_fddata_release(MsgFDData *data) { mem_release(data); } /* C Sends a message to a file descriptor. C is a pointer to the file descriptor. C is the message. C is its length. */ static void msg_out_fd(void *data, const void *mesg, size_t mesglen) { if (data && mesg) if (write(*(MsgFDData *)data, mesg, mesglen) == -1) /* Avoid gcc warning */; } /* =item C Creates a I object that sends messages to file descriptor C. It is the caller's responsibility to deallocate the new I with I or I. On success, returns the new I object. On error, returns C. =cut */ Msg *msg_create_fd(int fd) { return msg_create_fd_with_locker(NULL, fd); } /* =item C Equivalent to I except that multiple threads accessing the new I will be synchronised by C. =cut */ Msg *msg_create_fd_with_locker(Locker *locker, int fd) { MsgFDData *data; Msg *mesg; if (!(data = msg_fddata_create(fd))) return NULL; if (!(mesg = msg_create_with_locker(locker, MSG_FD, msg_out_fd, data, (msg_release_t *)msg_fddata_release))) { msg_fddata_release(data); return NULL; } return mesg; } /* =item C Creates a I object that sends messages to standard error. It is the caller's responsibility to deallocate the new I with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new I object. On error, returns C. =cut */ Msg *msg_create_stderr(void) { return msg_create_fd_with_locker(NULL, STDERR_FILENO); } /* =item C Equivalent to I except that multiple threads accessing the new I will be synchronised by C. =cut */ Msg *msg_create_stderr_with_locker(Locker *locker) { return msg_create_fd_with_locker(locker, STDERR_FILENO); } /* =item C Creates a I object that sends messages to standard output. It is the caller's responsibility to deallocate the new I with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new I object. On error, returns C. =cut */ Msg *msg_create_stdout(void) { return msg_create_fd_with_locker(NULL, STDOUT_FILENO); } /* =item C Equivalent to I except that multiple threads accessing the new I will be synchronised by C. =cut */ Msg *msg_create_stdout_with_locker(Locker *locker) { return msg_create_fd_with_locker(locker, STDOUT_FILENO); } /* C Initialises the internal data needed by a I object that sends messages to the file specified by C. This data consists of a copy of C and an open file descriptor to the file. The file descriptor is opened with the C, C, and C flags. On success, returns C<0>. On error, returns C<-1> with C set appropriately. */ static int msg_filedata_init(MsgFileData *data, const char *path) { mode_t mode; if (!data || !path) return set_errno(EINVAL); mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; if ((data->fd = open(path, O_WRONLY | O_CREAT | O_APPEND, mode)) == -1) return -1; return 0; } /* C Creates the internal data needed by a I object that sends messages to the file specified by C. On success, returns the data. On error, returns C with C set appropriately. */ static MsgFileData *msg_filedata_create(const char *path) { MsgFileData *data; if (!(data = mem_new(MsgFileData))) return NULL; if (msg_filedata_init(data, path) == -1) { mem_release(data); return NULL; } return data; } /* C Releases (deallocates) the internal data needed by a I object that sends messages to a file. The file descriptor is closed first. */ static void msg_filedata_release(MsgFileData *data) { if (!data) return; if (data->fd != -1) close(data->fd); mem_release(data); } /* C Sends a message to a file. C contains the file descriptor. C is the message. C is its length. On error, sets C appropriately. */ static void msg_out_file(void *data, const void *mesg, size_t mesglen) { MsgFileData *dst = data; char buf[MSG_SIZE]; size_t buflen; int err; time_t t = time(NULL); if ((err = locker_rdlock(timestamp_format_locker))) { set_errno(err); return; } strftime(buf, MSG_SIZE, timestamp_format, localtime(&t)); if ((err = locker_unlock(timestamp_format_locker))) { set_errno(err); return; } buflen = strlen(buf); if (buflen + mesglen >= MSG_SIZE) mesglen -= MSG_SIZE - buflen; memmove(buf + buflen, mesg, mesglen); if (mesg && dst && dst->fd != -1) if (write(dst->fd, buf, buflen + mesglen) == -1) /* Avoid gcc warning */; } /* =item C Creates a I object that sends messages to the file specified by C. It is the caller's responsibility to deallocate the new I with I or I. It is strongly recommended to use I, because it also sets the pointer variable to C. On success, returns the new I object. On error, returns C with C set appropriately. =cut */ Msg *msg_create_file(const char *path) { return msg_create_file_with_locker(NULL, path); } /* =item C Equivalent to I except that multiple threads accessing the new I will be synchronised by C. =cut */ Msg *msg_create_file_with_locker(Locker *locker, const char *path) { MsgFileData *data; Msg *mesg; if (!(data = msg_filedata_create(path))) return NULL; if (!(mesg = msg_create_with_locker(locker, MSG_FILE, msg_out_file, data, (msg_release_t *)msg_filedata_release))) { msg_filedata_release(data); return NULL; } return mesg; } /* C Initialises the internal data needed by a I object that sends messages to I. I is called with C and C