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