summaryrefslogtreecommitdiff
path: root/dhcpctl
diff options
context:
space:
mode:
authorThomas Markwalder <tmark@isc.org>2020-01-23 16:21:52 -0500
committerThomas Markwalder <tmark@isc.org>2022-01-20 16:30:49 -0500
commit7f1524669755d7a6e6cd1c3fb80084df273f3dc1 (patch)
tree6a377a3ccee3135da05adf12e138aec3c3e40d4e /dhcpctl
parent7de26fe7a1a2822f667ccaf7c633673cb2d0cead (diff)
downloadisc-dhcp-7f1524669755d7a6e6cd1c3fb80084df273f3dc1.tar.gz
[#76] Initial implemention to dhcpctl_timed_wait_for_completion
common/conflex.c includes/dhctoken.h dhcpctl/omshell.c Added support for "disconnect" dhcpctl/cltest.2 - new file that exercizes timed waits and disconnect dhcpctl/Makefile.am.in Added cltest2.c dhcpctl/dhcpctl.* dhcpctl_timed_wait_for_completion() - new function dhcpctl_disconnect() - new function Added debug logging omapip/dispatch.c Added protocol logging omapi_wait_for_completion() Fixed dangling waiter reference omapi_one_dispatch() Added logic to skip emit writefds from select list omapip/support.c Changed annoying DEBUG logs to DEBUG_PROTOCOL
Diffstat (limited to 'dhcpctl')
-rw-r--r--dhcpctl/Makefile.am9
-rw-r--r--dhcpctl/Makefile.am.in9
-rw-r--r--dhcpctl/Makefile.in179
-rw-r--r--dhcpctl/cltest2.c285
-rw-r--r--dhcpctl/dhcpctl.c145
-rw-r--r--dhcpctl/dhcpctl.h8
-rw-r--r--dhcpctl/omshell.c23
7 files changed, 559 insertions, 99 deletions
diff --git a/dhcpctl/Makefile.am b/dhcpctl/Makefile.am
index 0d669715..9e623375 100644
--- a/dhcpctl/Makefile.am
+++ b/dhcpctl/Makefile.am
@@ -5,7 +5,7 @@ BINDLIBISCDIR=@BINDLIBISCDIR@
bin_PROGRAMS = omshell
lib_LIBRARIES = libdhcpctl.a
-noinst_PROGRAMS = cltest
+noinst_PROGRAMS = cltest cltest2
man_MANS = omshell.1 dhcpctl.3
EXTRA_DIST = $(man_MANS)
@@ -24,3 +24,10 @@ cltest_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
$(BINDLIBDNSDIR)/libdns.a \
$(BINDLIBISCCFGDIR)/libisccfg.a \
$(BINDLIBISCDIR)/libisc.a
+
+cltest2_SOURCES = cltest2.c
+cltest2_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
+ $(BINDLIBIRSDIR)/libirs.a \
+ $(BINDLIBDNSDIR)/libdns.a \
+ $(BINDLIBISCCFGDIR)/libisccfg.a \
+ $(BINDLIBISCDIR)/libisc.a
diff --git a/dhcpctl/Makefile.am.in b/dhcpctl/Makefile.am.in
index 0d77ffc6..28333cef 100644
--- a/dhcpctl/Makefile.am.in
+++ b/dhcpctl/Makefile.am.in
@@ -5,7 +5,7 @@ BINDLIBISCDIR=@Q@BINDLIBISCDIR@Q@
bin_PROGRAMS = omshell
lib_@DHLIBS@ = libdhcpctl.@A@
-noinst_PROGRAMS = cltest
+noinst_PROGRAMS = cltest cltest2
man_MANS = omshell.1 dhcpctl.3
EXTRA_DIST = $(man_MANS)
@@ -24,3 +24,10 @@ cltest_LDADD = libdhcpctl.@A@ ../common/libdhcp.@A@ ../omapip/libomapi.@A@ \
$(BINDLIBDNSDIR)/libdns.@A@ \
$(BINDLIBISCCFGDIR)/libisccfg.@A@ \
$(BINDLIBISCDIR)/libisc.@A@
+
+cltest2_SOURCES = cltest2.c
+cltest2_LDADD = libdhcpctl.@A@ ../common/libdhcp.@A@ ../omapip/libomapi.@A@ \
+ $(BINDLIBIRSDIR)/libirs.@A@ \
+ $(BINDLIBDNSDIR)/libdns.@A@ \
+ $(BINDLIBISCCFGDIR)/libisccfg.@A@ \
+ $(BINDLIBISCDIR)/libisc.@A@
diff --git a/dhcpctl/Makefile.in b/dhcpctl/Makefile.in
index 3c8232d1..e1da56a5 100644
--- a/dhcpctl/Makefile.in
+++ b/dhcpctl/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -16,17 +16,7 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -90,20 +80,18 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = omshell$(EXEEXT)
-noinst_PROGRAMS = cltest$(EXEEXT)
+noinst_PROGRAMS = cltest$(EXEEXT) cltest2$(EXEEXT)
subdir = dhcpctl
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.am.in $(top_srcdir)/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/includes/config.h
CONFIG_CLEAN_FILES = Makefile.am
CONFIG_CLEAN_VPATH_FILES =
-am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" \
- "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)"
-PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -131,6 +119,8 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)"
LIBRARIES = $(lib_LIBRARIES)
ARFLAGS = cru
AM_V_AR = $(am__v_AR_@AM_V@)
@@ -142,12 +132,19 @@ libdhcpctl_a_LIBADD =
am_libdhcpctl_a_OBJECTS = dhcpctl.$(OBJEXT) callback.$(OBJEXT) \
remote.$(OBJEXT)
libdhcpctl_a_OBJECTS = $(am_libdhcpctl_a_OBJECTS)
+PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
am_cltest_OBJECTS = cltest.$(OBJEXT)
cltest_OBJECTS = $(am_cltest_OBJECTS)
cltest_DEPENDENCIES = libdhcpctl.a ../common/libdhcp.a \
../omapip/libomapi.a $(BINDLIBIRSDIR)/libirs.a \
$(BINDLIBDNSDIR)/libdns.a $(BINDLIBISCCFGDIR)/libisccfg.a \
$(BINDLIBISCDIR)/libisc.a
+am_cltest2_OBJECTS = cltest2.$(OBJEXT)
+cltest2_OBJECTS = $(am_cltest2_OBJECTS)
+cltest2_DEPENDENCIES = libdhcpctl.a ../common/libdhcp.a \
+ ../omapip/libomapi.a $(BINDLIBIRSDIR)/libirs.a \
+ $(BINDLIBDNSDIR)/libdns.a $(BINDLIBISCCFGDIR)/libisccfg.a \
+ $(BINDLIBISCDIR)/libisc.a
am_omshell_OBJECTS = omshell.$(OBJEXT)
omshell_OBJECTS = $(am_omshell_OBJECTS)
omshell_DEPENDENCIES = libdhcpctl.a ../common/libdhcp.a \
@@ -168,10 +165,7 @@ am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes
depcomp = $(SHELL) $(top_srcdir)/depcomp
-am__maybe_remake_depfiles = depfiles
-am__depfiles_remade = ./$(DEPDIR)/callback.Po ./$(DEPDIR)/cltest.Po \
- ./$(DEPDIR)/dhcpctl.Po ./$(DEPDIR)/omshell.Po \
- ./$(DEPDIR)/remote.Po
+am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -185,9 +179,10 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
-SOURCES = $(libdhcpctl_a_SOURCES) $(cltest_SOURCES) $(omshell_SOURCES)
-DIST_SOURCES = $(libdhcpctl_a_SOURCES) $(cltest_SOURCES) \
+SOURCES = $(libdhcpctl_a_SOURCES) $(cltest_SOURCES) $(cltest2_SOURCES) \
$(omshell_SOURCES)
+DIST_SOURCES = $(libdhcpctl_a_SOURCES) $(cltest_SOURCES) \
+ $(cltest2_SOURCES) $(omshell_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -216,8 +211,6 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.am.in $(srcdir)/Makefile.in \
- $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
A = @A@
ACLOCAL = @ACLOCAL@
@@ -360,6 +353,13 @@ cltest_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
$(BINDLIBISCCFGDIR)/libisccfg.a \
$(BINDLIBISCDIR)/libisc.a
+cltest2_SOURCES = cltest2.c
+cltest2_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
+ $(BINDLIBIRSDIR)/libirs.a \
+ $(BINDLIBDNSDIR)/libdns.a \
+ $(BINDLIBISCCFGDIR)/libisccfg.a \
+ $(BINDLIBISCDIR)/libisc.a
+
all: all-am
.SUFFIXES:
@@ -376,13 +376,14 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign dhcpctl/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign dhcpctl/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__maybe_remake_depfiles)'; \
- cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ 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)
@@ -395,6 +396,42 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
Makefile.am: $(top_builddir)/config.status $(srcdir)/Makefile.am.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLIBRARIES: $(lib_LIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(INSTALL_DATA) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(INSTALL_DATA) $$list2 "$(DESTDIR)$(libdir)" || exit $$?; }
+ @$(POST_INSTALL)
+ @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ if test -f $$p; then \
+ $(am__strip_dir) \
+ echo " ( cd '$(DESTDIR)$(libdir)' && $(RANLIB) $$f )"; \
+ ( cd "$(DESTDIR)$(libdir)" && $(RANLIB) $$f ) || exit $$?; \
+ else :; fi; \
+ done
+
+uninstall-libLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libdir)'; $(am__uninstall_files_from_dir)
+
+clean-libLIBRARIES:
+ -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES)
+
+libdhcpctl.a: $(libdhcpctl_a_OBJECTS) $(libdhcpctl_a_DEPENDENCIES) $(EXTRA_libdhcpctl_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libdhcpctl.a
+ $(AM_V_AR)$(libdhcpctl_a_AR) libdhcpctl.a $(libdhcpctl_a_OBJECTS) $(libdhcpctl_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libdhcpctl.a
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
@@ -440,47 +477,15 @@ clean-binPROGRAMS:
clean-noinstPROGRAMS:
-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
-install-libLIBRARIES: $(lib_LIBRARIES)
- @$(NORMAL_INSTALL)
- @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \
- list2=; for p in $$list; do \
- if test -f $$p; then \
- list2="$$list2 $$p"; \
- else :; fi; \
- done; \
- test -z "$$list2" || { \
- echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
- echo " $(INSTALL_DATA) $$list2 '$(DESTDIR)$(libdir)'"; \
- $(INSTALL_DATA) $$list2 "$(DESTDIR)$(libdir)" || exit $$?; }
- @$(POST_INSTALL)
- @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \
- for p in $$list; do \
- if test -f $$p; then \
- $(am__strip_dir) \
- echo " ( cd '$(DESTDIR)$(libdir)' && $(RANLIB) $$f )"; \
- ( cd "$(DESTDIR)$(libdir)" && $(RANLIB) $$f ) || exit $$?; \
- else :; fi; \
- done
-
-uninstall-libLIBRARIES:
- @$(NORMAL_UNINSTALL)
- @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \
- files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- dir='$(DESTDIR)$(libdir)'; $(am__uninstall_files_from_dir)
-
-clean-libLIBRARIES:
- -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES)
-
-libdhcpctl.a: $(libdhcpctl_a_OBJECTS) $(libdhcpctl_a_DEPENDENCIES) $(EXTRA_libdhcpctl_a_DEPENDENCIES)
- $(AM_V_at)-rm -f libdhcpctl.a
- $(AM_V_AR)$(libdhcpctl_a_AR) libdhcpctl.a $(libdhcpctl_a_OBJECTS) $(libdhcpctl_a_LIBADD)
- $(AM_V_at)$(RANLIB) libdhcpctl.a
cltest$(EXEEXT): $(cltest_OBJECTS) $(cltest_DEPENDENCIES) $(EXTRA_cltest_DEPENDENCIES)
@rm -f cltest$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(cltest_OBJECTS) $(cltest_LDADD) $(LIBS)
+cltest2$(EXEEXT): $(cltest2_OBJECTS) $(cltest2_DEPENDENCIES) $(EXTRA_cltest2_DEPENDENCIES)
+ @rm -f cltest2$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(cltest2_OBJECTS) $(cltest2_LDADD) $(LIBS)
+
omshell$(EXEEXT): $(omshell_OBJECTS) $(omshell_DEPENDENCIES) $(EXTRA_omshell_DEPENDENCIES)
@rm -f omshell$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(omshell_OBJECTS) $(omshell_LDADD) $(LIBS)
@@ -491,31 +496,26 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callback.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cltest.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpctl.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omshell.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote.Po@am__quote@ # am--include-marker
-
-$(am__depfiles_remade):
- @$(MKDIR_P) $(@D)
- @echo '# dummy' >$@-t && $(am__mv) $@-t $@
-
-am--depfiles: $(am__depfiles_remade)
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callback.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cltest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cltest2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpctl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omshell.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
install-man1: $(man_MANS)
@$(NORMAL_INSTALL)
@list1=''; \
@@ -655,10 +655,7 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-distdir: $(BUILT_SOURCES)
- $(MAKE) $(AM_MAKEFLAGS) distdir-am
-
-distdir-am: $(DISTFILES)
+distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
@@ -690,9 +687,9 @@ distdir-am: $(DISTFILES)
done
check-am: all-am
check: check-am
-all-am: Makefile $(PROGRAMS) $(LIBRARIES) $(MANS)
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(MANS)
installdirs:
- for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)"; do \
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -731,11 +728,7 @@ clean-am: clean-binPROGRAMS clean-generic clean-libLIBRARIES \
clean-noinstPROGRAMS mostlyclean-am
distclean: distclean-am
- -rm -f ./$(DEPDIR)/callback.Po
- -rm -f ./$(DEPDIR)/cltest.Po
- -rm -f ./$(DEPDIR)/dhcpctl.Po
- -rm -f ./$(DEPDIR)/omshell.Po
- -rm -f ./$(DEPDIR)/remote.Po
+ -rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@@ -781,11 +774,7 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
- -rm -f ./$(DEPDIR)/callback.Po
- -rm -f ./$(DEPDIR)/cltest.Po
- -rm -f ./$(DEPDIR)/dhcpctl.Po
- -rm -f ./$(DEPDIR)/omshell.Po
- -rm -f ./$(DEPDIR)/remote.Po
+ -rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
@@ -808,7 +797,7 @@ uninstall-man: uninstall-man1 uninstall-man3
.MAKE: install-am install-strip
-.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
clean-binPROGRAMS clean-generic clean-libLIBRARIES \
clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \
distclean-compile distclean-generic distclean-tags distdir dvi \
@@ -825,8 +814,6 @@ uninstall-man: uninstall-man1 uninstall-man3
uninstall-libLIBRARIES uninstall-man uninstall-man1 \
uninstall-man3
-.PRECIOUS: Makefile
-
# 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.
diff --git a/dhcpctl/cltest2.c b/dhcpctl/cltest2.c
new file mode 100644
index 00000000..26249a3e
--- /dev/null
+++ b/dhcpctl/cltest2.c
@@ -0,0 +1,285 @@
+/* cltest2.c
+
+ Example program that uses the dhcpctl library. */
+
+/*
+ * Copyright (c) 2020 by Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ * This software was contributed to Internet Systems Consortium
+ * by Brian Murrell.
+ */
+
+#include "config.h"
+
+#include <time.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "omapip/result.h"
+#include "dhcpctl.h"
+#include "dhcpd.h"
+
+int main (int, char **);
+
+static void usage (char *s) {
+ fprintf (stderr,
+ "Usage: %s [-s <server ip>] [-p <port>]", s);
+ exit (1);
+}
+
+static void fail_on_error(isc_result_t status, const char* message) {
+ if (status != ISC_R_SUCCESS) {
+ fprintf (stderr, "%s: %s\n",
+ message, isc_result_totext (status));
+ exit (1);
+ }
+}
+
+isc_result_t wait_with_retry(dhcpctl_handle handle, struct timeval* timeout, int retries);
+
+void print_object(char *msg, dhcpctl_handle handle);
+
+/* Simple test program that exercises dhcpctl calls as follows:
+ *
+ * 1. Connect to the given server
+ * 2. Create a local host object with hostname "cltest2.host"
+ * 3. Attempt to open the remote host object
+ * 4. If the host does not exist, add a client id and create it
+ * 5. Disconnect
+ * 6. Reconnect
+ * 7. Refresh the host object
+ *
+ * Note that this program tests dhcpctl_timed_wait_for_completion() by calling
+ * it with extremely small timeouts.
+*/
+
+int main (argc, argv)
+ int argc;
+ char **argv;
+{
+ isc_result_t status;
+ dhcpctl_handle connection;
+ dhcpctl_handle host;
+ char* ip_address = "127.0.0.1";
+ int port = 7911;
+ char* hostname = "cltest2.host";
+ struct timeval timeout;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp (argv[i], "-s")) {
+ ip_address = argv[i];
+ } else if (!strcmp (argv [i], "-p")) {
+ port=atoi(argv[i]);
+ } else if (argv[i][0] == '-') {
+ usage(argv[0]);
+ }
+ }
+
+ /* Initialize dhcpctl */
+ status = dhcpctl_initialize ();
+ fail_on_error(status ,"can't initialize dhcpctl");
+
+ /* Connect */
+ connection = 0;
+ status = dhcpctl_connect (&connection, ip_address, port, 0);
+ fail_on_error(status ,"connect failed");
+
+ /* Create the host object */
+ host = 0;
+ status = dhcpctl_new_object (&host, connection, "host");
+ fail_on_error(status ,"new oject failed");
+
+ status = dhcpctl_set_string_value (host, hostname, "name");
+ fail_on_error(status ,"cant set host name");
+
+ /* Attempt to open the object */
+ status = dhcpctl_open_object (host, connection, 0);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 20;
+ status = wait_with_retry(host, &timeout, 2);
+ switch (status) {
+ case ISC_R_NOTFOUND:
+ /* Host doesn't exist add it. We set an id so the create will be valid. */
+ status = dhcpctl_set_string_value (host, "abcdefg", "dhcp-client-identifier");
+ fail_on_error(status ,"can't set client id");
+
+ status = dhcpctl_open_object (host, connection,
+ DHCPCTL_CREATE | DHCPCTL_EXCL);
+ fail_on_error(status, "open(create) failed");
+
+ status = wait_with_retry(host, &timeout, 2);
+ fail_on_error(status, "wait after open(create)");
+
+ print_object("Host created", host);
+ break;
+
+ case ISC_R_SUCCESS:
+ print_object("Host exists", host);
+ break;
+
+ default:
+ fail_on_error(status, "initial open failed, waiting for completion");
+ break;
+ }
+
+
+ /* Now we'll test disconnect */
+ status = dhcpctl_disconnect(&connection, 0);
+ fail_on_error(status, "can't disconnect");
+
+ /* Reconnect */
+ status = dhcpctl_connect (&connection, ip_address, port, 0);
+ fail_on_error(status ,"can't reconnect");
+
+ /* Refresh the object */
+ status = dhcpctl_object_refresh (connection, host);
+ fail_on_error(status , "can't refresh");
+
+ status = wait_with_retry(host, &timeout, 2);
+ fail_on_error(status , "wait after refresh failed");
+
+ print_object("After reconnect/refresh", host);
+
+ exit (0);
+}
+
+/* Function to call and optionally retry dhcp_timed_wait_for_completion() */
+isc_result_t wait_with_retry(dhcpctl_handle handle, struct timeval* timeout, int retries) {
+ isc_result_t status;
+ isc_result_t waitstatus;
+ struct timeval use_timeout;
+
+ if (timeout) {
+ use_timeout.tv_sec = timeout->tv_sec;
+ use_timeout.tv_usec = timeout->tv_usec;
+ } else {
+ retries = 0;
+ }
+
+ int tries = 0;
+ do {
+ if (tries++) {
+ printf ("wait retry #%d\n", tries);
+ /* Set the timeout value to 30 secs */
+ use_timeout.tv_sec = 30;
+ use_timeout.tv_usec = 0;
+ }
+
+ // Call timed wait.
+ status = dhcpctl_timed_wait_for_completion (handle, &waitstatus,
+ (timeout ? &use_timeout: 0));
+ if (status == ISC_R_SUCCESS) {
+ return(waitstatus);
+ }
+
+ if (status != ISC_R_TIMEDOUT) {
+ fprintf (stderr, "timed wait failed: %s\n", isc_result_totext (status));
+ exit (1);
+ }
+ } while (--retries > 0);
+
+ return (ISC_R_TIMEDOUT);
+}
+
+/* Function to print out the values contained in an object. Largely
+ * stolen from omshell.c */
+void print_object(char* msg, dhcpctl_handle handle) {
+ dhcpctl_remote_object_t *r = (dhcpctl_remote_object_t *)handle;
+ omapi_generic_object_t *object = (omapi_generic_object_t *)(r->inner);
+ char hex_buf[4096];
+ int i;
+
+ printf ("%s:\n",msg);
+ for (i = 0; i < object->nvalues; i++) {
+ omapi_value_t *v = object->values[i];
+
+ if (!object->values[i])
+ continue;
+
+ printf ("\t%.*s = ", (int)v->name->len, v->name->value);
+
+ if (!v->value) {
+ printf ("<null>\n");
+ continue;
+ }
+
+ switch (v->value->type) {
+ case omapi_datatype_int:
+ printf ("%d\n", v->value->u.integer);
+ break;
+
+ case omapi_datatype_string:
+ printf ("\"%.*s\"\n", (int)v->value->u.buffer.len,
+ v->value->u.buffer.value);
+ break;
+
+ case omapi_datatype_data:
+ print_hex_or_string(v->value->u.buffer.len,
+ v->value->u.buffer.value,
+ sizeof(hex_buf), hex_buf);
+ printf("%s\n", hex_buf);
+ break;
+
+ case omapi_datatype_object:
+ printf ("<obj>\n");
+ break;
+ }
+ }
+}
+
+/* Dummy functions to appease linker */
+isc_result_t find_class (struct class **c, const char *n, const char *f, int l)
+{
+ return 0;
+}
+int parse_allow_deny (struct option_cache **oc, struct parse *cfile, int flag)
+{
+ return 0;
+}
+void dhcp (struct packet *packet) { }
+void bootp (struct packet *packet) { }
+
+#ifdef DHCPv6
+void dhcpv6(struct packet *packet) { }
+
+#ifdef DHCP4o6
+isc_result_t dhcpv4o6_handler(omapi_object_t *h)
+{
+ return ISC_R_NOTIMPLEMENTED;
+}
+#endif /* DHCP4o6 */
+#endif /* DHCPv6 */
+
+int check_collection (struct packet *p, struct lease *l, struct collection *c)
+{
+ return 0;
+}
+void classify (struct packet *packet, struct class *class) { }
+
+isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
+ control_object_state_t newstate)
+{
+ return ISC_R_SUCCESS;
+}
+
diff --git a/dhcpctl/dhcpctl.c b/dhcpctl/dhcpctl.c
index 3c78bc19..e8834382 100644
--- a/dhcpctl/dhcpctl.c
+++ b/dhcpctl/dhcpctl.c
@@ -29,6 +29,10 @@
#include "dhcpd.h"
#include <omapip/omapip_p.h>
#include "dhcpctl.h"
+#include <sys/time.h>
+
+
+/* #define DEBUG_DHCPCTL 1 */
omapi_object_type_t *dhcpctl_callback_type;
omapi_object_type_t *dhcpctl_remote_type;
@@ -97,6 +101,9 @@ dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection,
dhcpctl_handle authinfo)
{
isc_result_t status;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_connect(%s:%d)", server_name, port);
+#endif
status = omapi_generic_new (connection, MDL);
if (status != ISC_R_SUCCESS) {
@@ -105,19 +112,35 @@ dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection,
status = omapi_protocol_connect (*connection, server_name,
(unsigned)port, authinfo);
- if (status == ISC_R_SUCCESS)
+ if (status == ISC_R_SUCCESS) {
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_connect success");
+#endif
return status;
+ }
+
if (status != DHCP_R_INCOMPLETE) {
omapi_object_dereference (connection, MDL);
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_connect failed:%s",
+ isc_result_totext (status));
+#endif
return status;
}
status = omapi_wait_for_completion (*connection, 0);
if (status != ISC_R_SUCCESS) {
omapi_object_dereference (connection, MDL);
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_connect, wait failed:%s",
+ isc_result_totext (status));
+#endif
return status;
}
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_connect success");
+#endif
return status;
}
@@ -137,8 +160,58 @@ dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection,
dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h,
dhcpctl_status *s)
{
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_wait_for_completion");
+#endif
isc_result_t status;
status = omapi_wait_for_completion (h, 0);
+ if (status != ISC_R_SUCCESS) {
+ return status;
+ }
+ if (h -> type == dhcpctl_remote_type)
+ *s = ((dhcpctl_remote_object_t *)h) -> waitstatus;
+
+ return ISC_R_SUCCESS;
+}
+
+/* dhcpctl_wait_for_completion
+
+ synchronous
+ returns zero if the callback completes, a nonzero status if
+ there was some problem relating to the wait operation. The
+ status of the queued request will be stored through s, and
+ will also be either zero for success or nonzero for some kind
+ of failure. Never returns until completion or until the
+ connection to the server is lost. This performs the same
+ function as dhcpctl_set_callback and the subsequent callback,
+ for programs that want to do inline execution instead of using
+ callbacks. */
+
+dhcpctl_status dhcpctl_timed_wait_for_completion (dhcpctl_handle h,
+ dhcpctl_status *s,
+ struct timeval *t)
+{
+ isc_result_t status;
+ struct timeval adjusted_t;
+
+#ifdef DEBUG_DHCPCTL
+ if (t) {
+ log_debug ("dhcpctl_timed_wait_for_completion(%u.%u secs.usecs)",
+ (unsigned int)(t->tv_sec),
+ (unsigned int)(t->tv_usec));
+ } else {
+ log_debug ("dhcpctl_timed_wait_for_completion(no timeout)");
+ }
+#endif
+
+ if (t) {
+ struct timeval now;
+ gettimeofday (&now, (struct timezone *)0);
+ adjusted_t.tv_sec = now.tv_sec + t->tv_sec;
+ adjusted_t.tv_usec = now.tv_usec + t->tv_usec;
+ }
+
+ status = omapi_wait_for_completion (h, (t ? &adjusted_t : 0));
if (status != ISC_R_SUCCESS)
return status;
if (h -> type == dhcpctl_remote_type)
@@ -146,6 +219,7 @@ dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h,
return ISC_R_SUCCESS;
}
+
/* dhcpctl_get_value
synchronous
@@ -168,6 +242,9 @@ dhcpctl_status dhcpctl_get_value (dhcpctl_data_string *result,
omapi_value_t *tv = (omapi_value_t *)0;
unsigned len;
int ip;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_get_value(%s)", value_name);
+#endif
status = omapi_get_value_str (h, (omapi_object_t *)0, value_name, &tv);
if (status != ISC_R_SUCCESS)
@@ -232,6 +309,10 @@ dhcpctl_status dhcpctl_get_boolean (int *result,
isc_result_t status;
dhcpctl_data_string data = (dhcpctl_data_string)0;
int rv;
+
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_get_boolean(%s)", value_name);
+#endif
status = dhcpctl_get_value (&data, h, value_name);
if (status != ISC_R_SUCCESS)
@@ -258,6 +339,9 @@ dhcpctl_status dhcpctl_set_value (dhcpctl_handle h, dhcpctl_data_string value,
isc_result_t status;
omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
omapi_data_string_t *name = (omapi_data_string_t *)0;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_set_value(%s)", value_name);
+#endif
status = omapi_data_string_new (&name, strlen (value_name), MDL);
if (status != ISC_R_SUCCESS)
@@ -291,6 +375,9 @@ dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, const char *value,
isc_result_t status;
omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
omapi_data_string_t *name = (omapi_data_string_t *)0;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_set_string_value(%s)", value_name);
+#endif
status = omapi_data_string_new (&name, strlen (value_name), MDL);
if (status != ISC_R_SUCCESS)
@@ -324,6 +411,9 @@ dhcpctl_status dhcpctl_set_data_value (dhcpctl_handle h,
omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
omapi_data_string_t *name = (omapi_data_string_t *)0;
unsigned ll;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_set_data_value(%s)", value_name);
+#endif
ll = strlen (value_name);
status = omapi_data_string_new (&name, ll, MDL);
@@ -355,6 +445,9 @@ dhcpctl_status dhcpctl_set_null_value (dhcpctl_handle h,
isc_result_t status;
omapi_data_string_t *name = (omapi_data_string_t *)0;
unsigned ll;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_set_null_value(%s)", value_name);
+#endif
ll = strlen (value_name);
status = omapi_data_string_new (&name, ll, MDL);
@@ -379,6 +472,9 @@ dhcpctl_status dhcpctl_set_boolean_value (dhcpctl_handle h, int value,
isc_result_t status;
omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
omapi_data_string_t *name = (omapi_data_string_t *)0;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_set_boolean_value(%s)", value_name);
+#endif
status = omapi_data_string_new (&name, strlen (value_name), MDL);
if (status != ISC_R_SUCCESS)
@@ -408,6 +504,9 @@ dhcpctl_status dhcpctl_set_int_value (dhcpctl_handle h, int value,
isc_result_t status;
omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
omapi_data_string_t *name = (omapi_data_string_t *)0;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_set_int_value(%s)", value_name);
+#endif
status = omapi_data_string_new (&name, strlen (value_name), MDL);
if (status != ISC_R_SUCCESS)
@@ -438,6 +537,9 @@ dhcpctl_status dhcpctl_object_update (dhcpctl_handle connection,
isc_result_t status;
omapi_object_t *message = (omapi_object_t *)0;
dhcpctl_remote_object_t *ro;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_object_update");
+#endif
if (h -> type != dhcpctl_remote_type)
return DHCP_R_INVALIDARG;
@@ -487,6 +589,9 @@ dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle connection,
isc_result_t status;
omapi_object_t *message = (omapi_object_t *)0;
dhcpctl_remote_object_t *ro;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_object_refresh");
+#endif
if (h -> type != dhcpctl_remote_type)
return DHCP_R_INVALIDARG;
@@ -540,6 +645,9 @@ dhcpctl_status dhcpctl_object_remove (dhcpctl_handle connection,
isc_result_t status;
omapi_object_t *message = (omapi_object_t *)0;
dhcpctl_remote_object_t *ro;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_object_remove");
+#endif
if (h -> type != dhcpctl_remote_type)
return DHCP_R_INVALIDARG;
@@ -582,5 +690,40 @@ dhcpctl_status dhcpctl_object_remove (dhcpctl_handle connection,
isc_result_t dhcpctl_data_string_dereference (dhcpctl_data_string *vp,
const char *file, int line)
{
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_data_string_dereference");
+#endif
return omapi_data_string_dereference (vp, file, line);
}
+
+dhcpctl_status dhcpctl_disconnect (dhcpctl_handle *connection,
+ int force)
+{
+ isc_result_t status;
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_disconnect()");
+#endif
+ if (!connection || !((*connection)->outer) ||
+ !((*connection)->outer->type) ||
+ ((*connection)->outer->type != omapi_type_protocol) ||
+ !((*connection)->outer->outer)) {
+ log_debug("dhcpctl_disconnect detected invalid arg");
+ return DHCP_R_INVALIDARG;
+ }
+
+ status = omapi_disconnect ((*connection)->outer->outer, force);
+ if (status == ISC_R_SUCCESS) {
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_disconnect success");
+#endif
+ omapi_object_dereference (connection, MDL);
+ return status;
+ }
+
+#ifdef DEBUG_DHCPCTL
+ log_debug("dhcpctl_disconnect failed:%s",
+ isc_result_totext (status));
+#endif
+ return status;
+}
+
diff --git a/dhcpctl/dhcpctl.h b/dhcpctl/dhcpctl.h
index 3c0da74b..0f779bd8 100644
--- a/dhcpctl/dhcpctl.h
+++ b/dhcpctl/dhcpctl.h
@@ -63,6 +63,11 @@ dhcpctl_status dhcpctl_initialize (void);
dhcpctl_status dhcpctl_connect (dhcpctl_handle *,
const char *, int, dhcpctl_handle);
dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle, dhcpctl_status *);
+
+dhcpctl_status dhcpctl_timed_wait_for_completion (dhcpctl_handle h,
+ dhcpctl_status *s,
+ struct timeval *t);
+
dhcpctl_status dhcpctl_get_value (dhcpctl_data_string *,
dhcpctl_handle, const char *);
dhcpctl_status dhcpctl_get_boolean (int *, dhcpctl_handle, const char *);
@@ -116,4 +121,7 @@ isc_result_t dhcpctl_remote_stuff_values (omapi_object_t *,
omapi_object_t *);
isc_result_t dhcpctl_data_string_dereference (dhcpctl_data_string *,
const char *, int);
+
+dhcpctl_status dhcpctl_disconnect (dhcpctl_handle *, int);
+
#endif /* _DHCPCTL_H_ */
diff --git a/dhcpctl/omshell.c b/dhcpctl/omshell.c
index d5d31aa8..785f59a6 100644
--- a/dhcpctl/omshell.c
+++ b/dhcpctl/omshell.c
@@ -208,6 +208,7 @@ main(int argc, char **argv) {
printf (" server <server address>\n");
printf (" key <key name> <key value>\n");
printf (" connect\n");
+ printf (" disconnect\n");
printf (" new <object-type>\n");
printf (" set <name> = <value>\n");
printf (" create\n");
@@ -427,6 +428,28 @@ main(int argc, char **argv) {
connected = 1;
break;
+ case DISCONNECT:
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token != END_OF_FILE && token != EOL) {
+ printf ("usage: disconnect\n");
+ skip_to_semi (cfile);
+ break;
+ }
+
+ if (!connected || !connection) {
+ fprintf (stderr, "not connected\n");
+ break;
+ }
+
+ status = dhcpctl_disconnect (&connection, 0);
+ if (status != ISC_R_SUCCESS) {
+ fprintf (stderr, "dhcpctl_disconnect: %s\n",
+ isc_result_totext (status));
+ break;
+ }
+ connected = 0;
+ break;
+
case TOKEN_NEW:
token = next_token (&val, (unsigned *)0, cfile);
if ((!is_identifier (token) && token != STRING)) {