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