diff --git a/Makefile.am b/Makefile.am
index 01005985..36a8c3cd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,9 +1,9 @@
# Makefile.am for top level of netatalk package
if USE_BUILTIN_LIBEVENT
-SUBDIRS = libevent libatalk bin config etc man contrib distrib include doc macros test
+SUBDIRS = libevent include libatalk bin config etc man contrib distrib doc macros test
else
-SUBDIRS = libatalk bin config etc man contrib distrib include doc macros test
+SUBDIRS = include libatalk bin config etc man contrib distrib doc macros test
endif
EXTRA_DIST = CONTRIBUTORS COPYRIGHT COPYING NEWS VERSION
diff --git a/NEWS b/NEWS
index 154eccf2..c85c245d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,52 @@
+Changes in 3.0.3
+================
+* UPD: afpd: Increase default DSI server quantum to 1 MB
+* UPD: bundled libevent2 is now static
+* NEW: --with-lockfile=PATH configure option for specifying an
+ alternative path for the netatalk lockfile.
+* UPD: systemd service file use PIDFile and ExecReload.
+ From FR #70.
+* UPD: RedHat sysvinit: rm graceful, reimplement reload, add condrestart
+* FIX: Couldn't create folders on FreeBSD 9.1 ZFS fileystems.
+ Fixed bug #491.
+* FIX: Fix an issue with user homes when user home directory has not the
+ same name as the username.
+ Fixes bug #497.
+* UPD: Fix PAM config install, new default installation dir is
+ $sysconfdir/pam.d/. Add configure option --with-pam-confdir
+ to specify alternative path.
+* NEW: AFP stats about active session via dbus IPC. Client side python
+ program `afpstats`. Requires dbus, dbus-glib any python-dbus.
+ configure option --dbus-sysconf-dir for specifying dbus
+ system security configuration files.
+ New option 'afpstats' (default: no) which determines whether
+ to enable the feature or not.
+* NEW: configure option --with-init-dir
+* NEW: dtrace probes, cf include/atalk/afp_dtrace.d for available
+ probes.
+* UPD: Reload groups when reloading volumes. FR #71.
+* FIX: Attempt to read read-only ._ rfork results in disconnect.
+ Fixes bug #502.
+* FIX: File's ressource fork can't be read if metadata EA is missing.
+ Fixes bug #501.
+* FIX: Conversion from adouble v2 to ea for directories.
+ Fixes bug #500.
+* FIX: Error messages when mounting read-only filesystems.
+ Fixes bug #504.
+* FIX: Permissions of ._ AppleDouble ressource fork after conversion
+ from v2 to ea.
+ Fixes bug #505.
+* UPD: Use FreeBSD sendfile() capability to send protocol header.
+ From FR #75.
+* UPD: Increase IO size when sendfile() is not used.
+ From FR #76.
+* FIX: Can't set Finder label on symlinked folder with "follow symlinks = yes".
+ Fixes bug #508.
+* FIX: Setting POSIX ACLs on Linux
+ Fixes bug #506.
+* FIX: "ad ls" segfault if requested object is not in an AFP volume.
+ Fixes bug #496.
+
Changes in 3.0.2
================
* NEW: afpd: Put file extension type/creator mapping back in which had
diff --git a/VERSION b/VERSION
index d9c62ed9..282895a8 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.0.2
\ No newline at end of file
+3.0.3
\ No newline at end of file
diff --git a/bin/ad/ad_ls.c b/bin/ad/ad_ls.c
index d8362595..b5947e17 100644
--- a/bin/ad/ad_ls.c
+++ b/bin/ad/ad_ls.c
@@ -227,7 +227,7 @@ static void print_flags(char *path, afpvol_t *vol, const struct stat *st)
if (S_ISDIR(st->st_mode))
adflags = ADFLAGS_DIR;
- if (vol->vol->v_path == NULL)
+ if (vol->vol == NULL || vol->vol->v_path == NULL)
return;
ad_init(&ad, vol->vol);
diff --git a/bin/ad/ad_util.c b/bin/ad/ad_util.c
index 897bdf3b..fbe85235 100644
--- a/bin/ad/ad_util.c
+++ b/bin/ad/ad_util.c
@@ -138,9 +138,11 @@ int openvol(AFPObj *obj, const char *path, afpvol_t *vol)
void closevol(afpvol_t *vol)
{
- if (vol->vol->v_cdb) {
- cnid_close(vol->vol->v_cdb);
- vol->vol->v_cdb = NULL;
+ if (vol->vol) {
+ if (vol->vol->v_cdb) {
+ cnid_close(vol->vol->v_cdb);
+ vol->vol->v_cdb = NULL;
+ }
}
memset(vol, 0, sizeof(afpvol_t));
}
diff --git a/bootstrap b/bootstrap
index 76b98f3b..b847ba65 100755
--- a/bootstrap
+++ b/bootstrap
@@ -1,5 +1,50 @@
#!/bin/sh
+DIE=0
+
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`autoconf' installed to."
+ echo "Download the appropriate package for your distribution,"
+ echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+ DIE=1
+}
+
+(libtool --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`libtool' installed."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2d.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+}
+
+(automake --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`automake' installed."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+}
+
+(aclocal --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: Missing \`aclocal'. The version of \`automake'"
+ echo "installed doesn't appear recent enough."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+}
+
+(pkg-config --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`pkg-config' installed."
+ DIE=1
+}
+
+if test "$DIE" -eq 1; then
+ exit 1
+fi
+
set -x
rm -rf autom4te*.cache
diff --git a/config/Makefile.am b/config/Makefile.am
index 57c85ff3..e72c38f3 100644
--- a/config/Makefile.am
+++ b/config/Makefile.am
@@ -6,13 +6,19 @@ SUFFIXES = .tmpl .
TMPLFILES = afp.conf.tmpl
GENFILES = afp.conf
CLEANFILES = $(GENFILES)
-EXTRA_DIST = afp.conf.tmpl extmap.conf
+EXTRA_DIST = afp.conf.tmpl extmap.conf netatalk-dbus.conf
OVERWRITE_CONFIG = @OVERWRITE_CONFIG@
CONFFILES = extmap.conf
pkgconfdir = @PKGCONFDIR@
+
+if HAVE_DBUS_GLIB
+dbusservicedir = $(DBUS_SYS_DIR)
+dbusservice_DATA = netatalk-dbus.conf
+endif
+
#
# rule to parse template files
#
diff --git a/config/netatalk-dbus.conf b/config/netatalk-dbus.conf
new file mode 100644
index 00000000..1646efd4
--- /dev/null
+++ b/config/netatalk-dbus.conf
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/pam/.gitignore b/config/pam/.gitignore
index dbbab4b2..d209ccf9 100644
--- a/config/pam/.gitignore
+++ b/config/pam/.gitignore
@@ -1,5 +1,5 @@
Makefile
Makefile.in
netatalk.pam
-.gitignore
+netatalk
*.o
diff --git a/config/pam/Makefile.am b/config/pam/Makefile.am
index e01d784c..62affbda 100644
--- a/config/pam/Makefile.am
+++ b/config/pam/Makefile.am
@@ -1,10 +1,9 @@
## Makefile for distrib/pam/
SUFFIXES = .tmpl .
-pamdir = @PAMDIR@/etc/pam.d
-EXTRA_DIST = netatalk.pam.tmpl
-noinst_SCRIPTS = netatalk.pam
-CLEANFILES = netatalk.pam
+EXTRA_DIST = netatalk.tmpl
+noinst_SCRIPTS = netatalk
+CLEANFILES = netatalk
.tmpl:
sed -e "s,[@]PAM_DIRECTIVE[@],${PAM_DIRECTIVE},g" \
@@ -15,23 +14,6 @@ CLEANFILES = netatalk.pam
<$< >$@
if USE_PAM
-install-data-local: netatalk.pam
- $(mkinstalldirs) $(DESTDIR)$(pamdir)
- if test "x$(OVERWRITE_CONFIG)" = "xyes" -o ! -f $(DESTDIR)$(pamdir)/netatalk; then \
- echo "$(INSTALL_DATA) $$f $(DESTDIR)$(pamdir)/netatalk"; \
- $(INSTALL_DATA) netatalk.pam $(DESTDIR)$(pamdir)/netatalk || echo "WARNING: Can't install PAM files"; \
- else \
- echo "not overwriting $(DESTDIR)$(pamdir)/netatalk"; \
- fi;
-
-uninstall-local:
- echo rm -f $(DESTDIR)$(pamdir)/netatalk; \
- rm -f $(DESTDIR)$(pamdir)/netatalk; \
- for f in $(CONFFILES) $(GENFILES); do \
- echo rm -f $(DESTDIR)$(pkgconfdir)/$$f; \
- rm -f $(DESTDIR)$(pkgconfdir)/$$f; \
- done
-else
-install-data-local:
-uninstall-local:
+pamdir = $(PAMDIR)
+pam_DATA = netatalk
endif
diff --git a/config/pam/netatalk.pam.tmpl b/config/pam/netatalk.tmpl
similarity index 100%
rename from config/pam/netatalk.pam.tmpl
rename to config/pam/netatalk.tmpl
diff --git a/configure.ac b/configure.ac
index bfb578ca..566df4f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -180,12 +180,22 @@ AC_NETATALK_SENDFILE
dnl Check whether bundled libevent shall not be used
AC_NETATALK_LIBEVENT
+dnl libatalk API checks
+AC_DEVELOPER
+
+dnl Check for dtrace
+AC_NETATALK_DTRACE
+
+dnl Check for dbus-glib, for AFP stats on dbus
+AC_NETATALK_DBUS_GLIB
+
dnl FHS stuff has to be done last because it overrides other defaults
AC_NETATALK_FHS
-AC_DEVELOPER
+dnl netatalk lockfile path, must come after AC_NETATALK_FHS
+AC_NETATALK_LOCKFILE
-CFLAGS="-I\$(top_srcdir)/include -I\$(top_srcdir)/sys $CFLAGS"
+CFLAGS="-I\$(top_srcdir)/include -I\$(top_builddir)/include $CFLAGS"
UAMS_PATH="${uams_path}"
AC_SUBST(LIBS)
diff --git a/contrib/misc/libevent.patch b/contrib/misc/libevent.patch
index 7d69713e..14245d2d 100644
--- a/contrib/misc/libevent.patch
+++ b/contrib/misc/libevent.patch
@@ -1,8 +1,35 @@
diff --git a/libevent/Makefile.am b/libevent/Makefile.am
-index 46f6d34..dda19b2 100644
+index 09505bd..8114ad3 100644
--- a/libevent/Makefile.am
+++ b/libevent/Makefile.am
-@@ -173,7 +173,7 @@ NO_UNDEFINED =
+@@ -86,9 +86,6 @@ if INSTALL_LIBEVENT
+ dist_bin_SCRIPTS = event_rpcgen.py
+ endif
+
+-pkgconfigdir=$(libdir)/pkgconfig
+-LIBEVENT_PKGCONFIG=libevent.pc
+-
+ # These sources are conditionally added by configure.in or conditionally
+ # included from other files.
+ PLATFORM_DEPENDENT_SRC = \
+@@ -108,16 +105,13 @@ EXTRA_DIST = \
+ LIBEVENT_LIBS_LA = libevent.la libevent_core.la libevent_extra.la
+ if PTHREADS
+ LIBEVENT_LIBS_LA += libevent_pthreads.la
+-LIBEVENT_PKGCONFIG += libevent_pthreads.pc
+ endif
+ if OPENSSL
+ LIBEVENT_LIBS_LA += libevent_openssl.la
+-LIBEVENT_PKGCONFIG += libevent_openssl.pc
+ endif
+
+ if INSTALL_LIBEVENT
+ lib_LTLIBRARIES = $(LIBEVENT_LIBS_LA)
+-pkgconfig_DATA = $(LIBEVENT_PKGCONFIG)
+ else
+ noinst_LTLIBRARIES = $(LIBEVENT_LIBS_LA)
+ endif
+@@ -196,7 +190,7 @@ NO_UNDEFINED =
MAYBE_CORE =
endif
@@ -11,9 +38,12 @@ index 46f6d34..dda19b2 100644
libevent_la_SOURCES = $(CORE_SRC) $(EXTRA_SRC)
libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
-@@ -221,3 +221,5 @@ FORCE:
-
- DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h
+@@ -249,5 +243,7 @@ doxygen: FORCE
+ doxygen $(srcdir)/Doxyfile
+ FORCE:
-+install:
+-DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h
++DISTCLEANFILES = *~ ./include/event2/event-config.h
+
++install:
+
diff --git a/contrib/shell_utils/Makefile.am b/contrib/shell_utils/Makefile.am
index bb4d9cbf..dc4c7db7 100644
--- a/contrib/shell_utils/Makefile.am
+++ b/contrib/shell_utils/Makefile.am
@@ -18,6 +18,6 @@ SUFFIXES = .tmpl .
CLEANFILES = $(GENERATED_FILES)
-bin_SCRIPTS = $(PERLSCRIPTS) $(GENERATED_FILES)
+bin_SCRIPTS = $(PERLSCRIPTS) $(GENERATED_FILES) afpstats
-EXTRA_DIST = $(TEMPLATE_FILES) make-casetable.pl make-precompose.h.pl
+EXTRA_DIST = $(TEMPLATE_FILES) make-casetable.pl make-precompose.h.pl afpstats
diff --git a/contrib/shell_utils/afpstats b/contrib/shell_utils/afpstats
new file mode 100755
index 00000000..8c5413c8
--- /dev/null
+++ b/contrib/shell_utils/afpstats
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+usage = """Usage:
+python afpstats.py
+"""
+
+import sys
+from traceback import print_exc
+import dbus
+
+def main():
+ bus = dbus.SystemBus()
+
+ try:
+ remote_object = bus.get_object("org.netatalk.AFPStats",
+ "/org/netatalk/AFPStats")
+
+ except dbus.DBusException:
+ print_exc()
+ sys.exit(1)
+
+ iface = dbus.Interface(remote_object, "org.netatalk.AFPStats")
+
+ reply = iface.GetUsers()
+ for name in reply:
+ print name
+
+if __name__ == '__main__':
+ main()
diff --git a/distrib/initscripts/Makefile.am b/distrib/initscripts/Makefile.am
index 5bdf9510..79dcfb3f 100644
--- a/distrib/initscripts/Makefile.am
+++ b/distrib/initscripts/Makefile.am
@@ -13,6 +13,7 @@ pkgconfdir = @PKGCONFDIR@
-e s@:SBINDIR:@${sbindir}@ \
-e s@:ETCDIR:@${pkgconfdir}@ \
-e s@:NETATALK_VERSION:@${NETATALK_VERSION}@ \
+ -e s@:PATH_NETATALK_LOCK:@${PATH_NETATALK_LOCK}@ \
<$< >$@
GENERATED_FILES = \
@@ -53,7 +54,7 @@ uninstall: uninstall-startup
if USE_REDHAT_SYSV
-sysvdir = /etc/rc.d/init.d
+sysvdir = $(INIT_DIR)
sysv_SCRIPTS = netatalk
$(sysv_SCRIPTS): rc.redhat
@@ -75,7 +76,7 @@ endif
if USE_SYSTEMD
-servicedir = /lib/systemd/system
+servicedir = $(INIT_DIR)
service_DATA = netatalk.service
netatalk.service: service.systemd
@@ -97,7 +98,7 @@ endif
if USE_SUSE_SYSV
-sysvdir = /etc/init.d
+sysvdir = $(INIT_DIR)
sysv_SCRIPTS = netatalk
$(sysv_SCRIPTS): rc.suse
@@ -119,7 +120,7 @@ endif
if USE_NETBSD
-sysvdir = /etc/rc.d
+sysvdir = $(INIT_DIR)
sysv_SCRIPTS = netatalk
netatalk: rc.netbsd
@@ -140,7 +141,7 @@ endif
if USE_SOLARIS
-servicedir = /lib/svc/manifest/network/
+servicedir = $(INIT_DIR)
service_DATA = netatalk.xml
install-data-hook:
@@ -157,7 +158,7 @@ endif
if USE_GENTOO
-sysvdir = /etc/init.d
+sysvdir = $(INIT_DIR)
sysv_SCRIPTS = netatalk
$(sysv_SCRIPTS): rc.gentoo
@@ -179,7 +180,7 @@ endif
if USE_DEBIAN
-sysvdir = /etc/init.d
+sysvdir = $(INIT_DIR)
sysv_SCRIPTS = netatalk
$(sysv_SCRIPTS): rc.debian
diff --git a/distrib/initscripts/rc.redhat.tmpl b/distrib/initscripts/rc.redhat.tmpl
index 643448ae..0721d9f6 100644
--- a/distrib/initscripts/rc.redhat.tmpl
+++ b/distrib/initscripts/rc.redhat.tmpl
@@ -21,7 +21,7 @@ RETVAL=1
netatalk_startup() {
# Check that networking is up.
if [ ${NETWORKING} = "no" ]; then
- echo "[Network isn't started]";
+ echo "[Network isn't started]";
exit 1;
fi
@@ -51,11 +51,17 @@ netatalk_stop() {
fi
}
-# code to cause apfd and cnid_metad to restart
-netatalk_graceful() {
+# restart code
+netatalk_restart() {
+ netatalk_stop
+ netatalk_startup
+}
+
+# reload config files
+netatalk_reload() {
if [ -x ${NETATALK_SBIN}/netatalk ]; then
- echo -n $"Restarting cnid_metad and afpd: "
- killproc netatalk -QUIT
+ echo -n $"Reloading $prog: "
+ killproc netatalk -HUP
RETVAL=$?
echo
fi
@@ -68,20 +74,21 @@ case "$1" in
'stop')
netatalk_stop
;;
- 'restart'|'reload')
- $0 stop
- $0 start
- RETVAL=$?
+ 'restart')
+ netatalk_restart
+ ;;
+ 'reload'|'graceful')
+ netatalk_reload
;;
'status')
status netatalk
RETVAL=$?
;;
- 'graceful')
- netatalk_graceful
+ 'condrestart')
+ [ -f /var/lock/subsys/netatalk ] && netatalk_restart || :
;;
*)
- echo "Usage: $0 {start|stop|restart|reload|status|graceful}"
+ echo "Usage: $0 {start|stop|restart|reload|status|condrestart}"
exit 2
esac
diff --git a/distrib/initscripts/service.systemd.tmpl b/distrib/initscripts/service.systemd.tmpl
index d21dde92..670f1445 100644
--- a/distrib/initscripts/service.systemd.tmpl
+++ b/distrib/initscripts/service.systemd.tmpl
@@ -10,6 +10,8 @@ After=syslog.target network.target avahi-daemon.service
Type=forking
GuessMainPID=no
ExecStart=:SBINDIR:/netatalk
+PIDFile=:PATH_NETATALK_LOCK:
+ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=1
diff --git a/etc/afpd/Makefile.am b/etc/afpd/Makefile.am
index 2404ad7d..ddff6c3e 100644
--- a/etc/afpd/Makefile.am
+++ b/etc/afpd/Makefile.am
@@ -1,6 +1,10 @@
# Makefile.am for etc/afpd/
pkgconfdir = @PKGCONFDIR@
+BUILT_SOURCES =
+EXTRA_DIST = afpstats-service.xml afpstats_service_glue.h
+CLEANFILES =
+DISTCLEANFILES =
sbin_PROGRAMS = afpd
noinst_PROGRAMS = hash fce
@@ -42,6 +46,7 @@ afpd_SOURCES = \
unix.c \
volume.c
+
afpd_LDADD = \
$(top_builddir)/libatalk/libatalk.la \
@LIBGCRYPT_LIBS@ @QUOTA_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@ @GSSAPI_LIBS@ @KRB5_LIBS@
@@ -61,11 +66,36 @@ if HAVE_ACLS
afpd_SOURCES += acls.c
endif
+if HAVE_DBUS_GLIB
+BUILT_SOURCES += afpstats_service_glue.h
+DISTCLEANFILES += afpstats_service_glue.h
+
+afpstats_service_glue.h: afpstats-service.xml
+ $(LIBTOOL) --mode=execute \
+ dbus-binding-tool \
+ --prefix=afpstats_obj \
+ --mode=glib-server \
+ --output=afpstats_service_glue.h \
+ $(top_srcdir)/etc/afpd/afpstats-service.xml
+
+afpd_SOURCES += afpstats.c afpstats_obj.c
+afpd_CFLAGS += $(DBUS_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GTHREAD_CFLAGS) -DDBUS_COMPILATION
+afpd_LDFLAGS += $(DBUS_LIBS) $(DBUS_GLIB_LIBS) $(DBUS_GTHREAD_LIBS) -ldbus-glib-1
+endif
+
+if WITH_DTRACE
+DTRACE_OBJ = afpd-afp_dsi.o afpd-fork.o afpd-appl.o afpd-catsearch.o afpd-directory.o afpd-enumerate.o afpd-file.o afpd-filedir.o
+afp_dtrace.o: $(top_srcdir)/include/atalk/afp_dtrace.d $(DTRACE_OBJ)
+ if test -f afp_dtrace.o ; then rm -f afp_dtrace.o ; fi
+ $(LIBTOOL) --mode=execute dtrace -G -s $(top_srcdir)/include/atalk/afp_dtrace.d -o afp_dtrace.o $(DTRACE_OBJ)
+afpd_LDADD += afp_dtrace.o @DTRACE_LIBS@
+CLEANFILES += afp_dtrace.o
+endif
noinst_HEADERS = auth.h afp_config.h desktop.h directory.h fce_api_internal.h file.h \
filedir.h fork.h icon.h mangle.h misc.h status.h switch.h \
uam_auth.h uid.h unix.h volume.h hash.h acls.h acl_mappings.h extattrs.h \
- dircache.h afp_zeroconf.h afp_avahi.h afp_mdns.h
+ dircache.h afp_zeroconf.h afp_avahi.h afp_mdns.h afpstats.h afpstats_obj.h
hash_SOURCES = hash.c
hash_CFLAGS = -DKAZLIB_TEST_MAIN -I$(top_srcdir)/include
diff --git a/etc/afpd/acls.c b/etc/afpd/acls.c
index 55a1e3ae..6f2abdf3 100644
--- a/etc/afpd/acls.c
+++ b/etc/afpd/acls.c
@@ -1157,17 +1157,21 @@ static int set_acl(const struct vol *vol,
}
LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
- /* Ressourcefork first.
- Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
- might be strange for ACE_DELETE_CHILD and for inheritance flags. */
+ /* Ressourcefork first */
if ((ret = (vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces))) != 0) {
- LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
- if (errno == (EACCES | EPERM))
+ LOG(log_debug, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
+ switch (errno) {
+ case EACCES:
+ case EPERM:
EC_STATUS(AFPERR_ACCESS);
- else if (errno == ENOENT)
- EC_STATUS(AFPERR_NOITEM);
- else
+ break;
+ case ENOENT:
+ EC_STATUS(AFP_OK);
+ break;
+ default:
EC_STATUS(AFPERR_MISC);
+ break;
+ }
goto EC_CLEANUP;
}
if ((ret = (acl(name, ACE_SETACL, new_aces_count, new_aces))) != 0) {
@@ -1363,6 +1367,8 @@ static int check_acl_access(const AFPObj *obj,
LOG(log_maxdebug, logtype_afpd, "check_acl_access(dir: \"%s\", path: \"%s\", curdir: \"%s\", 0x%08x)",
cfrombstr(dir->d_fullpath), path, getcwdpath(), requested_rights);
+ AFP_ASSERT(vol);
+
/* This check is not used anymore, as OS X Server seems to be ignoring too */
#if 0
/* Get uid or gid from UUID */
diff --git a/etc/afpd/afp_dsi.c b/etc/afpd/afp_dsi.c
index 8e1f90d2..5082ee70 100644
--- a/etc/afpd/afp_dsi.c
+++ b/etc/afpd/afp_dsi.c
@@ -140,23 +140,6 @@ static void afp_dsi_die(int sig)
}
}
-/* SIGQUIT handler */
-static void ipc_reconnect_handler(int sig _U_)
-{
- if (reconnect_ipc(AFPobj) != 0) {
- LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC reconnect");
- afp_dsi_close(AFPobj);
- exit(EXITERR_SYS);
- }
-
- if (ipc_child_write(AFPobj->ipc_fd, IPC_GETSESSION, AFPobj->sinfo.clientid_len, AFPobj->sinfo.clientid) != 0) {
- LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC ID resend");
- afp_dsi_close(AFPobj);
- exit(EXITERR_SYS);
- }
- LOG(log_note, logtype_afpd, "ipc_reconnect_handler: IPC reconnect done");
-}
-
/* SIGURG handler (primary reconnect) */
static void afp_dsi_transfer_session(int sig _U_)
{
@@ -407,7 +390,7 @@ void afp_over_dsi_sighandlers(AFPObj *obj)
}
/* install SIGQUIT */
- action.sa_handler = ipc_reconnect_handler;
+ action.sa_handler = afp_dsi_die;
if ( sigaction(SIGQUIT, &action, NULL ) < 0 ) {
LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
afp_dsi_die(EXITERR_SYS);
@@ -490,6 +473,8 @@ void afp_over_dsi(AFPObj *obj)
int flag = 1;
setsockopt(dsi->socket, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
+ ipc_child_state(obj, DSI_RUNNING);
+
/* get stuck here until the end */
while (1) {
if (sigsetjmp(recon_jmp, 1) != 0)
@@ -514,15 +499,6 @@ void afp_over_dsi(AFPObj *obj)
exit(0);
}
-#if 0
- /* got ECONNRESET in read from client => exit*/
- if (dsi->flags & DSI_GOT_ECONNRESET) {
- LOG(log_note, logtype_afpd, "afp_over_dsi: client connection reset");
- afp_dsi_close(obj);
- exit(0);
- }
-#endif
-
if (dsi->flags & DSI_RECONINPROG) {
LOG(log_note, logtype_afpd, "afp_over_dsi: failed reconnect");
afp_dsi_close(obj);
@@ -533,8 +509,11 @@ void afp_over_dsi(AFPObj *obj)
if (dsi_disconnect(dsi) != 0)
afp_dsi_die(EXITERR_CLNT);
+ ipc_child_state(obj, DSI_DISCONNECTED);
+
while (dsi->flags & DSI_DISCONNECTED)
pause(); /* gets interrupted by SIGALARM or SIGURG tickle */
+ ipc_child_state(obj, DSI_RUNNING);
continue; /* continue receiving until disconnect timer expires
* or a primary reconnect succeeds */
}
@@ -543,6 +522,7 @@ void afp_over_dsi(AFPObj *obj)
LOG(log_debug, logtype_afpd, "afp_over_dsi: got data, ending normal sleep");
dsi->flags &= ~DSI_SLEEPING;
dsi->tickle = 0;
+ ipc_child_state(obj, DSI_RUNNING);
}
if (reload_request) {
@@ -623,10 +603,12 @@ void afp_over_dsi(AFPObj *obj)
LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
+ AFP_AFPFUNC_START(function, (char *)AfpNum2name(function));
err = (*afp_switch[function])(obj,
(char *)dsi->commands, dsi->cmdlen,
(char *)&dsi->data, &dsi->datalen);
+ AFP_AFPFUNC_DONE(function, (char *)AfpNum2name(function));
LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
AfpNum2name(function), AfpErr2name(err));
@@ -664,10 +646,14 @@ void afp_over_dsi(AFPObj *obj)
LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
+ AFP_AFPFUNC_START(function, (char *)AfpNum2name(function));
+
err = (*afp_switch[function])(obj,
(char *)dsi->commands, dsi->cmdlen,
(char *)&dsi->data, &dsi->datalen);
+ AFP_AFPFUNC_DONE(function, (char *)AfpNum2name(function));
+
LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
AfpNum2name(function), AfpErr2name(err));
diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c
index bac65d59..932e6a65 100644
--- a/etc/afpd/afp_options.c
+++ b/etc/afpd/afp_options.c
@@ -165,6 +165,20 @@ static void show_version_extended(void )
#else
puts( "No" );
#endif
+
+ printf( " D-Bus support:\t" );
+#ifdef HAVE_DBUS_GLIB
+ puts( "Yes" );
+#else
+ puts( "No" );
+#endif
+
+ printf( " DTrace probes:\t" );
+#ifdef WITH_DTRACE
+ puts( "Yes" );
+#else
+ puts( "No" );
+#endif
}
/*
diff --git a/etc/afpd/afpstats-service.xml b/etc/afpd/afpstats-service.xml
new file mode 100644
index 00000000..099c778a
--- /dev/null
+++ b/etc/afpd/afpstats-service.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/etc/afpd/afpstats.c b/etc/afpd/afpstats.c
new file mode 100644
index 00000000..80d3e6f5
--- /dev/null
+++ b/etc/afpd/afpstats.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013 Frank Lahm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "afpstats_obj.h"
+#include "afpstats_service_glue.h"
+
+/*
+ * Beware: this struct is accessed and modified from the main thread
+ * and from this thread, thus be careful to lock and unlock the mutex.
+ */
+static server_child_t *childs;
+
+static gpointer afpstats_thread(gpointer _data)
+{
+ DBusGConnection *bus;
+ DBusGProxy *bus_proxy;
+ GError *error = NULL;
+ GMainContext *ctxt;
+ GMainLoop *thread_loop;
+ guint request_name_result;
+ sigset_t sigs;
+
+ /* Block all signals in this thread */
+ sigfillset(&sigs);
+ pthread_sigmask(SIG_BLOCK, &sigs, NULL);
+
+ ctxt = g_main_context_new();
+ thread_loop = g_main_loop_new(ctxt, FALSE);
+
+ dbus_g_object_type_install_info(AFPSTATS_TYPE_OBJECT, &dbus_glib_afpstats_obj_object_info);
+
+ if (!(bus = dbus_g_bus_get_private(DBUS_BUS_SYSTEM, ctxt, &error))) {
+ LOG(log_error, logtype_afpd,"Couldn't connect to system bus: %s", error->message);
+ return NULL;
+ }
+
+ if (!(bus_proxy = dbus_g_proxy_new_for_name(bus, "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus"))) {
+ LOG(log_error, logtype_afpd,"Couldn't create bus proxy");
+ return NULL;
+ }
+
+ if (!dbus_g_proxy_call(bus_proxy, "RequestName", &error,
+ G_TYPE_STRING, "org.netatalk.AFPStats",
+ G_TYPE_UINT, 0,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &request_name_result,
+ G_TYPE_INVALID)) {
+ LOG(log_error, logtype_afpd, "Failed to acquire DBUS name: %s", error->message);
+ return NULL;
+ }
+
+ AFPStatsObj *obj = g_object_new(AFPSTATS_TYPE_OBJECT, NULL);
+ dbus_g_connection_register_g_object(bus, "/org/netatalk/AFPStats", G_OBJECT(obj));
+
+ g_main_loop_run(thread_loop);
+ return thread_loop;
+}
+
+static void my_glib_log(const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data)
+{
+ LOG(log_error, logtype_afpd, "%s: %s", log_domain, message);
+}
+
+server_child_t *afpstats_get_and_lock_childs(void)
+{
+ pthread_mutex_lock(&childs->servch_lock);
+ return childs;
+}
+
+void afpstats_unlock_childs(void)
+{
+ pthread_mutex_unlock(&childs->servch_lock);
+}
+
+int afpstats_init(server_child_t *childs_in)
+{
+ GThread *thread;
+
+ childs = childs_in;
+ g_type_init();
+ g_thread_init(NULL);
+ dbus_g_thread_init();
+ (void)g_log_set_default_handler(my_glib_log, NULL);
+
+ thread = g_thread_create(afpstats_thread, NULL, TRUE, NULL);
+
+ return 0;
+}
diff --git a/etc/afpd/afpstats.h b/etc/afpd/afpstats.h
new file mode 100644
index 00000000..9f742ad7
--- /dev/null
+++ b/etc/afpd/afpstats.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Frank Lahm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef AFPD_AFPSTATS_H
+#define AFPD_AFPSTATS_H
+
+#include
+
+extern int afpstats_init(server_child_t *);
+extern server_child_t *afpstats_get_and_lock_childs(void);
+extern void afpstats_unlock_childs(void);
+#endif
diff --git a/etc/afpd/afpstats_obj.c b/etc/afpd/afpstats_obj.c
new file mode 100644
index 00000000..755d7a59
--- /dev/null
+++ b/etc/afpd/afpstats_obj.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013 Frank Lahm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include "afpstats.h"
+#include "afpstats_obj.h"
+
+struct AFPStatsObj
+{
+ GObject parent;
+};
+
+struct AFPStatsObjClass
+{
+ GObjectClass parent;
+};
+
+static void afpstats_obj_init(AFPStatsObj *obj)
+{
+}
+
+static void afpstats_obj_class_init(AFPStatsObjClass *klass)
+{
+}
+
+static gpointer afpstats_obj_parent_class = NULL;
+
+static void afpstats_obj_class_intern_init(gpointer klass)
+{
+ afpstats_obj_parent_class = g_type_class_peek_parent(klass);
+ afpstats_obj_class_init((AFPStatsObjClass *)klass);
+}
+
+GType afpstats_obj_get_type(void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+ if (g_once_init_enter(&g_define_type_id__volatile)) {
+ GType g_define_type_id = g_type_register_static_simple(
+ G_TYPE_OBJECT,
+ g_intern_static_string("AFPStatsObj"),
+ sizeof(AFPStatsObjClass),
+ (GClassInitFunc)afpstats_obj_class_intern_init,
+ sizeof(AFPStatsObj),
+ (GInstanceInitFunc)afpstats_obj_init,
+ (GTypeFlags)0);
+ g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
+ }
+ return g_define_type_id__volatile;
+}
+
+gboolean afpstats_obj_get_users(AFPStatsObj *obj, gchar ***ret, GError **error)
+{
+ gchar **names;
+ server_child_t *childs = afpstats_get_and_lock_childs();
+ afp_child_t *child;
+ struct passwd *pw;
+ int i = 0, j;
+ char buf[256];
+
+ names = g_new(char *, childs->servch_count + 1);
+
+ for (j = 0; j < CHILD_HASHSIZE && i < childs->servch_count; j++) {
+ child = childs->servch_table[j];
+ while (child) {
+ if (child->afpch_valid && (pw = getpwuid(child->afpch_uid))) {
+ time_t time = child->afpch_logintime;
+ strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime(&time));
+ names[i++] = g_strdup_printf("name: %s, pid: %d, logintime: %s, state: %s, volumes: %s",
+ pw->pw_name, child->afpch_pid, buf,
+ child->afpch_state == DSI_RUNNING ? "active" :
+ child->afpch_state == DSI_SLEEPING ? "sleeping" :
+ child->afpch_state == DSI_EXTSLEEP ? "sleeping" :
+ child->afpch_state == DSI_DISCONNECTED ? "disconnected" :
+ "unknown",
+ child->afpch_volumes ? child->afpch_volumes : "-");
+ }
+ child = child->afpch_next;
+ }
+ }
+ names[i] = NULL;
+ *ret = names;
+
+ afpstats_unlock_childs();
+
+ return TRUE;
+}
diff --git a/etc/afpd/afpstats_obj.h b/etc/afpd/afpstats_obj.h
new file mode 100644
index 00000000..9d830006
--- /dev/null
+++ b/etc/afpd/afpstats_obj.h
@@ -0,0 +1,19 @@
+#ifndef AFPSTATS_OBJ_H
+#define AFPSTATS_OBJ_H
+
+#include
+
+typedef struct AFPStatsObj AFPStatsObj;
+typedef struct AFPStatsObjClass AFPStatsObjClass;
+
+GType afpstats_obj_get_type(void);
+gboolean afpstats_obj_get_users(AFPStatsObj *obj, gchar ***ret, GError **error);
+
+#define AFPSTATS_TYPE_OBJECT (afpstats_obj_get_type ())
+#define AFPSTATS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST((object), AFPSTATS_TYPE_OBJECT, AFPStatsObj))
+#define AFPSTATS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), AFPSTATS_TYPE_OBJECT, AFPStatsObjClass))
+#define AFPSTATS_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), AFPSTATS_TYPE_OBJECT))
+#define AFPSTATS_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), AFPSTATS_TYPE_OBJECT))
+#define AFPSTATS_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), AFPSTATS_TYPE_OBJECT, AFPStatsObjClass))
+
+#endif /* AFPSTATS_OBJ_H */
diff --git a/etc/afpd/afpstats_service_glue.h b/etc/afpd/afpstats_service_glue.h
new file mode 100644
index 00000000..65081c46
--- /dev/null
+++ b/etc/afpd/afpstats_service_glue.h
@@ -0,0 +1,121 @@
+/* Generated by dbus-binding-tool; do not edit! */
+
+
+#ifndef __dbus_glib_marshal_afpstats_obj_MARSHAL_H__
+#define __dbus_glib_marshal_afpstats_obj_MARSHAL_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#define g_marshal_value_peek_variant(v) g_value_get_variant (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* BOOLEAN:POINTER,POINTER */
+extern void dbus_glib_marshal_afpstats_obj_BOOLEAN__POINTER_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+void
+dbus_glib_marshal_afpstats_obj_BOOLEAN__POINTER_POINTER (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__POINTER_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_pointer (param_values + 2),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+G_END_DECLS
+
+#endif /* __dbus_glib_marshal_afpstats_obj_MARSHAL_H__ */
+
+#include
+static const DBusGMethodInfo dbus_glib_afpstats_obj_methods[] = {
+ { (GCallback) afpstats_obj_get_users, dbus_glib_marshal_afpstats_obj_BOOLEAN__POINTER_POINTER, 0 },
+};
+
+const DBusGObjectInfo dbus_glib_afpstats_obj_object_info = { 1,
+ dbus_glib_afpstats_obj_methods,
+ 1,
+"org.netatalk.AFPStats\0GetUsers\0S\0ret\0O\0F\0N\0as\0\0\0",
+"\0",
+"\0"
+};
+
diff --git a/etc/afpd/appl.c b/etc/afpd/appl.c
index 04dd92d6..f53803e0 100644
--- a/etc/afpd/appl.c
+++ b/etc/afpd/appl.c
@@ -170,7 +170,11 @@ makemacpath(const struct vol *vol, char *mpath, int mpathlen, struct dir *dir, c
}
/* next part */
- if ((uname = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL ) {
+ AFP_CNID_START("cnid_resolve");
+ uname = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen);
+ AFP_CNID_DONE();
+
+ if (uname == NULL) {
afp_errno = AFPERR_NOOBJ;
ret = NULL;
goto exit;
diff --git a/etc/afpd/auth.c b/etc/afpd/auth.c
index 7569cfef..bec624dc 100644
--- a/etc/afpd/auth.c
+++ b/etc/afpd/auth.c
@@ -39,6 +39,7 @@ extern void afp_get_cmdline( int *ac, char ***av );
#include
#include
#include
+#include
#include "auth.h"
#include "uam_auth.h"
@@ -210,23 +211,6 @@ static int set_auth_switch(const AFPObj *obj, int expired)
return AFP_OK;
}
-#define GROUPSTR_BUFSIZE 1024
-static const char *print_groups(int ngroups, gid_t *groups)
-{
- static char groupsstr[GROUPSTR_BUFSIZE];
- int i;
- char *s = groupsstr;
-
- if (ngroups == 0)
- return "-";
-
- for (i = 0; (i < ngroups) && (s < &groupsstr[GROUPSTR_BUFSIZE]); i++) {
- s += snprintf(s, &groupsstr[GROUPSTR_BUFSIZE] - s, " %u", groups[i]);
- }
-
- return groupsstr;
-}
-
static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expired)
{
#ifdef ADMIN_GRP
@@ -241,32 +225,8 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi
LOG(log_note, logtype_afpd, "%s Login by %s",
afp_versions[afp_version_index].av_name, pwd->pw_name);
- if (initgroups( pwd->pw_name, pwd->pw_gid ) < 0) {
-#ifdef RUN_AS_USER
- LOG(log_info, logtype_afpd, "running with uid %d", geteuid());
-#else /* RUN_AS_USER */
- LOG(log_error, logtype_afpd, "login: %s", strerror(errno));
- return AFPERR_BADUAM;
-#endif /* RUN_AS_USER */
-
- }
-
- /* Basically if the user is in the admin group, we stay root */
-
- if ((obj->ngroups = getgroups( 0, NULL )) < 0 ) {
- LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno) );
- return AFPERR_BADUAM;
- }
-
- if ( NULL == (obj->groups = calloc(obj->ngroups, sizeof(gid_t))) ) {
- LOG(log_error, logtype_afpd, "login: %s calloc: %d", obj->ngroups);
+ if (set_groups(obj, pwd) != 0)
return AFPERR_BADUAM;
- }
-
- if (( obj->ngroups = getgroups(obj->ngroups, obj->groups )) < 0 ) {
- LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno) );
- return AFPERR_BADUAM;
- }
#ifdef ADMIN_GRP
LOG(log_debug, logtype_afpd, "obj->options.admingid == %d", obj->options.admingid);
@@ -375,6 +335,7 @@ int afp_zzz(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen
if (dsi->flags & DSI_EXTSLEEP) {
LOG(log_note, logtype_afpd, "afp_zzz: waking up from extended sleep");
dsi->flags &= ~(DSI_SLEEPING | DSI_EXTSLEEP);
+ ipc_child_state(obj, DSI_RUNNING);
}
} else {
/* sleep request */
@@ -382,8 +343,10 @@ int afp_zzz(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen
if (data & AFPZZZ_EXT_SLEEP) {
LOG(log_note, logtype_afpd, "afp_zzz: entering extended sleep");
dsi->flags |= DSI_EXTSLEEP;
+ ipc_child_state(obj, DSI_EXTSLEEP);
} else {
LOG(log_note, logtype_afpd, "afp_zzz: entering normal sleep");
+ ipc_child_state(obj, DSI_SLEEPING);
}
}
@@ -912,7 +875,7 @@ int afp_changepw(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rb
if ( ibuf[0] != '\0' || ibuf[1] != '\0')
return AFPERR_PARAM;
ibuf += 2;
- len = MIN(sizeof(username), strlen(obj->username));
+ len = MIN(sizeof(username) - 1, strlen(obj->username));
memcpy(username, obj->username, len);
username[ len ] = '\0';
}
diff --git a/etc/afpd/catsearch.c b/etc/afpd/catsearch.c
index 9ffea6e2..63a9607c 100644
--- a/etc/afpd/catsearch.c
+++ b/etc/afpd/catsearch.c
@@ -743,11 +743,14 @@ static int catsearch_db(const AFPObj *obj,
LOG(log_debug, logtype_afpd, "catsearch_db: %s", buffer);
- if ((num_matches = cnid_find(vol->v_cdb,
- buffer,
- strlen(uname),
- resbuf,
- sizeof(resbuf))) == -1) {
+ AFP_CNID_START("cnid_find");
+ num_matches = cnid_find(vol->v_cdb,
+ buffer,
+ strlen(uname),
+ resbuf,
+ sizeof(resbuf));
+ AFP_CNID_DONE();
+ if (num_matches == -1) {
result = AFPERR_MISC;
goto catsearch_end;
}
@@ -763,8 +766,12 @@ static int catsearch_db(const AFPObj *obj,
memcpy(&cnid, resbuf + cur_pos * sizeof(cnid_t), sizeof(cnid_t));
did = cnid;
- if ((name = cnid_resolve(vol->v_cdb, &did, resolvebuf, 12 + MAXPATHLEN + 1)) == NULL)
+ AFP_CNID_START("cnid_resolve");
+ name = cnid_resolve(vol->v_cdb, &did, resolvebuf, 12 + MAXPATHLEN + 1);
+ AFP_CNID_DONE();
+ if (name == NULL)
goto next;
+
LOG(log_debug, logtype_afpd, "catsearch_db: {pos: %u, name:%s, cnid: %u}",
cur_pos, name, ntohl(cnid));
if ((dir = dirlookup(vol, did)) == NULL)
diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c
index 9a4fc64e..d58023e2 100644
--- a/etc/afpd/directory.c
+++ b/etc/afpd/directory.c
@@ -497,12 +497,15 @@ struct dir *dirlookup_bypath(const struct vol *vol, const char *path)
cfrombstr(l->entry[i]),
blength(l->entry[i]))) == NULL) {
- if ((cnid = cnid_add(vol->v_cdb, /* 6. */
- &st,
- did,
- cfrombstr(l->entry[i]),
- blength(l->entry[i]),
- 0)) == CNID_INVALID)
+ AFP_CNID_START("cnid_add");
+ cnid = cnid_add(vol->v_cdb, /* 6. */
+ &st,
+ did,
+ cfrombstr(l->entry[i]),
+ blength(l->entry[i]),
+ 0);
+ AFP_CNID_DONE();
+ if (cnid == CNID_INVALID)
EC_FAIL;
if ((dir = dirlookup(vol, cnid)) == NULL) /* 7. */
@@ -607,7 +610,11 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did)
/* Get it from the database */
cnid = did;
LOG(log_debug, logtype_afpd, "dirlookup(did: %u): querying CNID database", ntohl(did));
- if ((upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL) {
+
+ AFP_CNID_START("cnid_resolve");
+ upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen);
+ AFP_CNID_DONE();
+ if (upath == NULL) {
afp_errno = AFPERR_NOOBJ;
err = 1;
goto exit;
@@ -815,7 +822,7 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i
cnid_t id;
struct adouble ad;
struct adouble *adp = NULL;
- bstring fullpath;
+ bstring fullpath = NULL;
AFP_ASSERT(vol);
AFP_ASSERT(dir);
@@ -2329,7 +2336,9 @@ int deletecurdir(struct vol *vol)
err = netatalk_rmdir_all_errors(-1, cfrombstr(fdir->d_u_name));
if ( err == AFP_OK || err == AFPERR_NOOBJ) {
+ AFP_CNID_START("cnid_delete");
cnid_delete(vol->v_cdb, fdir->d_did);
+ AFP_CNID_DONE();
dir_remove( vol, fdir );
} else {
LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): netatalk_rmdir_all_errors error",
diff --git a/etc/afpd/enumerate.c b/etc/afpd/enumerate.c
index 0c3c0576..340f79ae 100644
--- a/etc/afpd/enumerate.c
+++ b/etc/afpd/enumerate.c
@@ -362,16 +362,19 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
/* conversions on the fly */
const char *convname;
- if (ad_convert(sd.sd_last, &s_path.st, vol, &convname) == 0 && convname) {
- s_path.u_name = (char *)convname;
- }
-
- /* Fixup CNID db if ad_convert resulted in a rename (then convname != NULL) */
- if (convname) {
- s_path.id = cnid_lookup(vol->v_cdb, &s_path.st, curdir->d_did, sd.sd_last, strlen(sd.sd_last));
- if (s_path.id != CNID_INVALID) {
- if (cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, (char *)convname, strlen(convname)) != 0)
- LOG(log_error, logtype_afpd, "enumerate: error updating CNID of \"%s\"", fullpathname(convname));
+ if (ad_convert(sd.sd_last, &s_path.st, vol, &convname) == 0) {
+ if (convname) {
+ s_path.u_name = (char *)convname;
+ AFP_CNID_START("cnid_lookup");
+ s_path.id = cnid_lookup(vol->v_cdb, &s_path.st, curdir->d_did, sd.sd_last, strlen(sd.sd_last));
+ AFP_CNID_DONE();
+ if (s_path.id != CNID_INVALID) {
+ AFP_CNID_START("cnid_update");
+ int cnid_up_ret = cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, (char *)convname, strlen(convname));
+ AFP_CNID_DONE();
+ if (cnid_up_ret != 0)
+ LOG(log_error, logtype_afpd, "enumerate: error updating CNID of \"%s\"", fullpathname(convname));
+ }
}
}
diff --git a/etc/afpd/fce_api.c b/etc/afpd/fce_api.c
index 49dd3cd7..36cce446 100644
--- a/etc/afpd/fce_api.c
+++ b/etc/afpd/fce_api.c
@@ -361,9 +361,10 @@ int fce_register(fce_ev_t event, const char *path, const char *oldpath, fce_obj_
return AFP_OK;
AFP_ASSERT(event >= FCE_FIRST_EVENT && event <= FCE_LAST_EVENT);
+ AFP_ASSERT(path);
LOG(log_debug, logtype_fce, "register_fce(path: %s, type: %s, event: %s",
- path , type == fce_dir ? "dir" : "file", fce_event_names[event]);
+ path, type == fce_dir ? "dir" : "file", fce_event_names[event]);
bname = basename_safe(path);
@@ -371,8 +372,6 @@ int fce_register(fce_ev_t event, const char *path, const char *oldpath, fce_obj_
/* No listeners configured */
return AFP_OK;
- if (path == NULL)
- return AFPERR_PARAM;
/* do some initialization on the fly the first time */
if (first_event) {
diff --git a/etc/afpd/file.c b/etc/afpd/file.c
index 153f1325..be1fafe5 100644
--- a/etc/afpd/file.c
+++ b/etc/afpd/file.c
@@ -219,7 +219,10 @@ uint32_t get_id(struct vol *vol,
catching moved files */
adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); /* (1) */
+ AFP_CNID_START("cnid_add");
dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); /* (2) */
+ AFP_CNID_DONE();
+
/* Throw errors if cnid_add fails. */
if (dbcnid == CNID_INVALID) {
switch (errno) {
@@ -335,6 +338,7 @@ int getmetadata(const AFPObj *obj,
|| (bconchar(fullpath, '/') != BSTR_OK)
|| (bcatcstr(fullpath, upath)) != BSTR_OK) {
LOG(log_error, logtype_afpd, "getmetadata: fullpath: %s", strerror(errno));
+ bdestroy(fullpath);
return AFPERR_MISC;
}
@@ -455,18 +459,23 @@ int getmetadata(const AFPObj *obj,
data += sizeof( aint );
break;
- case FILPBIT_RFLEN :
- if ( adp ) {
+ case FILPBIT_RFLEN: {
+ off_t rlen;
+ if (adp) {
if (adp->ad_rlen > 0xffffffff)
aint = 0xffffffff;
else
aint = htonl( adp->ad_rlen);
} else {
- aint = 0;
+ rlen = ad_reso_size(path->u_name, 0, NULL);
+ if (rlen > 0xffffffff)
+ rlen = 0xffffffff;
+ aint = htonl(rlen);
}
memcpy(data, &aint, sizeof( aint ));
data += sizeof( aint );
break;
+ }
/* Current client needs ProDOS info block for this file.
Use simple heuristic and let the Mac "type" string tell
@@ -534,15 +543,18 @@ int getmetadata(const AFPObj *obj,
data += sizeof( aint );
break;
case FILPBIT_EXTRFLEN:
- aint = 0;
- if (adp)
+ if (adp) {
aint = htonl(adp->ad_rlen >> 32);
- memcpy(data, &aint, sizeof( aint ));
- data += sizeof( aint );
- if (adp)
+ memcpy(data, &aint, sizeof( aint ));
+ data += sizeof( aint );
aint = htonl(adp->ad_rlen);
- memcpy(data, &aint, sizeof( aint ));
- data += sizeof( aint );
+ memcpy(data, &aint, sizeof( aint ));
+ data += sizeof( aint );
+ } else {
+ int64_t rlen = hton64(ad_reso_size(path->u_name, 0, NULL));
+ memcpy(data, &rlen, sizeof(rlen));
+ data += sizeof(rlen);
+ }
break;
case FILPBIT_UNIXPR :
/* accessmode may change st_mode with ACLs */
@@ -1579,7 +1591,7 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib)
adp = &ad;
}
- if ( adp && AD_RSRC_OPEN(adp) != -1 ) { /* there's a resource fork */
+ if ( adp && AD_RSRC_OPEN(adp) ) { /* there's a resource fork */
adflags |= ADFLAGS_RF;
/* FIXME we have a pb here because we want to know if a file is open
* there's a 'priority inversion' if you can't open the ressource fork RW
@@ -1601,8 +1613,15 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib)
err = AFPERR_BUSY;
} else if (!(err = vol->vfs->vfs_deletefile(vol, dirfd, file)) && !(err = netatalk_unlinkat(dirfd, file )) ) {
cnid_t id;
- if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) {
- cnid_delete(vol->v_cdb, id);
+ if (checkAttrib) {
+ AFP_CNID_START("cnid_get");
+ id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file));
+ AFP_CNID_DONE();
+ if (id) {
+ AFP_CNID_START("cnid_delete");
+ cnid_delete(vol->v_cdb, id);
+ AFP_CNID_DONE();
+ }
}
}
@@ -1675,7 +1694,10 @@ int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
return AFPERR_PARAM;
}
st = &s_path->st;
- if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
+ AFP_CNID_START("cnid_lookup");
+ id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath));
+ AFP_CNID_DONE();
+ if (id) {
memcpy(rbuf, &id, sizeof(id));
*rbuflen = sizeof(id);
return AFPERR_EXISTID;
@@ -1708,7 +1730,9 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
return 0;
/* update or add to cnid */
+ AFP_CNID_START("cnid_add");
aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
+ AFP_CNID_DONE();
return 0;
}
@@ -1787,7 +1811,10 @@ int afp_resolveid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_
return AFPERR_NOID;
}
retry:
- if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
+ AFP_CNID_START("cnid_resolve");
+ upath = cnid_resolve(vol->v_cdb, &id, buffer, len);
+ AFP_CNID_DONE();
+ if (upath == NULL) {
return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
}
@@ -1890,7 +1917,10 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
ibuf += sizeof(id);
fileid = id;
- if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
+ AFP_CNID_START("cnid_resolve");
+ upath = cnid_resolve(vol->v_cdb, &id, buffer, len);
+ AFP_CNID_DONE();
+ if (upath == NULL) {
return AFPERR_NOID;
}
@@ -1923,7 +1953,9 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
return AFPERR_BADTYPE;
delete:
+ AFP_CNID_START("cnid_delete");
if (cnid_delete(vol->v_cdb, fileid)) {
+ AFP_CNID_DONE();
switch (errno) {
case EROFS:
return AFPERR_VLOCK;
@@ -1934,7 +1966,7 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
return AFPERR_PARAM;
}
}
-
+ AFP_CNID_DONE();
return err;
}
@@ -2062,7 +2094,9 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
/* look for the source cnid. if it doesn't exist, don't worry about
* it. */
+ AFP_CNID_START("cnid_lookup");
sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
+ AFP_CNID_DONE();
if (NULL == ( dir = dirlookup( vol, did )) ) {
err = afp_errno; /* was AFPERR_PARAM */
@@ -2105,7 +2139,9 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
/* look for destination id. */
upath = path->u_name;
+ AFP_CNID_START("cnid_lookup");
did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
+ AFP_CNID_DONE();
/* construct a temp name.
* NOTE: the temp file will be in the dest file's directory. it
@@ -2139,13 +2175,20 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
goto err_dest_to_src;
of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
- /* id's need switching. src -> dest and dest -> src.
+ /*
+ * id's need switching. src -> dest and dest -> src.
* we need to re-stat() if it was a cross device copy.
- */
- if (sid)
+ */
+ if (sid) {
+ AFP_CNID_START("cnid_delete");
cnid_delete(vol->v_cdb, sid);
- if (did)
+ AFP_CNID_DONE();
+ }
+ if (did) {
+ AFP_CNID_START("cnid_delete");
cnid_delete(vol->v_cdb, did);
+ AFP_CNID_DONE();
+ }
if ((did && ( (crossdev && ostat(upath, &srcst, vol_syml_opt(vol)) < 0) ||
cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c
index 543db0dc..8feac755 100644
--- a/etc/afpd/filedir.c
+++ b/etc/afpd/filedir.c
@@ -248,7 +248,9 @@ static int moveandrename(struct vol *vol,
if (!isdir) {
if ((oldunixname = strdup(mtoupath(vol, oldname, sdir->d_did, utf8_encoding(vol->v_obj)))) == NULL)
return AFPERR_PARAM; /* can't convert */
+ AFP_CNID_START("cnid_get");
id = cnid_get(vol->v_cdb, sdir->d_did, oldunixname, strlen(oldunixname));
+ AFP_CNID_DONE();
#ifndef HAVE_ATFUNCS
/* Need full path */
@@ -263,7 +265,7 @@ static int moveandrename(struct vol *vol,
#ifdef HAVE_ATFUNCS
opened = of_findnameat(sdir_fd, &path);
#else
- opened = of_findname(&path);
+ opened = of_findname(vol, &path);
#endif /* HAVE_ATFUNCS */
if (opened) {
@@ -378,7 +380,9 @@ static int moveandrename(struct vol *vol,
}
/* fix up the catalog entry */
+ AFP_CNID_START("cnid_update");
cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath));
+ AFP_CNID_DONE();
}
exit:
@@ -521,10 +525,16 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
delcnid = deldir->d_did;
dir_remove(vol, deldir);
}
- if (delcnid == CNID_INVALID)
+ if (delcnid == CNID_INVALID) {
+ AFP_CNID_START("cnid_get");
delcnid = cnid_get(vol->v_cdb, curdir->d_did, upath, strlen(upath));
- if (delcnid != CNID_INVALID)
+ AFP_CNID_DONE();
+ }
+ if (delcnid != CNID_INVALID) {
+ AFP_CNID_START("cnid_delete");
cnid_delete(vol->v_cdb, delcnid);
+ AFP_CNID_DONE();
+ }
fce_register(FCE_DIR_DELETE, fullpathname(upath), NULL, fce_dir);
} else {
/* we have to cache this, the structs are lost in deletcurdir*/
@@ -582,8 +592,10 @@ char *absupath(const struct vol *vol, struct dir *dir, char *u)
return NULL;
if (bcatcstr(path, u) != BSTR_OK)
return NULL;
- if (path->slen > MAXPATHLEN)
+ if (path->slen > MAXPATHLEN) {
+ bdestroy(path);
return NULL;
+ }
LOG(log_debug, logtype_afpd, "absupath: %s", cfrombstr(path));
diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c
index 2d59b5da..4e47b91b 100644
--- a/etc/afpd/fork.c
+++ b/etc/afpd/fork.c
@@ -328,8 +328,6 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
} else {
eid = ADEID_RFORK;
adflags |= ADFLAGS_RF;
- if (!(access & OPENACC_WR))
- adflags |= ADFLAGS_NORF;
}
if (access & OPENACC_WR) {
@@ -791,6 +789,8 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
goto afp_read_err;
}
+ AFP_READ_START((long)reqcount);
+
/* reqcount isn't always truthful. we need to deal with that. */
size = ad_size(ofork->of_ad, eid);
@@ -798,7 +798,7 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
"afp_read(fork: %" PRIu16 " [%s], off: %" PRIu64 ", len: %" PRIu64 ", size: %" PRIu64 ")",
ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount, size);
- if (offset > size) {
+ if (offset >= size) {
err = AFPERR_EOF;
goto afp_read_err;
}
@@ -837,11 +837,13 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
}
#endif
- *rbuflen = MIN(reqcount, *rbuflen);
+ *rbuflen = MIN(reqcount, dsi->server_quantum);
- err = read_file(ofork, eid, offset, rbuf, rbuflen);
- if (err < 0)
+ cc = read_file(ofork, eid, offset, ibuf, rbuflen);
+ if (cc < 0) {
+ err = cc;
goto afp_read_done;
+ }
LOG(log_debug, logtype_afpd,
"afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
@@ -854,18 +856,22 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
* we know that we're sending some data. if we fail, something
* horrible happened.
*/
- if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
+ if ((cc = dsi_readinit(dsi, ibuf, *rbuflen, reqcount, err)) < 0)
goto afp_read_exit;
*rbuflen = cc;
while (*rbuflen > 0) {
- cc = read_file(ofork, eid, offset, rbuf, rbuflen);
+ /*
+ * This loop isn't really entered anymore, we've already
+ * sent the whole requested block in dsi_readinit().
+ */
+ cc = read_file(ofork, eid, offset, ibuf, rbuflen);
if (cc < 0)
goto afp_read_exit;
offset += *rbuflen;
/* dsi_read() also returns buffer size of next allocation */
- cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
+ cc = dsi_read(dsi, ibuf, *rbuflen); /* send it off */
if (cc < 0)
goto afp_read_exit;
*rbuflen = cc;
@@ -883,6 +889,8 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
afp_read_done:
if (obj->options.flags & OPTION_AFP_READ_LOCK)
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum);
+
+ AFP_READ_DONE();
return err;
afp_read_err:
@@ -1037,7 +1045,7 @@ int afp_closefork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, s
ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "rsrc");
if (of_closefork(obj, ofork) < 0 ) {
- LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_closefork: of_closefork: %s", strerror(errno) );
return( AFPERR_PARAM );
}
@@ -1153,6 +1161,8 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s
goto afp_write_err;
}
+ AFP_WRITE_START((long)reqcount);
+
saveoff = offset;
if (obj->options.flags & OPTION_AFP_READ_LOCK) {
if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, reqcount, ofork->of_refnum) < 0) {
@@ -1227,6 +1237,7 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s
ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
*rbuflen = set_off_t (offset, rbuf, is64);
+ AFP_WRITE_DONE();
return( AFP_OK );
afp_write_err:
diff --git a/etc/afpd/hash.c b/etc/afpd/hash.c
index 4861e811..a7c624d4 100644
--- a/etc/afpd/hash.c
+++ b/etc/afpd/hash.c
@@ -982,8 +982,10 @@ int main(void)
"s switch to non-functioning allocator\n"
"q quit";
- if (!h)
+ if (!h) {
puts("hash_create failed");
+ return 1;
+ }
for (;;) {
if (prompt)
@@ -1012,6 +1014,7 @@ int main(void)
puts("out of memory");
free((void *) key);
free(val);
+ break;
}
if (!hash_alloc_insert(h, key, val)) {
diff --git a/etc/afpd/main.c b/etc/afpd/main.c
index 0e0a858e..cd65f7a9 100644
--- a/etc/afpd/main.c
+++ b/etc/afpd/main.c
@@ -38,6 +38,7 @@
#include "fork.h"
#include "uam_auth.h"
#include "afp_zeroconf.h"
+#include "afpstats.h"
#define AFP_LISTENERS 32
#define FDSET_SAFETY 5
@@ -45,7 +46,7 @@
unsigned char nologin = 0;
static AFPObj obj;
-static server_child *server_children;
+static server_child_t *server_children;
static sig_atomic_t reloadconfig = 0;
static sig_atomic_t gotsigchld = 0;
@@ -54,9 +55,8 @@ static struct pollfd *fdset;
static struct polldata *polldata;
static int fdset_size; /* current allocated size */
static int fdset_used; /* number of used elements */
-static int disasociated_ipc_fd; /* disasociated sessions uses this fd for IPC */
-static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children);
+static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children);
static void afp_exit(int ret)
{
@@ -81,16 +81,6 @@ static void fd_set_listening_sockets(const AFPObj *config)
LISTEN_FD,
dsi);
}
-
- if (config->options.flags & OPTION_KEEPSESSIONS)
- fdset_add_fd(config->options.connections + AFP_LISTENERS + FDSET_SAFETY,
- &fdset,
- &polldata,
- &fdset_used,
- &fdset_size,
- disasociated_ipc_fd,
- DISASOCIATED_IPC_FD,
- NULL);
}
static void fd_reset_listening_sockets(const AFPObj *config)
@@ -100,9 +90,6 @@ static void fd_reset_listening_sockets(const AFPObj *config)
for (dsi = config->dsi; dsi; dsi = dsi->next) {
fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, dsi->serversock);
}
-
- if (config->options.flags & OPTION_KEEPSESSIONS)
- fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, disasociated_ipc_fd);
}
/* ------------------ */
@@ -112,22 +99,9 @@ static void afp_goaway(int sig)
case SIGTERM:
case SIGQUIT:
- switch (sig) {
- case SIGTERM:
- LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGTERM");
- break;
- case SIGQUIT:
- if (obj.options.flags & OPTION_KEEPSESSIONS) {
- LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGQUIT, NOT disconnecting clients");
- } else {
- LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGQUIT");
- sig = SIGTERM;
- }
- break;
- }
+ LOG(log_note, logtype_afpd, "AFP Server shutting down");
if (server_children)
- server_child_kill(server_children, CHILD_DSIFORK, sig);
-
+ server_child_kill(server_children, SIGTERM);
_exit(0);
break;
@@ -137,7 +111,7 @@ static void afp_goaway(int sig)
LOG(log_info, logtype_afpd, "disallowing logins");
if (server_children)
- server_child_kill(server_children, CHILD_DSIFORK, sig);
+ server_child_kill(server_children, sig);
break;
case SIGHUP :
@@ -167,11 +141,9 @@ static void child_handler(void)
#endif /* ! WAIT_ANY */
while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
- for (i = 0; i < server_children->nforks; i++) {
- if ((fd = server_child_remove(server_children, i, pid)) != -1) {
- fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, fd);
- break;
- }
+ if ((fd = server_child_remove(server_children, pid)) != -1) {
+ fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, fd);
+ break;
}
if (WIFEXITED(status)) {
@@ -232,7 +204,7 @@ int main(int ac, char **av)
/* install child handler for asp and dsi. we do this before afp_goaway
* as afp_goaway references stuff from here.
* XXX: this should really be setup after the initial connections. */
- if (!(server_children = server_child_alloc(obj.options.connections, CHILD_NFORKS))) {
+ if (!(server_children = server_child_alloc(obj.options.connections))) {
LOG(log_error, logtype_afpd, "main: server_child alloc: %s", strerror(errno) );
afp_exit(EXITERR_SYS);
}
@@ -340,6 +312,11 @@ int main(int ac, char **av)
sigaddset(&sigs, SIGCHLD);
pthread_sigmask(SIG_BLOCK, &sigs, NULL);
+#ifdef HAVE_DBUS_GLIB
+ /* Run dbus AFP statics thread */
+ if (obj.options.flags & OPTION_DBUS_AFPSTATS)
+ (void)afpstats_init(server_children);
+#endif
if (configinit(&obj) != 0) {
LOG(log_error, logtype_afpd, "main: no servers configured");
afp_exit(EXITERR_CONF);
@@ -350,12 +327,6 @@ int main(int ac, char **av)
cnid_init();
/* watch atp, dsi sockets and ipc parent/child file descriptor. */
-
- if (obj.options.flags & OPTION_KEEPSESSIONS) {
- LOG(log_note, logtype_afpd, "Activating continous service");
- disasociated_ipc_fd = ipc_server_uds(_PATH_AFP_IPC);
- }
-
fd_set_listening_sockets(&obj);
/* set limits */
@@ -433,7 +404,7 @@ int main(int ac, char **av)
&polldata,
&fdset_used,
&fdset_size,
- child->ipc_fd,
+ child->afpch_ipc_fd,
IPC_FD,
child);
}
@@ -441,46 +412,13 @@ int main(int ac, char **av)
case IPC_FD:
child = (afp_child_t *)polldata[i].data;
- LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->pid);
-
- if (ipc_server_read(server_children, child->ipc_fd) != 0) {
- fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->ipc_fd);
- close(child->ipc_fd);
- child->ipc_fd = -1;
- if ((obj.options.flags & OPTION_KEEPSESSIONS) && child->disasociated) {
- LOG(log_note, logtype_afpd, "main: removing reattached child[%u]", child->pid);
- server_child_remove(server_children, CHILD_DSIFORK, child->pid);
- }
- }
- break;
-
- case DISASOCIATED_IPC_FD:
- LOG(log_debug, logtype_afpd, "main: IPC reconnect request");
- if ((recon_ipc_fd = accept(disasociated_ipc_fd, NULL, NULL)) == -1) {
- LOG(log_error, logtype_afpd, "main: accept: %s", strerror(errno));
- break;
- }
- if (readt(recon_ipc_fd, &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) {
- LOG(log_error, logtype_afpd, "main: readt: %s", strerror(errno));
- close(recon_ipc_fd);
- break;
- }
- LOG(log_note, logtype_afpd, "main: IPC reconnect from pid [%u]", pid);
+ LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->afpch_pid);
- if ((child = server_child_add(server_children, CHILD_DSIFORK, pid, recon_ipc_fd)) == NULL) {
- LOG(log_error, logtype_afpd, "main: server_child_add");
- close(recon_ipc_fd);
- break;
+ if (ipc_server_read(server_children, child->afpch_ipc_fd) != 0) {
+ fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->afpch_ipc_fd);
+ close(child->afpch_ipc_fd);
+ child->afpch_ipc_fd = -1;
}
- child->disasociated = 1;
- fdset_add_fd(obj.options.connections + AFP_LISTENERS + FDSET_SAFETY,
- &fdset,
- &polldata,
- &fdset_used,
- &fdset_size,
- recon_ipc_fd,
- IPC_FD,
- child);
break;
default:
@@ -494,7 +432,7 @@ int main(int ac, char **av)
return 0;
}
-static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children)
+static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children)
{
afp_child_t *child = NULL;
diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c
index 844444ba..f5122373 100644
--- a/etc/afpd/volume.c
+++ b/etc/afpd/volume.c
@@ -39,6 +39,7 @@
#include
#include
#include
+#include
#ifdef CNID_DB
#include
@@ -176,13 +177,18 @@ static int get_tm_used(struct vol * restrict vol)
EC_NULL_LOG( infoplist = bformat("%s/%s/%s", vol->v_path, entry->d_name, "Info.plist") );
- if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1)
+ if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1) {
+ bdestroy(infoplist);
continue;
+ }
EC_NULL_LOG( bandsdir = bformat("%s/%s/%s/", vol->v_path, entry->d_name, "bands") );
- if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1)
+ if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1) {
+ bdestroy(infoplist);
+ bdestroy(bandsdir);
continue;
+ }
used += (links - 1) * bandsize;
LOG(log_debug, logtype_afpd, "getused(\"%s\"): bands: %" PRIu64 " bytes",
@@ -654,6 +660,31 @@ static int volume_openDB(const AFPObj *obj, struct vol *volume)
return (!volume->v_cdb)?-1:0;
}
+/*
+ * Send list of open volumes to afpd master via IPC
+ */
+static void server_ipc_volumes(AFPObj *obj)
+{
+ struct vol *volume, *vols;
+ volume = vols = getvolumes();
+ bstring openvolnames = bfromcstr("");
+ bool firstvol = true;
+
+ while (volume) {
+ if (volume->v_flags & AFPVOL_OPEN) {
+ if (!firstvol)
+ bcatcstr(openvolnames, ", ");
+ else
+ firstvol = false;
+ bcatcstr(openvolnames, volume->v_localname);
+ }
+ volume = volume->v_next;
+ }
+
+ ipc_child_write(obj->ipc_fd, IPC_VOLUMES, blength(openvolnames), bdata(openvolnames));
+ bdestroy(openvolnames);
+}
+
/* -------------------------
* we are the user here
*/
@@ -668,7 +699,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
size_t namelen;
uint16_t bitmap;
char *vol_uname;
- char *vol_mname;
+ char *vol_mname = NULL;
char *volname_tmp;
ibuf += 2;
@@ -791,7 +822,6 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
ret = AFPERR_MISC;
goto openvol_err;
}
- free(vol_mname);
volume->v_root = dir;
curdir = dir;
@@ -829,6 +859,8 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
if ((msg = iniparser_getstring(obj->iniconfig, volume->v_configname, "login message", NULL)) != NULL)
setmessage(msg);
+ free(vol_mname);
+ server_ipc_volumes(obj);
return( AFP_OK );
}
@@ -843,6 +875,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
cnid_close(volume->v_cdb);
volume->v_cdb = NULL;
}
+ free(vol_mname);
*rbuflen = 0;
return ret;
}
@@ -900,6 +933,7 @@ int afp_closevol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si
(void)chdir("/");
curdir = NULL;
closevol(obj, vol);
+ server_ipc_volumes(obj);
return( AFP_OK );
}
diff --git a/etc/cnid_dbd/cnid_metad.c b/etc/cnid_dbd/cnid_metad.c
index 18e063da..7b7664d5 100644
--- a/etc/cnid_dbd/cnid_metad.c
+++ b/etc/cnid_dbd/cnid_metad.c
@@ -184,8 +184,8 @@ static int maybe_start_dbd(const AFPObj *obj, char *dbdpn, const char *volpath)
time(&t);
if (!up) {
/* find an empty slot (i < maxvol) or the first free slot (i == maxvol)*/
- for (i = 0; i <= maxvol; i++) {
- if (srv[i].v_path == NULL && i < MAXVOLS) {
+ for (i = 0; i <= maxvol && i < MAXVOLS; i++) {
+ if (srv[i].v_path == NULL) {
up = &srv[i];
if ((up->v_path = strdup(volpath)) == NULL)
return -1;
diff --git a/etc/cnid_dbd/main.c b/etc/cnid_dbd/main.c
index 767e1e3c..0067504a 100644
--- a/etc/cnid_dbd/main.c
+++ b/etc/cnid_dbd/main.c
@@ -228,8 +228,10 @@ static int delete_db(void)
LOG(log_warning, logtype_cnid, "Recreated CNID BerkeleyDB databases of volume \"%s\"", vol->v_localname);
EC_CLEANUP:
- if (cwd != -1)
+ if (cwd != -1) {
fchdir(cwd);
+ close(cwd);
+ }
EC_EXIT;
}
diff --git a/etc/netatalk/netatalk.c b/etc/netatalk/netatalk.c
index 9ac72c5a..b3ab20a1 100644
--- a/etc/netatalk/netatalk.c
+++ b/etc/netatalk/netatalk.c
@@ -209,7 +209,7 @@ static void kill_childs(int sig, ...)
/* this get called when error conditions are met that require us to exit gracefully */
static void netatalk_exit(int ret)
{
- server_unlock(_PATH_NETATALK_LOCK);
+ server_unlock(PATH_NETATALK_LOCK);
exit(ret);
}
@@ -270,13 +270,13 @@ int main(int argc, char **argv)
}
}
- if (check_lockfile("netatalk", _PATH_NETATALK_LOCK) != 0)
+ if (check_lockfile("netatalk", PATH_NETATALK_LOCK) != 0)
exit(EXITERR_SYS);
if (!debug && daemonize(0, 0) != 0)
exit(EXITERR_SYS);
- if (create_lockfile("netatalk", _PATH_NETATALK_LOCK) != 0)
+ if (create_lockfile("netatalk", PATH_NETATALK_LOCK) != 0)
exit(EXITERR_SYS);
sigfillset(&blocksigs);
@@ -291,7 +291,7 @@ int main(int argc, char **argv)
LOG(log_note, logtype_default, "Netatalk AFP server starting");
if ((afpd_pid = run_process(_PATH_AFPD, "-d", "-F", obj.options.configfile, NULL)) == -1) {
- LOG(log_error, logtype_afpd, "Error starting 'cnid_metad'");
+ LOG(log_error, logtype_afpd, "Error starting 'afpd'");
netatalk_exit(EXITERR_CONF);
}
diff --git a/include/atalk/.gitignore b/include/atalk/.gitignore
index 4ee83854..d935e1e6 100644
--- a/include/atalk/.gitignore
+++ b/include/atalk/.gitignore
@@ -1,4 +1,4 @@
Makefile
Makefile.in
*.o
-lockrpc.gen.h
\ No newline at end of file
+afp_dtrace.h
diff --git a/include/atalk/Makefile.am b/include/atalk/Makefile.am
index 93d28929..42085187 100644
--- a/include/atalk/Makefile.am
+++ b/include/atalk/Makefile.am
@@ -1,6 +1,8 @@
# Makefile.am for include/atalk/
atalkincludedir = $(includedir)/atalk
+BUILT_SOURCES =
+CLEANFILES =
atalkinclude_HEADERS = \
adouble.h \
@@ -40,4 +42,13 @@ noinst_HEADERS = \
ftw.h \
dsi.h \
ldapconfig.h \
- fce_api.h
\ No newline at end of file
+ fce_api.h
+
+EXTRA_DIST = afp_dtrace.d
+
+if WITH_DTRACE
+BUILT_SOURCES += afp_dtrace.h
+CLEANFILES += afp_dtrace.h
+afp_dtrace.h: $(top_srcdir)/include/atalk/afp_dtrace.d
+ $(LIBTOOL) --mode=execute dtrace -o afp_dtrace.h -h -s $(top_srcdir)/include/atalk/afp_dtrace.d
+endif
diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h
index 6e76e51b..de0598b5 100644
--- a/include/atalk/adouble.h
+++ b/include/atalk/adouble.h
@@ -245,6 +245,7 @@ struct adouble {
#define ADFLAGS_TRUNC (1<<12) /* truncate, open called with O_TRUNC */
#define ADVOL_NODEV (1 << 0)
+#define ADVOL_RO (1 << 1)
#define ADVOL_UNIXPRIV (1 << 2) /* adouble unix priv */
#define ADVOL_INVDOTS (1 << 3) /* dot files (.DS_Store) are invisible) */
#define ADVOL_FOLLO_SYML (1 << 4)
@@ -409,6 +410,7 @@ extern int ad_metadata (const char *, int, struct adouble *);
extern int ad_metadataat (int, const char *, int, struct adouble *);
extern mode_t ad_hf_mode(mode_t mode);
extern int ad_valid_header_osx(const char *path);
+extern off_t ad_reso_size(const char *path, int adflags, struct adouble *ad);
/* ad_conv.c */
extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, const char **newpath);
diff --git a/include/atalk/afp_dtrace.d b/include/atalk/afp_dtrace.d
new file mode 100644
index 00000000..e9ee9893
--- /dev/null
+++ b/include/atalk/afp_dtrace.d
@@ -0,0 +1,10 @@
+provider afp {
+ probe afpfunc__start(int func, char *funcname);
+ probe afpfunc__done(int func, char *funcname);
+ probe read__start(long size);
+ probe read__done();
+ probe write__start(long size);
+ probe write__done();
+ probe cnid__start(char *cnidfunc);
+ probe cnid__done();
+};
diff --git a/include/atalk/dsi.h b/include/atalk/dsi.h
index 00c80d42..fc1af468 100644
--- a/include/atalk/dsi.h
+++ b/include/atalk/dsi.h
@@ -138,7 +138,7 @@ typedef struct DSI {
#define DSI_DEFQUANT 2 /* default attention quantum size */
#define DSI_SERVQUANT_MAX 0xffffffff /* server quantum */
#define DSI_SERVQUANT_MIN 32000 /* minimum server quantum */
-#define DSI_SERVQUANT_DEF 0x0004A2E0L /* default server quantum */
+#define DSI_SERVQUANT_DEF 0x100000L /* default server quantum (1 MB) */
/* default port number */
#define DSI_AFPOVERTCP_PORT 548
@@ -154,9 +154,6 @@ typedef struct DSI {
#define DSI_RECONSOCKET (1 << 7) /* we have a new socket from primary reconnect */
#define DSI_RECONINPROG (1 << 8) /* used in the new session in reconnect */
#define DSI_AFP_LOGGED_OUT (1 << 9) /* client called afp_logout, quit on next EOF from socket */
-#if 0
-#define DSI_GOT_ECONNRESET (1 << 10) /* got ECONNRESET from client => exit */
-#endif
/* basic initialization: dsi_init.c */
extern DSI *dsi_init(AFPObj *obj, const char *hostname, const char *address, const char *port);
@@ -165,7 +162,7 @@ extern int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address, con
extern void dsi_free(DSI *dsi);
/* in dsi_getsess.c */
-extern int dsi_getsession (DSI *, server_child *, const int, afp_child_t **);
+extern int dsi_getsession (DSI *, server_child_t *, const int, afp_child_t **);
extern void dsi_kill (int);
diff --git a/include/atalk/globals.h b/include/atalk/globals.h
index 75d4041b..96f062a0 100644
--- a/include/atalk/globals.h
+++ b/include/atalk/globals.h
@@ -19,6 +19,19 @@
#include
#include
#include
+#ifdef WITH_DTRACE
+#include
+#else
+/* List of empty dtrace macros */
+#define AFP_AFPFUNC_START(a,b)
+#define AFP_AFPFUNC_DONE(a, b)
+#define AFP_CNID_START(a)
+#define AFP_CNID_DONE()
+#define AFP_READ_START(a)
+#define AFP_READ_DONE()
+#define AFP_WRITE_START(a)
+#define AFP_WRITE_DONE()
+#endif
/* #define DOSFILELEN 12 */ /* Type1, DOS-compat*/
#define MACFILELEN 31 /* Type2, HFS-compat */
@@ -41,8 +54,8 @@
#define OPTION_UUID (1 << 7)
#define OPTION_ACL2MACCESS (1 << 8)
#define OPTION_NOZEROCONF (1 << 9)
-#define OPTION_KEEPSESSIONS (1 << 10) /* preserve sessions across master afpd restart with SIGQUIT */
#define OPTION_SHARE_RESERV (1 << 11) /* whether to use Solaris fcntl F_SHARE locks */
+#define OPTION_DBUS_AFPSTATS (1 << 12) /* whether to run dbus thread for afpstats */
#define PASSWD_NONE 0
#define PASSWD_SET (1 << 0)
diff --git a/include/atalk/paths.h b/include/atalk/paths.h
index 1aab9690..f5f6486c 100644
--- a/include/atalk/paths.h
+++ b/include/atalk/paths.h
@@ -13,35 +13,5 @@
#define ATALKPATHCAT(a,b) a/**/b
#endif
-
-/* lock file path. this should be re-organized a bit. */
-#if ! defined (_PATH_LOCKDIR)
-# if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__)
-# define _PATH_LOCKDIR "/var/run/"
-# elif defined (BSD4_4)
-# ifdef MACOSX_SERVER
-# define _PATH_LOCKDIR "/var/run/"
-# else
-# define _PATH_LOCKDIR "/var/spool/lock/"
-# endif
-# elif defined (linux)
-# define _PATH_LOCKDIR "/var/lock/"
-# else
-# define _PATH_LOCKDIR "/var/spool/locks/"
-# endif
-#endif
-
-
-/*
- * netatalk paths
- */
-#define _PATH_AFPTKT "/tmp/AFPtktXXXXXX"
-#define _PATH_AFP_IPC ATALKPATHCAT(_PATH_LOCKDIR,"afpd_ipc")
-#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__)
-# define _PATH_NETATALK_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"netatalk.pid")
-#else
-# define _PATH_NETATALK_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"netatalk")
-#endif
-
#endif /* atalk/paths.h */
diff --git a/include/atalk/server_child.h b/include/atalk/server_child.h
index ad41bcec..5e694018 100644
--- a/include/atalk/server_child.h
+++ b/include/atalk/server_child.h
@@ -12,41 +12,45 @@
/* useful stuff for child processes. most of this is hidden in
* server_child.c to ease changes in implementation */
-#define CHILD_NFORKS 2
-#define CHILD_ASPFORK 0
-#define CHILD_PAPFORK 0
-#define CHILD_DSIFORK 1
-
-typedef struct server_child {
- void *fork;
- int count, nsessions, nforks;
-} server_child;
-
-typedef struct server_child_data {
- pid_t pid; /* afpd worker process pid (from the worker afpd process )*/
- uid_t uid; /* user id of connected client (from the worker afpd process) */
- int valid; /* 1 if we have a clientid */
- int killed; /* 1 if we already tried to kill the client */
- int disasociated; /* 1 if this is not a child, but a child from a previous afpd master */
- uint32_t time; /* client boot time (from the mac client) */
- uint32_t idlen; /* clientid len (from the Mac client) */
- char *clientid; /* clientid (from the Mac client) */
- int ipc_fd; /* socket for IPC bw afpd parent and childs */
- struct server_child_data **prevp, *next;
+#define CHILD_HASHSIZE 32
+
+/* One AFP session child process */
+typedef struct afp_child {
+ pid_t afpch_pid; /* afpd worker process pid (from the worker afpd process )*/
+ uid_t afpch_uid; /* user id of connected client (from the worker afpd process) */
+ int afpch_valid; /* 1 if we have a clientid */
+ int afpch_killed; /* 1 if we already tried to kill the client */
+ uint32_t afpch_boottime; /* client boot time (from the mac client) */
+ time_t afpch_logintime; /* time the child was added */
+ uint32_t afpch_idlen; /* clientid len (from the Mac client) */
+ char *afpch_clientid; /* clientid (from the Mac client) */
+ int afpch_ipc_fd; /* socket for IPC bw afpd parent and childs */
+ int16_t afpch_state; /* state of AFP session (eg active, sleeping, disconnected) */
+ char *afpch_volumes; /* mounted volumes */
+ struct afp_child **afpch_prevp;
+ struct afp_child *afpch_next;
} afp_child_t;
+/* Info and table with all AFP session child processes */
+typedef struct {
+ pthread_mutex_t servch_lock; /* Lock */
+ int servch_count; /* Current count of active AFP sessions */
+ int servch_nsessions; /* Number of allowed AFP sessions */
+ afp_child_t *servch_table[CHILD_HASHSIZE]; /* Hashtable with data of AFP sesssions */
+} server_child_t;
+
/* server_child.c */
-extern server_child *server_child_alloc (const int, const int);
-extern afp_child_t *server_child_add (server_child *, int, pid_t, int ipc_fd);
-extern int server_child_remove (server_child *, const int, const pid_t);
-extern void server_child_free (server_child *);
-
-extern void server_child_kill (server_child *, const int, const int);
-extern void server_child_kill_one_by_id (server_child *children, const int forkid, const pid_t pid, const uid_t,
- const uint32_t len, char *id, uint32_t boottime);
-extern int server_child_transfer_session(server_child *children, int forkid, pid_t, uid_t, int, uint16_t);
-extern void server_child_setup (server_child *, const int, void (*)(const pid_t));
-extern void server_child_handler (server_child *);
-extern void server_reset_signal (void);
+extern server_child_t *server_child_alloc(int);
+extern afp_child_t *server_child_add(server_child_t *, pid_t, int ipc_fd);
+extern int server_child_remove(server_child_t *, pid_t);
+extern void server_child_free(server_child_t *);
+extern afp_child_t *server_child_resolve(server_child_t *childs, id_t pid);
+
+extern void server_child_kill(server_child_t *, int);
+extern void server_child_kill_one_by_id(server_child_t *children, pid_t pid, uid_t,
+ uint32_t len, char *id, uint32_t boottime);
+extern int server_child_transfer_session(server_child_t *children, pid_t, uid_t, int, uint16_t);
+extern void server_child_handler(server_child_t *);
+extern void server_reset_signal(void);
#endif
diff --git a/include/atalk/server_ipc.h b/include/atalk/server_ipc.h
index aca04f80..0c38a7b7 100644
--- a/include/atalk/server_ipc.h
+++ b/include/atalk/server_ipc.h
@@ -4,13 +4,14 @@
#include
#include
+/* Remember to add IPC commands to server_ipc.c:ipc_cmd_str[] */
#define IPC_DISCOLDSESSION 0
#define IPC_GETSESSION 1
+#define IPC_STATE 2 /* pass AFP session state */
+#define IPC_VOLUMES 3 /* pass list of open volumes */
-extern int ipc_server_uds(const char *name);
-extern int ipc_client_uds(const char *name);
-extern int reconnect_ipc(AFPObj *);
-extern int ipc_server_read(server_child *children, int fd);
+extern int ipc_server_read(server_child_t *children, int fd);
extern int ipc_child_write(int fd, uint16_t command, int len, void *token);
+extern int ipc_child_state(AFPObj *obj, uint16_t state);
#endif /* IPC_GETSESSION_LOGIN */
diff --git a/include/atalk/unix.h b/include/atalk/unix.h
index d3378ccb..c12bf5bc 100644
--- a/include/atalk/unix.h
+++ b/include/atalk/unix.h
@@ -23,6 +23,8 @@
#include
#include
+#include
+
#define NETATALK_DIOSZ_STACK 65536
#define NETATALK_DIOSZ_HEAP (1024*1024)
@@ -48,5 +50,6 @@ extern int copy_ea(const char *ea, int sfd, const char *src, const char *dst, mo
extern void become_root(void);
extern void unbecome_root(void);
extern int gmem(gid_t gid, int ngroups, gid_t *groups);
-
+extern int set_groups(AFPObj *obj, struct passwd *pwd);
+extern const char *print_groups(int ngroups, gid_t *groups);
#endif /* ATALK_UNIX_H */
diff --git a/include/atalk/util.h b/include/atalk/util.h
index 08c37394..facc7763 100644
--- a/include/atalk/util.h
+++ b/include/atalk/util.h
@@ -149,7 +149,7 @@ extern void apply_ip_mask(struct sockaddr *ai, int maskbits);
extern int compare_ip(const struct sockaddr *sa1, const struct sockaddr *sa2);
/* Structures and functions dealing with dynamic pollfd arrays */
-enum fdtype {IPC_FD, LISTEN_FD, DISASOCIATED_IPC_FD};
+enum fdtype {IPC_FD, LISTEN_FD};
struct polldata {
enum fdtype fdtype; /* IPC fd or listening socket fd */
void *data; /* pointer to AFPconfig for listening socket and *
diff --git a/libatalk/.gitignore b/libatalk/.gitignore
index 33a5b662..e9f48fae 100644
--- a/libatalk/.gitignore
+++ b/libatalk/.gitignore
@@ -6,3 +6,4 @@ Makefile.in
.libs
dummy.o
libatalk.abi.tmp
+*dev.abi
diff --git a/libatalk/Makefile.am b/libatalk/Makefile.am
index 732aeea8..00712dda 100644
--- a/libatalk/Makefile.am
+++ b/libatalk/Makefile.am
@@ -18,7 +18,7 @@
# current+1:0:0
#
-VERSION_INFO = 3:0:0
+VERSION_INFO = 4:0:0
# History: VERSION_INFO
#
@@ -30,6 +30,7 @@ VERSION_INFO = 3:0:0
# 3.0 1:0:0
# 3.0.1 2:0:0
# 3.0.2 3:0:0
+# 3.0.3 4:0:0
SUBDIRS = acl adouble bstring compat cnid dsi iniparser tdb util unicode vfs
@@ -94,4 +95,5 @@ EXTRA_DIST = \
libatalk-3.0beta2.abi \
libatalk-3.0.abi \
libatalk-3.0.1.abi \
- libatalk-3.0.2.abi
+ libatalk-3.0.2.abi \
+ libatalk-3.0.3.abi
diff --git a/libatalk/acl/unix.c b/libatalk/acl/unix.c
index 62849351..cc69d8ad 100644
--- a/libatalk/acl/unix.c
+++ b/libatalk/acl/unix.c
@@ -308,6 +308,14 @@ int posix_chmod(const char *name, mode_t mode) {
/* Call chmod() first because there might be some special bits to be set which
* aren't related to access control.
*/
+#ifdef BSD4_4
+ /*
+ * On FreeBSD chmod_acl() ends up in here too, but on
+ * FreeBSD sine ~9.1 with ZFS doesn't allow setting the g+s bit.
+ * Fixes PR #491.
+ */
+ mode &= 0777;
+#endif
ret = chmod(name, mode);
if (ret)
diff --git a/libatalk/acl/uuid.c b/libatalk/acl/uuid.c
index c1bc065f..ff58c3dd 100644
--- a/libatalk/acl/uuid.c
+++ b/libatalk/acl/uuid.c
@@ -254,6 +254,7 @@ int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) {
uid = ntohl(tmp);
if ((pwd = getpwuid(uid)) == NULL) {
/* not found, add negative entry to cache */
+ *name = NULL;
add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
ret = -1;
} else {
@@ -263,7 +264,7 @@ int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) {
}
LOG(log_debug, logtype_afpd,
"getnamefromuuid{local}: UUID: %s -> name: %s, type:%s",
- uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]);
+ uuid_bin2string(uuidp), *name ? *name : "-", uuidtype[(*type) & UUIDTYPESTR_MASK]);
return ret;
} else if (memcmp(uuidp, local_group_uuid, 12) == 0) {
*type = UUID_GROUP;
diff --git a/libatalk/adouble/ad_conv.c b/libatalk/adouble/ad_conv.c
index a9fae763..b1785c01 100644
--- a/libatalk/adouble/ad_conv.c
+++ b/libatalk/adouble/ad_conv.c
@@ -65,6 +65,7 @@ static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struc
switch (S_IFMT & sp->st_mode) {
case S_IFREG:
+ case S_IFDIR:
break;
default:
return 0;
@@ -156,6 +157,8 @@ static int ad_conv_v22ea_rf(const char *path, const struct stat *sp, const struc
EC_ZERO_LOG( copy_fork(ADEID_RFORK, &adea, &adv2) );
adea.ad_rlen = adv2.ad_rlen;
ad_flush(&adea);
+ fchmod(ad_reso_fileno(&adea), sp->st_mode & 0666);
+ fchown(ad_reso_fileno(&adea), sp->st_uid, sp->st_gid);
}
EC_CLEANUP:
@@ -201,21 +204,31 @@ static int ad_conv_dehex(const char *path, const struct stat *sp, const struct v
{
EC_INIT;
static char buf[MAXPATHLEN];
- const char *p;
int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
bstring newpath = NULL;
+ static bstring str2e = NULL;
+ static bstring str2f = NULL;
+ static bstring strdot = NULL;
+ static bstring strcolon = NULL;
+
+ if (str2e == NULL) {
+ str2e = bfromcstr(":2e");
+ str2f = bfromcstr(":2f");
+ strdot = bfromcstr(".");
+ strcolon = bfromcstr(":");
+ }
LOG(log_debug, logtype_ad,"ad_conv_dehex(\"%s\"): BEGIN", fullpathname(path));
*newpathp = NULL;
- if ((p = strchr(path, ':')) == NULL)
+ if (((strstr(path, ":2e")) == NULL) && ((strstr(path, ":2f")) == NULL) )
goto EC_CLEANUP;
EC_NULL( newpath = bfromcstr(path) );
- EC_ZERO( bfindreplace(newpath, bfromcstr(":2e"), bfromcstr("."), 0) );
- EC_ZERO( bfindreplace(newpath, bfromcstr(":2f"), bfromcstr(":"), 0) );
+ EC_ZERO( bfindreplace(newpath, str2e, strdot, 0) );
+ EC_ZERO( bfindreplace(newpath, str2f, strcolon, 0) );
become_root();
if (adflags != ADFLAGS_DIR)
@@ -253,6 +266,9 @@ int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, c
if (newpath)
*newpath = NULL;
+ if (vol->v_flags & AFPVOL_RO)
+ EC_EXIT_STATUS(0);
+
if ((vol->v_adouble == AD_VERSION_EA) && !(vol->v_flags & AFPVOL_NOV2TOEACONV))
EC_ZERO( ad_conv_v22ea(path, sp, vol) );
diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c
index 5205b9e2..a2f6f00e 100644
--- a/libatalk/adouble/ad_open.c
+++ b/libatalk/adouble/ad_open.c
@@ -113,7 +113,7 @@ static int ad_mkrf_ea(const char *path);
#endif
static int ad_header_read_ea(const char *path, struct adouble *ad, const struct stat *hst);
static int ad_header_upgrade_ea(struct adouble *ad, const char *name);
-static int ad_reso_size(const char *path, int adflags, struct adouble *ad);
+off_t ad_reso_size(const char *path, int adflags, struct adouble *ad);
static int ad_mkrf_osx(const char *path);
@@ -523,7 +523,7 @@ int ad_valid_header_osx(const char *path)
adosx.ad_version = ntohl(adosx.ad_version);
if ((adosx.ad_magic != AD_MAGIC) || (adosx.ad_version != AD_VERSION2)) {
- LOG(log_warning, logtype_ad, "ad_valid_header_osx: not an adouble:osx file");
+ LOG(log_warning, logtype_ad, "ad_valid_header_osx(\"%s\"): not an adouble:osx file", fullpathname(path));
EC_FAIL;
}
@@ -624,14 +624,14 @@ static int ad_header_read_ea(const char *path, struct adouble *ad, const struct
if (ad_meta_fileno(ad) != -1)
header_len = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_META, ad->ad_data, AD_DATASZ_EA);
else
- header_len = sys_lgetxattr(path, AD_EA_META, ad->ad_data, AD_DATASZ_EA);
+ header_len = sys_getxattr(path, AD_EA_META, ad->ad_data, AD_DATASZ_EA);
if (header_len < 1) {
LOG(log_debug, logtype_ad, "ad_header_read_ea: %s", strerror(errno));
return -1;
}
if (header_len < AD_HEADER_LEN) {
- LOG(log_error, logtype_ad, "ad_header_read_ea: bogus AppleDouble header.");
+ LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): bogus AppleDouble header.", fullpathname(path));
errno = EIO;
return -1;
}
@@ -643,7 +643,7 @@ static int ad_header_read_ea(const char *path, struct adouble *ad, const struct
ad->ad_version = ntohl( ad->ad_version );
if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION2)) {
- LOG(log_error, logtype_ad, "ad_header_read_ea: wrong magic or version");
+ LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): wrong magic or version", fullpathname(path));
errno = EIO;
return -1;
}
@@ -656,7 +656,7 @@ static int ad_header_read_ea(const char *path, struct adouble *ad, const struct
if (len + AD_HEADER_LEN > sizeof(ad->ad_data))
len = sizeof(ad->ad_data) - AD_HEADER_LEN;
if (len > header_len - AD_HEADER_LEN) {
- LOG(log_error, logtype_ad, "ad_header_read_ea: can't read entry info.");
+ LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): can't read entry info.", fullpathname(path));
errno = EIO;
return -1;
}
@@ -766,7 +766,8 @@ static int ad_header_upgrade_ea(struct adouble *ad _U_, const char *name _U_)
*
* We're called because opening ADFLAGS_HF caused an error.
* 1. In case ad_open is called with ADFLAGS_NOHF the error is suppressed.
- * 2. If ad_open was called with ADFLAGS_DF we may have opened the datafork and thus
+ * 2. Open non-existent ressource fork, this will just result in first read return EOF
+ * 3. If ad_open was called with ADFLAGS_DF we may have opened the datafork and thus
* ought to close it before returning with an error condition.
*/
static int ad_error(struct adouble *ad, int adflags)
@@ -775,7 +776,9 @@ static int ad_error(struct adouble *ad, int adflags)
if (adflags & ADFLAGS_NOHF) { /* 1 */
return 0;
}
- if (adflags & (ADFLAGS_DF | ADFLAGS_SETSHRMD | ADFLAGS_CHECK_OF)) { /* 2 */
+ if ((adflags & ADFLAGS_RDONLY) && (adflags & ADFLAGS_RF) && (errno == ENOENT)) /* 2 */
+ return 0;
+ if (adflags & (ADFLAGS_DF | ADFLAGS_SETSHRMD | ADFLAGS_CHECK_OF)) { /* 3 */
ad_close( ad, ADFLAGS_DF );
err = errno;
}
@@ -1084,6 +1087,10 @@ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble
errno = ENOENT;
EC_FAIL;
}
+ if ((adflags & ADFLAGS_CREATE) && (ad->ad_options & ADVOL_RO)) {
+ errno = EROFS;
+ EC_FAIL;
+ }
LOG(log_debug, logtype_ad, "ad_open_hf_ea(\"%s\"): creating metadata EA", path);
@@ -1102,7 +1109,7 @@ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble
if (ad_meta_fileno(ad) != -1)
ad->ad_mdp->adf_refcount++;
- (void)ad_reso_size(path, adflags, ad);
+ ad->ad_rlen = ad_reso_size(path, adflags, ad);
EC_CLEANUP:
if (ret != 0 && opened && ad_meta_fileno(ad) != -1) {
@@ -1125,7 +1132,6 @@ static int ad_open_hf(const char *path, int adflags, int mode, struct adouble *a
int ret = 0;
memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
- ad->ad_rlen = 0;
switch (ad->ad_vers) {
case AD_VERSION2:
@@ -1148,48 +1154,47 @@ static int ad_open_hf(const char *path, int adflags, int mode, struct adouble *a
}
/*!
- * Get resofork length for adouble:ea
+ * Get resofork length for adouble:ea, parameter 'ad' may be NULL
*/
-static int ad_reso_size(const char *path, int adflags, struct adouble *ad)
+off_t ad_reso_size(const char *path, int adflags, struct adouble *ad)
{
EC_INIT;
struct stat st;
+ off_t rlen;
- if (adflags & ADFLAGS_DIR) {
- ad->ad_rlen = 0;
- goto EC_CLEANUP;
- }
+ if (adflags & ADFLAGS_DIR)
+ EC_FAIL;
LOG(log_debug, logtype_ad, "ad_reso_size(\"%s\"): BEGIN", path);
#ifdef HAVE_EAFD
ssize_t easz;
- if (ad_reso_fileno(ad) != -1) {
+ if (ad && ad_reso_fileno(ad) != -1) {
EC_NEG1( fstat(ad_reso_fileno(ad), &st) );
- ad->ad_rlen = st.st_size;
- } else if (ad_meta_fileno(ad) != -1) {
- EC_NEG1( (ad->ad_rlen = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_RESO, NULL, 0)) );
+ rlen = st.st_size;
+ } else if (ad && ad_meta_fileno(ad) != -1) {
+ EC_NEG1( (rlen = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_RESO, NULL, 0)) );
} else {
- EC_NEG1( (ad->ad_rlen = sys_lgetxattr(path, AD_EA_RESO, NULL, 0)) );
+ EC_NEG1( (rlen = sys_lgetxattr(path, AD_EA_RESO, NULL, 0)) );
}
#else
const char *rfpath;
- EC_NULL_LOG( rfpath = ad->ad_ops->ad_path(path, adflags));
+ EC_NULL_LOG( rfpath = ad_path_osx(path, adflags));
EC_ZERO( lstat(rfpath, &st));
if (st.st_size > ADEDOFF_RFORK_OSX)
- ad->ad_rlen = st.st_size - ADEDOFF_RFORK_OSX;
+ rlen = st.st_size - ADEDOFF_RFORK_OSX;
else
- ad->ad_rlen = 0;
+ rlen = 0;
#endif
- LOG(log_debug, logtype_ad, "ad_reso_size(\"%s\"): size: %zd", path, ad->ad_rlen);
+ LOG(log_debug, logtype_ad, "ad_reso_size(\"%s\"): size: %zd", path, rlen);
EC_CLEANUP:
if (ret != 0)
- ad->ad_rlen = 0;
- EC_EXIT;
+ rlen = 0;
+ return rlen;
}
static int ad_open_rf_v2(const char *path, int adflags, int mode, struct adouble *ad)
@@ -1203,7 +1208,7 @@ static int ad_open_rf_v2(const char *path, int adflags, int mode, struct adouble
LOG(log_debug, logtype_ad, "ad_open_rf_v2(\"%s\"): BEGIN", fullpathname(path));
- if (!AD_META_OPEN(ad) && !(adflags & ADFLAGS_NORF))
+ if (!AD_META_OPEN(ad) && !(adflags & (ADFLAGS_NORF | ADFLAGS_RDONLY)))
EC_FAIL;
if (AD_META_OPEN(ad))
ad->ad_reso_refcount++;
@@ -1237,8 +1242,9 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble
EC_FAIL;
}
ad->ad_rfp->adf_flags &= ~( O_TRUNC | O_CREAT );
+ ad->ad_reso_refcount++;
ad->ad_rfp->adf_refcount++;
- EC_NEG1_LOG( ad_reso_size(path, adflags, ad));
+ EC_NEG1_LOG( ad->ad_rlen = ad_reso_size(path, adflags, ad));
goto EC_CLEANUP;
}
#ifdef HAVE_EAFD
@@ -1246,22 +1252,64 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble
EC_FAIL;
if ((ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad), AD_EA_RESO, oflags)) == -1) {
if (!(adflags & ADFLAGS_CREATE)) {
- errno = ENOENT;
- EC_FAIL;
+ switch (errno) {
+ case EACCES:
+ case EPERM:
+ case EROFS:
+ if (!(adflags & ADFLAGS_RDONLY)) {
+ LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(path), strerror(errno));
+ EC_FAIL;
+ }
+ oflags &= ~O_RDWR;
+ oflags |= O_RDONLY;
+ if ((ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad), AD_EA_RESO, oflags)) == -1) {
+ LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(path), strerror(errno));
+ EC_FAIL;
+ }
+ break;
+ case ENOENT:
+ EC_EXIT_STATUS(0);
+ default:
+ LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(path), strerror(errno));
+ EC_FAIL;
+ }
+ } else {
+ oflags |= O_CREAT;
+ EC_NEG1_LOG( ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad),
+ AD_EA_RESO, oflags, 0666) );
}
- oflags |= O_CREAT;
- EC_NEG1_LOG( ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad),
- AD_EA_RESO, oflags, 0666) );
}
#else
EC_NULL_LOG( rfpath = ad->ad_ops->ad_path(path, adflags) );
if ((ad_reso_fileno(ad) = open(rfpath, oflags)) == -1) {
- if (!(adflags & ADFLAGS_CREATE))
- EC_FAIL;
- oflags |= O_CREAT;
- EC_NEG1_LOG( ad_reso_fileno(ad) = open(rfpath, oflags, mode) );
- LOG(log_debug, logtype_ad, "ad_open_rf(\"%s\"): created adouble rfork: \"%s\"",
- path, rfpath);
+ if (!(adflags & ADFLAGS_CREATE)) {
+ switch (errno) {
+ case EACCES:
+ case EPERM:
+ case EROFS:
+ if (!(adflags & ADFLAGS_RDONLY)) {
+ LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(rfpath), strerror(errno));
+ EC_FAIL;
+ }
+ oflags &= ~O_RDWR;
+ oflags |= O_RDONLY;
+ if ((ad_reso_fileno(ad) = open(rfpath, oflags)) == -1) {
+ LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(rfpath), strerror(errno));
+ EC_FAIL;
+ }
+ break;
+ case ENOENT:
+ EC_EXIT_STATUS(0);
+ default:
+ LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(rfpath), strerror(errno));
+ EC_FAIL;
+ }
+ } else {
+ oflags |= O_CREAT;
+ EC_NEG1_LOG( ad_reso_fileno(ad) = open(rfpath, oflags, mode) );
+ LOG(log_debug, logtype_ad, "ad_open_rf(\"%s\"): created adouble rfork: \"%s\"",
+ path, rfpath);
+ }
}
#endif
opened = 1;
@@ -1287,7 +1335,7 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble
}
#endif
- (void)ad_reso_size(path, adflags, ad);
+ ad->ad_rlen = ad_reso_size(path, adflags, ad);
EC_CLEANUP:
if (ret != 0) {
@@ -1561,6 +1609,7 @@ static void ad_init_func(struct adouble *ad)
ad_reso_fileno(ad) = -1;
ad_meta_fileno(ad) = -1;
ad->ad_refcount = 1;
+ ad->ad_rlen = 0;
return;
}
@@ -1824,7 +1873,7 @@ int ad_openat(struct adouble *ad,
EC_INIT;
int cwdfd = -1;
va_list args;
- mode_t mode;
+ mode_t mode = 0;
if (dirfd != -1) {
if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0))
diff --git a/libatalk/dsi/dsi_getsess.c b/libatalk/dsi/dsi_getsess.c
index cde5def7..38477be9 100644
--- a/libatalk/dsi/dsi_getsess.c
+++ b/libatalk/dsi/dsi_getsess.c
@@ -32,7 +32,7 @@
* @param childp (w) after fork: parent return pointer to child, child returns NULL
* @returns 0 on sucess, any other value denotes failure
*/
-int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_child_t **childp)
+int dsi_getsession(DSI *dsi, server_child_t *serv_children, int tickleval, afp_child_t **childp)
{
pid_t pid;
int ipc_fds[2];
@@ -61,7 +61,7 @@ int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_chi
/* using SIGKILL is hokey, but the child might not have
* re-established its signal handler for SIGTERM yet. */
close(ipc_fds[1]);
- if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds[0])) == NULL) {
+ if ((child = server_child_add(serv_children, pid, ipc_fds[0])) == NULL) {
LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
close(ipc_fds[0]);
dsi->header.dsi_flags = DSIFL_REPLY;
@@ -77,7 +77,7 @@ int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_chi
/* child: check number of open connections. this is one off the
* actual count. */
- if ((serv_children->count >= serv_children->nsessions) &&
+ if ((serv_children->servch_count >= serv_children->servch_nsessions) &&
(dsi->header.dsi_command == DSIFUNC_OPEN)) {
LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
dsi->header.dsi_flags = DSIFL_REPLY;
diff --git a/libatalk/dsi/dsi_stream.c b/libatalk/dsi/dsi_stream.c
index 711a037b..05c36fc8 100644
--- a/libatalk/dsi/dsi_stream.c
+++ b/libatalk/dsi/dsi_stream.c
@@ -115,7 +115,7 @@ static int dsi_peek(DSI *dsi)
if (FD_ISSET(dsi->socket, &readfds)) {
len = dsi->end - dsi->eof; /* it's ensured above that there's space */
- if ((len = read(dsi->socket, dsi->eof, len)) <= 0) {
+ if ((len = recv(dsi->socket, dsi->eof, len, 0)) <= 0) {
if (len == 0) {
LOG(log_error, logtype_dsi, "dsi_peek: EOF");
return -1;
@@ -213,7 +213,7 @@ static size_t dsi_buffered_stream_read(DSI *dsi, uint8_t *data, const size_t len
buflen = MIN(8192, dsi->end - dsi->eof);
if (buflen > 0) {
ssize_t ret;
- ret = read(dsi->socket, dsi->eof, buflen);
+ ret = recv(dsi->socket, dsi->eof, buflen, 0);
if (ret > 0)
dsi->eof += ret;
}
@@ -344,6 +344,16 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz
int sfvcnt;
struct sendfilevec vec[2];
ssize_t nwritten;
+#elif defined(FREEBSD)
+ ssize_t nwritten;
+ void *hdrp;
+ struct sf_hdtr hdr;
+ struct iovec iovec;
+ hdr.headers = &iovec;
+ hdr.hdr_cnt = 1;
+ hdr.trailers = NULL;
+ hdr.trl_cnt = 0;
+ hdrp = &hdr;
#endif
LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(off: %jd, len: %zu)", (intmax_t)offset, length);
@@ -372,6 +382,9 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz
vec[1].sfv_flag = 0;
vec[1].sfv_off = offset;
vec[1].sfv_len = length;
+#elif defined(FREEBSD)
+ iovec.iov_base = block;
+ iovec.iov_len = DSI_BLOCKSIZ;
#else
dsi_stream_write(dsi, block, sizeof(block), DSI_MSG_MORE);
#endif
@@ -380,6 +393,10 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz
#ifdef HAVE_SENDFILEV
nwritten = 0;
len = sendfilev(dsi->socket, vec, sfvcnt, &nwritten);
+#elif defined(FREEBSD)
+ len = sendfile(fromfd, dsi->socket, pos, total - written, hdrp, &nwritten, 0);
+ if (len == 0)
+ len = nwritten;
#else
len = sys_sendfile(dsi->socket, fromfd, &pos, total - written);
#endif
@@ -388,16 +405,14 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz
case EINTR:
case EAGAIN:
len = 0;
-#ifdef HAVE_SENDFILEV
+#if defined(HAVE_SENDFILEV) || defined(FREEBSD)
len = (size_t)nwritten;
-#else
-#if defined(SOLARIS) || defined(FREEBSD)
+#elif defined(SOLARIS)
if (pos > offset) {
/* we actually have sent sth., adjust counters and keep trying */
len = pos - offset;
offset = pos;
}
-#endif /* defined(SOLARIS) || defined(FREEBSD) */
#endif /* HAVE_SENDFILEV */
if (dsi_peek(dsi) != 0) {
@@ -426,6 +441,18 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz
vec[0].sfv_off += len;
vec[0].sfv_len -= len;
}
+#elif defined(FREEBSD)
+ if (hdrp) {
+ if (len >= iovec.iov_len) {
+ hdrp = NULL;
+ len -= iovec.iov_len; /* len now contains how much sendfile() actually sent from the file */
+ } else {
+ iovec.iov_len -= len;
+ iovec.iov_base += len;
+ len = 0;
+ }
+ }
+ pos += len;
#endif /* HAVE_SENDFILEV */
LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: wrote: %zd", len);
written += len;
@@ -471,10 +498,6 @@ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
stored += len;
} else { /* eof or error */
/* don't log EOF error if it's just after connect (OSX 10.3 probe) */
-#if 0
- if (errno == ECONNRESET)
- dsi->flags |= DSI_GOT_ECONNRESET;
-#endif
if (len || stored || dsi->read_count) {
if (! (dsi->flags & DSI_DISCONNECTED)) {
LOG(log_error, logtype_dsi, "dsi_stream_read: len:%d, %s",
@@ -500,6 +523,7 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length)
{
char block[DSI_BLOCKSIZ];
struct iovec iov[2];
+ int iovecs = 2;
size_t towrite;
ssize_t len;
@@ -526,7 +550,7 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length)
towrite = sizeof(block) + length;
dsi->write_count += towrite;
while (towrite > 0) {
- if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || (len == 0))
+ if (((len = writev(dsi->socket, iov, iovecs)) == -1 && errno == EINTR) || (len == 0))
continue;
if ((size_t)len == towrite) /* wrote everything out */
@@ -547,12 +571,13 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length)
iov[0].iov_base = (char *) iov[0].iov_base + len;
iov[0].iov_len -= len;
} else { /* skip to data */
- if (iov[0].iov_len) {
+ if (iovecs == 2) {
+ iovecs = 1;
len -= iov[0].iov_len;
- iov[0].iov_len = 0;
+ iov[0] = iov[1];
}
- iov[1].iov_base = (char *) iov[1].iov_base + len;
- iov[1].iov_len -= len;
+ iov[0].iov_base = (char *) iov[0].iov_base + len;
+ iov[0].iov_len -= len;
}
}
diff --git a/libatalk/libatalk-3.0.3.abi b/libatalk/libatalk-3.0.3.abi
new file mode 100644
index 00000000..17e9539a
--- /dev/null
+++ b/libatalk/libatalk-3.0.3.abi
@@ -0,0 +1,566 @@
+acl_ldap_freeconfig: void (void)
+acl_ldap_readconfig: int (dictionary *)
+ad_close: int (struct adouble *, int)
+ad_convert: int (const char *, const struct stat *, const struct vol *, const char **)
+ad_copy_header: int (struct adouble *, struct adouble *)
+add_cachebyname: int (const char *, const uuidp_t, const uuidtype_t, const long unsigned int)
+add_cachebyuuid: int (uuidp_t, const char *, uuidtype_t, const long unsigned int)
+add_charset: charset_t (const char *)
+ad_dir: char *(const char *)
+ad_dtruncate: int (struct adouble *, const off_t)
+adflags2logstr: const char *(int)
+ad_flush: int (struct adouble *)
+ad_forcegetid: uint32_t (struct adouble *)
+adf_pread: ssize_t (struct ad_fd *, void *, size_t, off_t)
+adf_pwrite: ssize_t (struct ad_fd *, const void *, size_t, off_t)
+ad_getattr: int (const struct adouble *, uint16_t *)
+ad_getdate: int (const struct adouble *, unsigned int, uint32_t *)
+ad_getentryoff: off_t (const struct adouble *, int)
+ad_getfuid: uid_t (void)
+ad_getid: uint32_t (struct adouble *, const dev_t, const ino_t, const cnid_t, const void *)
+ad_hf_mode: mode_t (mode_t)
+ad_init: void (struct adouble *, const struct vol *)
+ad_init_old: void (struct adouble *, int, int)
+ad_lock: int (struct adouble *, uint32_t, int, off_t, off_t, int)
+ad_metadata: int (const char *, int, struct adouble *)
+ad_metadataat: int (int, const char *, int, struct adouble *)
+ad_mkdir: int (const char *, mode_t)
+ad_mode: int (const char *, mode_t)
+ad_open: int (struct adouble *, const char *, int, ...)
+ad_openat: int (struct adouble *, int, const char *, int, ...)
+ad_openforks: uint16_t (struct adouble *, uint16_t)
+ad_path: const char *(const char *, int)
+ad_path_ea: const char *(const char *, int)
+ad_path_osx: const char *(const char *, int)
+ad_read: ssize_t (struct adouble *, const uint32_t, off_t, char *, const size_t)
+ad_readfile_init: int (const struct adouble *, const int, off_t *, const int)
+ad_rebuild_adouble_header_ea: int (struct adouble *)
+ad_rebuild_adouble_header_v2: int (struct adouble *)
+ad_refresh: int (const char *, struct adouble *)
+ad_reso_size: off_t (const char *, int, struct adouble *)
+ad_rtruncate: int (struct adouble *, const off_t)
+ad_setattr: int (const struct adouble *, const uint16_t)
+ad_setdate: int (struct adouble *, unsigned int, uint32_t)
+ad_setfuid: int (const uid_t)
+ad_setid: int (struct adouble *, const dev_t, const ino_t, const uint32_t, const cnid_t, const void *)
+ad_setname: int (struct adouble *, const char *)
+ad_size: off_t (const struct adouble *, const uint32_t)
+ad_stat: int (const char *, struct stat *)
+ad_testlock: int (struct adouble *, int, const off_t)
+ad_tmplock: int (struct adouble *, uint32_t, int, off_t, off_t, int)
+ad_unlock: void (struct adouble *, const int, int)
+ad_valid_header_osx: int (const char *)
+ad_write: ssize_t (struct adouble *, uint32_t, off_t, int, const char *, size_t)
+afp_config_free: void (AFPObj *)
+afp_config_parse: int (AFPObj *, char *)
+allow_severity: 5
+apply_ip_mask: void (struct sockaddr *, int)
+atalk_iconv: size_t (atalk_iconv_t, const char **, size_t *, char **, size_t *)
+atalk_iconv_close: int (atalk_iconv_t)
+atalk_iconv_open: atalk_iconv_t (const char *, const char *)
+atalk_register_charset: int (struct charset_functions *)
+balloc: int (bstring, int)
+ballocmin: int (bstring, int)
+basename_safe: const char *(const char *)
+bassign: int (bstring, const_bstring)
+bassignblk: int (bstring, const void *, int)
+bassigncstr: int (bstring, const char *)
+bassignformat: int (bstring, const char *, ...)
+bassigngets: int (bstring, bNgetc, void *, char)
+bassignmidstr: int (bstring, const_bstring, int, int)
+bcatblk: int (bstring, const void *, int)
+bcatcstr: int (bstring, const char *)
+bconcat: int (bstring, const_bstring)
+bconchar: int (bstring, char)
+bcstrfree: int (char *)
+bdelete: int (bstring, int, int)
+bdestroy: int (bstring)
+become_root: void (void)
+bfindreplace: int (bstring, const_bstring, const_bstring, int)
+bfindreplacecaseless: int (bstring, const_bstring, const_bstring, int)
+bformat: bstring (const char *, ...)
+bformata: int (bstring, const char *, ...)
+bfromcstr: bstring (const char *)
+bfromcstralloc: bstring (int, const char *)
+bgetsa: int (bstring, bNgetc, void *, char)
+bgetstream: bstring (bNgetc, void *, char)
+binchr: int (const_bstring, int, const_bstring)
+binchrr: int (const_bstring, int, const_bstring)
+binsert: int (bstring, int, const_bstring, unsigned char)
+binsertch: int (bstring, int, int, unsigned char)
+binstr: int (const_bstring, int, const_bstring)
+binstrcaseless: int (const_bstring, int, const_bstring)
+binstrr: int (const_bstring, int, const_bstring)
+binstrrcaseless: int (const_bstring, int, const_bstring)
+biseq: int (const_bstring, const_bstring)
+biseqcaseless: int (const_bstring, const_bstring)
+biseqcstr: int (const_bstring, const char *)
+biseqcstrcaseless: int (const_bstring, const char *)
+bisstemeqblk: int (const_bstring, const void *, int)
+bisstemeqcaselessblk: int (const_bstring, const void *, int)
+bjoin: bstring (const struct bstrList *, const_bstring)
+bjoinInv: bstring (const struct bstrList *, const_bstring)
+blk2bstr: bstring (const void *, int)
+bltrimws: int (bstring)
+bmidstr: bstring (const_bstring, int, int)
+bninchr: int (const_bstring, int, const_bstring)
+bninchrr: int (const_bstring, int, const_bstring)
+bpattern: int (bstring, int)
+bread: bstring (bNread, void *)
+breada: int (bstring, bNread, void *)
+brefcstr: bstring (char *)
+breplace: int (bstring, int, int, const_bstring, unsigned char)
+brtrimws: int (bstring)
+bsbufflength: int (struct bStream *, int)
+bsclose: void *(struct bStream *)
+bseof: int (const struct bStream *)
+bsetstr: int (bstring, int, const_bstring, unsigned char)
+bsopen: struct bStream *(bNread, void *)
+bspeek: int (bstring, const struct bStream *)
+bsplit: struct bstrList *(const_bstring, unsigned char)
+bsplitcb: int (const_bstring, unsigned char, int, int (*)(void *, int, int), void *)
+bsplits: struct bstrList *(const_bstring, const_bstring)
+bsplitscb: int (const_bstring, const_bstring, int, int (*)(void *, int, int), void *)
+bsplitstr: struct bstrList *(const_bstring, const_bstring)
+bsplitstrcb: int (const_bstring, const_bstring, int, int (*)(void *, int, int), void *)
+bsread: int (bstring, struct bStream *, int)
+bsreada: int (bstring, struct bStream *, int)
+bsreadln: int (bstring, struct bStream *, char)
+bsreadlna: int (bstring, struct bStream *, char)
+bsreadlns: int (bstring, struct bStream *, const_bstring)
+bsreadlnsa: int (bstring, struct bStream *, const_bstring)
+bssplitscb: int (struct bStream *, const_bstring, int (*)(void *, int, const_bstring), void *)
+bssplitstrcb: int (struct bStream *, const_bstring, int (*)(void *, int, const_bstring), void *)
+bstr2cstr: char *(const_bstring, char)
+bstrchrp: int (const_bstring, int, int)
+bstrcmp: int (const_bstring, const_bstring)
+bstrcpy: bstring (const_bstring)
+bstricmp: int (const_bstring, const_bstring)
+bstrListAlloc: int (struct bstrList *, int)
+bstrListAllocMin: int (struct bstrList *, int)
+bstrListCreate: struct bstrList *(void)
+bstrListCreateMin: struct bstrList *(int)
+bstrListDestroy: int (struct bstrList *)
+bstrListPop: bstring (struct bstrList *)
+bstrListPush: int (struct bstrList *, bstring)
+bstrncmp: int (const_bstring, const_bstring, int)
+bstrnicmp: int (const_bstring, const_bstring, int)
+bstrrchrp: int (const_bstring, int, int)
+bsunread: int (struct bStream *, const_bstring)
+btolower: int (bstring)
+btoupper: int (bstring)
+btrimws: int (bstring)
+btrunc: int (bstring, int)
+bunrefcstr: int (bstring)
+bvcformata: int (bstring, int, const char *, struct __va_list_tag *)
+charset_decompose: size_t (charset_t, char *, size_t, char *, size_t)
+charset_mac_centraleurope: {name = "MAC_CENTRALEUROPE", kTextEncoding = 29, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0}
+charset_mac_chinese_simp: {name = "MAC_CHINESE_SIMP", kTextEncoding = 25, pull = , push = , flags = 85, iname = "EUC-CN", prev = 0x0, next = 0x0}
+charset_mac_chinese_trad: {name = "MAC_CHINESE_TRAD", kTextEncoding = 2, pull = , push = , flags = 85, iname = "BIG-5", prev = 0x0, next = 0x0}
+charset_mac_cyrillic: {name = "MAC_CYRILLIC", kTextEncoding = 7, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0}
+charset_mac_greek: {name = "MAC_GREEK", kTextEncoding = 6, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0}
+charset_mac_hebrew: {name = "MAC_HEBREW", kTextEncoding = 5, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0}
+charset_mac_japanese: {name = "MAC_JAPANESE", kTextEncoding = 1, pull = , push = , flags = 85, iname = "SHIFT_JIS", prev = 0x0, next = 0x0}
+charset_mac_korean: {name = "MAC_KOREAN", kTextEncoding = 3, pull = , push = , flags = 85, iname = "EUC-KR", prev = 0x0, next = 0x0}
+charset_mac_roman: {name = "MAC_ROMAN", kTextEncoding = 0, pull = , push = , flags = 21, iname = 0x0, prev = 0x0, next = 0x0}
+charset_mac_turkish: {name = "MAC_TURKISH", kTextEncoding = 35, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0}
+charset_precompose: size_t (charset_t, char *, size_t, char *, size_t)
+charset_strlower: size_t (charset_t, const char *, size_t, char *, size_t)
+charset_strupper: size_t (charset_t, const char *, size_t, char *, size_t)
+charset_to_ucs2_allocate: size_t (charset_t, uint16_t **, const char *)
+charset_to_utf8_allocate: size_t (charset_t, char **, const char *)
+charset_utf8: {name = "UTF8", kTextEncoding = 134217987, pull = , push = , flags = 22, iname = 0x0, prev = 0x0, next = 0x0}
+charset_utf8_mac: {name = "UTF8-MAC", kTextEncoding = 134217987, pull = , push = , flags = 27, iname = 0x0, prev = 0x0, next = 0x0}
+check_lockfile: int (const char *, const char *)
+cjk_char_pull: size_t (uint16_t, uint16_t *, const uint32_t *)
+cjk_char_push: size_t (uint16_t, uint8_t *)
+cjk_compose: uint16_t (uint16_t, uint16_t, const uint32_t *, size_t)
+cjk_compose_seq: uint16_t (const uint16_t *, size_t *, const uint32_t *, size_t)
+cjk_generic_pull: size_t (size_t (*)(uint16_t *, const uint8_t *, size_t *), void *, char **, size_t *, char **, size_t *)
+cjk_generic_push: size_t (size_t (*)(uint8_t *, const uint16_t *, size_t *), void *, char **, size_t *, char **, size_t *)
+cjk_lookup: uint16_t (uint16_t, const cjk_index_t *, const uint16_t *)
+cnid_add: cnid_t (struct _cnid_db *, const struct stat *, const cnid_t, const char *, const size_t, cnid_t)
+cnid_close: void (struct _cnid_db *)
+cnid_dbd_add: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t, cnid_t)
+cnid_dbd_close: void (struct _cnid_db *)
+cnid_dbd_delete: int (struct _cnid_db *, const cnid_t)
+cnid_dbd_find: int (struct _cnid_db *, const char *, size_t, void *, size_t)
+cnid_dbd_get: cnid_t (struct _cnid_db *, cnid_t, const char *, size_t)
+cnid_dbd_getstamp: int (struct _cnid_db *, void *, const size_t)
+cnid_dbd_lookup: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t)
+cnid_dbd_module: {name = "dbd", db_list = {next = 0x0, prev = 0x0}, cnid_open = 0, flags = 0}
+cnid_dbd_open: struct _cnid_db *(struct cnid_open_args *)
+cnid_dbd_rebuild_add: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t, cnid_t)
+cnid_dbd_resolve: char *(struct _cnid_db *, cnid_t *, void *, size_t)
+cnid_dbd_update: int (struct _cnid_db *, cnid_t, const struct stat *, cnid_t, const char *, size_t)
+cnid_dbd_wipe: int (struct _cnid_db *)
+cnid_delete: int (struct _cnid_db *, cnid_t)
+cnid_find: int (struct _cnid_db *, const char *, size_t, void *, size_t)
+cnid_get: cnid_t (struct _cnid_db *, const cnid_t, char *, const size_t)
+cnid_getstamp: int (struct _cnid_db *, void *, const size_t)
+cnid_init: void (void)
+cnid_last_add: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t, cnid_t)
+cnid_last_close: void (struct _cnid_db *)
+cnid_last_delete: int (struct _cnid_db *, const cnid_t)
+cnid_last_get: cnid_t (struct _cnid_db *, cnid_t, const char *, size_t)
+cnid_last_lookup: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t)
+cnid_last_module: {name = "last", db_list = {next = 0x0, prev = 0x0}, cnid_open = 0, flags = 0}
+cnid_last_open: struct _cnid_db *(struct cnid_open_args *)
+cnid_last_resolve: char *(struct _cnid_db *, cnid_t *, void *, size_t)
+cnid_last_update: int (struct _cnid_db *, cnid_t, const struct stat *, cnid_t, const char *, size_t)
+cnid_lookup: cnid_t (struct _cnid_db *, const struct stat *, const cnid_t, char *, const size_t)
+cnid_open: struct _cnid_db *(const char *, mode_t, char *, int, const char *, const char *)
+cnid_rebuild_add: cnid_t (struct _cnid_db *, const struct stat *, const cnid_t, char *, const size_t, cnid_t)
+cnid_register: void (struct _cnid_module *)
+cnid_resolve: char *(struct _cnid_db *, cnid_t *, void *, size_t)
+cnid_tdb_add: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t, cnid_t)
+cnid_tdb_close: void (struct _cnid_db *)
+cnid_tdb_delete: int (struct _cnid_db *, const cnid_t)
+cnid_tdb_get: cnid_t (struct _cnid_db *, cnid_t, const char *, size_t)
+cnid_tdb_lookup: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t)
+cnid_tdb_module: {name = "tdb", db_list = {next = 0x0, prev = 0x0}, cnid_open = 0, flags = 12}
+cnid_tdb_open: struct _cnid_db *(struct cnid_open_args *)
+cnid_tdb_resolve: char *(struct _cnid_db *, cnid_t *, void *, size_t)
+cnid_tdb_update: int (struct _cnid_db *, cnid_t, const struct stat *, cnid_t, const char *, size_t)
+cnid_update: int (struct _cnid_db *, const cnid_t, const struct stat *, const cnid_t, char *, const size_t)
+cnid_wipe: int (struct _cnid_db *)
+compare_ip: int (const struct sockaddr *, const struct sockaddr *)
+convert_charset: size_t (charset_t, charset_t, charset_t, const char *, size_t, char *, size_t, uint16_t *)
+convert_string: size_t (charset_t, charset_t, const void *, size_t, void *, size_t)
+convert_string_allocate: size_t (charset_t, charset_t, const void *, size_t, char **)
+copy_ea: int (const char *, int, const char *, const char *, mode_t)
+copy_file: int (int, const char *, const char *, mode_t)
+copy_file_fd: int (int, int)
+copy_fork: int (int, struct adouble *, struct adouble *)
+create_lockfile: int (const char *, const char *)
+daemonize: int (int, int)
+decompose_w: size_t (uint16_t *, size_t, uint16_t *, size_t *)
+deny_severity: 3
+dequeue: void *(q_t *)
+_diacasemap: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 231, 203, 229, 128, 204, 129, 130, 131, 233, 230, 232, 234, 237, 235, 236, 132, 238, 241, 239, 133, 205, 242, 244, 243, 134, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 198, 183, 184, 184, 186, 187, 188, 189, 174, 175, 192, 193, 194, 195, 196, 197, 198, 199...}
+_dialowermap: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 138, 140, 141, 142, 150, 154, 159, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 132, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 190, 191, 176, 177, 178, 179, 180, 181, 198, 183, 185, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199...}
+dictionary_del: void (dictionary *)
+dictionary_dump: void (dictionary *, FILE *)
+dictionary_get: const char *(const dictionary *, const char *, const char *, const char *)
+dictionary_hash: unsigned int (char *)
+dictionary_new: dictionary *(int)
+dictionary_set: int (dictionary *, char *, char *, char *)
+dictionary_unset: void (dictionary *, char *, char *)
+dir_rx_set: int (mode_t)
+dsi_attention: int (DSI *, AFPUserBytes)
+dsi_close: void (DSI *)
+dsi_cmdreply: int (DSI *, const int)
+dsi_disconnect: int (DSI *)
+dsi_free: void (DSI *)
+dsi_getsession: int (DSI *, server_child_t *, int, afp_child_t **)
+dsi_getstatus: void (DSI *)
+dsi_init: DSI *(AFPObj *, const char *, const char *, const char *)
+dsi_opensession: void (DSI *)
+dsi_read: ssize_t (DSI *, void *, const size_t)
+dsi_readdone: void (DSI *)
+dsi_readinit: ssize_t (DSI *, void *, const size_t, const size_t, const int)
+dsi_stream_read: size_t (DSI *, void *, const size_t)
+dsi_stream_read_file: ssize_t (DSI *, const int, off_t, const size_t, const int)
+dsi_stream_receive: int (DSI *)
+dsi_stream_send: int (DSI *, void *, size_t)
+dsi_stream_write: ssize_t (DSI *, void *, const size_t, int)
+dsi_tcp_init: int (DSI *, const char *, const char *, const char *)
+dsi_tickle: int (DSI *)
+dsi_write: size_t (DSI *, void *, const size_t)
+dsi_writeflush: void (DSI *)
+dsi_writeinit: size_t (DSI *, void *, const size_t)
+ea_chmod_dir: int (const struct vol *, const char *, mode_t, struct stat *)
+ea_chmod_file: int (const struct vol *, const char *, mode_t, struct stat *)
+ea_chown: int (const struct vol *, const char *, uid_t, gid_t)
+ea_close: int (struct ea *)
+ea_copyfile: int (const struct vol *, int, const char *, const char *)
+ea_deletefile: int (const struct vol *, int, const char *)
+ea_open: int (const struct vol *, const char *, eaflags_t, struct ea *)
+ea_openat: int (const struct vol *, int, const char *, eaflags_t, struct ea *)
+ea_path: char *(const struct ea *, const char *, int)
+ea_renamefile: int (const struct vol *, int, const char *, const char *)
+enqueue: qnode_t *(q_t *, void *)
+fault_setup: void (void (*)(void *))
+fdset_add_fd: void (int, struct pollfd **, struct polldata **, int *, int *, int, enum fdtype, void *)
+fdset_del_fd: void (struct pollfd **, struct polldata **, int *, int *, int)
+find_charset_functions: struct charset_functions *(const char *)
+_fini:
+free_charset_names: void (void)
+freeifacelist: void (char **)
+fullpathname: const char *(const char *)
+getcwdpath: const char *(void)
+getdefextmap: struct extmap *(void)
+get_eacontent: int (const struct vol *, char *, size_t *, const char *, int, const char *, int)
+get_easize: int (const struct vol *, char *, size_t *, const char *, int, const char *)
+getextmap: struct extmap *(const char *)
+getifacelist: char **(void)
+getip_port: unsigned int (const struct sockaddr *)
+getip_string: const char *(const struct sockaddr *)
+getnamefromuuid: int (const uuidp_t, char **, uuidtype_t *)
+getuuidfromname: int (const char *, uuidtype_t, unsigned char *)
+getvolbyname: struct vol *(const char *)
+getvolbypath: struct vol *(AFPObj *, const char *)
+getvolbyvid: struct vol *(const uint16_t)
+getvolumes: struct vol *(void)
+gmem: int (gid_t, int, gid_t *)
+iniparser_dump: void (const dictionary *, FILE *)
+iniparser_dump_ini: void (const dictionary *, FILE *)
+iniparser_find_entry: int (const dictionary *, const char *)
+iniparser_freedict: void (dictionary *)
+iniparser_getboolean: int (const dictionary *, const char *, const char *, int)
+iniparser_getdouble: double (const dictionary *, const char *, const char *, double)
+iniparser_getint: int (const dictionary *, const char *, const char *, int)
+iniparser_getnsec: int (const dictionary *)
+iniparser_getsecname: const char *(const dictionary *, int)
+iniparser_getstrdup: char *(const dictionary *, const char *, const char *, const char *)
+iniparser_getstring: const char *(const dictionary *, const char *, const char *, const char *)
+iniparser_load: dictionary *(const char *)
+iniparser_set: int (dictionary *, char *, char *, char *)
+iniparser_unset: void (dictionary *, char *, char *)
+_init:
+init_iconv: void (void)
+initline: void (int, char *)
+initvol_vfs: void (struct vol *)
+ipc_child_state: int (AFPObj *, uint16_t)
+ipc_child_write: int (int, uint16_t, int, void *)
+ipc_server_read: int (server_child_t *, int)
+islower_sp: int (uint32_t)
+islower_w: int (uint16_t)
+isupper_sp: int (uint32_t)
+isupper_w: int (uint16_t)
+ldap_auth_dn: 0x0
+ldap_auth_method: 0
+ldap_auth_pw: 0x0
+ldap_config_valid: 0
+ldap_getnamefromuuid: int (const char *, char **, uuidtype_t *)
+ldap_getuuidfromname: int (const char *, uuidtype_t, char **)
+ldap_group_attr: 0x0
+ldap_groupbase: 0x0
+ldap_groupscope: 0
+ldap_name_attr: 0x0
+ldap_prefs: {{pref = 0x0, name = "ldap server", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap auth method", strorint = 1, intfromarray = 1, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap auth dn", strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}, {pref = 0x0, name = "ldap auth pw", strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}, {pref = 0x0, name = "ldap userbase", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap userscope", strorint = 1, intfromarray = 1, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap groupbase", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap groupscope", strorint = 1, intfromarray = 1, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap uuid attr", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap uuid string", strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}, {pref = 0x0, name = "ldap name attr", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap group attr", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap uid attr", strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}, {pref = 0x0, name = "ldap uuid encoding", strorint = 1, intfromarray = 1, valid = 0, valid_save = 0}, {pref = 0x0, name = 0x0, strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}}
+ldap_server: 0x0
+ldap_uid_attr: 0x0
+ldap_userbase: 0x0
+ldap_userscope: 0
+ldap_uuid_attr: 0x0
+ldap_uuid_encoding: 0
+ldap_uuid_string: 0x0
+list_eas: int (const struct vol *, char *, size_t *, const char *, int)
+load_charset: int (struct vol *)
+load_volumes: int (AFPObj *)
+localuuid_from_id: void (unsigned char *, uuidtype_t, unsigned int)
+lock_reg: int (int, int, int, off_t, int, off_t)
+log_config: {inited = false, syslog_opened = false, console = false, processname = '\0' , syslog_facility = 0, syslog_display_options = 0}
+make_log_entry: void (enum loglevels, enum logtypes, const char *, int, char *, ...)
+make_tdb_data: unsigned char *(uint32_t, const struct stat *, const cnid_t, const char *, const size_t)
+mb_generic_pull: size_t (int (*)(uint16_t *, const unsigned char *), void *, char **, size_t *, char **, size_t *)
+mb_generic_push: size_t (int (*)(unsigned char *, uint16_t), void *, char **, size_t *, char **, size_t *)
+netatalk_panic: void (const char *)
+netatalk_rmdir: int (int, const char *)
+netatalk_rmdir_all_errors: int (int, const char *)
+netatalk_unlink: int (const char *)
+netatalk_unlinkat: int (int, const char *)
+nftw: int (const char *, nftw_func_t, dir_notification_func_t, int, int)
+ochdir: int (const char *, int)
+ochmod: int (char *, mode_t, const struct stat *, int)
+ochown: int (const char *, uid_t, gid_t, int)
+opendirat: DIR *(int, const char *)
+openflags2logstr: const char *(int)
+ostat: int (const char *, struct stat *, int)
+ostatat: int (int, const char *, struct stat *, int)
+parseline: int (int, char *)
+posix_chmod: int (const char *, mode_t)
+posix_fchmod: int (int, mode_t)
+precompose_w: size_t (uint16_t *, size_t, uint16_t *, size_t *)
+prefs_array: {{pref = "ldap auth method", valuestring = "none", value = 0}, {pref = "ldap auth method", valuestring = "simple", value = 128}, {pref = "ldap auth method", valuestring = "sasl", value = 163}, {pref = "ldap userscope", valuestring = "base", value = 0}, {pref = "ldap userscope", valuestring = "one", value = 1}, {pref = "ldap userscope", valuestring = "sub", value = 2}, {pref = "ldap groupscope", valuestring = "base", value = 0}, {pref = "ldap groupscope", valuestring = "one", value = 1}, {pref = "ldap groupscope", valuestring = "sub", value = 2}, {pref = "ldap uuid encoding", valuestring = "ms-guid", value = 1}, {pref = "ldap uuid encoding", valuestring = "string", value = 0}, {pref = 0x0, valuestring = 0x0, value = 0}}
+prequeue: qnode_t *(q_t *, void *)
+print_groups: const char *(int, gid_t *)
+queue_destroy: void (q_t *, void (*)(void *))
+queue_init: q_t *(void)
+randombytes: void (void *, int)
+readt: ssize_t (int, void *, const size_t, int, int)
+realpath_safe: char *(const char *)
+recv_fd: int (int, int)
+rel_path_in_vol: bstring (const char *, const char *)
+remove_acl_vfs: int (const char *)
+remove_ea: int (const struct vol *, const char *, const char *, int)
+run_cmd: int (const char *, char **)
+search_cachebyname: int (const char *, uuidtype_t *, unsigned char *)
+search_cachebyuuid: int (uuidp_t, char **, uuidtype_t *)
+send_fd: int (int, int)
+server_child_add: afp_child_t *(server_child_t *, pid_t, int)
+server_child_alloc: server_child_t *(int)
+server_child_free: void (server_child_t *)
+server_child_kill: void (server_child_t *, int)
+server_child_kill_one_by_id: void (server_child_t *, pid_t, uid_t, uint32_t, char *, uint32_t)
+server_child_remove: int (server_child_t *, pid_t)
+server_child_resolve: afp_child_t *(server_child_t *, id_t)
+server_child_transfer_session: int (server_child_t *, pid_t, uid_t, int, uint16_t)
+server_lock: pid_t (char *, char *, int)
+server_reset_signal: void (void)
+set_charset_name: int (charset_t, const char *)
+set_ea: int (const struct vol *, const char *, const char *, const char *, size_t, int)
+setfilmode: int (const struct vol *, const char *, mode_t, struct stat *)
+set_groups: int (AFPObj *, struct passwd *)
+setnonblock: int (int, int)
+set_processname: void (const char *)
+setuplog: void (const char *, const char *)
+statat: int (int, const char *, struct stat *)
+strcasechr_sp: uint16_t *(const uint16_t *, uint32_t)
+strcasechr_w: uint16_t *(const uint16_t *, uint16_t)
+strcasecmp_w: int (const uint16_t *, const uint16_t *)
+strcasestr_w: uint16_t *(const uint16_t *, const uint16_t *)
+strcat_w: uint16_t *(uint16_t *, const uint16_t *)
+strchr_w: uint16_t *(const uint16_t *, uint16_t)
+strcmp_w: int (const uint16_t *, const uint16_t *)
+strdiacasecmp: int (const char *, const char *)
+strdup_w: uint16_t *(const uint16_t *)
+stripped_slashes_basename: char *(char *)
+strlcat: size_t (char *, const char *, size_t)
+strlcpy: size_t (char *, const char *, size_t)
+strlen_w: size_t (const uint16_t *)
+strlower_w: int (uint16_t *)
+strncasecmp_w: int (const uint16_t *, const uint16_t *, size_t)
+strncat_w: uint16_t *(uint16_t *, const uint16_t *, const size_t)
+strncmp_w: int (const uint16_t *, const uint16_t *, size_t)
+strncpy_w: uint16_t *(uint16_t *, const uint16_t *, const size_t)
+strndiacasecmp: int (const char *, const char *, size_t)
+strndup_w: uint16_t *(const uint16_t *, size_t)
+strnlen_w: size_t (const uint16_t *, size_t)
+strstr_w: uint16_t *(const uint16_t *, const uint16_t *)
+strtok_quote: char *(char *, const char *)
+strupper_w: int (uint16_t *)
+sys_ea_copyfile: int (const struct vol *, int, const char *, const char *)
+sys_fgetxattr: ssize_t (int, const char *, void *, size_t)
+sys_fsetxattr: int (int, const char *, const void *, size_t, int)
+sys_ftruncate: int (int, off_t)
+sys_get_eacontent: int (const struct vol *, char *, size_t *, const char *, int, const char *, int)
+sys_get_easize: int (const struct vol *, char *, size_t *, const char *, int, const char *)
+sys_getxattr: ssize_t (const char *, const char *, void *, size_t)
+sys_getxattrfd: int (int, const char *, int, ...)
+sys_lgetxattr: ssize_t (const char *, const char *, void *, size_t)
+sys_list_eas: int (const struct vol *, char *, size_t *, const char *, int)
+sys_listxattr: ssize_t (const char *, char *, size_t)
+sys_llistxattr: ssize_t (const char *, char *, size_t)
+sys_lremovexattr: int (const char *, const char *)
+sys_lsetxattr: int (const char *, const char *, const void *, size_t, int)
+sys_remove_ea: int (const struct vol *, const char *, const char *, int)
+sys_removexattr: int (const char *, const char *)
+sys_sendfile: ssize_t (int, int, off_t *, size_t)
+sys_set_ea: int (const struct vol *, const char *, const char *, const char *, size_t, int)
+sys_setxattr: int (const char *, const char *, const void *, size_t, int)
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_allocate: tdb_off_t (struct tdb_context *, tdb_len_t, struct tdb_record *)
+tdb_alloc_read: unsigned char *(struct tdb_context *, tdb_off_t, tdb_len_t)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_brlock: int (struct tdb_context *, tdb_off_t, int, int, int, size_t)
+tdb_brlock_upgrade: int (struct tdb_context *, tdb_off_t, size_t)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_convert: void *(void *, uint32_t)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_do_delete: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_expand: int (struct tdb_context *, tdb_off_t)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_find_lock_hash: tdb_off_t (struct tdb_context *, TDB_DATA, uint32_t, int, struct tdb_record *)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_free: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_io_init: void (struct tdb_context *)
+tdb_lock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lock_record: int (struct tdb_context *, tdb_off_t)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_mmap: void (struct tdb_context *)
+tdb_munmap: int (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: {dptr = 0x0, dsize = 0}
+tdb_ofs_read: int (struct tdb_context *, tdb_off_t, tdb_off_t *)
+tdb_ofs_write: int (struct tdb_context *, tdb_off_t, tdb_off_t *)
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_data: int (struct tdb_context *, TDB_DATA, tdb_off_t, tdb_len_t, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_rec_free_read: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_rec_read: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_rec_write: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+_tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_lock: int (struct tdb_context *, int)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_recover: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_unlock: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_unlock_record: int (struct tdb_context *, tdb_off_t)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
+tdb_write_lock_record: int (struct tdb_context *, tdb_off_t)
+tdb_write_unlock_record: int (struct tdb_context *, tdb_off_t)
+tolower_sp: uint32_t (uint32_t)
+tolower_w: uint16_t (uint16_t)
+toupper_sp: uint32_t (uint32_t)
+toupper_w: uint16_t (uint16_t)
+type_configs: {{set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}}
+ucs2_to_charset: size_t (charset_t, const uint16_t *, char *, size_t)
+ucs2_to_charset_allocate: size_t (charset_t, char **, const uint16_t *)
+unbecome_root: void (void)
+unix_rename: int (int, const char *, int, const char *)
+unix_strlower: size_t (const char *, size_t, char *, size_t)
+unix_strupper: size_t (const char *, size_t, char *, size_t)
+unload_volumes: void (AFPObj *)
+utf8_charlen: size_t (char *)
+utf8_decompose: size_t (char *, size_t, char *, size_t)
+utf8_precompose: size_t (char *, size_t, char *, size_t)
+utf8_strlen_validate: size_t (char *)
+utf8_strlower: size_t (const char *, size_t, char *, size_t)
+utf8_strupper: size_t (const char *, size_t, char *, size_t)
+utf8_to_charset_allocate: size_t (charset_t, char **, const char *)
+uuid_bin2string: const char *(const unsigned char *)
+uuidcache_dump: void (void)
+uuid_string2bin: void (const char *, unsigned char *)
+uuidtype: {"", "USER", "GROUP", "LOCAL"}
+volume_free: void (struct vol *)
+volume_unlink: void (struct vol *)
+writet: ssize_t (int, void *, const size_t, int, int)
diff --git a/libatalk/util/logger.c b/libatalk/util/logger.c
index 55630d1b..94423426 100644
--- a/libatalk/util/logger.c
+++ b/libatalk/util/logger.c
@@ -594,11 +594,8 @@ void make_log_entry(enum loglevels loglevel, enum logtypes logtype,
loglevel, logtype);
/* If default wasnt setup its fd is -1 */
- iov[0].iov_base = log_details_buffer;
- iov[0].iov_len = strlen(log_details_buffer);
- iov[1].iov_base = temp_buffer;
- iov[1].iov_len = strlen(temp_buffer);
- writev( fd, iov, 2);
+ write(fd, log_details_buffer, strlen(log_details_buffer));
+ write(fd, temp_buffer, strlen(temp_buffer));
} else {
write(fd, temp_buffer, strlen(temp_buffer));
}
diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c
index b1ca02d1..6445d3fe 100644
--- a/libatalk/util/netatalk_conf.c
+++ b/libatalk/util/netatalk_conf.c
@@ -801,6 +801,8 @@ static struct vol *creatvol(AFPObj *obj,
volume->v_ad_options |= ADVOL_INVDOTS;
if ((volume->v_flags & AFPVOL_FOLLOWSYM))
volume->v_ad_options |= ADVOL_FOLLO_SYML;
+ if ((volume->v_flags & AFPVOL_RO))
+ volume->v_ad_options |= ADVOL_RO;
/* Mac to Unix conversion flags*/
if ((volume->v_flags & AFPVOL_EILSEQ))
@@ -1323,6 +1325,9 @@ int load_volumes(AFPObj *obj)
LOG(log_debug, logtype_afpd, "load_volumes: BEGIN");
+ if (obj->uid)
+ pwent = getpwuid(obj->uid);
+
if (Volumes) {
if (!volfile_changed(&obj->options))
goto EC_CLEANUP;
@@ -1330,6 +1335,15 @@ int load_volumes(AFPObj *obj)
for (vol = Volumes; vol; vol = vol->v_next) {
vol->v_deleted = 1;
}
+ if (obj->uid) {
+ become_root();
+ ret = set_groups(obj, pwent);
+ unbecome_root();
+ if (ret != 0) {
+ LOG(log_error, logtype_afpd, "load_volumes: set_groups: %s", strerror(errno));
+ EC_FAIL;
+ }
+ }
} else {
LOG(log_debug, logtype_afpd, "load_volumes: no volumes yet");
EC_ZERO_LOG( lstat(obj->options.configfile, &st) );
@@ -1354,9 +1368,6 @@ int load_volumes(AFPObj *obj)
break;
}
- if (obj->uid)
- pwent = getpwuid(obj->uid);
-
if (obj->iniconfig)
iniparser_freedict(obj->iniconfig);
LOG(log_debug, logtype_afpd, "load_volumes: loading: %s", obj->options.configfile);
@@ -1432,6 +1443,56 @@ struct vol *getvolbyvid(const uint16_t vid )
return( vol );
}
+/*
+ * get username by path
+ *
+ * getvolbypath() assumes that the user home directory has the same name as the username.
+ * If that is not true, getuserbypath() is called and tries to retrieve the username
+ * from the directory owner, checking its validity.
+ *
+ * @param path (r) absolute volume path
+ * @returns NULL if no match is found, pointer to username if successfull
+ *
+ */
+static char *getuserbypath(const char *path)
+{
+ EC_INIT;
+ struct stat sbuf;
+ struct passwd *pwd;
+ char *hdir = NULL;
+
+ LOG(log_debug, logtype_afpd, "getuserbypath(\"%s\")", path);
+
+ /* does folder exists? */
+ if (stat(path, &sbuf) != 0)
+ EC_FAIL;
+
+ /* get uid of dir owner */
+ if ((pwd = getpwuid(sbuf.st_uid)) == NULL)
+ EC_FAIL;
+
+ /* does user home directory exists? */
+ if (stat(pwd->pw_dir, &sbuf) != 0)
+ EC_FAIL;
+
+ /* resolve and remove symlinks */
+ if ((hdir = realpath_safe(pwd->pw_dir)) == NULL)
+ EC_FAIL;
+
+ /* handle subdirectories, path = */
+ if (strncmp(path, hdir, strlen(hdir)) != 0)
+ EC_FAIL;
+
+ LOG(log_debug, logtype_afpd, "getuserbypath: match user: %s, home: %s, realhome: %s",
+ pwd->pw_name, pwd->pw_dir, hdir);
+
+EC_CLEANUP:
+ if (hdir)
+ free(hdir);
+ if (ret != 0)
+ return NULL;
+ return pwd->pw_name;
+}
/*!
* Search volume by path, creating user home vols as necessary
*
@@ -1447,6 +1508,9 @@ struct vol *getvolbyvid(const uint16_t vid )
* (3) If there is, match "path" with "basedir regex" to get the user home parent dir
* (4) Built user home path by appending the basedir matched in (3) and appending the username
* (5) The next path element then is the username
+ * (5b) getvolbypath() assumes that the user home directory has the same name as the username.
+ * If that is not true, getuserbypath() is called and tries to retrieve the username
+ * from the directory owner, checking its validity
* (6) Append [Homes]->path subdirectory if defined
* (7) Create volume
*
@@ -1539,6 +1603,14 @@ struct vol *getvolbypath(AFPObj *obj, const char *path)
subpath = prw;
strlcat(tmpbuf, user, MAXPATHLEN);
+ if (getpwnam(user) == NULL) {
+ /* (5b) */
+ char *tuser;
+ if ((tuser = getuserbypath(tmpbuf)) != NULL) {
+ free(user);
+ user = strdup(tuser);
+ }
+ }
strlcpy(obj->username, user, MAXUSERLEN);
strlcat(tmpbuf, "/", MAXPATHLEN);
@@ -1641,8 +1713,6 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
options->flags |= OPTION_ANNOUNCESSH;
if (iniparser_getboolean(config, INISEC_GLOBAL, "map acls", 1))
options->flags |= OPTION_ACL2MACCESS;
- if (iniparser_getboolean(config, INISEC_GLOBAL, "keep sessions", 0))
- options->flags |= OPTION_KEEPSESSIONS;
if (iniparser_getboolean(config, INISEC_GLOBAL, "close vol", 0))
options->flags |= OPTION_CLOSEVOL;
if (!iniparser_getboolean(config, INISEC_GLOBAL, "client polling", 0))
@@ -1651,6 +1721,8 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
options->flags |= OPTION_NOSENDFILE;
if (iniparser_getboolean(config, INISEC_GLOBAL, "solaris share reservations", 1))
options->flags |= OPTION_SHARE_RESERV;
+ if (iniparser_getboolean(config, INISEC_GLOBAL, "afpstats", 0))
+ options->flags |= OPTION_DBUS_AFPSTATS;
if (iniparser_getboolean(config, INISEC_GLOBAL, "afp read locks", 0))
options->flags |= OPTION_AFP_READ_LOCK;
if (!iniparser_getboolean(config, INISEC_GLOBAL, "save password", 1))
diff --git a/libatalk/util/server_child.c b/libatalk/util/server_child.c
index 547d68d9..da78c6a0 100644
--- a/libatalk/util/server_child.c
+++ b/libatalk/util/server_child.c
@@ -1,8 +1,8 @@
/*
* Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
+ * Copyright (c) 2013 Frank Lahm
#include
#include
+#include
#include
#include
@@ -47,41 +48,34 @@
#endif
/* hash/child functions: hash OR's pid */
-#define CHILD_HASHSIZE 32
#define HASH(i) ((((i) >> 8) ^ (i)) & (CHILD_HASHSIZE - 1))
-typedef struct server_child_fork {
- struct server_child_data *table[CHILD_HASHSIZE];
- void (*cleanup)(const pid_t);
-} server_child_fork;
-
-static inline void hash_child(struct server_child_data **htable,
- struct server_child_data *child)
+static inline void hash_child(afp_child_t **htable, afp_child_t *child)
{
- struct server_child_data **table;
+ afp_child_t **table;
- table = &htable[HASH(child->pid)];
- if ((child->next = *table) != NULL)
- (*table)->prevp = &child->next;
+ table = &htable[HASH(child->afpch_pid)];
+ if ((child->afpch_next = *table) != NULL)
+ (*table)->afpch_prevp = &child->afpch_next;
*table = child;
- child->prevp = table;
+ child->afpch_prevp = table;
}
-static inline void unhash_child(struct server_child_data *child)
+static inline void unhash_child(afp_child_t *child)
{
- if (child->prevp) {
- if (child->next)
- child->next->prevp = child->prevp;
- *(child->prevp) = child->next;
+ if (child->afpch_prevp) {
+ if (child->afpch_next)
+ child->afpch_next->afpch_prevp = child->afpch_prevp;
+ *(child->afpch_prevp) = child->afpch_next;
}
}
-static struct server_child_data *resolve_child(struct server_child_data **table, pid_t pid)
+afp_child_t *server_child_resolve(server_child_t *childs, id_t pid)
{
- struct server_child_data *child;
+ afp_child_t *child;
- for (child = table[HASH(pid)]; child; child = child->next) {
- if (child->pid == pid)
+ for (child = childs->servch_table[HASH(pid)]; child; child = child->afpch_next) {
+ if (child->afpch_pid == pid)
break;
}
@@ -89,23 +83,15 @@ static struct server_child_data *resolve_child(struct server_child_data **table,
}
/* initialize server_child structure */
-server_child *server_child_alloc(const int connections, const int nforks)
+server_child_t *server_child_alloc(int connections)
{
- server_child *children;
-
- children = (server_child *) calloc(1, sizeof(server_child));
- if (!children)
- return NULL;
-
- children->nsessions = connections;
- children->nforks = nforks;
- children->fork = (void *) calloc(nforks, sizeof(server_child_fork));
+ server_child_t *children;
- if (!children->fork) {
- free(children);
+ if (!(children = (server_child_t *)calloc(1, sizeof(server_child_t))))
return NULL;
- }
+ children->servch_nsessions = connections;
+ pthread_mutex_init(&children->servch_lock, NULL);
return children;
}
@@ -113,17 +99,11 @@ server_child *server_child_alloc(const int connections, const int nforks)
* add a child
* @return pointer to struct server_child_data on success, NULL on error
*/
-afp_child_t *server_child_add(server_child *children, int forkid, pid_t pid, int ipc_fd)
+afp_child_t *server_child_add(server_child_t *children, pid_t pid, int ipc_fd)
{
- server_child_fork *fork;
afp_child_t *child = NULL;
- sigset_t sig, oldsig;
- /* we need to prevent deletions from occuring before we get a
- * chance to add the child in. */
- sigemptyset(&sig);
- sigaddset(&sig, SIGCHLD);
- pthread_sigmask(SIG_BLOCK, &sig, &oldsig);
+ pthread_mutex_lock(&children->servch_lock);
/* it's possible that the child could have already died before the
* pthread_sigmask. we need to check for this. */
@@ -132,118 +112,106 @@ afp_child_t *server_child_add(server_child *children, int forkid, pid_t pid, int
goto exit;
}
- fork = (server_child_fork *) children->fork + forkid;
-
/* if we already have an entry. just return. */
- if ((child = resolve_child(fork->table, pid)))
+ if ((child = server_child_resolve(children, pid)))
goto exit;
if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
goto exit;
- child->pid = pid;
- child->valid = 0;
- child->killed = 0;
- child->ipc_fd = ipc_fd;
+ child->afpch_pid = pid;
+ child->afpch_ipc_fd = ipc_fd;
+ child->afpch_logintime = time(NULL);
- hash_child(fork->table, child);
- children->count++;
+ hash_child(children->servch_table, child);
+ children->servch_count++;
exit:
- pthread_sigmask(SIG_SETMASK, &oldsig, NULL);
+ pthread_mutex_unlock(&children->servch_lock);
return child;
}
/* remove a child and free it */
-int server_child_remove(server_child *children, const int forkid, pid_t pid)
+int server_child_remove(server_child_t *children, pid_t pid)
{
int fd;
- server_child_fork *fork;
- struct server_child_data *child;
+ afp_child_t *child;
- fork = (server_child_fork *) children->fork + forkid;
- if (!(child = resolve_child(fork->table, pid)))
+ if (!(child = server_child_resolve(children, pid)))
return -1;
+ pthread_mutex_lock(&children->servch_lock);
+
unhash_child(child);
- if (child->clientid) {
- free(child->clientid);
- child->clientid = NULL;
+ if (child->afpch_clientid) {
+ free(child->afpch_clientid);
+ child->afpch_clientid = NULL;
}
/* In main:child_handler() we need the fd in order to remove it from the pollfd set */
- fd = child->ipc_fd;
+ fd = child->afpch_ipc_fd;
if (fd != -1)
close(fd);
free(child);
- children->count--;
+ children->servch_count--;
- if (fork->cleanup)
- fork->cleanup(pid);
+ pthread_mutex_unlock(&children->servch_lock);
return fd;
}
/* free everything: by using a hash table, this increases the cost of
* this part over a linked list by the size of the hash table */
-void server_child_free(server_child *children)
+void server_child_free(server_child_t *children)
{
- server_child_fork *fork;
- struct server_child_data *child, *tmp;
- int i, j;
-
- for (i = 0; i < children->nforks; i++) {
- fork = (server_child_fork *) children->fork + i;
- for (j = 0; j < CHILD_HASHSIZE; j++) {
- child = fork->table[j]; /* start at the beginning */
- while (child) {
- tmp = child->next;
- close(child->ipc_fd);
- if (child->clientid) {
- free(child->clientid);
- }
- free(child);
- child = tmp;
- }
+ afp_child_t *child, *tmp;
+ int j;
+
+ for (j = 0; j < CHILD_HASHSIZE; j++) {
+ child = children->servch_table[j]; /* start at the beginning */
+ while (child) {
+ tmp = child->afpch_next;
+ close(child->afpch_ipc_fd);
+ if (child->afpch_clientid)
+ free(child->afpch_clientid);
+ if (child->afpch_volumes)
+ free(child->afpch_volumes);
+ free(child);
+ child = tmp;
}
}
- free(children->fork);
+
free(children);
}
/* send signal to all child processes */
-void server_child_kill(server_child *children, int forkid, int sig)
+void server_child_kill(server_child_t *children, int sig)
{
- server_child_fork *fork;
- struct server_child_data *child, *tmp;
+ afp_child_t *child, *tmp;
int i;
- fork = (server_child_fork *) children->fork + forkid;
for (i = 0; i < CHILD_HASHSIZE; i++) {
- child = fork->table[i];
+ child = children->servch_table[i];
while (child) {
- tmp = child->next;
- kill(child->pid, sig);
+ tmp = child->afpch_next;
+ kill(child->afpch_pid, sig);
child = tmp;
}
}
}
-/* send kill to a child processes.
- * a plain-old linked list
- * FIXME use resolve_child ?
- */
-static int kill_child(struct server_child_data *child)
+/* send kill to a child processes */
+static int kill_child(afp_child_t *child)
{
- if (!child->killed) {
- kill(child->pid, SIGTERM);
+ if (!child->afpch_killed) {
+ kill(child->afpch_pid, SIGTERM);
/* we don't wait because there's no guarantee that we can really kill it */
- child->killed = 1;
+ child->afpch_killed = 1;
return 1;
} else {
- LOG(log_info, logtype_default, "Unresponsive child[%d], sending SIGKILL", child->pid);
- kill(child->pid, SIGKILL);
+ LOG(log_info, logtype_default, "Unresponsive child[%d], sending SIGKILL", child->afpch_pid);
+ kill(child->afpch_pid, SIGKILL);
}
return 1;
}
@@ -252,19 +220,16 @@ static int kill_child(struct server_child_data *child)
* Try to find an old session and pass socket
* @returns -1 on error, 0 if no matching session was found, 1 if session was found and socket passed
*/
-int server_child_transfer_session(server_child *children,
- int forkid,
+int server_child_transfer_session(server_child_t *children,
pid_t pid,
uid_t uid,
int afp_socket,
uint16_t DSI_requestID)
{
EC_INIT;
- server_child_fork *fork;
- struct server_child_data *child;
+ afp_child_t *child;
- fork = (server_child_fork *) children->fork + forkid;
- if ((child = resolve_child(fork->table, pid)) == NULL) {
+ if ((child = server_child_resolve(children, pid)) == NULL) {
LOG(log_note, logtype_default, "Reconnect: no child[%u]", pid);
if (kill(pid, 0) == 0) {
LOG(log_note, logtype_default, "Reconnect: terminating old session[%u]", pid);
@@ -279,23 +244,23 @@ int server_child_transfer_session(server_child *children,
return 0;
}
- if (!child->valid) {
+ if (!child->afpch_valid) {
/* hmm, client 'guess' the pid, rogue? */
LOG(log_error, logtype_default, "Reconnect: invalidated child[%u]", pid);
return 0;
- } else if (child->uid != uid) {
+ } else if (child->afpch_uid != uid) {
LOG(log_error, logtype_default, "Reconnect: child[%u] not the same user", pid);
return 0;
}
LOG(log_note, logtype_default, "Reconnect: transfering session to child[%u]", pid);
- if (writet(child->ipc_fd, &DSI_requestID, 2, 0, 2) != 2) {
+ if (writet(child->afpch_ipc_fd, &DSI_requestID, 2, 0, 2) != 2) {
LOG(log_error, logtype_default, "Reconnect: error sending DSI id to child[%u]", pid);
EC_STATUS(-1);
goto EC_CLEANUP;
}
- EC_ZERO_LOG(send_fd(child->ipc_fd, afp_socket));
+ EC_ZERO_LOG(send_fd(child->afpch_ipc_fd, afp_socket));
EC_ZERO_LOG(kill(pid, SIGURG));
EC_STATUS(1);
@@ -307,65 +272,55 @@ int server_child_transfer_session(server_child *children,
/* see if there is a process for the same mac */
/* if the times don't match mac has been rebooted */
-void server_child_kill_one_by_id(server_child *children, int forkid, pid_t pid,
+void server_child_kill_one_by_id(server_child_t *children, pid_t pid,
uid_t uid, uint32_t idlen, char *id, uint32_t boottime)
{
- server_child_fork *fork;
- struct server_child_data *child, *tmp;
+ afp_child_t *child, *tmp;
int i;
- fork = (server_child_fork *)children->fork + forkid;
-
+ pthread_mutex_lock(&children->servch_lock);
+
for (i = 0; i < CHILD_HASHSIZE; i++) {
- child = fork->table[i];
+ child = children->servch_table[i];
while (child) {
- tmp = child->next;
- if ( child->pid != pid) {
- if (child->idlen == idlen && memcmp(child->clientid, id, idlen) == 0) {
- if ( child->time != boottime ) {
+ tmp = child->afpch_next;
+ if (child->afpch_pid != pid) {
+ if (child->afpch_idlen == idlen && memcmp(child->afpch_clientid, id, idlen) == 0) {
+ if ( child->afpch_boottime != boottime ) {
/* Client rebooted */
- if (uid == child->uid) {
+ if (uid == child->afpch_uid) {
kill_child(child);
LOG(log_warning, logtype_default,
"Terminated disconnected child[%u], client rebooted.",
- child->pid);
+ child->afpch_pid);
} else {
LOG(log_warning, logtype_default,
- "Session with different pid[%u]", child->pid);
+ "Session with different pid[%u]", child->afpch_pid);
}
} else {
/* One client with multiple sessions */
LOG(log_debug, logtype_default,
- "Found another session[%u] for client[%u]", child->pid, pid);
+ "Found another session[%u] for client[%u]", child->afpch_pid, pid);
}
}
} else {
/* update childs own slot */
- child->time = boottime;
- if (child->clientid)
- free(child->clientid);
- LOG(log_debug, logtype_default, "Setting client ID for %u", child->pid);
- child->uid = uid;
- child->valid = 1;
- child->idlen = idlen;
- child->clientid = id;
+ child->afpch_boottime = boottime;
+ if (child->afpch_clientid)
+ free(child->afpch_clientid);
+ LOG(log_debug, logtype_default, "Setting client ID for %u", child->afpch_pid);
+ child->afpch_uid = uid;
+ child->afpch_valid = 1;
+ child->afpch_idlen = idlen;
+ child->afpch_clientid = id;
}
child = tmp;
}
}
-}
-/* for extra cleanup if necessary */
-void server_child_setup(server_child *children, const int forkid,
- void (*fcn)(const pid_t))
-{
- server_child_fork *fork;
-
- fork = (server_child_fork *) children->fork + forkid;
- fork->cleanup = fcn;
+ pthread_mutex_unlock(&children->servch_lock);
}
-
/* ---------------------------
* reset children signals
*/
diff --git a/libatalk/util/server_ipc.c b/libatalk/util/server_ipc.c
index 815c58d8..e49d165d 100644
--- a/libatalk/util/server_ipc.c
+++ b/libatalk/util/server_ipc.c
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
#include
@@ -42,13 +43,15 @@ typedef struct ipc_header {
} ipc_header_t;
static char *ipc_cmd_str[] = { "IPC_DISCOLDSESSION",
- "IPC_GETSESSION"};
+ "IPC_GETSESSION",
+ "IPC_STATE",
+ "IPC_VOLUMES"};
/*
* Pass afp_socket to old disconnected session if one has a matching token (token = pid)
* @returns -1 on error, 0 if no matching session was found, 1 if session was found and socket passed
*/
-static int ipc_kill_token(struct ipc_header *ipc, server_child *children)
+static int ipc_kill_token(struct ipc_header *ipc, server_child_t *children)
{
pid_t pid;
@@ -59,7 +62,6 @@ static int ipc_kill_token(struct ipc_header *ipc, server_child *children)
memcpy (&pid, ipc->msg, sizeof(pid_t));
return server_child_transfer_session(children,
- CHILD_DSIFORK,
pid,
ipc->uid,
ipc->afp_socket,
@@ -67,7 +69,7 @@ static int ipc_kill_token(struct ipc_header *ipc, server_child *children)
}
/* ----------------- */
-static int ipc_get_session(struct ipc_header *ipc, server_child *children)
+static int ipc_get_session(struct ipc_header *ipc, server_child_t *children)
{
uint32_t boottime;
uint32_t idlen;
@@ -96,7 +98,6 @@ static int ipc_get_session(struct ipc_header *ipc, server_child *children)
ipc->child_pid, ipc->uid, boottime);
server_child_kill_one_by_id(children,
- CHILD_DSIFORK,
ipc->child_pid,
ipc->uid,
idlen,
@@ -106,100 +107,48 @@ static int ipc_get_session(struct ipc_header *ipc, server_child *children)
return 0;
}
-/***********************************************************************************
- * Public functions
- ***********************************************************************************/
-
-/*!
- * Listen on UNIX domain socket "name" for IPC from old sesssion
- *
- * @args name (r) file name to use for UNIX domain socket
- * @returns socket fd, -1 on error
- */
-int ipc_server_uds(const char *name)
+static int ipc_set_state(struct ipc_header *ipc, server_child_t *children)
{
EC_INIT;
- struct sockaddr_un address;
- socklen_t address_length;
- int fd = -1;
-
- EC_NEG1_LOG( fd = socket(PF_UNIX, SOCK_STREAM, 0) );
- EC_ZERO_LOG( setnonblock(fd, 1) );
- unlink(name);
- address.sun_family = AF_UNIX;
- address_length = sizeof(address.sun_family) + sprintf(address.sun_path, "%s", name);
- EC_ZERO_LOG( bind(fd, (struct sockaddr *)&address, address_length) );
- EC_ZERO_LOG( listen(fd, 1024) );
+ afp_child_t *child;
-EC_CLEANUP:
- if (ret != 0) {
- return -1;
- }
+ pthread_mutex_lock(&children->servch_lock);
+
+ if ((child = server_child_resolve(children, ipc->child_pid)) == NULL)
+ EC_FAIL;
+
+ memcpy(&child->afpch_state, ipc->msg, sizeof(uint16_t));
- return fd;
+EC_CLEANUP:
+ pthread_mutex_unlock(&children->servch_lock);
+ EC_EXIT;
}
-/*!
- * Connect to UNIX domain socket "name" for IPC with new afpd master
- *
- * 1. Connect
- * 2. send pid, which establishes a child structure for us in the master
- *
- * @args name (r) file name to use for UNIX domain socket
- * @returns socket fd, -1 on error
- */
-int ipc_client_uds(const char *name)
+static int ipc_set_volumes(struct ipc_header *ipc, server_child_t *children)
{
EC_INIT;
- struct sockaddr_un address;
- socklen_t address_length;
- int fd = -1;
- pid_t pid = getpid();
-
- EC_NEG1_LOG( fd = socket(PF_UNIX, SOCK_STREAM, 0) );
- address.sun_family = AF_UNIX;
- address_length = sizeof(address.sun_family) + sprintf(address.sun_path, "%s", name);
-
- EC_ZERO_LOG( connect(fd, (struct sockaddr *)&address, address_length) ); /* 1 */
- LOG(log_debug, logtype_afpd, "ipc_client_uds: connected to master");
+ afp_child_t *child;
- EC_ZERO_LOG( setnonblock(fd, 1) );
+ pthread_mutex_lock(&children->servch_lock);
- if (writet(fd, &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) {
- LOG(log_error, logtype_afpd, "ipc_client_uds: writet: %s", strerror(errno));
+ if ((child = server_child_resolve(children, ipc->child_pid)) == NULL)
EC_FAIL;
+
+ if (child->afpch_volumes) {
+ free(child->afpch_volumes);
+ child->afpch_volumes = NULL;
}
+ if (ipc->len)
+ child->afpch_volumes = strdup(ipc->msg);
EC_CLEANUP:
- if (ret != 0) {
- return -1;
- }
- LOG(log_debug, logtype_afpd, "ipc_client_uds: fd: %d", fd);
- return fd;
+ pthread_mutex_unlock(&children->servch_lock);
+ EC_EXIT;
}
-int reconnect_ipc(AFPObj *obj)
-{
- int retrycount = 0;
-
- LOG(log_debug, logtype_afpd, "reconnect_ipc: start");
-
- close(obj->ipc_fd);
- obj->ipc_fd = -1;
-
- sleep((getpid() % 5) + 15); /* give it enough time to start */
-
- while (retrycount++ < 10) {
- if ((obj->ipc_fd = ipc_client_uds(_PATH_AFP_IPC)) == -1) {
- LOG(log_error, logtype_afpd, "reconnect_ipc: cant reconnect to master");
- sleep(1);
- continue;
- }
- LOG(log_debug, logtype_afpd, "reconnect_ipc: succesfull IPC reconnect");
- return 0;
- }
- return -1;
-}
+/***********************************************************************************
+ * Public functions
+ ***********************************************************************************/
/* -----------------
* Ipc format
@@ -219,7 +168,7 @@ int reconnect_ipc(AFPObj *obj)
*
* @returns -1 on error, 0 on success
*/
-int ipc_server_read(server_child *children, int fd)
+int ipc_server_read(server_child_t *children, int fd)
{
int ret;
struct ipc_header ipc;
@@ -294,6 +243,16 @@ int ipc_server_read(server_child *children, int fd)
return -1;
break;
+ case IPC_STATE:
+ if (ipc_set_state(&ipc, children) != 0)
+ return -1;
+ break;
+
+ case IPC_VOLUMES:
+ if (ipc_set_volumes(&ipc, children) != 0)
+ return -1;
+ break;
+
default:
LOG (log_info, logtype_afpd, "ipc_read: unknown command: %d", ipc.command);
return -1;
@@ -345,3 +304,8 @@ int ipc_child_write(int fd, uint16_t command, int len, void *msg)
return 0;
}
+
+int ipc_child_state(AFPObj *obj, uint16_t state)
+{
+ return ipc_child_write(obj->ipc_fd, IPC_STATE, sizeof(uint16_t), &state);
+}
diff --git a/libatalk/util/socket.c b/libatalk/util/socket.c
index eda69c6c..1df0b96b 100644
--- a/libatalk/util/socket.c
+++ b/libatalk/util/socket.c
@@ -104,7 +104,7 @@ ssize_t readt(int socket, void *data, const size_t length, int setnonblocking, i
end.tv_sec += timeout;
while (stored < length) {
- len = read(socket, (char *) data + stored, length - stored);
+ len = recv(socket, (char *) data + stored, length - stored, 0);
if (len == -1) {
switch (errno) {
case EINTR:
diff --git a/libatalk/util/unix.c b/libatalk/util/unix.c
index 7c80e22d..37bfe140 100644
--- a/libatalk/util/unix.c
+++ b/libatalk/util/unix.c
@@ -507,3 +507,45 @@ char *strtok_quote(char *s, const char *delim)
}
return token;
}
+
+int set_groups(AFPObj *obj, struct passwd *pwd)
+{
+ if (initgroups(pwd->pw_name, pwd->pw_gid) < 0)
+ LOG(log_error, logtype_afpd, "initgroups(%s, %d): %s", pwd->pw_name, pwd->pw_gid, strerror(errno));
+
+ if ((obj->ngroups = getgroups(0, NULL)) < 0) {
+ LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno));
+ return -1;
+ }
+
+ if (obj->groups)
+ free(obj->groups);
+ if (NULL == (obj->groups = calloc(obj->ngroups, sizeof(gid_t))) ) {
+ LOG(log_error, logtype_afpd, "login: %s calloc: %d", obj->ngroups);
+ return -1;
+ }
+
+ if ((obj->ngroups = getgroups(obj->ngroups, obj->groups)) < 0 ) {
+ LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+#define GROUPSTR_BUFSIZE 1024
+const char *print_groups(int ngroups, gid_t *groups)
+{
+ static char groupsstr[GROUPSTR_BUFSIZE];
+ int i;
+ char *s = groupsstr;
+
+ if (ngroups == 0)
+ return "-";
+
+ for (i = 0; (i < ngroups) && (s < &groupsstr[GROUPSTR_BUFSIZE]); i++) {
+ s += snprintf(s, &groupsstr[GROUPSTR_BUFSIZE] - s, " %u", groups[i]);
+ }
+
+ return groupsstr;
+}
diff --git a/libatalk/vfs/acl.c b/libatalk/vfs/acl.c
index c936f178..d7c8eb62 100644
--- a/libatalk/vfs/acl.c
+++ b/libatalk/vfs/acl.c
@@ -108,7 +108,7 @@ int remove_acl_vfs(const char *name)
/* Remove default ACL if it's a dir */
- EC_ZERO_LOG_ERR(stat(name, &st), AFPERR_MISC);
+ EC_ZERO_ERR(stat(name, &st), AFPERR_MISC);
if (S_ISDIR(st.st_mode)) {
EC_NULL_LOG_ERR(acl = acl_init(0), AFPERR_MISC);
EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_DEFAULT, acl), AFPERR_MISC);
@@ -129,6 +129,7 @@ int remove_acl_vfs(const char *name)
EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_ACCESS, acl), AFPERR_MISC);
EC_CLEANUP:
+ if (errno == ENOENT) EC_STATUS(0);
if (acl) acl_free(acl);
EC_EXIT;
diff --git a/libatalk/vfs/extattr.c b/libatalk/vfs/extattr.c
index 5206aa6d..73724d53 100644
--- a/libatalk/vfs/extattr.c
+++ b/libatalk/vfs/extattr.c
@@ -910,6 +910,7 @@ static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
switch (errno) {
case ENOENT:
case EEXIST:
+ case EACCES:
break;
default:
LOG(log_debug, logtype_default, "openat(\"%s\"): %s",
diff --git a/libatalk/vfs/vfs.c b/libatalk/vfs/vfs.c
index 3dd3ebb4..d79ac05e 100644
--- a/libatalk/vfs/vfs.c
+++ b/libatalk/vfs/vfs.c
@@ -355,24 +355,17 @@ static int RF_solaris_acl(VFS_FUNC_ARGS_ACL)
struct stat st;
int len;
- if ((stat(path, &st)) != 0)
- return -1;
- if (S_ISDIR(st.st_mode)) {
- len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
- if (len < 0 || len >= MAXPATHLEN)
- return -1;
- /* set acl on .AppleDouble dir first */
- if ((acl(buf, cmd, count, aces)) != 0)
- return -1;
- /* now set ACL on ressource fork */
- if ((acl(vol->ad_path(path, ADFLAGS_DIR), cmd, count, aces)) != 0)
- return -1;
- } else
- /* set ACL on ressource fork */
- if ((acl(vol->ad_path(path, ADFLAGS_HF), cmd, count, aces)) != 0)
- return -1;
-
- return 0;
+ if ((stat(path, &st)) != 0) {
+ if (errno == ENOENT)
+ return AFP_OK;
+ return AFPERR_MISC;
+ }
+ if (!S_ISDIR(st.st_mode)) {
+ /* set ACL on ressource fork */
+ if ((acl(vol->ad_path(path, ADFLAGS_HF), cmd, count, aces)) != 0)
+ return AFPERR_MISC;
+ }
+ return AFP_OK;
}
static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
@@ -381,20 +374,15 @@ static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
static char buf[ MAXPATHLEN + 1];
int len;
- if (dir) {
- len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
- if (len < 0 || len >= MAXPATHLEN)
- return AFPERR_MISC;
- /* remove ACL from .AppleDouble/.Parent first */
- if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_DIR))) != AFP_OK)
- return ret;
- /* now remove from .AppleDouble dir */
- if ((ret = remove_acl_vfs(buf)) != AFP_OK)
- return ret;
- } else
- /* remove ACL from ressource fork */
- if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK)
- return ret;
+ if (dir)
+ return AFP_OK;
+
+ /* remove ACL from ressource fork */
+ if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK) {
+ if (errno == ENOENT)
+ return AFP_OK;
+ return ret;
+ }
return AFP_OK;
}
@@ -404,52 +392,35 @@ static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
static int RF_posix_acl(VFS_FUNC_ARGS_ACL)
{
EC_INIT;
- static char buf[ MAXPATHLEN + 1];
struct stat st;
- int len;
- if (S_ISDIR(st.st_mode)) {
- len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
- if (len < 0 || len >= MAXPATHLEN)
- EC_FAIL;
- /* set acl on .AppleDouble dir first */
- EC_ZERO_LOG(acl_set_file(buf, type, acl));
+ if (stat(path, &st) == -1)
+ EC_FAIL;
- if (type == ACL_TYPE_ACCESS)
- /* set ACL on ressource fork (".Parent") too */
- EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_DIR), type, acl));
- } else {
+ if (!S_ISDIR(st.st_mode)) {
/* set ACL on ressource fork */
- EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl));
+ EC_ZERO_ERR( acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl), AFPERR_MISC );
}
EC_CLEANUP:
- if (ret != 0)
- return AFPERR_MISC;
- return AFP_OK;
+ if (errno == ENOENT)
+ EC_STATUS(AFP_OK);
+ EC_EXIT;
}
static int RF_posix_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
{
EC_INIT;
- static char buf[ MAXPATHLEN + 1];
- int len;
- if (dir) {
- len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
- if (len < 0 || len >= MAXPATHLEN)
- return AFPERR_MISC;
- /* remove ACL from .AppleDouble/.Parent first */
- EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_DIR)), AFPERR_MISC);
+ if (dir)
+ EC_EXIT_STATUS(AFP_OK);
- /* now remove from .AppleDouble dir */
- EC_ZERO_LOG_ERR(remove_acl_vfs(buf), AFPERR_MISC);
- } else {
- /* remove ACL from ressource fork */
- EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF)), AFPERR_MISC);
- }
+ /* remove ACL from ressource fork */
+ EC_ZERO_ERR( remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF)), AFPERR_MISC );
EC_CLEANUP:
+ if (errno == ENOENT)
+ EC_STATUS(AFP_OK);
EC_EXIT;
}
#endif
diff --git a/libevent/Makefile.am b/libevent/Makefile.am
index 09505bd7..8114ad36 100644
--- a/libevent/Makefile.am
+++ b/libevent/Makefile.am
@@ -86,9 +86,6 @@ if INSTALL_LIBEVENT
dist_bin_SCRIPTS = event_rpcgen.py
endif
-pkgconfigdir=$(libdir)/pkgconfig
-LIBEVENT_PKGCONFIG=libevent.pc
-
# These sources are conditionally added by configure.in or conditionally
# included from other files.
PLATFORM_DEPENDENT_SRC = \
@@ -108,16 +105,13 @@ EXTRA_DIST = \
LIBEVENT_LIBS_LA = libevent.la libevent_core.la libevent_extra.la
if PTHREADS
LIBEVENT_LIBS_LA += libevent_pthreads.la
-LIBEVENT_PKGCONFIG += libevent_pthreads.pc
endif
if OPENSSL
LIBEVENT_LIBS_LA += libevent_openssl.la
-LIBEVENT_PKGCONFIG += libevent_openssl.pc
endif
if INSTALL_LIBEVENT
lib_LTLIBRARIES = $(LIBEVENT_LIBS_LA)
-pkgconfig_DATA = $(LIBEVENT_PKGCONFIG)
else
noinst_LTLIBRARIES = $(LIBEVENT_LIBS_LA)
endif
@@ -196,7 +190,7 @@ NO_UNDEFINED =
MAYBE_CORE =
endif
-GENERIC_LDFLAGS = -version-info $(VERSION_INFO) $(RELEASE) $(NO_UNDEFINED)
+GENERIC_LDFLAGS = -static
libevent_la_SOURCES = $(CORE_SRC) $(EXTRA_SRC)
libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
@@ -249,5 +243,7 @@ doxygen: FORCE
doxygen $(srcdir)/Doxyfile
FORCE:
-DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h
+DISTCLEANFILES = *~ ./include/event2/event-config.h
+
+install:
diff --git a/macros/netatalk.m4 b/macros/netatalk.m4
index e77aac53..beceeef9 100644
--- a/macros/netatalk.m4
+++ b/macros/netatalk.m4
@@ -1,5 +1,75 @@
dnl Kitchen sink for configuration macros
+dnl Check for dtrace
+AC_DEFUN([AC_NETATALK_DTRACE], [
+ AC_ARG_WITH(dtrace,
+ AS_HELP_STRING(
+ [--with-dtrace],
+ [Enable dtrace probes (default: enabled if dtrace found)]
+ ),
+ [WDTRACE=$withval],
+ [WDTRACE=auto]
+ )
+ if test "x$WDTRACE" = "xyes" -o "x$WDTRACE" = "xauto" ; then
+ AC_CHECK_PROG([atalk_cv_have_dtrace], [dtrace], [yes], [no])
+ if test "x$atalk_cv_have_dtrace" = "xno" ; then
+ if test "x$WDTRACE" = "xyes" ; then
+ AC_MSG_FAILURE([dtrace requested but not found])
+ fi
+ WDTRACE="no"
+ else
+ WDTRACE="yes"
+ fi
+ fi
+
+ if test x"$WDTRACE" = x"yes" ; then
+ AC_DEFINE([WITH_DTRACE], [1], [dtrace probes])
+ DTRACE_LIBS=""
+ if test x"$this_os" = x"freebsd" ; then
+ DTRACE_LIBS="-lelf"
+ fi
+ AC_SUBST(DTRACE_LIBS)
+ fi
+ AM_CONDITIONAL(WITH_DTRACE, test "x$WDTRACE" = "xyes")
+])
+
+dnl Check for dbus-glib, for AFP stats
+AC_DEFUN([AC_NETATALK_DBUS_GLIB], [
+ atalk_cv_with_dbus=no
+ PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.1, have_dbus=yes, have_dbus=no)
+ PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, have_dbus_glib=yes, have_dbus_glib=no)
+ PKG_CHECK_MODULES(DBUS_GTHREAD, gthread-2.0, have_dbus_gthread=yes, have_dbus_gthread=no)
+ AC_SUBST(DBUS_CFLAGS)
+ AC_SUBST(DBUS_LIBS)
+ AC_SUBST(DBUS_GLIB_CFLAGS)
+ AC_SUBST(DBUS_GLIB_LIBS)
+ AC_SUBST(DBUS_GTHREAD_CFLAGS)
+ AC_SUBST(DBUS_GTHREAD_LIBS)
+ if test x$have_dbus_glib = xyes -a x$have_dbus = xyes -a x$have_dbus_gthread = xyes ; then
+ saved_CFLAGS=$CFLAGS
+ saved_LIBS=$LIBS
+ CFLAGS="$CFLAGS $DBUS_GLIB_CFLAGS"
+ LIBS="$LIBS $DBUS_GLIB_LIBS"
+ AC_CHECK_FUNC([dbus_g_bus_get_private], [atalk_cv_with_dbus=yes], [atalk_cv_with_dbus=no])
+ CFLAGS="$saved_CFLAGS"
+ LIBS="$saved_LIBS"
+ fi
+ AM_CONDITIONAL(HAVE_DBUS_GLIB, test x$atalk_cv_with_dbus = xyes)
+
+ AC_ARG_WITH(
+ dbus-sysconf-dir,
+ [AS_HELP_STRING([--with-dbus-sysconf-dir=PATH],[Path to dbus system bus security configuration directory (default: ${sysconfdir}/dbus-1/system.d/)])],
+ ac_cv_dbus_sysdir=$withval,
+ ac_cv_dbus_sysdir='${sysconfdir}/dbus-1/system.d'
+ )
+
+ if test x$atalk_cv_with_dbus = xyes ; then
+ AC_DEFINE(HAVE_DBUS_GLIB, 1, [Define if support for dbus-glib was found])
+ DBUS_SYS_DIR="$ac_cv_dbus_sysdir"
+ AC_SUBST(DBUS_SYS_DIR)
+ fi
+])
+
dnl Whether to enable developer build
AC_DEFUN([AC_DEVELOPER], [
AC_MSG_CHECKING([whether to enable developer build])
@@ -36,7 +106,9 @@ AC_DEFUN([AC_NETATALK_LIBEVENT], [
AC_MSG_ERROR([--with-libevent requires a path])
fi
AC_MSG_RESULT([$use_bundled_libevent])
- AC_CONFIG_SUBDIRS([libevent])
+ if test x"$use_bundled_libevent" = x"yes" ; then
+ AC_CONFIG_SUBDIRS([libevent])
+ fi
AC_SUBST(LIBEVENT_CFLAGS)
AC_SUBST(LIBEVENT_LDFLAGS)
AM_CONDITIONAL(USE_BUILTIN_LIBEVENT, test x"$use_bundled_libevent" = x"yes")
@@ -60,13 +132,47 @@ AC_ARG_ENABLE(fhs,
use_pam_so=yes
AC_DEFINE(FHS_COMPATIBILITY, 1, [Define if you want compatibily with the FHS])
AC_MSG_RESULT([yes])
+ atalk_cv_fhs_compat=yes
else
AC_MSG_RESULT([no])
+ atalk_cv_fhs_compat=no
fi
],[
AC_MSG_RESULT([no])
- ]
-)])
+ atalk_cv_fhs_compat=no
+])])
+
+dnl netatalk lockfile path
+AC_DEFUN([AC_NETATALK_LOCKFILE], [
+ AC_MSG_CHECKING([netatalk lockfile path])
+ AC_ARG_WITH(
+ lockfile,
+ [AS_HELP_STRING([--with-lockfile=PATH],[Path of netatalk lockfile])],
+ ac_cv_netatalk_lock=$withval,
+ ac_cv_netatalk_lock=""
+ )
+ if test -z "$ac_cv_netatalk_lock" ; then
+ ac_cv_netatalk_lock=/var/spool/locks/netatalk
+ if test x"$atalk_cv_fhs_compat" = x"yes" ; then
+ ac_cv_netatalk_lock=/var/run/netatalk.pid
+ else
+ case "$host_os" in
+ *freebsd*)
+ ac_cv_netatalk_lock=/var/spool/lock/netatalk
+ ;;
+ *netbsd*|*openbsd*)
+ ac_cv_netatalk_lock=/var/run/netatalk.pid
+ ;;
+ *linux*)
+ ac_cv_netatalk_lock=/var/lock/netatalk
+ ;;
+ esac
+ fi
+ fi
+ AC_DEFINE_UNQUOTED(PATH_NETATALK_LOCK, ["$ac_cv_netatalk_lock"], [netatalk lockfile path])
+ AC_SUBST(PATH_NETATALK_LOCK, ["$ac_cv_netatalk_lock"])
+ AC_MSG_RESULT([$ac_cv_netatalk_lock])
+])
dnl 64bit platform check
AC_DEFUN([AC_NETATALK_64BIT_LIBS], [
@@ -249,7 +355,7 @@ AC_ARG_ENABLE(shell-check,
)
])
-dnl Check for optional sysv initscript install
+dnl Check for optional initscript install
AC_DEFUN([AC_NETATALK_INIT_STYLE], [
AC_ARG_WITH(init-style,
[ --with-init-style use OS specific init config [[redhat-sysv|redhat-systemd|suse-sysv|suse-systemd|gentoo|netbsd|debian|solaris|systemd]]],
@@ -261,36 +367,46 @@ AC_DEFUN([AC_NETATALK_INIT_STYLE], [
;;
"redhat-sysv")
AC_MSG_RESULT([enabling redhat-style sysv initscript support])
+ ac_cv_init_dir="/etc/rc.d/init.d"
;;
"redhat-systemd")
AC_MSG_RESULT([enabling redhat-style systemd support])
+ ac_cv_init_dir="/lib/systemd/system"
;;
"suse")
AC_MSG_ERROR([--with-init-style=suse is obsoleted. Use suse-sysv or suse-systemd.])
;;
"suse-sysv")
AC_MSG_RESULT([enabling suse-style sysv initscript support])
+ ac_cv_init_dir="/etc/init.d"
;;
"suse-systemd")
AC_MSG_RESULT([enabling suse-style systemd support (>=openSUSE12.1)])
+ ac_cv_init_dir="/lib/systemd/system"
;;
"gentoo")
AC_MSG_RESULT([enabling gentoo-style initscript support])
+ ac_cv_init_dir="/etc/init.d"
;;
"netbsd")
AC_MSG_RESULT([enabling netbsd-style initscript support])
+ ac_cv_init_dir="/etc/rc.d"
;;
"debian")
AC_MSG_RESULT([enabling debian-style initscript support])
+ ac_cv_init_dir="/etc/init.d"
;;
"solaris")
AC_MSG_RESULT([enabling solaris-style SMF support])
+ ac_cv_init_dir="/lib/svc/manifest/network/"
;;
"systemd")
AC_MSG_RESULT([enabling general systemd support])
+ ac_cv_init_dir="/lib/systemd/system"
;;
"none")
AC_MSG_RESULT([disabling init-style support])
+ ac_cv_init_dir="none"
;;
*)
AC_MSG_ERROR([illegal init-style])
@@ -305,6 +421,12 @@ AC_DEFUN([AC_NETATALK_INIT_STYLE], [
AM_CONDITIONAL(USE_SYSTEMD, test x$init_style = xsystemd || test x$init_style = xredhat-systemd || test x$init_style = xsuse-systemd)
AM_CONDITIONAL(USE_UNDEF, test x$init_style = xnone)
+ AC_ARG_WITH(init-dir,
+ [ --with-init-dir=PATH path to OS specific init directory],
+ ac_cv_init_dir="$withval", ac_cv_init_dir="$ac_cv_init_dir"
+ )
+ INIT_DIR="$ac_cv_init_dir"
+ AC_SUBST(INIT_DIR, ["$ac_cv_init_dir"])
])
dnl OS specific configuration
diff --git a/macros/pam-check.m4 b/macros/pam-check.m4
index 17a92898..609c92dc 100644
--- a/macros/pam-check.m4
+++ b/macros/pam-check.m4
@@ -138,6 +138,15 @@ AC_DEFUN([AC_NETATALK_PATH_PAM], [
AC_DEFINE(USE_PAM, 1, [Define to enable PAM support])
fi
+ AC_ARG_WITH(
+ pam-confdir,
+ [AS_HELP_STRING([--with-pam-confdir=PATH],[Path to PAM config dir (default: ${sysconfdir}/pam.d)])],
+ ac_cv_pamdir=$withval,
+ ac_cv_pamdir='${sysconfdir}/pam.d'
+ )
+
+ PAMDIR="$ac_cv_pamdir"
+
LIB_REMOVE_USR_LIB(PAM_LIBS)
CFLAGS_REMOVE_USR_INCLUDE(PAM_CFLAGS)
AC_SUBST(PAMDIR)
diff --git a/macros/summary.m4 b/macros/summary.m4
index 6c696fc2..b8db2579 100644
--- a/macros/summary.m4
+++ b/macros/summary.m4
@@ -53,14 +53,27 @@ dnl AC_MSG_RESULT([ Samba sharemode interop: $neta_cv_have_smbshmd])
AC_MSG_RESULT([ ACL support: $with_acl_support])
AC_MSG_RESULT([ Kerberos support: $with_kerberos])
AC_MSG_RESULT([ LDAP support: $netatalk_cv_ldap])
- if test x"$use_pam_so" = x"yes" -a x"$netatalk_cv_install_pam" = x"no"; then
+ AC_MSG_RESULT([ dbus support: $atalk_cv_with_dbus])
+ AC_MSG_RESULT([ dtrace probes: $WDTRACE])
+ AC_MSG_RESULT([ Paths:])
+ AC_MSG_RESULT([ Netatalk lockfile: $ac_cv_netatalk_lock])
+ if test "x$init_style" != x"none"; then
+ AC_MSG_RESULT([ init directory: $ac_cv_init_dir])
+ fi
+ if test x"$atalk_cv_with_dbus" = x"yes"; then
+ AC_MSG_RESULT([ dbus system directory: $ac_cv_dbus_sysdir])
+ fi
+ if test x"$use_pam_so" = x"yes"; then
+ if test x"$netatalk_cv_install_pam" = x"yes"; then
+ AC_MSG_RESULT([ pam config directory: $ac_cv_pamdir])
+ else
AC_MSG_RESULT([])
AC_MSG_WARN([ PAM support was configured for your system, but the netatalk PAM configuration file])
AC_MSG_WARN([ cannot be installed. Please install the config/netatalk.pamd file manually.])
AC_MSG_WARN([ If you're running Solaris or BSD you'll have to edit /etc/pam.conf to get PAM working.])
AC_MSG_WARN([ You can also re-run configure and specify --without-pam to disable PAM support.])
+ fi
fi
-
])
diff --git a/man/man1/.gitignore b/man/man1/.gitignore
index c767a967..39ffeb2f 100644
--- a/man/man1/.gitignore
+++ b/man/man1/.gitignore
@@ -6,6 +6,6 @@ apple_mv.1
apple_rm.1
asip-status.pl.1
afpldaptest.1
+afpstats.1
uniconv.1
-.gitignore
*.o
diff --git a/man/man1/Makefile.am b/man/man1/Makefile.am
index fe81a7d7..20dede4e 100644
--- a/man/man1/Makefile.am
+++ b/man/man1/Makefile.am
@@ -12,8 +12,8 @@ SUFFIXES= .tmpl .
-e s@:DEFAULT_CNID_SCHEME:@${DEFAULT_CNID_SCHEME}@ \
<$< >$@
-GENERATED_MANS = uniconv.1 asip-status.pl.1 afpldaptest.1
-TEMPLATE_FILES = uniconv.1.tmpl asip-status.pl.1.tmpl afpldaptest.1.tmpl
+GENERATED_MANS = uniconv.1 asip-status.pl.1 afpldaptest.1 afpstats.1
+TEMPLATE_FILES = uniconv.1.tmpl asip-status.pl.1.tmpl afpldaptest.1.tmpl afpstats.1.tmpl
NONGENERATED_MANS = ad.1 \
afppasswd.1 \
diff --git a/man/man1/afpstats.1.tmpl b/man/man1/afpstats.1.tmpl
new file mode 100644
index 00000000..b7980996
--- /dev/null
+++ b/man/man1/afpstats.1.tmpl
@@ -0,0 +1,50 @@
+'\" t
+.\" Title: afpstats
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.78.0
+.\" Date: 24 Mar 2013
+.\" Manual: Netatalk 3.0
+.\" Source: Netatalk 3.0
+.\" Language: English
+.\"
+.TH "AFPSTATS" "1" "24 Mar 2013" "Netatalk 3.0" "Netatalk 3.0"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+afpstats \- List AFP statistics
+.SH "SYNOPSIS"
+.HP \w'\fBafpstats\fR\fB\fR\ 'u
+\fBafpstats\fR\fB\fR
+.SH "DESCRIPTION"
+.PP
+\fBafpstats\fR
+list AFP statistics via D\-Bus IPC\&.
+.SH "NOTE"
+.PP
+\fBafpd\fR
+must support D\-Bus\&. Check it by "\fBafpd \-V\fR"\&.
+.PP
+"\fBafpstats = yes\fR" must be set in
+:ETCDIR:/afp\&.conf\&.
+.SH "SEE ALSO"
+.PP
+\fBafpd\fR(8),
+\fBafp.conf\fR(5),
+\fBdbus-daemon\fR(1)
diff --git a/man/man5/afp.conf.5.tmpl b/man/man5/afp.conf.5.tmpl
index 9f9d007b..60ec8d0e 100644
--- a/man/man5/afp.conf.5.tmpl
+++ b/man/man5/afp.conf.5.tmpl
@@ -2,12 +2,12 @@
.\" Title: afp.conf
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.78.0
-.\" Date: 19 Jan 2013
+.\" Date: 19 Feb 2013
.\" Manual: Netatalk 3.0
.\" Source: Netatalk 3.0
.\" Language: English
.\"
-.TH "AFP\&.CONF" "5" "19 Jan 2013" "Netatalk 3.0" "Netatalk 3.0"
+.TH "AFP\&.CONF" "5" "19 Feb 2013" "Netatalk 3.0" "Netatalk 3.0"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -465,7 +465,7 @@ Sets the maximum number of clients that can simultaneously connect to the server
.PP
server quantum = \fInumber\fR \fB(G)\fR
.RS 4
-This specifies the DSI server quantum\&. The default value is 303840\&. The maximum value is 0xFFFFFFFFF, the minimum is 32000\&. If you specify a value that is out of range, the default value will be set\&. Do not change this value unless you\*(Aqre absolutely sure, what you\*(Aqre doing
+This specifies the DSI server quantum\&. The default value is 1 MB\&. The maximum value is 0xFFFFFFFFF, the minimum is 32000\&. If you specify a value that is out of range, the default value will be set\&. Do not change this value unless you\*(Aqre absolutely sure, what you\*(Aqre doing
.RE
.PP
sleep time = \fInumber\fR \fB(G)\fR
@@ -508,6 +508,11 @@ afp read locks = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR
Whether to apply locks to the byte region read in FPRead calls\&. The AFP spec mandates this, but it\*(Aqs not really in line with UNIX semantics and is a performance hug\&.
.RE
.PP
+afpstats = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR
+.RS 4
+Whether to provide AFP runtime statistics (connected users, open volumes) via dbus\&.
+.RE
+.PP
basedir regex = \fIregex\fR \fB(H)\fR
.RS 4
Regular expression which matches the parent directory of the user homes\&. If
@@ -549,13 +554,6 @@ AFP user home volume name\&. The default is
\fIuser\*(Aqs home\fR\&.
.RE
.PP
-keep sessions = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR
-.RS 4
-Enable "Continuous AFP Service"\&. This means restarting AFP and CNID service daemons master processes, but keeping the AFP session processes\&. This can be used to install (most) updates to Netatalk without interrupting active AFP sessions\&. Existing AFP sessions will still run the version from before updating, but new AFP sessions will run the updated code\&. After enabling this option when sending SIGQUIT to the
-\fInetatalk\fR
-service controller process, the AFP and CNID daemons will exit and then the service controller will restart them\&. AFP session processes are notified of the master afpd shutdown, they will then sleep 15\-20 seconds and then try to reconnect their IPC channel to the master afpd process\&. The IPC channel between the AFP master service daemon and the AFP session child is used for keeping session state of AFP sessions in the AFP master process\&. The session state is needed when AFP clients experience eg network outages and try to reconnect to the AFP server\&.
-.RE
-.PP
login message = \fImessage\fR \fB(G)/(V)\fR
.RS 4
Sets a message to be displayed when clients logon to the server\&. The message should be in
@@ -878,7 +876,7 @@ cnid scheme = \fIbackend\fR \fB(V)\fR
set the CNID backend to be used for the volume, default is [:DEFAULT_CNID_SCHEME:] available schemes: [:COMPILED_BACKENDS:]
.RE
.PP
-ea = \fInone|auto|sys|ad\fR
+ea = \fInone|auto|sys|ad\fR \fB(V)\fR
.RS 4
Specify how Extended Attributes
are stored\&.
@@ -921,7 +919,7 @@ specifies the Mac client charset for this Volume, e\&.g\&.
\fIMAC_CYRILLIC\fR\&. If not specified the global setting is applied\&. This setting is only required if you need volumes, where the Mac charset differs from the one globally set in the [Global] section\&.
.RE
.PP
-casefold = \fBoption\fR
+casefold = \fBoption\fR \fB(V)\fR
.RS 4
The casefold option handles, if the case of filenames should be changed\&. The available options are:
.sp
@@ -958,7 +956,7 @@ is for directories only\&. Don\*(Aqt use with "\fBunix priv = no\fR"\&.
.\}
.nf
file perm = 0660 directory perm =
- 0770
+ 0770
.fi
.if n \{\
.RE
@@ -1037,7 +1035,7 @@ The default setting is false thus symlinks are not followed on the server\&. Thi
.PP
invisible dots = \fIBOOLEAN\fR (default: \fIno\fR) \fB(V)\fR
.RS 4
-make dot files invisible\&.
+make dot files invisible\&. WARNING: enabling this option will lead to unwanted sideeffects were OS X applications when saving files to a temporary file starting with a dot first, then renaming the temp file to its final name, result in the saved file being invisible\&. The only thing this option is useful for is making files that start with a dot invisible on Mac OS 9\&. It\*(Aqs completely useless on Mac OS X, as both in Finder and in Terminal files starting with a dot are hidden anyway\&.
.RE
.PP
network ids = \fIBOOLEAN\fR (default: \fIyes\fR) \fB(V)\fR
diff --git a/man/man8/netatalk.8.tmpl b/man/man8/netatalk.8.tmpl
index 88cb179e..06878da5 100644
--- a/man/man8/netatalk.8.tmpl
+++ b/man/man8/netatalk.8.tmpl
@@ -48,12 +48,6 @@ SIGTERM
Stop Netatalk service, AFP and CNID daemons
.RE
.PP
-SIGQUIT
-.RS 4
-Restart AFP and CNID master daemons, but keep all session AFP processes running\&. Can be used to implement
-AFP service without downtime\&.
-.RE
-.PP
SIGHUP
.RS 4
Sending a
diff --git a/test/afpd/Makefile.am b/test/afpd/Makefile.am
index 01278ecd..34e28f48 100644
--- a/test/afpd/Makefile.am
+++ b/test/afpd/Makefile.am
@@ -64,3 +64,12 @@ test_LDADD = \
@LIBGCRYPT_LIBS@ @QUOTA_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@ @GSSAPI_LIBS@ @KRB5_LIBS@
test_LDFLAGS = -export-dynamic
+
+if WITH_DTRACE
+DTRACE_OBJ = test-afp_dsi.o test-fork.o test-appl.o test-catsearch.o test-directory.o test-enumerate.o test-file.o test-filedir.o
+afp_dtrace.o: $(top_srcdir)/include/atalk/afp_dtrace.d $(DTRACE_OBJ)
+ if test -f afp_dtrace.o ; then rm -f afp_dtrace.o ; fi
+ $(LIBTOOL) --mode=execute dtrace -G -s $(top_srcdir)/include/atalk/afp_dtrace.d -o afp_dtrace.o $(DTRACE_OBJ)
+test_LDADD += afp_dtrace.o @DTRACE_LIBS@
+CLEANFILES += afp_dtrace.o
+endif