Imported Upstream version 2.4.3
This commit is contained in:
commit
26fb71b504
446 changed files with 148951 additions and 0 deletions
15
common/Makefile.am
Normal file
15
common/Makefile.am
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Network UPS Tools: common
|
||||
|
||||
AM_CFLAGS = -I$(top_srcdir)/include
|
||||
|
||||
noinst_LIBRARIES = libcommon.a
|
||||
libcommon_a_SOURCES = common.c state.c upsconf.c ../include/nut_version.h
|
||||
libcommon_a_LIBADD = libparseconf.la
|
||||
|
||||
../include/nut_version.h: FORCE
|
||||
(cd ../include/ && $(MAKE) $(AM_MAKEFLAGS) nut_version.h)
|
||||
|
||||
FORCE:
|
||||
|
||||
noinst_LTLIBRARIES = libparseconf.la
|
||||
libparseconf_la_SOURCES = parseconf.c
|
555
common/Makefile.in
Normal file
555
common/Makefile.in
Normal file
|
@ -0,0 +1,555 @@
|
|||
# Makefile.in generated by automake 1.11 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
|
||||
# Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Network UPS Tools: common
|
||||
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
subdir = common
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_create_stdint_h.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
|
||||
$(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/m4/nut_arg_with.m4 \
|
||||
$(top_srcdir)/m4/nut_check_ipv6.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libgd.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libhal.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libneon.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libnetsnmp.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libpowerman.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libssl.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libusb.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libwrap.m4 \
|
||||
$(top_srcdir)/m4/nut_check_os.m4 \
|
||||
$(top_srcdir)/m4/nut_report_feature.m4 \
|
||||
$(top_srcdir)/m4/nut_type_socklen_t.m4 \
|
||||
$(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/include/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
LIBRARIES = $(noinst_LIBRARIES)
|
||||
ARFLAGS = cru
|
||||
libcommon_a_AR = $(AR) $(ARFLAGS)
|
||||
libcommon_a_DEPENDENCIES = libparseconf.la
|
||||
am_libcommon_a_OBJECTS = common.$(OBJEXT) state.$(OBJEXT) \
|
||||
upsconf.$(OBJEXT)
|
||||
libcommon_a_OBJECTS = $(am_libcommon_a_OBJECTS)
|
||||
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
||||
libparseconf_la_LIBADD =
|
||||
am_libparseconf_la_OBJECTS = parseconf.lo
|
||||
libparseconf_la_OBJECTS = $(am_libparseconf_la_OBJECTS)
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(libcommon_a_SOURCES) $(libparseconf_la_SOURCES)
|
||||
DIST_SOURCES = $(libcommon_a_SOURCES) $(libparseconf_la_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BINDIR = @BINDIR@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CONFPATH = @CONFPATH@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@
|
||||
DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@
|
||||
DRIVER_MAN_LIST = @DRIVER_MAN_LIST@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
HAL_CALLOUTS_PATH = @HAL_CALLOUTS_PATH@
|
||||
HAL_DEVICE_MATCH_KEY = @HAL_DEVICE_MATCH_KEY@
|
||||
HAL_FDI_PATH = @HAL_FDI_PATH@
|
||||
HAL_USER = @HAL_USER@
|
||||
HAVE_GLIB_2_14 = @HAVE_GLIB_2_14@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBGD_CFLAGS = @LIBGD_CFLAGS@
|
||||
LIBGD_LDFLAGS = @LIBGD_LDFLAGS@
|
||||
LIBHAL_CFLAGS = @LIBHAL_CFLAGS@
|
||||
LIBHAL_LDFLAGS = @LIBHAL_LDFLAGS@
|
||||
LIBNEON_CFLAGS = @LIBNEON_CFLAGS@
|
||||
LIBNEON_LDFLAGS = @LIBNEON_LDFLAGS@
|
||||
LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@
|
||||
LIBNETSNMP_LDFLAGS = @LIBNETSNMP_LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@
|
||||
LIBPOWERMAN_LDFLAGS = @LIBPOWERMAN_LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
LIBSSL_CFLAGS = @LIBSSL_CFLAGS@
|
||||
LIBSSL_LDFLAGS = @LIBSSL_LDFLAGS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIBUSB_CFLAGS = @LIBUSB_CFLAGS@
|
||||
LIBUSB_LDFLAGS = @LIBUSB_LDFLAGS@
|
||||
LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@
|
||||
LIBWRAP_LDFLAGS = @LIBWRAP_LDFLAGS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NETLIBS = @NETLIBS@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OS_NAME = @OS_NAME@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
RUN_AS_GROUP = @RUN_AS_GROUP@
|
||||
RUN_AS_USER = @RUN_AS_USER@
|
||||
SED = @SED@
|
||||
SERLIBS = @SERLIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STATEPATH = @STATEPATH@
|
||||
STRIP = @STRIP@
|
||||
SUN_LIBUSB = @SUN_LIBUSB@
|
||||
VERSION = @VERSION@
|
||||
WORDS_BIGENDIAN = @WORDS_BIGENDIAN@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
cgiexecdir = @cgiexecdir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
driverexecdir = @driverexecdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
hotplugdir = @hotplugdir@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
lt_ECHO = @lt_ECHO@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
pkgconfigdir = @pkgconfigdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
udevdir = @udevdir@
|
||||
AM_CFLAGS = -I$(top_srcdir)/include
|
||||
noinst_LIBRARIES = libcommon.a
|
||||
libcommon_a_SOURCES = common.c state.c upsconf.c ../include/nut_version.h
|
||||
libcommon_a_LIBADD = libparseconf.la
|
||||
noinst_LTLIBRARIES = libparseconf.la
|
||||
libparseconf_la_SOURCES = parseconf.c
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu common/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu common/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstLIBRARIES:
|
||||
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
|
||||
libcommon.a: $(libcommon_a_OBJECTS) $(libcommon_a_DEPENDENCIES)
|
||||
-rm -f libcommon.a
|
||||
$(libcommon_a_AR) libcommon.a $(libcommon_a_OBJECTS) $(libcommon_a_LIBADD)
|
||||
$(RANLIB) libcommon.a
|
||||
|
||||
clean-noinstLTLIBRARIES:
|
||||
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
|
||||
@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
libparseconf.la: $(libparseconf_la_OBJECTS) $(libparseconf_la_DEPENDENCIES)
|
||||
$(LINK) $(libparseconf_la_OBJECTS) $(libparseconf_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parseconf.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/state.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsconf.Po@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LIBRARIES) $(LTLIBRARIES)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
|
||||
clean-noinstLTLIBRARIES mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool clean-noinstLIBRARIES clean-noinstLTLIBRARIES \
|
||||
ctags distclean distclean-compile distclean-generic \
|
||||
distclean-libtool distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags uninstall uninstall-am
|
||||
|
||||
|
||||
../include/nut_version.h: FORCE
|
||||
(cd ../include/ && $(MAKE) $(AM_MAKEFLAGS) nut_version.h)
|
||||
|
||||
FORCE:
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
540
common/common.c
Normal file
540
common/common.c
Normal file
|
@ -0,0 +1,540 @@
|
|||
/* common.c - common useful functions
|
||||
|
||||
Copyright (C) 2000 Russell Kroll <rkroll@exploits.org>
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <syslog.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
/* the reason we define UPS_VERSION as a static string, rather than a
|
||||
macro, is to make dependency tracking easier (only common.o depends
|
||||
on nut_version_macro.h), and also to prevent all sources from
|
||||
having to be recompiled each time the version changes (they only
|
||||
need to be re-linked). */
|
||||
#include "nut_version.h"
|
||||
const char *UPS_VERSION = NUT_VERSION_MACRO;
|
||||
|
||||
int nut_debug_level = 0;
|
||||
static int upslog_flags = UPSLOG_STDERR;
|
||||
|
||||
static void xbit_set(int *val, int flag)
|
||||
{
|
||||
*val = (*val |= flag);
|
||||
}
|
||||
|
||||
static void xbit_clear(int *val, int flag)
|
||||
{
|
||||
*val = (*val ^= (*val & flag));
|
||||
}
|
||||
|
||||
static int xbit_test(int val, int flag)
|
||||
{
|
||||
return ((val & flag) == flag);
|
||||
}
|
||||
|
||||
/* enable writing upslog_with_errno() and upslogx() type messages to
|
||||
the syslog */
|
||||
void syslogbit_set(void)
|
||||
{
|
||||
xbit_set(&upslog_flags, UPSLOG_SYSLOG);
|
||||
}
|
||||
|
||||
/* get the syslog ready for us */
|
||||
void open_syslog(const char *progname)
|
||||
{
|
||||
int opt;
|
||||
|
||||
opt = LOG_PID;
|
||||
|
||||
/* we need this to grab /dev/log before chroot */
|
||||
#ifdef LOG_NDELAY
|
||||
opt |= LOG_NDELAY;
|
||||
#endif
|
||||
|
||||
openlog(progname, opt, LOG_FACILITY);
|
||||
}
|
||||
|
||||
/* close ttys and become a daemon */
|
||||
void background(void)
|
||||
{
|
||||
int pid;
|
||||
|
||||
if ((pid = fork()) < 0)
|
||||
fatal_with_errno(EXIT_FAILURE, "Unable to enter background");
|
||||
|
||||
xbit_set(&upslog_flags, UPSLOG_SYSLOG);
|
||||
xbit_clear(&upslog_flags, UPSLOG_STDERR);
|
||||
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
|
||||
if (pid != 0)
|
||||
_exit(EXIT_SUCCESS); /* parent */
|
||||
|
||||
/* child */
|
||||
|
||||
/* make fds 0-2 point somewhere defined */
|
||||
if (open("/dev/null", O_RDWR) != 0)
|
||||
fatal_with_errno(EXIT_FAILURE, "open /dev/null");
|
||||
|
||||
if (dup(0) == -1)
|
||||
fatal_with_errno(EXIT_FAILURE, "dup");
|
||||
|
||||
if (dup(0) == -1)
|
||||
fatal_with_errno(EXIT_FAILURE, "dup");
|
||||
|
||||
#ifdef HAVE_SETSID
|
||||
setsid(); /* make a new session to dodge signals */
|
||||
#endif
|
||||
|
||||
upslogx(LOG_INFO, "Startup successful");
|
||||
}
|
||||
|
||||
/* do this here to keep pwd/grp stuff out of the main files */
|
||||
struct passwd *get_user_pwent(const char *name)
|
||||
{
|
||||
struct passwd *r;
|
||||
errno = 0;
|
||||
if ((r = getpwnam(name)))
|
||||
return r;
|
||||
|
||||
/* POSIX does not specify that "user not found" is an error, so
|
||||
some implementations of getpwnam() do not set errno when this
|
||||
happens. */
|
||||
if (errno == 0)
|
||||
fatalx(EXIT_FAILURE, "user %s not found", name);
|
||||
else
|
||||
fatal_with_errno(EXIT_FAILURE, "getpwnam(%s)", name);
|
||||
|
||||
return NULL; /* to make the compiler happy */
|
||||
}
|
||||
|
||||
/* change to the user defined in the struct */
|
||||
void become_user(struct passwd *pw)
|
||||
{
|
||||
/* if we can't switch users, then don't even try */
|
||||
if ((geteuid() != 0) && (getuid() != 0))
|
||||
return;
|
||||
|
||||
if (getuid() == 0)
|
||||
if (seteuid(0))
|
||||
fatal_with_errno(EXIT_FAILURE, "getuid gave 0, but seteuid(0) failed");
|
||||
|
||||
if (initgroups(pw->pw_name, pw->pw_gid) == -1)
|
||||
fatal_with_errno(EXIT_FAILURE, "initgroups");
|
||||
|
||||
if (setgid(pw->pw_gid) == -1)
|
||||
fatal_with_errno(EXIT_FAILURE, "setgid");
|
||||
|
||||
if (setuid(pw->pw_uid) == -1)
|
||||
fatal_with_errno(EXIT_FAILURE, "setuid");
|
||||
}
|
||||
|
||||
/* drop down into a directory and throw away pointers to the old path */
|
||||
void chroot_start(const char *path)
|
||||
{
|
||||
if (chdir(path))
|
||||
fatal_with_errno(EXIT_FAILURE, "chdir(%s)", path);
|
||||
|
||||
if (chroot(path))
|
||||
fatal_with_errno(EXIT_FAILURE, "chroot(%s)", path);
|
||||
|
||||
if (chdir("/"))
|
||||
fatal_with_errno(EXIT_FAILURE, "chdir(/)");
|
||||
|
||||
upsdebugx(1, "chrooted into %s", path);
|
||||
}
|
||||
|
||||
/* drop off a pidfile for this process */
|
||||
void writepid(const char *name)
|
||||
{
|
||||
char fn[SMALLBUF];
|
||||
FILE *pidf;
|
||||
int mask;
|
||||
|
||||
/* use full path if present, else build filename in PIDPATH */
|
||||
if (*name == '/')
|
||||
snprintf(fn, sizeof(fn), "%s", name);
|
||||
else
|
||||
snprintf(fn, sizeof(fn), "%s/%s.pid", PIDPATH, name);
|
||||
|
||||
mask = umask(022);
|
||||
pidf = fopen(fn, "w");
|
||||
|
||||
if (pidf) {
|
||||
fprintf(pidf, "%d\n", (int) getpid());
|
||||
fclose(pidf);
|
||||
} else {
|
||||
upslog_with_errno(LOG_NOTICE, "writepid: fopen %s", fn);
|
||||
}
|
||||
|
||||
umask(mask);
|
||||
}
|
||||
|
||||
/* open pidfn, get the pid, then send it sig */
|
||||
int sendsignalfn(const char *pidfn, int sig)
|
||||
{
|
||||
char buf[SMALLBUF];
|
||||
FILE *pidf;
|
||||
int pid, ret;
|
||||
|
||||
pidf = fopen(pidfn, "r");
|
||||
if (!pidf) {
|
||||
upslog_with_errno(LOG_NOTICE, "fopen %s", pidfn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fgets(buf, sizeof(buf), pidf) == NULL) {
|
||||
upslogx(LOG_NOTICE, "Failed to read pid from %s", pidfn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = strtol(buf, (char **)NULL, 10);
|
||||
|
||||
if (pid < 2) {
|
||||
upslogx(LOG_NOTICE, "Ignoring invalid pid number %d", pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* see if this is going to work first */
|
||||
ret = kill(pid, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
perror("kill");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now actually send it */
|
||||
ret = kill(pid, sig);
|
||||
|
||||
if (ret < 0) {
|
||||
perror("kill");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snprintfcat(char *dst, size_t size, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
size_t len = strlen(dst);
|
||||
int ret;
|
||||
|
||||
size--;
|
||||
assert(len <= size);
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vsnprintf(dst + len, size - len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
dst[size] = '\0';
|
||||
return len + ret;
|
||||
}
|
||||
|
||||
/* lazy way to send a signal if the program uses the PIDPATH */
|
||||
int sendsignal(const char *progname, int sig)
|
||||
{
|
||||
char fn[SMALLBUF];
|
||||
|
||||
snprintf(fn, sizeof(fn), "%s/%s.pid", PIDPATH, progname);
|
||||
|
||||
return sendsignalfn(fn, sig);
|
||||
}
|
||||
|
||||
const char *xbasename(const char *file)
|
||||
{
|
||||
const char *p = strrchr(file, '/');
|
||||
|
||||
if (p == NULL)
|
||||
return file;
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
static void vupslog(int priority, const char *fmt, va_list va, int use_strerror)
|
||||
{
|
||||
int ret;
|
||||
char buf[LARGEBUF];
|
||||
|
||||
ret = vsnprintf(buf, sizeof(buf), fmt, va);
|
||||
|
||||
if ((ret < 0) || (ret >= (int) sizeof(buf)))
|
||||
syslog(LOG_WARNING, "vupslog: vsnprintf needed more than %d bytes",
|
||||
LARGEBUF);
|
||||
|
||||
if (use_strerror)
|
||||
snprintfcat(buf, sizeof(buf), ": %s", strerror(errno));
|
||||
|
||||
if (nut_debug_level > 0) {
|
||||
static struct timeval start = { 0 };
|
||||
struct timeval now;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
if (start.tv_sec == 0) {
|
||||
start = now;
|
||||
}
|
||||
|
||||
if (start.tv_usec > now.tv_usec) {
|
||||
now.tv_usec += 1000000;
|
||||
now.tv_sec -= 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%4.0f.%06ld\t", difftime(now.tv_sec, start.tv_sec), (long)(now.tv_usec - start.tv_usec));
|
||||
}
|
||||
|
||||
if (xbit_test(upslog_flags, UPSLOG_STDERR))
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
if (xbit_test(upslog_flags, UPSLOG_SYSLOG))
|
||||
syslog(priority, "%s", buf);
|
||||
}
|
||||
|
||||
/* Return the default path for the directory containing configuration files */
|
||||
const char * confpath(void)
|
||||
{
|
||||
const char * path;
|
||||
|
||||
if ((path = getenv("NUT_CONFPATH")) == NULL)
|
||||
path = CONFPATH;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* Return the default path for the directory containing state files */
|
||||
const char * dflt_statepath(void)
|
||||
{
|
||||
const char * path;
|
||||
|
||||
if ((path = getenv("NUT_STATEPATH")) == NULL)
|
||||
path = STATEPATH;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* Return the alternate path for pid files */
|
||||
const char * altpidpath(void)
|
||||
{
|
||||
#ifdef ALTPIDPATH
|
||||
return ALTPIDPATH;
|
||||
#else
|
||||
return dflt_statepath();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* logs the formatted string to any configured logging devices + the output of strerror(errno) */
|
||||
void upslog_with_errno(int priority, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
vupslog(priority, fmt, va, 1);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
/* logs the formatted string to any configured logging devices */
|
||||
void upslogx(int priority, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
vupslog(priority, fmt, va, 0);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void upsdebug_with_errno(int level, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
if (nut_debug_level < level)
|
||||
return;
|
||||
|
||||
va_start(va, fmt);
|
||||
vupslog(LOG_DEBUG, fmt, va, 1);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void upsdebugx(int level, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
if (nut_debug_level < level)
|
||||
return;
|
||||
|
||||
va_start(va, fmt);
|
||||
vupslog(LOG_DEBUG, fmt, va, 0);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
/* dump message msg and len bytes from buf to upsdebugx(level) in
|
||||
hexadecimal. (This function replaces Philippe Marzouk's original
|
||||
dump_hex() function) */
|
||||
void upsdebug_hex(int level, const char *msg, const void *buf, int len)
|
||||
{
|
||||
char line[100];
|
||||
int n; /* number of characters currently in line */
|
||||
int i; /* number of bytes output from buffer */
|
||||
|
||||
n = snprintf(line, sizeof(line), "%s: (%d bytes) =>", msg, len);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
if (n > 72) {
|
||||
upsdebugx(level, "%s", line);
|
||||
line[0] = 0;
|
||||
}
|
||||
|
||||
n = snprintfcat(line, sizeof(line), n ? " %02x" : "%02x",
|
||||
((unsigned char *)buf)[i]);
|
||||
}
|
||||
upsdebugx(level, "%s", line);
|
||||
}
|
||||
|
||||
static void vfatal(const char *fmt, va_list va, int use_strerror)
|
||||
{
|
||||
if (xbit_test(upslog_flags, UPSLOG_STDERR_ON_FATAL))
|
||||
xbit_set(&upslog_flags, UPSLOG_STDERR);
|
||||
if (xbit_test(upslog_flags, UPSLOG_SYSLOG_ON_FATAL))
|
||||
xbit_set(&upslog_flags, UPSLOG_SYSLOG);
|
||||
|
||||
vupslog(LOG_ERR, fmt, va, use_strerror);
|
||||
}
|
||||
|
||||
void fatal_with_errno(int status, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
vfatal(fmt, va, (errno > 0) ? 1 : 0);
|
||||
va_end(va);
|
||||
|
||||
exit(status);
|
||||
}
|
||||
|
||||
void fatalx(int status, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
vfatal(fmt, va, 0);
|
||||
va_end(va);
|
||||
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static const char *oom_msg = "Out of memory";
|
||||
|
||||
void *xmalloc(size_t size)
|
||||
{
|
||||
void *p = malloc(size);
|
||||
|
||||
if (p == NULL)
|
||||
fatal_with_errno(EXIT_FAILURE, "%s", oom_msg);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *xcalloc(size_t number, size_t size)
|
||||
{
|
||||
void *p = calloc(number, size);
|
||||
|
||||
if (p == NULL)
|
||||
fatal_with_errno(EXIT_FAILURE, "%s", oom_msg);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
void *p = realloc(ptr, size);
|
||||
|
||||
if (p == NULL)
|
||||
fatal_with_errno(EXIT_FAILURE, "%s", oom_msg);
|
||||
return p;
|
||||
}
|
||||
|
||||
char *xstrdup(const char *string)
|
||||
{
|
||||
char *p = strdup(string);
|
||||
|
||||
if (p == NULL)
|
||||
fatal_with_errno(EXIT_FAILURE, "%s", oom_msg);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* modify in - strip all trailing instances of <sep> */
|
||||
char *rtrim(char *in, const char sep)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = &in[strlen(in) - 1];
|
||||
|
||||
while ((p >= in) && (*p == sep))
|
||||
*p-- = '\0';
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
/* Read up to buflen bytes from fd and return the number of bytes
|
||||
read. If no data is available within d_sec + d_usec, return 0.
|
||||
On error, a value < 0 is returned (errno indicates error). */
|
||||
int select_read(const int fd, void *buf, const size_t buflen, const long d_sec, const long d_usec)
|
||||
{
|
||||
int ret;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
|
||||
tv.tv_sec = d_sec;
|
||||
tv.tv_usec = d_usec;
|
||||
|
||||
ret = select(fd + 1, &fds, NULL, NULL, &tv);
|
||||
|
||||
if (ret < 1) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return read(fd, buf, buflen);
|
||||
}
|
||||
|
||||
/* Write up to buflen bytes to fd and return the number of bytes
|
||||
written. If no data is available within d_sec + d_usec, return 0.
|
||||
On error, a value < 0 is returned (errno indicates error). */
|
||||
int select_write(const int fd, const void *buf, const size_t buflen, const long d_sec, const long d_usec)
|
||||
{
|
||||
int ret;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
|
||||
tv.tv_sec = d_sec;
|
||||
tv.tv_usec = d_usec;
|
||||
|
||||
ret = select(fd + 1, NULL, &fds, NULL, &tv);
|
||||
|
||||
if (ret < 1) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return write(fd, buf, buflen);
|
||||
}
|
616
common/parseconf.c
Normal file
616
common/parseconf.c
Normal file
|
@ -0,0 +1,616 @@
|
|||
/* parseconf.c - state machine-driven dynamic configuration file parser
|
||||
|
||||
Copyright (C) 2002 Russell Kroll <rkroll@exploits.org>
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
/* parseconf, version 4.
|
||||
*
|
||||
* This one abandons the "callback" system introduced last time. It
|
||||
* didn't turn out as well as I had hoped - you got stuck "behind"
|
||||
* parseconf too often.
|
||||
*
|
||||
* There is now a context buffer, and you call pconf_init to set it up.
|
||||
* All subsequent calls must have it as the first argument. There are
|
||||
* two entry points for parsing lines. You can have it read a file
|
||||
* (pconf_file_begin and pconf_file_next), take lines directly from
|
||||
* the caller (pconf_line), or go along a character at a time (pconf_char).
|
||||
* The parsing is identical no matter how you feed it.
|
||||
*
|
||||
* Since there are no more callbacks, you take the successful return
|
||||
* from the function and access ctx->arglist and ctx->numargs yourself.
|
||||
* You must check for errors with pconf_parse_error before using them,
|
||||
* since it might not be complete. This lets the caller handle all
|
||||
* error reporting that's nonfatal.
|
||||
*
|
||||
* Fatal errors are those that involve memory allocation. If the user
|
||||
* defines an error handler when calling pconf_init, that function will
|
||||
* be called with the error message before parseconf exits. By default
|
||||
* it will just write the message to stderr before exiting.
|
||||
*
|
||||
* Input vs. Output:
|
||||
*
|
||||
* What it reads --> What ends up in each argument
|
||||
*
|
||||
* this is a line --> "this" "is" "a" "line"
|
||||
* this "is also" a line --> "this" "is also" "a" "line"
|
||||
* embedded\ space --> "embedded space"
|
||||
* embedded\\backslash --> "embedded\backslash"
|
||||
*
|
||||
* Arguments are split by whitespace (isspace()) unless that whitespace
|
||||
* occurs inside a "quoted pair like this".
|
||||
*
|
||||
* You can also escape the double quote (") character. The backslash
|
||||
* also allows you to join lines, allowing you to have logical lines
|
||||
* that span physical lines, just like you can do in some shells.
|
||||
*
|
||||
* Lines normally end with a newline, but reaching EOF will also force
|
||||
* parsing on what's been scanned so far.
|
||||
*
|
||||
* Design:
|
||||
*
|
||||
* Characters are read one at a time to drive the state machine.
|
||||
* As words are completed (by hitting whitespace or ending a "" item),
|
||||
* they are committed to the next buffer in the arglist. realloc is
|
||||
* used, so the buffer can grow to handle bigger words.
|
||||
*
|
||||
* The arglist also grows as necessary with a similar approach. As a
|
||||
* result, you can parse extremely long words and lines with an insane
|
||||
* number of elements.
|
||||
*
|
||||
* Finally, there is argsize, which remembers how long each of the
|
||||
* arglist elements are. This is how we know when to expand them.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "parseconf.h"
|
||||
|
||||
/* possible states */
|
||||
|
||||
#define STATE_FINDWORDSTART 1
|
||||
#define STATE_FINDEOL 2
|
||||
#define STATE_QUOTECOLLECT 3
|
||||
#define STATE_QC_LITERAL 4
|
||||
#define STATE_COLLECT 5
|
||||
#define STATE_COLLECTLITERAL 6
|
||||
#define STATE_ENDOFLINE 7
|
||||
#define STATE_PARSEERR 8
|
||||
|
||||
static void pconf_fatal(PCONF_CTX_t *ctx, const char *errtxt)
|
||||
{
|
||||
if (ctx->errhandler)
|
||||
ctx->errhandler(errtxt);
|
||||
else
|
||||
fprintf(stderr, "parseconf: fatal error: %s\n", errtxt);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void add_arg_word(PCONF_CTX_t *ctx)
|
||||
{
|
||||
int argpos;
|
||||
size_t wbuflen;
|
||||
|
||||
/* this is where the new value goes */
|
||||
argpos = ctx->numargs;
|
||||
|
||||
ctx->numargs++;
|
||||
|
||||
/* when facing more args than ever before, expand the list */
|
||||
if (ctx->numargs > ctx->maxargs) {
|
||||
ctx->maxargs = ctx->numargs;
|
||||
|
||||
/* resize the lists */
|
||||
ctx->arglist = realloc(ctx->arglist,
|
||||
sizeof(char *) * ctx->numargs);
|
||||
|
||||
if (!ctx->arglist)
|
||||
pconf_fatal(ctx, "realloc arglist failed");
|
||||
|
||||
ctx->argsize = realloc(ctx->argsize,
|
||||
sizeof(int *) * ctx->numargs);
|
||||
|
||||
if (!ctx->argsize)
|
||||
pconf_fatal(ctx, "realloc argsize failed");
|
||||
|
||||
/* ensure sane starting values */
|
||||
ctx->arglist[argpos] = NULL;
|
||||
ctx->argsize[argpos] = 0;
|
||||
}
|
||||
|
||||
wbuflen = strlen(ctx->wordbuf);
|
||||
|
||||
/* now see if the string itself grew compared to last time */
|
||||
if (wbuflen >= ctx->argsize[argpos]) {
|
||||
size_t newlen;
|
||||
|
||||
/* allow for the trailing NULL */
|
||||
newlen = wbuflen + 1;
|
||||
|
||||
/* expand the string storage */
|
||||
ctx->arglist[argpos] = realloc(ctx->arglist[argpos], newlen);
|
||||
|
||||
if (!ctx->arglist[argpos])
|
||||
pconf_fatal(ctx, "realloc arglist member failed");
|
||||
|
||||
/* remember the new size */
|
||||
ctx->argsize[argpos] = newlen;
|
||||
}
|
||||
|
||||
/* strncpy doesn't give us a trailing NULL, so prep the space */
|
||||
memset(ctx->arglist[argpos], '\0', ctx->argsize[argpos]);
|
||||
|
||||
/* finally copy the new value into the provided space */
|
||||
strncpy(ctx->arglist[argpos], ctx->wordbuf, wbuflen);
|
||||
}
|
||||
|
||||
static void addchar(PCONF_CTX_t *ctx)
|
||||
{
|
||||
size_t wbuflen;
|
||||
|
||||
wbuflen = strlen(ctx->wordbuf);
|
||||
|
||||
if (ctx->wordlen_limit != 0) {
|
||||
if (wbuflen >= ctx->wordlen_limit) {
|
||||
|
||||
/* limit reached: don't append any more */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* allow for the null */
|
||||
if (wbuflen >= (ctx->wordbufsize - 1)) {
|
||||
ctx->wordbufsize += 8;
|
||||
|
||||
ctx->wordbuf = realloc(ctx->wordbuf, ctx->wordbufsize);
|
||||
|
||||
if (!ctx->wordbuf)
|
||||
pconf_fatal(ctx, "realloc wordbuf failed");
|
||||
|
||||
/* repoint as wordbuf may have moved */
|
||||
ctx->wordptr = &ctx->wordbuf[wbuflen];
|
||||
}
|
||||
|
||||
*ctx->wordptr++ = ctx->ch;
|
||||
*ctx->wordptr = '\0';
|
||||
}
|
||||
|
||||
static void endofword(PCONF_CTX_t *ctx)
|
||||
{
|
||||
if (ctx->arg_limit != 0) {
|
||||
if (ctx->numargs >= ctx->arg_limit) {
|
||||
|
||||
/* don't accept this word - just drop it */
|
||||
ctx->wordptr = ctx->wordbuf;
|
||||
*ctx->wordptr = '\0';
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
add_arg_word(ctx);
|
||||
|
||||
ctx->wordptr = ctx->wordbuf;
|
||||
*ctx->wordptr = '\0';
|
||||
}
|
||||
|
||||
/* look for the beginning of a word */
|
||||
static int findwordstart(PCONF_CTX_t *ctx)
|
||||
{
|
||||
/* newline = the physical line is over, so the logical one is too */
|
||||
if (ctx->ch == 10)
|
||||
return STATE_ENDOFLINE;
|
||||
|
||||
/* the rest of the line is a comment */
|
||||
if (ctx->ch == '#')
|
||||
return STATE_FINDEOL;
|
||||
|
||||
/* space = not in a word yet, so loop back */
|
||||
if (isspace(ctx->ch))
|
||||
return STATE_FINDWORDSTART;
|
||||
|
||||
/* \ = literal = accept the next char blindly */
|
||||
if (ctx->ch == '\\')
|
||||
return STATE_COLLECTLITERAL;
|
||||
|
||||
/* " = begin word bounded by quotes */
|
||||
if (ctx->ch == '"')
|
||||
return STATE_QUOTECOLLECT;
|
||||
|
||||
/* at this point the word just started */
|
||||
addchar(ctx);
|
||||
return STATE_COLLECT;
|
||||
}
|
||||
|
||||
/* eat characters until the end of the line is found */
|
||||
static int findeol(PCONF_CTX_t *ctx)
|
||||
{
|
||||
/* newline = found it, so start a new line */
|
||||
if (ctx->ch == 10)
|
||||
return STATE_ENDOFLINE;
|
||||
|
||||
/* come back here */
|
||||
return STATE_FINDEOL;
|
||||
}
|
||||
|
||||
/* set up the error reporting details */
|
||||
static void pconf_seterr(PCONF_CTX_t *ctx, const char *errmsg)
|
||||
{
|
||||
snprintf(ctx->errmsg, PCONF_ERR_LEN, "%s", errmsg);
|
||||
|
||||
ctx->error = 1;
|
||||
}
|
||||
|
||||
/* quote characters inside a word bounded by "quotes" */
|
||||
static int quotecollect(PCONF_CTX_t *ctx)
|
||||
{
|
||||
/* user is trying to break us */
|
||||
if (ctx->ch == '#') {
|
||||
pconf_seterr(ctx, "Unbalanced word due to unescaped # in quotes");
|
||||
endofword(ctx);
|
||||
|
||||
/* this makes us drop all the way out of the caller */
|
||||
return STATE_PARSEERR;
|
||||
}
|
||||
|
||||
/* another " means we're done with this word */
|
||||
if (ctx->ch == '"') {
|
||||
endofword(ctx);
|
||||
|
||||
return STATE_FINDWORDSTART;
|
||||
}
|
||||
|
||||
/* literal - special case since it needs to return here */
|
||||
if (ctx->ch == '\\')
|
||||
return STATE_QC_LITERAL;
|
||||
|
||||
/* otherwise save it and loop back */
|
||||
addchar(ctx);
|
||||
|
||||
return STATE_QUOTECOLLECT;
|
||||
}
|
||||
|
||||
/* take almost anything literally, but return to quotecollect */
|
||||
static int qc_literal(PCONF_CTX_t *ctx)
|
||||
{
|
||||
/* continue onto the next line of the file */
|
||||
if (ctx->ch == 10)
|
||||
return STATE_QUOTECOLLECT;
|
||||
|
||||
addchar(ctx);
|
||||
return STATE_QUOTECOLLECT;
|
||||
}
|
||||
|
||||
/* collect characters inside a word */
|
||||
static int collect(PCONF_CTX_t *ctx)
|
||||
{
|
||||
/* comment means the word is done, and skip to the end of the line */
|
||||
if (ctx->ch == '#') {
|
||||
endofword(ctx);
|
||||
|
||||
return STATE_FINDEOL;
|
||||
}
|
||||
|
||||
/* newline means the word is done, and the line is done */
|
||||
if (ctx->ch == 10) {
|
||||
endofword(ctx);
|
||||
|
||||
return STATE_ENDOFLINE;
|
||||
}
|
||||
|
||||
/* space means the word is done */
|
||||
if (isspace(ctx->ch)) {
|
||||
endofword(ctx);
|
||||
|
||||
return STATE_FINDWORDSTART;
|
||||
}
|
||||
|
||||
/* \ = literal = accept the next char blindly */
|
||||
if (ctx->ch == '\\')
|
||||
return STATE_COLLECTLITERAL;
|
||||
|
||||
/* otherwise store it and come back for more */
|
||||
addchar(ctx);
|
||||
return STATE_COLLECT;
|
||||
}
|
||||
|
||||
/* take almost anything literally */
|
||||
static int collectliteral(PCONF_CTX_t *ctx)
|
||||
{
|
||||
/* continue to the next line */
|
||||
if (ctx->ch == 10)
|
||||
return STATE_COLLECT;
|
||||
|
||||
addchar(ctx);
|
||||
return STATE_COLLECT;
|
||||
}
|
||||
|
||||
/* clean up memory before going back to the user */
|
||||
static void free_storage(PCONF_CTX_t *ctx)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
free(ctx->wordbuf);
|
||||
|
||||
/* clear out the individual words first */
|
||||
for (i = 0; i < ctx->maxargs; i++)
|
||||
free(ctx->arglist[i]);
|
||||
|
||||
free(ctx->arglist);
|
||||
free(ctx->argsize);
|
||||
|
||||
/* put things back to the initial state */
|
||||
ctx->arglist = NULL;
|
||||
ctx->argsize = NULL;
|
||||
ctx->numargs = 0;
|
||||
ctx->maxargs = 0;
|
||||
}
|
||||
|
||||
int pconf_init(PCONF_CTX_t *ctx, void errhandler(const char *))
|
||||
{
|
||||
/* set up the ctx elements */
|
||||
|
||||
ctx->f = NULL;
|
||||
ctx->state = STATE_FINDWORDSTART;
|
||||
ctx->numargs = 0;
|
||||
ctx->maxargs = 0;
|
||||
ctx->arg_limit = PCONF_DEFAULT_ARG_LIMIT;
|
||||
ctx->wordlen_limit = PCONF_DEFAULT_WORDLEN_LIMIT;
|
||||
ctx->linenum = 0;
|
||||
ctx->error = 0;
|
||||
ctx->arglist = NULL;
|
||||
ctx->argsize = NULL;
|
||||
|
||||
ctx->wordbufsize = 16;
|
||||
ctx->wordbuf = calloc(1, ctx->wordbufsize);
|
||||
|
||||
if (!ctx->wordbuf)
|
||||
pconf_fatal(ctx, "malloc wordbuf failed");
|
||||
ctx->wordptr = ctx->wordbuf;
|
||||
|
||||
ctx->errhandler = errhandler;
|
||||
ctx->magic = PCONF_CTX_t_MAGIC;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_magic(PCONF_CTX_t *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return 0;
|
||||
|
||||
if (ctx->magic != PCONF_CTX_t_MAGIC) {
|
||||
snprintf(ctx->errmsg, PCONF_ERR_LEN, "Invalid ctx buffer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pconf_file_begin(PCONF_CTX_t *ctx, const char *fn)
|
||||
{
|
||||
if (!check_magic(ctx))
|
||||
return 0;
|
||||
|
||||
ctx->f = fopen(fn, "r");
|
||||
|
||||
if (!ctx->f) {
|
||||
snprintf(ctx->errmsg, PCONF_ERR_LEN, "Can't open %s: %s",
|
||||
fn, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1; /* OK */
|
||||
}
|
||||
|
||||
static void parse_char(PCONF_CTX_t *ctx)
|
||||
{
|
||||
switch(ctx->state) {
|
||||
case STATE_FINDWORDSTART:
|
||||
ctx->state = findwordstart(ctx);
|
||||
break;
|
||||
|
||||
case STATE_FINDEOL:
|
||||
ctx->state = findeol(ctx);
|
||||
break;
|
||||
|
||||
case STATE_QUOTECOLLECT:
|
||||
ctx->state = quotecollect(ctx);
|
||||
break;
|
||||
|
||||
case STATE_QC_LITERAL:
|
||||
ctx->state = qc_literal(ctx);
|
||||
break;
|
||||
|
||||
case STATE_COLLECT:
|
||||
ctx->state = collect(ctx);
|
||||
break;
|
||||
|
||||
case STATE_COLLECTLITERAL:
|
||||
ctx->state = collectliteral(ctx);
|
||||
break;
|
||||
} /* switch */
|
||||
}
|
||||
|
||||
/* return 1 if an error occurred, but only do it once */
|
||||
int pconf_parse_error(PCONF_CTX_t *ctx)
|
||||
{
|
||||
if (!check_magic(ctx))
|
||||
return 0;
|
||||
|
||||
if (ctx->error == 1) {
|
||||
ctx->error = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* clean up the ctx space */
|
||||
void pconf_finish(PCONF_CTX_t *ctx)
|
||||
{
|
||||
if (!check_magic(ctx))
|
||||
return;
|
||||
|
||||
if (ctx->f)
|
||||
fclose(ctx->f);
|
||||
|
||||
free_storage(ctx);
|
||||
|
||||
ctx->magic = 0;
|
||||
}
|
||||
|
||||
/* read from a file until a whole line is ready for use */
|
||||
int pconf_file_next(PCONF_CTX_t *ctx)
|
||||
{
|
||||
if (!check_magic(ctx))
|
||||
return 0;
|
||||
|
||||
ctx->linenum++;
|
||||
|
||||
/* start over for the new line */
|
||||
ctx->numargs = 0;
|
||||
ctx->state = STATE_FINDWORDSTART;
|
||||
|
||||
while ((ctx->ch = fgetc(ctx->f)) != EOF) {
|
||||
parse_char(ctx);
|
||||
|
||||
if (ctx->state == STATE_PARSEERR)
|
||||
return 1;
|
||||
|
||||
if (ctx->state == STATE_ENDOFLINE)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* deal with files that don't end in a newline */
|
||||
|
||||
if (ctx->numargs != 0) {
|
||||
|
||||
/* still building a word? */
|
||||
if (ctx->wordptr != ctx->wordbuf)
|
||||
endofword(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* finished with nothing left over */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse a provided line */
|
||||
int pconf_line(PCONF_CTX_t *ctx, const char *line)
|
||||
{
|
||||
size_t i, linelen;
|
||||
|
||||
if (!check_magic(ctx))
|
||||
return 0;
|
||||
|
||||
ctx->linenum++;
|
||||
|
||||
/* start over for the new line */
|
||||
ctx->numargs = 0;
|
||||
ctx->state = STATE_FINDWORDSTART;
|
||||
|
||||
linelen = strlen(line);
|
||||
|
||||
for (i = 0; i < linelen; i++) {
|
||||
ctx->ch = line[i];
|
||||
|
||||
parse_char(ctx);
|
||||
|
||||
if (ctx->state == STATE_PARSEERR)
|
||||
return 1;
|
||||
|
||||
if (ctx->state == STATE_ENDOFLINE)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* deal with any lingering characters */
|
||||
|
||||
/* still building a word? */
|
||||
if (ctx->wordptr != ctx->wordbuf)
|
||||
endofword(ctx); /* tie it off */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define PCONF_ESCAPE "#\\\""
|
||||
|
||||
char *pconf_encode(const char *src, char *dest, size_t destsize)
|
||||
{
|
||||
size_t i, srclen, destlen, maxlen;
|
||||
|
||||
if (destsize < 1)
|
||||
return dest;
|
||||
|
||||
memset(dest, '\0', destsize);
|
||||
|
||||
/* always leave room for a final NULL */
|
||||
maxlen = destsize - 1;
|
||||
srclen = strlen(src);
|
||||
destlen = 0;
|
||||
|
||||
for (i = 0; i < srclen; i++) {
|
||||
if (strchr(PCONF_ESCAPE, src[i])) {
|
||||
|
||||
/* if they both won't fit, we're done */
|
||||
if (destlen >= maxlen - 1)
|
||||
return dest;
|
||||
|
||||
dest[destlen++] = '\\';
|
||||
}
|
||||
|
||||
/* bail out when dest is full */
|
||||
if (destlen >= maxlen)
|
||||
return dest;
|
||||
|
||||
dest[destlen++] = src[i];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* parse input a character at a time */
|
||||
int pconf_char(PCONF_CTX_t *ctx, char ch)
|
||||
{
|
||||
if (!check_magic(ctx))
|
||||
return -1;
|
||||
|
||||
/* if the last call finished a line, clean stuff up for another */
|
||||
if ((ctx->state == STATE_ENDOFLINE) || (ctx->state == STATE_PARSEERR)) {
|
||||
ctx->numargs = 0;
|
||||
ctx->state = STATE_FINDWORDSTART;
|
||||
}
|
||||
|
||||
ctx->ch = ch;
|
||||
parse_char(ctx);
|
||||
|
||||
if (ctx->state == STATE_ENDOFLINE)
|
||||
return 1;
|
||||
|
||||
if (ctx->state == STATE_PARSEERR)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
492
common/state.c
Normal file
492
common/state.c
Normal file
|
@ -0,0 +1,492 @@
|
|||
/* state.c - Network UPS Tools common state management functions
|
||||
|
||||
Copyright (C)
|
||||
2003 Russell Kroll <rkroll@exploits.org>
|
||||
2008 Arjen de Korte <adkorte-guest@alioth.debian.org>
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "state.h"
|
||||
#include "parseconf.h"
|
||||
|
||||
static void val_escape(struct st_tree_t *node)
|
||||
{
|
||||
char etmp[ST_MAX_VALUE_LEN];
|
||||
|
||||
/* escape any tricky stuff like \ and " */
|
||||
pconf_encode(node->raw, etmp, sizeof(etmp));
|
||||
|
||||
/* if nothing was escaped, we don't need to do anything else */
|
||||
if (!strcmp(node->raw, etmp)) {
|
||||
node->val = node->raw;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if the escaped value grew, deal with it */
|
||||
if (node->safesize < (strlen(etmp) + 1)) {
|
||||
node->safesize = strlen(etmp) + 1;
|
||||
node->safe = xrealloc(node->safe, node->safesize);
|
||||
}
|
||||
|
||||
snprintf(node->safe, node->safesize, "%s", etmp);
|
||||
node->val = node->safe;
|
||||
}
|
||||
|
||||
static void st_tree_enum_free(struct enum_t *list)
|
||||
{
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
|
||||
st_tree_enum_free(list->next);
|
||||
|
||||
free(list->val);
|
||||
free(list);
|
||||
}
|
||||
|
||||
/* free all memory associated with a node */
|
||||
static void st_tree_node_free(struct st_tree_t *node)
|
||||
{
|
||||
free(node->var);
|
||||
free(node->raw);
|
||||
free(node->safe);
|
||||
|
||||
/* never free node->val, since it's just a pointer to raw or safe */
|
||||
|
||||
/* blow away the list of enums */
|
||||
st_tree_enum_free(node->enum_list);
|
||||
|
||||
/* now finally kill the node itself */
|
||||
free(node);
|
||||
}
|
||||
|
||||
/* add a subtree to another subtree */
|
||||
static void st_tree_node_add(struct st_tree_t **nptr, struct st_tree_t *sptr)
|
||||
{
|
||||
if (!sptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (*nptr) {
|
||||
|
||||
struct st_tree_t *node = *nptr;
|
||||
|
||||
if (strcasecmp(node->var, sptr->var) > 0) {
|
||||
nptr = &node->left;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(node->var, sptr->var) < 0) {
|
||||
nptr = &node->right;
|
||||
continue;
|
||||
}
|
||||
|
||||
upsdebugx(1, "%s: duplicate value (shouldn't happen)", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
*nptr = sptr;
|
||||
}
|
||||
|
||||
/* remove a variable from a tree */
|
||||
int state_delinfo(struct st_tree_t **nptr, const char *var)
|
||||
{
|
||||
while (*nptr) {
|
||||
|
||||
struct st_tree_t *node = *nptr;
|
||||
|
||||
if (strcasecmp(node->var, var) > 0) {
|
||||
nptr = &node->left;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(node->var, var) < 0) {
|
||||
nptr = &node->right;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* whatever is on the left, hang it off current right */
|
||||
st_tree_node_add(&node->right, node->left);
|
||||
|
||||
/* now point the parent at the old right child */
|
||||
*nptr = node->right;
|
||||
|
||||
st_tree_node_free(node);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
/* interface */
|
||||
|
||||
int state_setinfo(struct st_tree_t **nptr, const char *var, const char *val)
|
||||
{
|
||||
while (*nptr) {
|
||||
|
||||
struct st_tree_t *node = *nptr;
|
||||
|
||||
if (strcasecmp(node->var, var) > 0) {
|
||||
nptr = &node->left;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(node->var, var) < 0) {
|
||||
nptr = &node->right;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* updating an existing entry */
|
||||
if (!strcasecmp(node->raw, val)) {
|
||||
return 0; /* no change */
|
||||
}
|
||||
|
||||
/* changes should be ignored */
|
||||
if (node->flags & ST_FLAG_IMMUTABLE) {
|
||||
return 0; /* no change */
|
||||
}
|
||||
|
||||
/* expand the buffer if the value grows */
|
||||
if (node->rawsize < (strlen(val) + 1)) {
|
||||
node->rawsize = strlen(val) + 1;
|
||||
node->raw = xrealloc(node->raw, node->rawsize);
|
||||
}
|
||||
|
||||
/* store the literal value for later comparisons */
|
||||
snprintf(node->raw, node->rawsize, "%s", val);
|
||||
|
||||
val_escape(node);
|
||||
|
||||
return 1; /* changed */
|
||||
}
|
||||
|
||||
*nptr = xcalloc(1, sizeof(**nptr));
|
||||
|
||||
(*nptr)->var = xstrdup(var);
|
||||
(*nptr)->raw = xstrdup(val);
|
||||
(*nptr)->rawsize = strlen(val) + 1;
|
||||
|
||||
val_escape(*nptr);
|
||||
|
||||
return 1; /* added */
|
||||
}
|
||||
|
||||
static int st_tree_enum_add(struct enum_t **list, const char *enc)
|
||||
{
|
||||
struct enum_t *item;
|
||||
|
||||
while (*list) {
|
||||
|
||||
if (strcmp((*list)->val, enc)) {
|
||||
list = &(*list)->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
return 0; /* duplicate */
|
||||
}
|
||||
|
||||
item = xcalloc(1, sizeof(*item));
|
||||
item->val = xstrdup(enc);
|
||||
item->next = *list;
|
||||
|
||||
/* now we're done creating it, add it to the list */
|
||||
*list = item;
|
||||
|
||||
return 1; /* added */
|
||||
}
|
||||
|
||||
int state_addenum(struct st_tree_t *root, const char *var, const char *val)
|
||||
{
|
||||
struct st_tree_t *sttmp;
|
||||
char enc[ST_MAX_VALUE_LEN];
|
||||
|
||||
/* find the tree node for var */
|
||||
sttmp = state_tree_find(root, var);
|
||||
|
||||
if (!sttmp) {
|
||||
upslogx(LOG_ERR, "state_addenum: base variable (%s) "
|
||||
"does not exist", var);
|
||||
return 0; /* failed */
|
||||
}
|
||||
|
||||
/* smooth over any oddities in the enum value */
|
||||
pconf_encode(val, enc, sizeof(enc));
|
||||
|
||||
return st_tree_enum_add(&sttmp->enum_list, enc);
|
||||
}
|
||||
|
||||
int state_setaux(struct st_tree_t *root, const char *var, const char *auxs)
|
||||
{
|
||||
struct st_tree_t *sttmp;
|
||||
int aux;
|
||||
|
||||
/* find the tree node for var */
|
||||
sttmp = state_tree_find(root, var);
|
||||
|
||||
if (!sttmp) {
|
||||
upslogx(LOG_ERR, "state_addenum: base variable (%s) "
|
||||
"does not exist", var);
|
||||
return -1; /* failed */
|
||||
}
|
||||
|
||||
aux = strtol(auxs, (char **) NULL, 10);
|
||||
|
||||
/* silently ignore matches */
|
||||
if (sttmp->aux == aux) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sttmp->aux = aux;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *state_getinfo(struct st_tree_t *root, const char *var)
|
||||
{
|
||||
struct st_tree_t *sttmp;
|
||||
|
||||
/* find the tree node for var */
|
||||
sttmp = state_tree_find(root, var);
|
||||
|
||||
if (!sttmp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sttmp->val;
|
||||
}
|
||||
|
||||
int state_getflags(struct st_tree_t *root, const char *var)
|
||||
{
|
||||
struct st_tree_t *sttmp;
|
||||
|
||||
/* find the tree node for var */
|
||||
sttmp = state_tree_find(root, var);
|
||||
|
||||
if (!sttmp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sttmp->flags;
|
||||
}
|
||||
|
||||
int state_getaux(struct st_tree_t *root, const char *var)
|
||||
{
|
||||
struct st_tree_t *sttmp;
|
||||
|
||||
/* find the tree node for var */
|
||||
sttmp = state_tree_find(root, var);
|
||||
|
||||
if (!sttmp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sttmp->aux;
|
||||
}
|
||||
|
||||
const struct enum_t *state_getenumlist(struct st_tree_t *root, const char *var)
|
||||
{
|
||||
struct st_tree_t *sttmp;
|
||||
|
||||
/* find the tree node for var */
|
||||
sttmp = state_tree_find(root, var);
|
||||
|
||||
if (!sttmp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sttmp->enum_list;
|
||||
}
|
||||
|
||||
void state_setflags(struct st_tree_t *root, const char *var, int numflags, char **flag)
|
||||
{
|
||||
int i;
|
||||
struct st_tree_t *sttmp;
|
||||
|
||||
/* find the tree node for var */
|
||||
sttmp = state_tree_find(root, var);
|
||||
|
||||
if (!sttmp) {
|
||||
upslogx(LOG_ERR, "state_setflags: base variable (%s) "
|
||||
"does not exist", var);
|
||||
return;
|
||||
}
|
||||
|
||||
sttmp->flags = 0;
|
||||
|
||||
for (i = 0; i < numflags; i++) {
|
||||
|
||||
if (!strcasecmp(flag[i], "RW")) {
|
||||
sttmp->flags |= ST_FLAG_RW;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcasecmp(flag[i], "STRING")) {
|
||||
sttmp->flags |= ST_FLAG_STRING;
|
||||
continue;
|
||||
}
|
||||
|
||||
upsdebugx(2, "Unrecognized flag [%s]", flag[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int state_addcmd(struct cmdlist_t **list, const char *cmd)
|
||||
{
|
||||
struct cmdlist_t *item;
|
||||
|
||||
while (*list) {
|
||||
|
||||
if (strcasecmp((*list)->name, cmd) > 0) {
|
||||
/* insertion point reached */
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp((*list)->name, cmd) < 0) {
|
||||
list = &(*list)->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
return 0; /* duplicate */
|
||||
}
|
||||
|
||||
item = xcalloc(1, sizeof(*item));
|
||||
item->name = xstrdup(cmd);
|
||||
item->next = *list;
|
||||
|
||||
/* now we're done creating it, insert it in the list */
|
||||
*list = item;
|
||||
|
||||
return 1; /* added */
|
||||
}
|
||||
|
||||
void state_infofree(struct st_tree_t *node)
|
||||
{
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
state_infofree(node->left);
|
||||
state_infofree(node->right);
|
||||
|
||||
st_tree_node_free(node);
|
||||
}
|
||||
|
||||
void state_cmdfree(struct cmdlist_t *list)
|
||||
{
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
|
||||
state_cmdfree(list->next);
|
||||
|
||||
free(list->name);
|
||||
free(list);
|
||||
}
|
||||
|
||||
int state_delcmd(struct cmdlist_t **list, const char *cmd)
|
||||
{
|
||||
while (*list) {
|
||||
|
||||
struct cmdlist_t *item = *list;
|
||||
|
||||
if (strcasecmp(item->name, cmd) > 0) {
|
||||
/* not found */
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp(item->name, cmd) < 0) {
|
||||
list = &item->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we found it! */
|
||||
|
||||
*list = item->next;
|
||||
|
||||
free(item->name);
|
||||
free(item);
|
||||
|
||||
return 1; /* deleted */
|
||||
}
|
||||
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
static int st_tree_del_enum(struct enum_t **list, const char *val)
|
||||
{
|
||||
while (*list) {
|
||||
|
||||
struct enum_t *item = *list;
|
||||
|
||||
/* if this is not the right value, go on to the next */
|
||||
if (strcasecmp(item->val, val)) {
|
||||
list = &item->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we found it! */
|
||||
*list = item->next;
|
||||
|
||||
free(item->val);
|
||||
free(item);
|
||||
|
||||
return 1; /* deleted */
|
||||
}
|
||||
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
int state_delenum(struct st_tree_t *root, const char *var, const char *val)
|
||||
{
|
||||
struct st_tree_t *sttmp;
|
||||
|
||||
/* find the tree node for var */
|
||||
sttmp = state_tree_find(root, var);
|
||||
|
||||
if (!sttmp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return st_tree_del_enum(&sttmp->enum_list, val);
|
||||
}
|
||||
|
||||
struct st_tree_t *state_tree_find(struct st_tree_t *node, const char *var)
|
||||
{
|
||||
while (node) {
|
||||
|
||||
if (strcasecmp(node->var, var) > 0) {
|
||||
node = node->left;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(node->var, var) < 0) {
|
||||
node = node->right;
|
||||
continue;
|
||||
}
|
||||
|
||||
break; /* found */
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
107
common/upsconf.c
Normal file
107
common/upsconf.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* upsconf.c - code for handling ups.conf ini-style parsing
|
||||
|
||||
Copyright (C) 2001 Russell Kroll <rkroll@exploits.org>
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "upsconf.h"
|
||||
#include "common.h"
|
||||
#include "parseconf.h"
|
||||
|
||||
static char *ups_section;
|
||||
|
||||
/* handle arguments separated by parseconf */
|
||||
static void conf_args(int numargs, char **arg)
|
||||
{
|
||||
char *ep;
|
||||
|
||||
if (numargs < 1)
|
||||
return;
|
||||
|
||||
/* look for section headers - [upsname] */
|
||||
if ((arg[0][0] == '[') && (arg[0][strlen(arg[0])-1] == ']')) {
|
||||
|
||||
free(ups_section);
|
||||
|
||||
arg[0][strlen(arg[0])-1] = '\0';
|
||||
ups_section = xstrdup(&arg[0][1]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* handle 'foo=bar' (compressed form) */
|
||||
ep = strchr(arg[0], '=');
|
||||
if (ep) {
|
||||
*ep = '\0';
|
||||
|
||||
do_upsconf_args(ups_section, arg[0], ep+1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* handle 'foo' (flag) */
|
||||
if (numargs == 1) {
|
||||
do_upsconf_args(ups_section, arg[0], NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (numargs < 3)
|
||||
return;
|
||||
|
||||
/* handle 'foo = bar' (split form) */
|
||||
if (!strcmp(arg[1], "=")) {
|
||||
do_upsconf_args(ups_section, arg[0], arg[2]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* called for fatal errors in parseconf like malloc failures */
|
||||
static void upsconf_err(const char *errmsg)
|
||||
{
|
||||
upslogx(LOG_ERR, "Fatal error in parseconf(ups.conf): %s", errmsg);
|
||||
}
|
||||
|
||||
/* open the ups.conf, parse it, and call back do_upsconf_args() */
|
||||
void read_upsconf(void)
|
||||
{
|
||||
char fn[SMALLBUF];
|
||||
PCONF_CTX_t ctx;
|
||||
|
||||
ups_section = NULL;
|
||||
snprintf(fn, sizeof(fn), "%s/ups.conf", confpath());
|
||||
|
||||
pconf_init(&ctx, upsconf_err);
|
||||
|
||||
if (!pconf_file_begin(&ctx, fn))
|
||||
fatalx(EXIT_FAILURE, "Can't open %s: %s", fn, ctx.errmsg);
|
||||
|
||||
while (pconf_file_next(&ctx)) {
|
||||
if (pconf_parse_error(&ctx)) {
|
||||
upslogx(LOG_ERR, "Parse error: %s:%d: %s",
|
||||
fn, ctx.linenum, ctx.errmsg);
|
||||
continue;
|
||||
}
|
||||
|
||||
conf_args(ctx.numargs, ctx.arglist);
|
||||
}
|
||||
|
||||
pconf_finish(&ctx);
|
||||
|
||||
free(ups_section);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue