diff options
Diffstat (limited to '')
-rw-r--r-- | utils/idmapd/Makefile.am | 65 | ||||
-rw-r--r-- | utils/idmapd/Makefile.in | 859 | ||||
-rw-r--r-- | utils/idmapd/idmapd.c | 1091 | ||||
-rw-r--r-- | utils/idmapd/idmapd.man | 134 | ||||
-rw-r--r-- | utils/idmapd/nfs_idmap.h | 64 | ||||
-rw-r--r-- | utils/idmapd/queue.h | 499 |
6 files changed, 2712 insertions, 0 deletions
diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am new file mode 100644 index 0000000..e09e8c5 --- /dev/null +++ b/utils/idmapd/Makefile.am @@ -0,0 +1,65 @@ +## Process this file with automake to produce Makefile.in + +man8_MANS = idmapd.man + +AM_CPPFLAGS += -I ../../support/nfsidmap + +RPCPREFIX = rpc. +KPREFIX = @kprefix@ +sbin_PROGRAMS = idmapd + +EXTRA_DIST = \ + $(man8_MANS) + +idmapd_SOURCES = \ + idmapd.c \ + \ + nfs_idmap.h \ + queue.h + +idmapd_LDADD = ../../support/nfs/libnfs.la \ + ../../support/nfsidmap/libnfsidmap.la \ + $(LIBEVENT) + +MAINTAINERCLEANFILES = Makefile.in + +####################################################################### +# The following allows the current practice of having +# daemons renamed during the install to include RPCPREFIX +# and the KPREFIX +# This could all be done much easier with program_transform_name +# ( program_transform_name = s/^/$(RPCPREFIX)$(KPREFIX)/ ) +# but that also renames the man pages, which the current +# practice does not do. +install-exec-hook: + (cd $(DESTDIR)$(sbindir) && \ + for p in $(sbin_PROGRAMS); do \ + mv -f $$p$(EXEEXT) $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ + done) +uninstall-hook: + (cd $(DESTDIR)$(sbindir) && \ + for p in $(sbin_PROGRAMS); do \ + rm -f $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ + done) + + +# XXX This makes some assumptions about what automake does. +# XXX But there is no install-man-hook or install-man-local. +install-man: install-man8 install-man-links +uninstall-man: uninstall-man8 uninstall-man-links + +install-man-links: + (cd $(DESTDIR)$(man8dir) && \ + for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ + inst=`echo $$m | sed -e 's/man$$/8/'`; \ + rm -f $(RPCPREFIX)$$inst ; \ + $(LN_S) $$inst $(RPCPREFIX)$$inst ; \ + done) + +uninstall-man-links: + (cd $(DESTDIR)$(man8dir) && \ + for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ + inst=`echo $$m | sed -e 's/man$$/8/'`; \ + rm -f $(RPCPREFIX)$$inst ; \ + done) + diff --git a/utils/idmapd/Makefile.in b/utils/idmapd/Makefile.in new file mode 100644 index 0000000..e81f630 --- /dev/null +++ b/utils/idmapd/Makefile.in @@ -0,0 +1,859 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 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@ + +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__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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@ +sbin_PROGRAMS = idmapd$(EXEEXT) +subdir = utils/idmapd +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(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)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)" +PROGRAMS = $(sbin_PROGRAMS) +am_idmapd_OBJECTS = idmapd.$(OBJEXT) +idmapd_OBJECTS = $(am_idmapd_OBJECTS) +am__DEPENDENCIES_1 = +idmapd_DEPENDENCIES = ../../support/nfs/libnfs.la \ + ../../support/nfsidmap/libnfsidmap.la $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/idmapd.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +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 = $(idmapd_SOURCES) +DIST_SOURCES = $(idmapd_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +man8dir = $(mandir)/man8 +NROFF = nroff +MANS = $(man8_MANS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ -I ../../support/nfsidmap +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +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_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +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@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +man8_MANS = idmapd.man +RPCPREFIX = rpc. +KPREFIX = @kprefix@ +EXTRA_DIST = \ + $(man8_MANS) + +idmapd_SOURCES = \ + idmapd.c \ + \ + nfs_idmap.h \ + queue.h + +idmapd_LDADD = ../../support/nfs/libnfs.la \ + ../../support/nfsidmap/libnfsidmap.la \ + $(LIBEVENT) + +MAINTAINERCLEANFILES = Makefile.in +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 utils/idmapd/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu utils/idmapd/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);; \ + 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): +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +idmapd$(EXEEXT): $(idmapd_OBJECTS) $(idmapd_DEPENDENCIES) $(EXTRA_idmapd_DEPENDENCIES) + @rm -f idmapd$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(idmapd_OBJECTS) $(idmapd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idmapd.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 $@ $< + +.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) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man8: $(man8_MANS) + @$(NORMAL_INSTALL) + @list1='$(man8_MANS)'; \ + list2=''; \ + test -n "$(man8dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.8[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ + done; } + +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +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." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/idmapd.Po + -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-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-sbinPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/idmapd.Po + -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: uninstall-man uninstall-sbinPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-hook +.MAKE: install-am install-exec-am install-strip uninstall-am + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-sbinPROGRAMS cscopelist-am \ + ctags ctags-am 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-exec-hook install-html install-html-am \ + install-info install-info-am install-man install-man8 \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-sbinPROGRAMS 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 tags-am uninstall uninstall-am uninstall-hook \ + uninstall-man uninstall-man8 uninstall-sbinPROGRAMS + +.PRECIOUS: Makefile + + +####################################################################### +# The following allows the current practice of having +# daemons renamed during the install to include RPCPREFIX +# and the KPREFIX +# This could all be done much easier with program_transform_name +# ( program_transform_name = s/^/$(RPCPREFIX)$(KPREFIX)/ ) +# but that also renames the man pages, which the current +# practice does not do. +install-exec-hook: + (cd $(DESTDIR)$(sbindir) && \ + for p in $(sbin_PROGRAMS); do \ + mv -f $$p$(EXEEXT) $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ + done) +uninstall-hook: + (cd $(DESTDIR)$(sbindir) && \ + for p in $(sbin_PROGRAMS); do \ + rm -f $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ + done) + +# XXX This makes some assumptions about what automake does. +# XXX But there is no install-man-hook or install-man-local. +install-man: install-man8 install-man-links +uninstall-man: uninstall-man8 uninstall-man-links + +install-man-links: + (cd $(DESTDIR)$(man8dir) && \ + for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ + inst=`echo $$m | sed -e 's/man$$/8/'`; \ + rm -f $(RPCPREFIX)$$inst ; \ + $(LN_S) $$inst $(RPCPREFIX)$$inst ; \ + done) + +uninstall-man-links: + (cd $(DESTDIR)$(man8dir) && \ + for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ + inst=`echo $$m | sed -e 's/man$$/8/'`; \ + rm -f $(RPCPREFIX)$$inst ; \ + done) + +# 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: diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c new file mode 100644 index 0000000..cd9a965 --- /dev/null +++ b/utils/idmapd/idmapd.c @@ -0,0 +1,1091 @@ +/* + * idmapd.c + * + * Userland daemon for idmap. + * + * Copyright (c) 2002 The Regents of the University of Michigan. + * All rights reserved. + * + * Marius Aamodt Eriksen <marius@umich.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/inotify.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <time.h> + +#include "nfs_idmap.h" + +#include <err.h> +#include <errno.h> +#include <event2/event.h> +#include <fcntl.h> +#include <dirent.h> +#include <unistd.h> +#include <netdb.h> +#include <inttypes.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <pwd.h> +#include <grp.h> +#include <limits.h> +#include <ctype.h> +#include <libgen.h> +#include <nfsidmap.h> + +#include "xlog.h" +#include "conffile.h" +#include "queue.h" +#include "nfslib.h" + +#ifndef PIPEFS_DIR +#define PIPEFS_DIR NFS_STATEDIR "/rpc_pipefs/" +#endif + +#ifndef NFSD_DIR +#define NFSD_DIR "/proc/net/rpc" +#endif + +#ifndef CLIENT_CACHE_TIMEOUT_FILE +#define CLIENT_CACHE_TIMEOUT_FILE "/proc/sys/fs/nfs/idmap_cache_timeout" +#endif + +#ifndef NFS4NOBODY_USER +#define NFS4NOBODY_USER "nobody" +#endif + +#ifndef NFS4NOBODY_GROUP +#define NFS4NOBODY_GROUP "nobody" +#endif + +/* From Niels */ +#define CONF_SAVE(w, f) do { \ + char *p = f; \ + if (p != NULL) \ + (w) = p; \ +} while (0) + +#define IC_IDNAME 0 +#define IC_IDNAME_CHAN NFSD_DIR "/nfs4.idtoname/channel" +#define IC_IDNAME_FLUSH NFSD_DIR "/nfs4.idtoname/flush" + +#define IC_NAMEID 1 +#define IC_NAMEID_CHAN NFSD_DIR "/nfs4.nametoid/channel" +#define IC_NAMEID_FLUSH NFSD_DIR "/nfs4.nametoid/flush" + +struct idmap_client { + short ic_which; + char ic_clid[30]; + char *ic_id; + char ic_path[PATH_MAX]; + int ic_fd; + int ic_dirfd; + int ic_scanned; + struct event *ic_event; + TAILQ_ENTRY(idmap_client) ic_next; +}; +static struct idmap_client nfsd_ic[2] = { +{ + .ic_which = IC_IDNAME, + .ic_clid = "", + .ic_id = "Server", + .ic_path = IC_IDNAME_CHAN, + .ic_fd = -1, + .ic_dirfd = -1, + .ic_scanned = 0 +}, +{ + .ic_which = IC_NAMEID, + .ic_clid = "", + .ic_id = "Server", + .ic_path = IC_NAMEID_CHAN, + .ic_fd = -1, + .ic_dirfd = -1, + .ic_scanned = 0 +}, +}; + +TAILQ_HEAD(idmap_clientq, idmap_client); + +static void dirscancb(int, short, void *); +static void clntscancb(int, short, void *); +static void svrreopen(int, short, void *); +static int nfsopen(struct idmap_client *); +static void nfscb(int, short, void *); +static void nfsdcb(int, short, void *); +static int addfield(char **, ssize_t *, char *); +static int getfield(char **, char *, size_t); + +static void imconv(struct idmap_client *, struct idmap_msg *); +static void idtonameres(struct idmap_msg *); +static void nametoidres(struct idmap_msg *); + +static int nfsdopen(void); +static void nfsdclose(void); +static int nfsdopenone(struct idmap_client *); +static void nfsdreopen_one(struct idmap_client *); +static void nfsdreopen(void); + +static int verbose = 0; +#define DEFAULT_IDMAP_CACHE_EXPIRY 600 /* seconds */ +static int cache_entry_expiration = 0; +static char pipefsdir[PATH_MAX]; +static char *nobodyuser, *nobodygroup; +static uid_t nobodyuid; +static gid_t nobodygid; +static struct event_base *evbase = NULL; +static bool signal_received = false; +static int inotify_fd = -1; + +static void +sig_die(int signal) +{ + if (signal_received) { + xlog_warn("forced exiting on signal %d\n", signal); + exit(0); + } + + signal_received = true; + xlog_warn("exiting on signal %d\n", signal); + event_base_loopexit(evbase, NULL); +} + +static int +flush_nfsd_cache(char *path, time_t now) +{ + int fd; + char stime[32]; + + sprintf(stime, "%" PRId64 "\n", (int64_t)now); + fd = open(path, O_RDWR); + if (fd == -1) + return -1; + if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) { + errx(1, "Flushing nfsd cache failed: errno %d (%s)", + errno, strerror(errno)); + } + close(fd); + return 0; +} + +static int +flush_nfsd_idmap_cache(void) +{ + time_t now = time(NULL); + int ret; + + ret = flush_nfsd_cache(IC_IDNAME_FLUSH, now); + if (ret) + return ret; + ret = flush_nfsd_cache(IC_NAMEID_FLUSH, now); + return ret; +} + +static void usage(char *progname) +{ + fprintf(stderr, "Usage: %s [-hfvCS] [-p path] [-c path]\n", + basename(progname)); +} + +int +main(int argc, char **argv) +{ + int wd = -1, opt, fg = 0, nfsdret = -1; + struct idmap_clientq icq; + struct event *rootdirev = NULL, *clntdirev = NULL, + *svrdirev = NULL, *inotifyev = NULL; + struct event *initialize = NULL; + struct passwd *pw; + struct group *gr; + struct stat sb; + char *xpipefsdir = NULL; + int serverstart = 1, clientstart = 1; + int ret; + char *progname; + char *conf_path = NULL; + + nobodyuser = NFS4NOBODY_USER; + nobodygroup = NFS4NOBODY_GROUP; + strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir)); + + if ((progname = strrchr(argv[0], '/'))) + progname++; + else + progname = argv[0]; + xlog_open(progname); + +#define GETOPTSTR "hvfd:p:U:G:c:CS" + opterr=0; /* Turn off error messages */ + while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { + if (opt == 'c') { + warnx("-c is deprecated and may be removed in the " + "future. See idmapd(8)."); + conf_path = optarg; + } + if (opt == '?') { + if (strchr(GETOPTSTR, optopt)) + warnx("'-%c' option requires an argument.", optopt); + else + warnx("'-%c' is an invalid argument.", optopt); + usage(progname); + exit(1); + } + } + optind = 1; + + if (conf_path) { /* deprecated -c option was specified */ + if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) { + warn("Skipping configuration file \"%s\"", conf_path); + conf_path = NULL; + } else { + conf_init_file(conf_path); + verbose = conf_get_num("General", "Verbosity", 0); + cache_entry_expiration = conf_get_num("General", + "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY); + CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); + if (xpipefsdir != NULL) + strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); + CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User")); + CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group")); + if (conf_get_bool("General", "server-only", false)) + clientstart = 0; + if (conf_get_bool("General", "client-only", false)) + serverstart = 0; + } + } else { + conf_path = NFS_CONFFILE; + conf_init_file(conf_path); + CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); + if (xpipefsdir != NULL) + strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); + + conf_path = _PATH_IDMAPDCONF; + conf_init_file(conf_path); + verbose = conf_get_num("General", "Verbosity", 0); + cache_entry_expiration = conf_get_num("General", + "cache-expiration", DEFAULT_IDMAP_CACHE_EXPIRY); + CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User")); + CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group")); + if (conf_get_bool("General", "server-only", false)) + clientstart = 0; + if (conf_get_bool("General", "client-only", false)) + serverstart = 0; + } + + while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) + switch (opt) { + case 'v': + verbose++; + break; + case 'f': + fg = 1; + break; + case 'p': + strlcpy(pipefsdir, optarg, sizeof(pipefsdir)); + break; + case 'd': + case 'U': + case 'G': + errx(1, "the -d, -U, and -G options have been removed;" + " please use the configuration file instead."); + case 'C': + serverstart = 0; + break; + case 'S': + clientstart = 0; + break; + case 'h': + usage(progname); + exit(0); + default: + break; + } + + if (!serverstart && !clientstart) + errx(1, "it is illegal to specify both -C and -S"); + + strncat(pipefsdir, "/nfs", sizeof(pipefsdir)-1); + + daemon_init(fg); + + if ((pw = getpwnam(nobodyuser)) == NULL) + errx(1, "Could not find user \"%s\"", nobodyuser); + nobodyuid = pw->pw_uid; + + if ((gr = getgrnam(nobodygroup)) == NULL) + errx(1, "Could not find group \"%s\"", nobodygroup); + nobodygid = gr->gr_gid; + +#ifdef HAVE_NFS4_SET_DEBUG + nfs4_set_debug(verbose, xlog_warn); +#endif + if (conf_path == NULL) + conf_path = _PATH_IDMAPDCONF; + if (nfs4_init_name_mapping(conf_path)) + errx(1, "Unable to create name to user id mappings."); + + evbase = event_base_new(); + if (evbase == NULL) + errx(1, "Failed to create event base."); + + if (verbose > 1) + xlog_warn("Expiration time is %d seconds.", + cache_entry_expiration); + if (serverstart) { + nfsdret = nfsdopen(); + if (nfsdret == 0) { + ret = flush_nfsd_idmap_cache(); + if (ret) + xlog_err("main: Failed to flush nfsd idmap cache\n: %s", strerror(errno)); + } + } + + if (clientstart) { + struct timeval now = { + .tv_sec = 0, + .tv_usec = 0, + }; + + if (cache_entry_expiration != DEFAULT_IDMAP_CACHE_EXPIRY) { + int timeout_fd, len; + char timeout_buf[12]; + if ((timeout_fd = open(CLIENT_CACHE_TIMEOUT_FILE, + O_RDWR)) == -1) { + xlog_warn("Unable to open '%s' to set " + "client cache expiration time " + "to %d seconds\n", + CLIENT_CACHE_TIMEOUT_FILE, + cache_entry_expiration); + } else { + len = snprintf(timeout_buf, sizeof(timeout_buf), + "%d", cache_entry_expiration); + if ((write(timeout_fd, timeout_buf, len)) != len) + xlog_warn("Error writing '%s' to " + "'%s' to set client " + "cache expiration time\n", + timeout_buf, + CLIENT_CACHE_TIMEOUT_FILE); + close(timeout_fd); + } + } + + inotify_fd = inotify_init1(IN_NONBLOCK); + if (inotify_fd == -1) { + xlog_err("Unable to initialise inotify_init1: %s\n", strerror(errno)); + } else { + wd = inotify_add_watch(inotify_fd, pipefsdir, IN_CREATE | IN_DELETE); + if (wd < 0) + xlog_err("Unable to inotify_add_watch(%s): %s\n", pipefsdir, strerror(errno)); + } + + TAILQ_INIT(&icq); + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); + + /* These events are persistent */ + rootdirev = evsignal_new(evbase, SIGUSR1, dirscancb, &icq); + if (rootdirev == NULL) + errx(1, "Failed to create SIGUSR1 event."); + evsignal_add(rootdirev, NULL); + clntdirev = evsignal_new(evbase, SIGUSR2, clntscancb, &icq); + if (clntdirev == NULL) + errx(1, "Failed to create SIGUSR2 event."); + evsignal_add(clntdirev, NULL); + svrdirev = evsignal_new(evbase, SIGHUP, svrreopen, NULL); + if (svrdirev == NULL) + errx(1, "Failed to create SIGHUP event."); + evsignal_add(svrdirev, NULL); + if ( wd >= 0) { + inotifyev = event_new(evbase, inotify_fd, + EV_READ | EV_PERSIST, dirscancb, &icq); + if (inotifyev == NULL) + errx(1, "Failed to create inotify read event."); + event_add(inotifyev, NULL); + } + + /* Fetch current state */ + /* (Delay till start of event_dispatch to avoid possibly losing + * a SIGUSR1 between here and the call to event_dispatch().) */ + initialize = evtimer_new(evbase, dirscancb, &icq); + if (initialize == NULL) + errx(1, "Failed to create initialize event."); + evtimer_add(initialize, &now); + } + + if (nfsdret != 0 && wd < 0) + xlog_err("main: Neither NFS client nor NFSd found"); + + daemon_ready(); + + if (event_base_dispatch(evbase) < 0) + xlog_err("main: event_dispatch returns errno %d (%s)", + errno, strerror(errno)); + + nfs4_term_name_mapping(); + nfsdclose(); + + if (inotifyev) + event_free(inotifyev); + if (inotify_fd != -1) + close(inotify_fd); + + if (initialize) + event_free(initialize); + if (rootdirev) + event_free(rootdirev); + if (clntdirev) + event_free(clntdirev); + if (svrdirev) + event_free(svrdirev); + event_base_free(evbase); + + return 0; +} + +static void +flush_inotify(int fd) +{ + while (true) { + char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event)))); + const struct inotify_event *ev; + ssize_t len; + char *ptr; + + len = read(fd, buf, sizeof(buf)); + if (len == -1 && errno == EINTR) + continue; + + if (len <= 0) + break; + + for (ptr = buf; ptr < buf + len; + ptr += sizeof(struct inotify_event) + ev->len) { + + ev = (const struct inotify_event *)ptr; + if (verbose > 2) + xlog_warn("pipefs inotify: wd=%i, mask=0x%08x, len=%i, name=%s", + ev->wd, ev->mask, ev->len, ev->len ? ev->name : ""); + } + } +} + +static void +dirscancb(int fd, short UNUSED(which), void *data) +{ + int nent, i; + struct dirent **ents; + struct idmap_client *ic, *nextic; + char path[PATH_MAX+256]; /* + sizeof(d_name) */ + struct idmap_clientq *icq = data; + + if (fd != -1) + flush_inotify(fd); + + TAILQ_FOREACH(ic, icq, ic_next) { + ic->ic_scanned = 0; + } + + nent = scandir(pipefsdir, &ents, NULL, alphasort); + if (nent == -1) { + xlog_warn("dirscancb: scandir(%s): %s", pipefsdir, strerror(errno)); + return; + } + + for (i = 0; i < nent; i++) { + if (ents[i]->d_reclen > 4 && + strncmp(ents[i]->d_name, "clnt", 4) == 0) { + TAILQ_FOREACH(ic, icq, ic_next) + if (strcmp(ents[i]->d_name + 4, ic->ic_clid) == 0) + break; + if (ic != NULL) + goto next; + + if ((ic = calloc(1, sizeof(*ic))) == NULL) + goto out; + strlcpy(ic->ic_clid, ents[i]->d_name + 4, + sizeof(ic->ic_clid)); + path[0] = '\0'; + snprintf(path, sizeof(path), "%s/%s", + pipefsdir, ents[i]->d_name); + + if ((ic->ic_dirfd = open(path, O_RDONLY, 0)) == -1) { + if (verbose > 0) + xlog_warn("dirscancb: open(%s): %s", path, strerror(errno)); + free(ic); + goto out; + } + + strlcat(path, "/idmap", sizeof(path)); + strlcpy(ic->ic_path, path, sizeof(ic->ic_path)); + + if (nfsopen(ic) == -1) { + close(ic->ic_dirfd); + free(ic); + goto out; + } + + if (verbose > 2) + xlog_warn("New client: %s", ic->ic_clid); + + ic->ic_id = "Client"; + + TAILQ_INSERT_TAIL(icq, ic, ic_next); + + next: + ic->ic_scanned = 1; + } + } + + ic = TAILQ_FIRST(icq); + while(ic != NULL) { + nextic=TAILQ_NEXT(ic, ic_next); + if (!ic->ic_scanned) { + if (ic->ic_event) + event_free(ic->ic_event); + if (ic->ic_fd != -1) + close(ic->ic_fd); + if (ic->ic_dirfd != -1) + close(ic->ic_dirfd); + TAILQ_REMOVE(icq, ic, ic_next); + if (verbose > 2) { + xlog_warn("Stale client: %s", ic->ic_clid); + xlog_warn("\t-> closed %s", ic->ic_path); + } + free(ic); + } + ic = nextic; + } + +out: + for (i = 0; i < nent; i++) + free(ents[i]); + free(ents); + return; +} + +static void +svrreopen(int UNUSED(fd), short UNUSED(which), void *UNUSED(data)) +{ + nfsdreopen(); +} + +static void +clntscancb(int UNUSED(fd), short UNUSED(which), void *data) +{ + struct idmap_clientq *icq = data; + struct idmap_client *ic, *ic_next; + + for (ic = TAILQ_FIRST(icq); ic != NULL; ic = ic_next) { + ic_next = TAILQ_NEXT(ic, ic_next); + if (ic->ic_fd == -1 && nfsopen(ic) == -1) { + close(ic->ic_dirfd); + TAILQ_REMOVE(icq, ic, ic_next); + free(ic); + } + } +} + +static void +nfsdcb(int UNUSED(fd), short which, void *data) +{ + struct idmap_client *ic = data; + struct idmap_msg im; + u_char buf[IDMAP_MAXMSGSZ + 1]; + ssize_t len; + ssize_t bsiz; + char *bp, typebuf[IDMAP_MAXMSGSZ], + buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p; + unsigned long tmp; + + if (which != EV_READ) + return; + + len = read(ic->ic_fd, buf, sizeof(buf)); + if (len == 0) + /* No upcall to read; not necessarily a problem: */ + return; + if (len < 0) { + xlog_warn("nfsdcb: read(%s) failed: errno %d (%s)", + ic->ic_path, errno, + strerror(errno)); + nfsdreopen_one(ic); + return; + } + + /* Get rid of newline and terminate buffer*/ + buf[len - 1] = '\0'; + bp = (char *)buf; + + memset(&im, 0, sizeof(im)); + + /* Authentication name -- ignored for now*/ + if (getfield(&bp, authbuf, sizeof(authbuf)) == -1) { + xlog_warn("nfsdcb: bad authentication name in upcall\n"); + return; + } + if (getfield(&bp, typebuf, sizeof(typebuf)) == -1) { + xlog_warn("nfsdcb: bad type in upcall\n"); + return; + } + if (verbose > 2) + xlog_warn("nfsdcb: authbuf=%s authtype=%s", + authbuf, typebuf); + + im.im_type = strcmp(typebuf, "user") == 0 ? + IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; + + switch (ic->ic_which) { + case IC_NAMEID: + im.im_conv = IDMAP_CONV_NAMETOID; + if (getfield(&bp, im.im_name, sizeof(im.im_name)) == -1) { + xlog_warn("nfsdcb: bad name in upcall\n"); + return; + } + break; + case IC_IDNAME: + im.im_conv = IDMAP_CONV_IDTONAME; + if (getfield(&bp, buf1, sizeof(buf1)) == -1) { + xlog_warn("nfsdcb: bad id in upcall\n"); + return; + } + tmp = strtoul(buf1, (char **)NULL, 10); + im.im_id = (u_int32_t)tmp; + if ((tmp == ULONG_MAX && errno == ERANGE) + || (unsigned long)im.im_id != tmp) { + xlog_warn("nfsdcb: id '%s' too big!\n", buf1); + return; + } + break; + default: + xlog_warn("nfsdcb: Unknown which type %d", ic->ic_which); + return; + } + + imconv(ic, &im); + + buf[0] = '\0'; + bp = (char *)buf; + bsiz = sizeof(buf); + + /* Authentication name */ + addfield(&bp, &bsiz, authbuf); + + switch (ic->ic_which) { + case IC_NAMEID: + /* Type */ + p = im.im_type == IDMAP_TYPE_USER ? "user" : "group"; + addfield(&bp, &bsiz, p); + /* Name */ + addfield(&bp, &bsiz, im.im_name); + /* expiry */ + snprintf(buf1, sizeof(buf1), "%" PRId64, + (int64_t)time(NULL) + cache_entry_expiration); + addfield(&bp, &bsiz, buf1); + /* Note that we don't want to write the id if the mapping + * failed; instead, by leaving it off, we write a negative + * cache entry which will result in an error returned to + * the client. We don't want a chown or setacl referring + * to an unknown user to result in giving permissions to + * "nobody"! */ + if (im.im_status == IDMAP_STATUS_SUCCESS) { + /* ID */ + snprintf(buf1, sizeof(buf1), "%u", im.im_id); + addfield(&bp, &bsiz, buf1); + + } + //if (bsiz == sizeof(buf)) /* XXX */ + + bp[-1] = '\n'; + + break; + case IC_IDNAME: + /* Type */ + p = im.im_type == IDMAP_TYPE_USER ? "user" : "group"; + addfield(&bp, &bsiz, p); + /* ID */ + snprintf(buf1, sizeof(buf1), "%u", im.im_id); + addfield(&bp, &bsiz, buf1); + /* expiry */ + snprintf(buf1, sizeof(buf1), "%" PRId64, + (int64_t)time(NULL) + cache_entry_expiration); + addfield(&bp, &bsiz, buf1); + /* Note we're ignoring the status field in this case; we'll + * just map to nobody instead. */ + /* Name */ + addfield(&bp, &bsiz, im.im_name); + + bp[-1] = '\n'; + + break; + default: + xlog_warn("nfsdcb: Unknown which type %d", ic->ic_which); + return; + } + + bsiz = sizeof(buf) - bsiz; + + if (atomicio((void*)write, ic->ic_fd, buf, bsiz) != bsiz) + xlog_warn("nfsdcb: write(%s) failed: errno %d (%s)", + ic->ic_path, errno, strerror(errno)); +} + +static void +imconv(struct idmap_client *ic, struct idmap_msg *im) +{ + u_int32_t len; + + switch (im->im_conv) { + case IDMAP_CONV_IDTONAME: + idtonameres(im); + if (verbose > 1) + xlog_warn("%s %s: (%s) id \"%d\" -> name \"%s\"", + ic->ic_id, ic->ic_clid, + im->im_type == IDMAP_TYPE_USER ? "user" : "group", + im->im_id, im->im_name); + break; + case IDMAP_CONV_NAMETOID: + len = strnlen(im->im_name, IDMAP_NAMESZ - 1); + /* Check for NULL termination just to be careful */ + if (im->im_name[len+1] != '\0') + return; + nametoidres(im); + if (verbose > 1) + xlog_warn("%s %s: (%s) name \"%s\" -> id \"%d\"", + ic->ic_id, ic->ic_clid, + im->im_type == IDMAP_TYPE_USER ? "user" : "group", + im->im_name, im->im_id); + break; + default: + xlog_warn("imconv: Invalid conversion type (%d) in message", + im->im_conv); + im->im_status |= IDMAP_STATUS_INVALIDMSG; + break; + } +} + +static void +nfscb(int UNUSED(fd), short which, void *data) +{ + struct idmap_client *ic = data; + struct idmap_msg im; + + if (which != EV_READ) + return; + + if (atomicio(read, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) { + if (verbose > 0) + xlog_warn("nfscb: read(%s): %s", ic->ic_path, strerror(errno)); + return; + } + + imconv(ic, &im); + + /* XXX: I don't like ignoring this error in the id->name case, + * but we've never returned it, and I need to check that the client + * can handle it gracefully before starting to return it now. */ + + if (im.im_status == IDMAP_STATUS_LOOKUPFAIL) + im.im_status = IDMAP_STATUS_SUCCESS; + + if (atomicio((void*)write, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) + xlog_warn("nfscb: write(%s): %s", ic->ic_path, strerror(errno)); +} + +static void +nfsdclose_one(struct idmap_client *ic) +{ + if (ic->ic_event) { + event_free(ic->ic_event); + ic->ic_event = NULL; + } + if (ic->ic_fd != -1) { + close(ic->ic_fd); + ic->ic_fd = -1; + } +} + +static void +nfsdreopen_one(struct idmap_client *ic) +{ + int fd; + + if (verbose > 2) + xlog_warn("ReOpening %s", ic->ic_path); + + if ((fd = open(ic->ic_path, O_RDWR, 0)) != -1) { + nfsdclose_one(ic); + + ic->ic_fd = fd; + ic->ic_event = event_new(evbase, ic->ic_fd, EV_READ | EV_PERSIST, nfsdcb, ic); + if (ic->ic_event == NULL) { + xlog_warn("nfsdreopen: Failed to create event for '%s'", + ic->ic_path); + close(ic->ic_fd); + ic->ic_fd = -1; + return; + } + event_add(ic->ic_event, NULL); + } else { + xlog_warn("nfsdreopen: Opening '%s' failed: errno %d (%s)", + ic->ic_path, errno, strerror(errno)); + } +} + +static void +nfsdreopen(void) +{ + nfsdreopen_one(&nfsd_ic[IC_NAMEID]); + nfsdreopen_one(&nfsd_ic[IC_IDNAME]); + return; +} + +static int +nfsdopen(void) +{ + return ((nfsdopenone(&nfsd_ic[IC_NAMEID]) == 0 && + nfsdopenone(&nfsd_ic[IC_IDNAME]) == 0) ? 0 : -1); +} + +static void +nfsdclose(void) +{ + nfsdclose_one(&nfsd_ic[IC_NAMEID]); + nfsdclose_one(&nfsd_ic[IC_IDNAME]); +} + +static int +nfsdopenone(struct idmap_client *ic) +{ + if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) { + if (verbose > 0) + xlog_warn("nfsdopenone: Opening %s failed: " + "errno %d (%s)", + ic->ic_path, errno, strerror(errno)); + return (-1); + } + + ic->ic_event = event_new(evbase, ic->ic_fd, EV_READ | EV_PERSIST, nfsdcb, ic); + if (ic->ic_event == NULL) { + if (verbose > 0) + xlog_warn("nfsdopenone: Create event for %s failed", + ic->ic_path); + close(ic->ic_fd); + ic->ic_fd = -1; + return (-1); + } + event_add(ic->ic_event, NULL); + + if (verbose > 2) + xlog_warn("Opened %s", ic->ic_path); + + return (0); +} + +static int +nfsopen(struct idmap_client *ic) +{ + if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) { + if (errno == ENOENT) { + char *slash; + + slash = strrchr(ic->ic_path, '/'); + if (!slash) + return -1; + *slash = 0; + inotify_add_watch(inotify_fd, ic->ic_path, IN_CREATE | IN_ONLYDIR | IN_ONESHOT); + *slash = '/'; + if (verbose > 2) + xlog_warn("Path %s not available. waiting...", ic->ic_path); + return -1; + } + + xlog_warn("nfsopen: open(%s): %s", ic->ic_path, strerror(errno)); + return (-1); + } + + ic->ic_event = event_new(evbase, ic->ic_fd, EV_READ | EV_PERSIST, nfscb, ic); + if (ic->ic_event == NULL) { + xlog_warn("nfsopen: Create event for %s failed", ic->ic_path); + close(ic->ic_fd); + ic->ic_fd = -1; + return -1; + } + event_add(ic->ic_event, NULL); + if (verbose > 2) + xlog_warn("Opened %s", ic->ic_path); + + return (0); +} + +static void +idtonameres(struct idmap_msg *im) +{ + char domain[NFS4_MAX_DOMAIN_LEN]; + int ret = 0; + + ret = nfs4_get_default_domain(NULL, domain, sizeof(domain)); + switch (im->im_type) { + case IDMAP_TYPE_USER: + ret = nfs4_uid_to_name(im->im_id, domain, im->im_name, + sizeof(im->im_name)); + if (ret) { + if (strlen(nobodyuser) < sizeof(im->im_name)) + strcpy(im->im_name, nobodyuser); + else + strcpy(im->im_name, NFS4NOBODY_USER); + } + break; + case IDMAP_TYPE_GROUP: + ret = nfs4_gid_to_name(im->im_id, domain, im->im_name, + sizeof(im->im_name)); + if (ret) { + if (strlen(nobodygroup) < sizeof(im->im_name)) + strcpy(im->im_name, nobodygroup); + else + strcpy(im->im_name, NFS4NOBODY_GROUP); + } + break; + } + if (ret) + im->im_status = IDMAP_STATUS_LOOKUPFAIL; + else + im->im_status = IDMAP_STATUS_SUCCESS; +} + +static void +nametoidres(struct idmap_msg *im) +{ + uid_t uid; + gid_t gid; + int ret = 0; + + /* XXX: move nobody stuff to library calls + * (nfs4_get_nobody_user(domain), nfs4_get_nobody_group(domain)) */ + + im->im_status = IDMAP_STATUS_SUCCESS; + + switch (im->im_type) { + case IDMAP_TYPE_USER: + ret = nfs4_name_to_uid(im->im_name, &uid); + im->im_id = (u_int32_t) uid; + if (ret) { + im->im_status = IDMAP_STATUS_LOOKUPFAIL; + im->im_id = nobodyuid; + } + return; + case IDMAP_TYPE_GROUP: + ret = nfs4_name_to_gid(im->im_name, &gid); + im->im_id = (u_int32_t) gid; + if (ret) { + im->im_status = IDMAP_STATUS_LOOKUPFAIL; + im->im_id = nobodygid; + } + return; + } +} + +static int +addfield(char **bpp, ssize_t *bsizp, char *fld) +{ + char ch, *bp = *bpp; + ssize_t bsiz = *bsizp; + + while ((ch = *fld++) != '\0' && bsiz > 0) { + switch(ch) { + case ' ': + case '\t': + case '\n': + case '\\': + if (bsiz >= 4) { + bp += snprintf(bp, bsiz, "\\%03o", ch); + bsiz -= 4; + } + break; + default: + *bp++ = ch; + bsiz--; + break; + } + } + + if (bsiz < 1 || ch != '\0') + return (-1); + + *bp++ = ' '; + bsiz--; + + *bpp = bp; + *bsizp = bsiz; + + return (0); +} + +static int +getfield(char **bpp, char *fld, size_t fldsz) +{ + char *bp; + unsigned int val; + int n; + + while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0') + ; + + if (bp == NULL || bp[0] == '\0' || bp[0] == '\n') + return (-1); + + while (*bp != '\0' && fldsz > 1) { + if (*bp == '\\') { + if ((n = sscanf(bp, "\\%03o", &val)) != 1) + return (-1); + if (val > UCHAR_MAX) + return (-1); + *fld++ = val; + bp += 4; + } else { + *fld++ = *bp; + bp++; + } + fldsz--; + } + + if (*bp != '\0') + return (-1); + *fld = '\0'; + + return (0); +} diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man new file mode 100644 index 0000000..8215d25 --- /dev/null +++ b/utils/idmapd/idmapd.man @@ -0,0 +1,134 @@ +.\" $OpenBSD: mdoc.template,v 1.6 2001/02/03 08:22:44 niklas Exp $ +.\" +.\" The following requests are required for all man pages. +.Dd February 3, 2003 +.Dt RPC.IDMAPD 8 +.Os +.Sh NAME +.Nm rpc.idmapd +.Nd NFSv4 ID <-> Name Mapper +.Sh SYNOPSIS +.\" For a program: program [-abc] file ... +.Nm rpc.idmapd +.Op Fl h +.Op Fl f +.Op Fl v +.Op Fl C +.Op Fl S +.Op Fl p Ar path +.Op Fl c Ar path +.Sh DESCRIPTION +.Nm +is the NFSv4 ID <-> name mapping daemon. It provides functionality to +the NFSv4 kernel client and server, to which it communicates via +upcalls, by translating user and group IDs to names, and vice versa. +.Pp +The system derives the +.Em user +part of the string by performing a password or group lookup. +The lookup mechanism is configured in +.Pa /etc/idmapd.conf +.Pp +By default, the +.Em domain +part of the string is the system's DNS domain name. +It can also be specified in +.Pa /etc/idmapd.conf +if the system is multi-homed, +or if the system's DNS domain name does +not match the name of the system's Kerberos realm. +.Pp +When the domain is not specified in /etc/idmapd.conf +the local DNS server will be queried for the +.Sy _nfsv4idmapdomain +text record. If the record exists +that will be used as the domain. When the record +does not exist, the domain part of the DNS domain +will used. +.Pp +Note that on more recent kernels only the NFSv4 server uses +.Nm . +The NFSv4 client instead uses +.Xr nfsidmap 8 , +and only falls back to +.Nm +if there was a problem running the +.Xr nfsidmap 8 +program. +.Pp +The options are as follows: +.Bl -tag -width Ds_imagedir +.It Fl h +Display usage message. +.It Fl v +Increases the verbosity level (can be specified multiple times). +.It Fl f +Runs +.Nm +in the foreground and prints all output to the terminal. +.It Fl p Ar path +Specifies the location of the RPC pipefs to be +.Ar path . +The default value is \&"/var/lib/nfs/rpc_pipefs\&". +.It Fl c Ar path +Use configuration file +.Ar path . +This option is deprecated. +.It Fl C +Client-only: perform no idmapping for any NFS server, even if one is detected. +.It Fl S +Server-only: perform no idmapping for any NFS client, even if one is detected. +.El +.Sh CONFIGURATION FILES +.Nm +recognizes the following value from the +.Sy [general] +section of the +.Pa /etc/nfs.conf +configuration file: +.Bl -tag -width Ds_imagedir +.It Sy pipefs-directory +Equivalent to +.Sy -p . +.El +.Pp +All other settings related to id mapping are found in the +.Pa /etc/idmapd.conf +configuration file. +.Sh EXAMPLES +.Cm rpc.idmapd -f -vvv +.Pp +Runs +.Nm +printing all +messages to console, and with a verbosity level of 3. +.\" This next request is for sections 2 and 3 function return values only. +.\" .Sh RETURN VALUES +.\" The next request is for sections 2 and 3 error and signal handling only. +.\" .Sh ERRORS +.\" This next request is for section 4 only. +.\" .Sh DIAGNOSTICS +.\" This next request is for sections 1, 6, 7 & 8 only. +.\" .Sh ENVIRONMENT +.Sh FILES +.Pa /etc/idmapd.conf , +.Pa /etc/nfs.conf +.Sh SEE ALSO +.Xr idmapd.conf 5 , +.Xr nfs.conf 5 , +.Xr nfsidmap 8 +.\".Sh SEE ALSO +.\".Xr nylon.conf 4 +.\" .Sh COMPATIBILITY +.\".Sh STANDARDS +.\".Sh ACKNOWLEDGEMENTS +.Sh AUTHORS +The +.Nm +software has been developed by Marius Aamodt Eriksen +.Aq marius@citi.umich.edu . +.\" .Sh HISTORY +.\".Sh BUGS +.\"Please report any bugs to Marius Aamodt Eriksen +.\".Aq marius@monkey.org . +.\" .Sh CAVEATS diff --git a/utils/idmapd/nfs_idmap.h b/utils/idmapd/nfs_idmap.h new file mode 100644 index 0000000..59bced3 --- /dev/null +++ b/utils/idmapd/nfs_idmap.h @@ -0,0 +1,64 @@ +/* + * include/linux/nfs_idmap.h + * + * UID and GID to name mapping for clients. + * + * Copyright (c) 2002 The Regents of the University of Michigan. + * All rights reserved. + * + * Marius Aamodt Eriksen <marius@umich.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NFS_IDMAP_H +#define NFS_IDMAP_H + +/* XXX from bits/utmp.h */ +#define IDMAP_NAMESZ 128 + +#define IDMAP_TYPE_USER 0 +#define IDMAP_TYPE_GROUP 1 + +#define IDMAP_CONV_IDTONAME 0 +#define IDMAP_CONV_NAMETOID 1 + +#define IDMAP_STATUS_INVALIDMSG 0x01 +#define IDMAP_STATUS_AGAIN 0x02 +#define IDMAP_STATUS_LOOKUPFAIL 0x04 +#define IDMAP_STATUS_SUCCESS 0x08 + +#define IDMAP_MAXMSGSZ 256 + +struct idmap_msg { + u_int8_t im_type; + u_int8_t im_conv; + char im_name[IDMAP_NAMESZ]; + u_int32_t im_id; + u_int8_t im_status; +}; + +#endif /* NFS_IDMAP_H */ diff --git a/utils/idmapd/queue.h b/utils/idmapd/queue.h new file mode 100644 index 0000000..2823fe7 --- /dev/null +++ b/utils/idmapd/queue.h @@ -0,0 +1,499 @@ +/* $OpenBSD: queue.h,v 1.22 2001/06/23 04:39:35 angelos Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while( curelm->field.sle_next != (elm) ) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ + if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_REVERSE(var, head, field, headname) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ |