]> arthur.barton.de Git - netatalk.git/commitdiff
Merge remote-tracking branch 'origin/develop' into spotlight
authorRalph Boehme <sloowfranklin@gmail.com>
Thu, 21 Feb 2013 17:43:15 +0000 (18:43 +0100)
committerRalph Boehme <sloowfranklin@gmail.com>
Thu, 21 Feb 2013 17:43:15 +0000 (18:43 +0100)
Conflicts:
config/Makefile.am
etc/afpd/afp_dsi.c
etc/afpd/auth.c
include/atalk/Makefile.am

16 files changed:
1  2 
config/Makefile.am
configure.ac
etc/afpd/Makefile.am
etc/afpd/afp_dsi.c
etc/afpd/auth.c
etc/afpd/file.c
etc/afpd/main.c
etc/netatalk/netatalk.c
include/atalk/Makefile.am
include/atalk/dsi.h
include/atalk/globals.h
libatalk/util/logger.c
libatalk/util/netatalk_conf.c
macros/netatalk.m4
macros/summary.m4
test/afpd/Makefile.am

diff --combined config/Makefile.am
index d7a0906e02c46e03b3025c19cbfe2059fa2eea67,e72c38f39f3044065f772f7e4c79e7562b1b0cf4..3fd2872c160ffda0b0066e385f006480369852d9
@@@ -3,16 -3,22 +3,22 @@@
  SUBDIRS = pam
  SUFFIXES = .tmpl .
  
 -TMPLFILES = afp.conf.tmpl
 -GENFILES = afp.conf
 +TMPLFILES = afp.conf.tmpl dbus-session.conf.tmpl
 +GENFILES = afp.conf dbus-session.conf
  CLEANFILES = $(GENFILES)
- EXTRA_DIST = afp.conf.tmpl extmap.conf dbus-session.conf.tmpl
 -EXTRA_DIST = afp.conf.tmpl extmap.conf netatalk-dbus.conf
++EXTRA_DIST = afp.conf.tmpl extmap.conf dbus-session.conf.tmpl 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
  #
@@@ -41,9 -47,6 +47,9 @@@ uninstall-local
        done
        rm -f $(DESTDIR)$(localstatedir)/netatalk/README
        rm -f $(DESTDIR)$(localstatedir)/netatalk/CNID/README
 +if HAVE_TRACKER_RDF
 +      rm -f $(DESTDIR)$(pkgconfdir)/tracker/tracker.cfg
 +endif
  if USE_DEBIAN
        rm -f $(DESTDIR)/etc/default/netatalk
  endif
@@@ -66,11 -69,3 +72,11 @@@ install-config-files: $(CONFFILES) $(GE
                        echo "not overwriting $$f"; \
                fi; \
        done
 +if HAVE_TRACKER_RDF
 +      if test "x$(OVERWRITE_CONFIG)" = "xyes" -o ! -f $(DESTDIR)$(pkgconfdir)/tracker/tracker.cfg ; then \
 +              if test ! -d $(DESTDIR)$(pkgconfdir)/tracker ; then \
 +                      mkdir $(DESTDIR)$(pkgconfdir)/tracker ; \
 +              fi ; \
 +              $(INSTALL_DATA) tracker.cfg $(DESTDIR)$(pkgconfdir)/tracker/ ; \
 +      fi
 +endif
diff --combined configure.ac
index 0b5a752e520d84f1da9133964c9e0816b17cec47,566df4f4618623ab246041b84185063b6fe59ec4..d79766086256004481f73d33fe8e2670754fb9d7
@@@ -25,8 -25,6 +25,8 @@@ AC_PROG_P
  AM_PROG_CC_C_O
  AC_C_BIGENDIAN
  AC_C_INLINE
 +AC_PROG_LEX
 +AC_PROG_YACC
  
  dnl Check if we can use attribute unused (gcc only) from ethereal
  AC_MSG_CHECKING(to see if we can add '__attribute__((unused))' to CFLAGS)
@@@ -182,19 -180,22 +182,25 @@@ AC_NETATALK_SENDFIL
  dnl Check whether bundled libevent shall not be used
  AC_NETATALK_LIBEVENT
  
 +dnl Check for Tracker
 +AC_NETATALK_SPOTLIGHT
 +
  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
  
  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)
@@@ -249,7 -250,6 +255,7 @@@ AC_OUTPUT([Makefil
        etc/afpd/Makefile
        etc/cnid_dbd/Makefile
        etc/netatalk/Makefile
 +      etc/spotlight/Makefile
        etc/uams/Makefile
        include/Makefile
        include/atalk/Makefile
        libatalk/compat/Makefile
        libatalk/dsi/Makefile
        libatalk/iniparser/Makefile
 +      libatalk/talloc/Makefile
        libatalk/tdb/Makefile
        libatalk/unicode/Makefile
        libatalk/unicode/charsets/Makefile
diff --combined etc/afpd/Makefile.am
index 6372f7ea4ddc97dc85d24a33e070902bcdf5eb12,2e242d957ae43463e96bcaf896ecd5fedf609c29..47b8e2760bc39c66d75c6d40f326cde29574dc0c
@@@ -1,9 -1,13 +1,13 @@@
  # Makefile.am for etc/afpd/
  
  pkgconfdir = @PKGCONFDIR@
+ BUILT_SOURCES =
+ EXTRA_DIST =
+ CLEANFILES =
+ DISTCLEANFILES =
  
  sbin_PROGRAMS = afpd
 -noinst_PROGRAMS = hash fce
 +noinst_PROGRAMS = hash fce spot
  
  afpd_SOURCES = \
        afp_avahi.c \
@@@ -35,8 -39,6 +39,8 @@@
        nfsquota.c \
        ofork.c \
        quota.c \
 +      spotlight.c \
 +      spotlight_marshalling.c \
        status.c \
        switch.c \
        uam.c \
@@@ -44,6 -46,7 +48,7 @@@
        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@
@@@ -63,11 -66,37 +68,37 @@@ if HAVE_ACL
  afpd_SOURCES += acls.c
  endif
  
+ if HAVE_DBUS_GLIB
+ BUILT_SOURCES += afpstats_service_glue.h
+ EXTRA_DIST += afpstats-service.xml
+ 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
  fce_SOURCES = fce_api.c fce_util.c
  fce_CFLAGS = -DFCE_TEST_MAIN -I$(top_srcdir)/include
  fce_LDADD = $(top_builddir)/libatalk/libatalk.la
 +
 +spot_SOURCES = spotlight.c spotlight_marshalling.c
 +spot_CFLAGS = -DSPOT_TEST_MAIN
 +spot_LDADD = $(top_builddir)/libatalk/libatalk.la
diff --combined etc/afpd/afp_dsi.c
index 7549fbdf9c5d38d5e71bbb552ce089480a72b6ee,5082ee70fea0f83d6d528fcc49a875520376d99c..63d2f286499db68372e57bfa1e285e7fa9273b06
@@@ -39,7 -39,6 +39,7 @@@
  #include <atalk/fce_api.h>
  #include <atalk/globals.h>
  #include <atalk/netatalk_conf.h>
 +#include <atalk/spotlight.h>
  
  #include "switch.h"
  #include "auth.h"
@@@ -474,10 -473,8 +474,12 @@@ void afp_over_dsi(AFPObj *obj
      int flag = 1;
      setsockopt(dsi->socket, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
  
 +    /* Initialize Spotlight */
 +    if ((obj->options.flags & OPTION_SPOTLIGHT) && (obj->options.slmod_path))
 +        sl_mod_load(obj->options.slmod_path);
 +
+     ipc_child_state(obj, DSI_RUNNING);
      /* get stuck here until the end */
      while (1) {
          if (sigsetjmp(recon_jmp, 1) != 0)
                  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);
              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  */
          }
              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) {
  
                      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));
  
  
                  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 --combined etc/afpd/auth.c
index 7a211bb815a4c1910888c45af60532ebae229a7e,bec624dc6cd32efc72b9838381a5b8f12ad6593b..dcb36a2ce4701f260273cafeab5a859fd9ab664a
@@@ -39,7 -39,7 +39,8 @@@ extern void afp_get_cmdline( int *ac, c
  #include <atalk/server_ipc.h>
  #include <atalk/uuid.h>
  #include <atalk/globals.h>
 +#include <atalk/spotlight.h>
+ #include <atalk/unix.h>
  
  #include "auth.h"
  #include "uam_auth.h"
@@@ -184,7 -184,7 +185,7 @@@ static int set_auth_switch(const AFPOb
          case 31:
              uam_afpserver_action(AFP_SYNCDIR, UAM_AFPSERVER_POSTAUTH, afp_syncdir, NULL);
              uam_afpserver_action(AFP_SYNCFORK, UAM_AFPSERVER_POSTAUTH, afp_syncfork, NULL);
 -            uam_afpserver_action(AFP_SPOTLIGHT_PRIVATE, UAM_AFPSERVER_POSTAUTH, afp_null_nolog, NULL);
 +            uam_afpserver_action(AFP_SPOTLIGHT_PRIVATE, UAM_AFPSERVER_POSTAUTH, afp_spotlight_rpc, NULL);
              uam_afpserver_action(AFP_ENUMERATE_EXT2, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext2, NULL);
  
          case 30:
      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
      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);
@@@ -376,6 -335,7 +336,7 @@@ int afp_zzz(AFPObj *obj, char *ibuf, si
          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 */
          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);
          }
      }
  
diff --combined etc/afpd/file.c
index 4c7eed5741ac87d3e0a8dc4b992bff4f763580ae,bd516087a78debe218e6d0654b38f2ceea1b251e..307f6204f02d7155c2c6aa4dfe8293522f53cda1
@@@ -25,7 -25,6 +25,7 @@@
  #include <atalk/globals.h>
  #include <atalk/fce_api.h>
  #include <atalk/netatalk_conf.h>
 +#include <atalk/spotlight.h>
  
  #include "directory.h"
  #include "dircache.h"
@@@ -220,7 -219,10 +220,10 @@@ restart
             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) {
@@@ -753,9 -755,9 +756,9 @@@ createfile_iderr
      ad_flush(&ad);
      ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF );
      fce_register(FCE_FILE_CREATE, fullpathname(upath), NULL, fce_file);
 +    sl_index_file(path);
  
      curdir->d_offcnt++;
 -
      setvoltime(obj, vol );
  
      return (retvalue);
@@@ -1603,8 -1605,15 +1606,15 @@@ int deletefile(const struct vol *vol, i
          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();
+             }
          }
      }
  
@@@ -1677,7 -1686,10 +1687,10 @@@ int afp_createid(AFPObj *obj _U_, char 
              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;
@@@ -1710,7 -1722,9 +1723,9 @@@ static int reenumerate_loop(struct dire
          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;
  }
@@@ -1789,7 -1803,10 +1804,10 @@@ int afp_resolveid(AFPObj *obj, char *ib
          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 */
      }
  
@@@ -1892,7 -1909,10 +1910,10 @@@ int afp_deleteid(AFPObj *obj _U_, char 
      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;
      }
  
          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;
              return AFPERR_PARAM;
          }
      }
+     AFP_CNID_DONE();
      return err;
  }
  
@@@ -2064,7 -2086,9 +2087,9 @@@ int afp_exchangefiles(AFPObj *obj, cha
      
      /* 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 */
  
      /* 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
          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 --combined etc/afpd/main.c
index 268643c0c73d0a233102841974ba62b81f619020,2265047958dc35f5b56512f272b129d0984652fd..76095b8ccd1e6ff43356c4a5284013c8cd849eb3
@@@ -38,6 -38,7 +38,7 @@@
  #include "fork.h"
  #include "uam_auth.h"
  #include "afp_zeroconf.h"
+ #include "afpstats.h"
  
  #define AFP_LISTENERS 32
  #define FDSET_SAFETY  5
@@@ -319,13 -320,18 +320,18 @@@ int main(int ac, char **av
  
      /* Initialize */
      cnid_init();
 -    
 +
      /* watch atp, dsi sockets and ipc parent/child file descriptor. */
      fd_set_listening_sockets(&obj);
  
      /* set limits */
      (void)setlimits();
  
+ #ifdef HAVE_DBUS_GLIB
+     /* Run dbus AFP statics thread */
+     (void)afpstats_init(server_children);
+ #endif
      afp_child_t *child;
      int recon_ipc_fd;
      pid_t pid;
diff --combined etc/netatalk/netatalk.c
index 81df96105a7c69cffb23da3f250dbe2f43a685ba,b3ab20a159a232c82f1ce739b6e89947b1b3484f..8c46e4f5ca0fce631f17ede35ca3aa0319579672
@@@ -40,8 -40,6 +40,8 @@@
  #include <atalk/errchk.h>
  #include <atalk/globals.h>
  #include <atalk/netatalk_conf.h>
 +#include <atalk/bstrlib.h>
 +#include <atalk/bstradd.h>
  
  #include <event2/event.h>
  
@@@ -54,50 -52,11 +54,50 @@@ static void kill_childs(int sig, ...)
  
  /* static variables */
  static AFPObj obj;
 -static pid_t afpd_pid = -1,  cnid_metad_pid = -1;
 -static uint afpd_restarts, cnid_metad_restarts;
 +static pid_t afpd_pid = -1,  cnid_metad_pid = -1, dbus_pid = -1, trackerd_pid = -1;
 +static uint afpd_restarts, cnid_metad_restarts, dbus_restarts, trackerd_restarts;
  static struct event_base *base;
  struct event *sigterm_ev, *sigquit_ev, *sigchld_ev, *timer_ev;
  static int in_shutdown;
 +static const char *dbus_path;
 +static char *trackerd_loglev;
 +
 +/******************************************************************
 + * Misc stuff
 + ******************************************************************/
 +
 +/* Set Tracker Miners to index all our volumes */
 +static int set_sl_volumes(void)
 +{
 +    EC_INIT;
 +    const struct vol *volumes, *vol;
 +    struct bstrList *vollist = bstrListCreate();
 +    bstring sep = bfromcstr(", ");
 +    bstring volnamelist = NULL, cmd = NULL;
 +
 +    EC_NULL_LOG( volumes = getvolumes() );
 +
 +    for (vol = volumes; vol; vol = vol->v_next) {
 +        bstring volnamequot = bformat("'%s'", vol->v_path);
 +        bstrListPush(vollist, volnamequot);
 +    }
 +
 +    volnamelist = bjoin(vollist, sep);
 +    cmd = bformat("gsettings set org.freedesktop.Tracker.Miner.Files index-recursive-directories \"[%s]\"", bdata(volnamelist));
 +    LOG(log_debug, logtype_sl, "set_sl_volumes: %s", bdata(cmd));
 +    system(bdata(cmd));
 +
 +EC_CLEANUP:
 +    if (cmd)
 +        bdestroy(cmd);
 +    if (sep)
 +        bdestroy(sep);
 +    if (vollist)
 +        bstrListDestroy(vollist);
 +    if (volnamelist)
 +        bdestroy(volnamelist);
 +    EC_EXIT;
 +}
  
  /******************************************************************
   * libevent helper functions
@@@ -154,27 -113,21 +154,27 @@@ static void sigterm_cb(evutil_socket_t 
      event_del(sigquit_ev);
      event_del(timer_ev);
  
 -    kill_childs(SIGTERM, &afpd_pid, &cnid_metad_pid, NULL);
 +#ifdef HAVE_TRACKER_SPARQL
 +    system("tracker-control -t");
 +#endif
 +    kill_childs(SIGTERM, &afpd_pid, &cnid_metad_pid, &dbus_pid, &trackerd_pid, NULL);
  }
  
  /* SIGQUIT callback */
  static void sigquit_cb(evutil_socket_t fd, short what, void *arg)
  {
      LOG(log_note, logtype_afpd, "Exiting on SIGQUIT");
 -    kill_childs(SIGQUIT, &afpd_pid, &cnid_metad_pid, NULL);
 +#ifdef HAVE_TRACKER_SPARQL
 +    system("tracker-control -t");
 +#endif
 +    kill_childs(SIGQUIT, &afpd_pid, &cnid_metad_pid, &dbus_pid, &trackerd_pid, NULL);
  }
  
 -/* SIGQUIT callback */
 +/* SIGHUP callback */
  static void sighup_cb(evutil_socket_t fd, short what, void *arg)
  {
      LOG(log_note, logtype_afpd, "Received SIGHUP, sending all processes signal to reload config");
 -    kill_childs(SIGHUP, &afpd_pid, &cnid_metad_pid, NULL);
 +    kill_childs(SIGHUP, &afpd_pid, &cnid_metad_pid, &trackerd_pid, NULL);
  }
  
  /* SIGCHLD callback */
@@@ -183,32 -136,30 +183,32 @@@ static void sigchld_cb(evutil_socket_t 
      int status;
      pid_t pid;
  
 -    LOG(log_debug, logtype_afpd, "Got SIGCHLD event");
 -  
      while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
          if (WIFEXITED(status)) {
              if (WEXITSTATUS(status))
 -                LOG(log_info, logtype_afpd, "child[%d]: exited %d", pid, WEXITSTATUS(status));
 +                LOG(log_info, logtype_default, "child[%d]: exited %d", pid, WEXITSTATUS(status));
              else
 -                LOG(log_info, logtype_afpd, "child[%d]: done", pid);
 +                LOG(log_info, logtype_default, "child[%d]: done", pid);
          } else {
              if (WIFSIGNALED(status))
 -                LOG(log_info, logtype_afpd, "child[%d]: killed by signal %d", pid, WTERMSIG(status));
 +                LOG(log_info, logtype_default, "child[%d]: killed by signal %d", pid, WTERMSIG(status));
              else
 -                LOG(log_info, logtype_afpd, "child[%d]: died", pid);
 +                LOG(log_info, logtype_default, "child[%d]: died", pid);
          }
  
          if (pid == afpd_pid)
              afpd_pid = -1;
          else if (pid == cnid_metad_pid)
              cnid_metad_pid = -1;
 +        else if (pid == dbus_pid)
 +            dbus_pid = -1;
 +        else if (pid == trackerd_pid)
 +            trackerd_pid = -1;
          else
              LOG(log_error, logtype_afpd, "Bad pid: %d", pid);
      }
  
 -    if (in_shutdown && afpd_pid == -1 && cnid_metad_pid == -1)
 +    if (in_shutdown && afpd_pid == -1 && cnid_metad_pid == -1 && dbus_pid == -1 && trackerd_pid == -1)
          event_base_loopbreak(base);
  }
  
@@@ -222,7 -173,7 +222,7 @@@ static void timer_cb(evutil_socket_t fd
          afpd_restarts++;
          LOG(log_note, logtype_afpd, "Restarting 'afpd' (restarts: %u)", afpd_restarts);
          if ((afpd_pid = run_process(_PATH_AFPD, "-d", "-F", obj.options.configfile, NULL)) == -1) {
 -            LOG(log_error, logtype_afpd, "Error starting 'afpd'");
 +            LOG(log_error, logtype_default, "Error starting 'afpd'");
          }
      }
  
          cnid_metad_restarts++;
          LOG(log_note, logtype_afpd, "Restarting 'cnid_metad' (restarts: %u)", cnid_metad_restarts);
          if ((cnid_metad_pid = run_process(_PATH_CNID_METAD, "-d", "-F", obj.options.configfile, NULL)) == -1) {
 -            LOG(log_error, logtype_afpd, "Error starting 'cnid_metad'");
 +            LOG(log_error, logtype_default, "Error starting 'cnid_metad'");
 +        }
 +    }
 +
 +    if (dbus_pid == -1) {
 +        dbus_restarts++;
 +        LOG(log_note, logtype_afpd, "Restarting 'dbus' (restarts: %u)", dbus_restarts);
 +        if ((dbus_pid = run_process(dbus_path, "--config-file=" _PATH_CONFDIR "dbus.session.conf", NULL)) == -1) {
 +            LOG(log_error, logtype_default, "Error starting '%s'", dbus_path);
          }
      }
 +
 +#ifdef HAVE_TRACKER_RDF
 +    if (trackerd_pid == -1) {
 +        trackerd_restarts++;
 +        LOG(log_note, logtype_afpd, "Restarting 'trackerd' (restarts: %u)", trackerd_restarts);
 +        if ((trackerd_pid = run_process(TRACKER_RDF_PREFIX "/bin/trackerd", trackerd_loglev, NULL)) == -1) {
 +            LOG(log_error, logtype_default, "Error starting '%s'", "/usr/bin/trackerd");
 +        }
 +    }
 +#endif
  }
  
  /******************************************************************
@@@ -284,8 -217,7 +284,8 @@@ static void netatalk_exit(int ret
  static pid_t run_process(const char *path, ...)
  {
      int ret, i = 0;
 -    char *myargv[10];
 +#define MYARVSIZE 64
 +    char *myargv[MYARVSIZE];
      va_list args;
      pid_t pid;
  
      if (pid == 0) {
          myargv[i++] = (char *)path;
          va_start(args, path);
 -        while ((myargv[i++] = va_arg(args, char *)) != NULL)
 -            ;
 +        while (i < MYARVSIZE) {
 +            if ((myargv[i++] = va_arg(args, char *)) == NULL)
 +                break;
 +        }
          va_end(args);
  
          ret = execv(path, myargv);
@@@ -355,15 -285,13 +355,15 @@@ int main(int argc, char **argv
      if (afp_config_parse(&obj, "netatalk") != 0)
          netatalk_exit(EXITERR_CONF);
  
 +    load_volumes(&obj);
 +
      event_set_log_callback(libevent_logmsg_cb);
      event_set_fatal_callback(netatalk_exit);
  
      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);
      }
  
      sigdelset(&blocksigs, SIGHUP);
      sigprocmask(SIG_SETMASK, &blocksigs, NULL);
  
 +#ifdef HAVE_TRACKER
 +    setenv("DBUS_SESSION_BUS_ADDRESS", "unix:path=/tmp/spotlight.ipc", 1);
 +    setenv("XDG_DATA_HOME", _PATH_STATEDIR, 0);
 +    setenv("XDG_CACHE_HOME", _PATH_STATEDIR, 0);
 +    setenv("XDG_CONFIG_HOME", _PATH_CONFDIR, 0);
 +#endif
 +
 +#ifdef HAVE_TRACKER_RDF
 +    /* This assumes Tracker 0.6 with RDF is only used on Solaris and derived platforms */
 +    dbus_path = iniparser_getstring(obj.iniconfig, INISEC_GLOBAL, "dbus daemon path", "/usr/lib/dbus-daemon");
 +#else
 +    dbus_path = iniparser_getstring(obj.iniconfig, INISEC_GLOBAL, "dbus daemon path", "/bin/dbus-daemon");
 +#endif
 +    LOG(log_debug, logtype_default, "DBUS: '%s'", dbus_path);
 +    if ((dbus_pid = run_process(dbus_path, "--config-file=" _PATH_CONFDIR "dbus-session.conf", NULL)) == -1) {
 +        LOG(log_error, logtype_default, "Error starting '%s'", dbus_path);
 +        netatalk_exit(EXITERR_CONF);
 +    }
 +
 +    /* Allow dbus some time to start up */
 +    sleep(1);
 +
 +#ifdef HAVE_TRACKER_SPARQL
 +    set_sl_volumes();
 +    system(TRACKER_PREFIX "/bin/tracker-control -s");
 +#endif
 +#ifdef HAVE_TRACKER_RDF
 +    if (asprintf(&trackerd_loglev, "--verbosity=%d", obj.options.tracker_loglevel) == -1)
 +        netatalk_exit(EXITERR_CONF);
 +    if ((trackerd_pid = run_process(TRACKER_RDF_PREFIX "/bin/trackerd", trackerd_loglev, NULL)) == -1) {
 +        LOG(log_error, logtype_default, "Error starting '%s'", TRACKER_RDF_PREFIX "/bin/trackerd");
 +        netatalk_exit(EXITERR_CONF);
 +    }
 +#endif
 +
      /* run the event loop */
      ret = event_base_dispatch(base);
  
 -    if (afpd_pid != -1 || cnid_metad_pid != -1) {
 +    if (afpd_pid != -1 || cnid_metad_pid != -1 || dbus_pid != -1 || trackerd_pid != -1) {
          if (afpd_pid != -1)
              LOG(log_error, logtype_afpd, "AFP service did not shutdown, killing it");
          if (cnid_metad_pid != -1)
              LOG(log_error, logtype_afpd, "CNID database service did not shutdown, killing it");
 -        kill_childs(SIGKILL, &afpd_pid, &cnid_metad_pid, NULL);
 +        if (dbus_pid != -1)
 +            LOG(log_error, logtype_afpd, "DBUS session daemon still running, killing it");
 +        if (trackerd_pid != -1)
 +            LOG(log_error, logtype_afpd, "trackerd still running, killing it");
 +        kill_childs(SIGKILL, &afpd_pid, &cnid_metad_pid, &dbus_pid, &trackerd_pid, NULL);
      }
  
      LOG(log_note, logtype_afpd, "Netatalk AFP server exiting");
index 8c58f0e9d8a35821956981e4bae67426d019c063,42085187de9665cefac9ca580b6c2ce541b59270..2f63e0f676e76edea239c6738f93c6751e3522e4
@@@ -1,6 -1,8 +1,8 @@@
  # Makefile.am for include/atalk/
  
  atalkincludedir = $(includedir)/atalk
+ BUILT_SOURCES = 
+ CLEANFILES =
  
  atalkinclude_HEADERS = \
        adouble.h \
@@@ -40,8 -42,13 +42,17 @@@ noinst_HEADERS = 
        ftw.h \
        dsi.h \
        ldapconfig.h \
 -      fce_api.h
 +      talloc.h \
 +      dalloc.h \
 +      byteorder.h \
 +      fce_api.h \
 +      spotlight.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 --combined include/atalk/dsi.h
index 0427da1f9ab4aee41b4253dbff616fc6b0bcbf19,fc1af468ac3156934f4ce1771bb19e7ed18591b4..11452550fb14817be673860dc81cf4c93897f9a7
@@@ -53,7 -53,7 +53,7 @@@ struct dsi_block 
      uint32_t dsi_reserved;   /* reserved field */
  };
  
 -#define DSI_DATASIZ       8192
 +#define DSI_DATASIZ       65536
  
  /* child and parent processes might interpret a couple of these
   * differently. */
@@@ -154,9 -154,6 +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);
diff --combined include/atalk/globals.h
index f857db24abb5f393423102e6cd0ffc6ba2b211ec,e5fbb292f9ba1cf561141d3e18c8eabfe37d6629..455a92b5fc95977b39b1a6eefa682810838a8eba
  #include <atalk/unicode.h>
  #include <atalk/uam.h>
  #include <atalk/iniparser.h>
+ #ifdef WITH_DTRACE
+ #include <atalk/afp_dtrace.h>
+ #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 */
@@@ -42,7 -55,7 +55,7 @@@
  #define OPTION_ACL2MACCESS   (1 << 8)
  #define OPTION_NOZEROCONF    (1 << 9)
  #define OPTION_SHARE_RESERV  (1 << 11) /* whether to use Solaris fcntl F_SHARE locks */
 -
 +#define OPTION_SPOTLIGHT     (1 << 12) /* whether to enable Spotlight support */
  #define PASSWD_NONE     0
  #define PASSWD_SET     (1 << 0)
  #define PASSWD_NOSAVE  (1 << 1)
@@@ -102,8 -115,6 +115,8 @@@ struct afp_options 
      char *logfile;
      char *mimicmodel;
      char *adminauthuser;
 +    char *slmod_path;
 +    int tracker_loglevel;
      struct afp_volume_name volfile;
  };
  
diff --combined libatalk/util/logger.c
index 7290867b459ae8a5d6187530c2d1ca2eda30b0b3,944234266eb4dc716144d5b1dc3f74021c341e49..4bf0e33802551ee3fac2a17cfadae4117360ae2d
@@@ -62,7 -62,6 +62,7 @@@ Netatalk 2001 (c
    "UAMS",                            \
    "FCE",                             \
    "ad",                              \
 +  "Spotlight",                       \
    "end_of_list_marker"}
  
  /* =========================================================================
@@@ -87,9 -86,8 +87,9 @@@ UAM_MODULE_EXPORT logtype_conf_t type_c
      DEFAULT_LOG_CONFIG, /* logtype_afpd */
      DEFAULT_LOG_CONFIG, /* logtype_dsi */
      DEFAULT_LOG_CONFIG, /* logtype_uams */
 -    DEFAULT_LOG_CONFIG,  /* logtype_fce */
 -    DEFAULT_LOG_CONFIG  /* logtype_ad */
 +    DEFAULT_LOG_CONFIG, /* logtype_fce */
 +    DEFAULT_LOG_CONFIG, /* logtype_ad */
 +    DEFAULT_LOG_CONFIG  /* logtype_sl */
  };
  
  static void syslog_setup(int loglevel, enum logtypes logtype, int display_options, int facility);
@@@ -596,11 -594,8 +596,8 @@@ log
                                   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));
      }
index 9636922b81487b1bc6000ac1885763b0bbd093da,b51b2a0d13cffad8d1b7c70bbcc4e3077c22e5f2..e56701ad18c3eed122c87e7aacdb15ffd3721756
@@@ -916,16 -916,16 +916,16 @@@ static struct vol *creatvol(AFPObj *obj
      initvol_vfs(volume);
  
      /* get/store uuid from file in afpd master*/
 -    if (!(pwd) && (volume->v_flags & AFPVOL_TM)) {
 -        char *uuid = get_vol_uuid(obj, volume->v_localname);
 -        if (!uuid) {
 -            LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID",
 -                volume->v_localname);
 -        } else {
 -            volume->v_uuid = uuid;
 -            LOG(log_debug, logtype_afpd, "Volume '%s': UUID '%s'",
 -                volume->v_localname, volume->v_uuid);
 -        }
 +    become_root();
 +    char *uuid = get_vol_uuid(obj, volume->v_localname);
 +    unbecome_root();
 +    if (!uuid) {
 +        LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID",
 +            volume->v_localname);
 +    } else {
 +        volume->v_uuid = uuid;
 +        LOG(log_debug, logtype_afpd, "Volume '%s': UUID '%s'",
 +            volume->v_localname, volume->v_uuid);
      }
  
      /* no errors shall happen beyond this point because the cleanup would mess the volume chain up */
@@@ -1323,6 -1323,9 +1323,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;
          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) );
          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 -1441,56 +1441,56 @@@ struct vol *getvolbyvid(const uint16_t 
      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
   *
   * (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 -1601,14 +1601,14 @@@ struct vol *getvolbypath(AFPObj *obj, c
          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);
  
@@@ -1622,12 -1692,6 +1692,12 @@@ int afp_config_parse(AFPObj *AFPObj, ch
      options->configfile  = AFPObj->cmdlineconfigfile ? strdup(AFPObj->cmdlineconfigfile) : strdup(_PATH_CONFDIR "afp.conf");
      options->sigconffile = strdup(_PATH_STATEDIR "afp_signature.conf");
      options->uuidconf    = strdup(_PATH_STATEDIR "afp_voluuid.conf");
 +#ifdef HAVE_TRACKER_SPARQL
 +    options->slmod_path  = strdup(_PATH_AFPDUAMPATH "slmod_sparql.so");
 +#endif
 +#ifdef HAVE_TRACKER_RDF
 +    options->slmod_path  = strdup(_PATH_AFPDUAMPATH "slmod_rdf.so");
 +#endif
      options->flags       = OPTION_UUID | AFPObj->cmdlineflags;
      
      if ((config = iniparser_load(AFPObj->options.configfile)) == NULL)
          options->flags |= OPTION_SHARE_RESERV;
      if (iniparser_getboolean(config, INISEC_GLOBAL, "afp read locks", 0))
          options->flags |= OPTION_AFP_READ_LOCK;
 +    if (iniparser_getboolean(config, INISEC_GLOBAL, "spotlight", 0))
 +        options->flags |= OPTION_SPOTLIGHT;
      if (!iniparser_getboolean(config, INISEC_GLOBAL, "save password", 1))
          options->passwdbits |= PASSWD_NOSAVE;
      if (iniparser_getboolean(config, INISEC_GLOBAL, "set password", 0))
      options->fce_fmodwait   = iniparser_getint   (config, INISEC_GLOBAL, "fce holdfmod",   60);
      options->sleep          = iniparser_getint   (config, INISEC_GLOBAL, "sleep time",     10);
      options->disconnected   = iniparser_getint   (config, INISEC_GLOBAL, "disconnect time",24);
 +    options->tracker_loglevel = iniparser_getint (config, INISEC_GLOBAL, "tracker loglevel", 1);
  
      if ((p = iniparser_getstring(config, INISEC_GLOBAL, "hostname", NULL))) {
          EC_NULL_LOG( options->hostname = strdup(p) );
@@@ -1886,8 -1947,6 +1956,8 @@@ void afp_config_free(AFPObj *obj
          CONFIG_ARG_FREE(obj->options.Cnid_port);
      if (obj->options.fqdn)
          CONFIG_ARG_FREE(obj->options.fqdn);
 +    if (obj->options.slmod_path)
 +        CONFIG_ARG_FREE(obj->options.slmod_path);
  
      if (obj->options.unixcodepage)
          CONFIG_ARG_FREE(obj->options.unixcodepage);
diff --combined macros/netatalk.m4
index cafa285d5d7e3cd887170c179347c13c4317b245,70ada56ce07ca1ace0f85535a74694ac23c55f36..ddaa2521408779f1ca88f824ebd241cae05c8b77
@@@ -1,5 -1,65 +1,65 @@@
  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], [
+     PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.1, have_dbus=yes, have_dbus=no)
+     PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0 >= 2.6, 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)
+     AM_CONDITIONAL(HAVE_DBUS_GLIB, test x$have_dbus_glib = xyes -a x$have_dbus = xyes)
+     AC_ARG_WITH(
+         dbus-sysconf-dir,
+         [AS_HELP_STRING([--with-dbus-sysconf-dir],[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$have_dbus_glib = xyes -a x$have_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])
      AM_CONDITIONAL(DEVELOPER, test x"$enable_dev" = x"yes")
  ])
  
 +dnl Tracker, for Spotlight
 +AC_DEFUN([AC_NETATALK_SPOTLIGHT], [
 +    ac_cv_have_tracker=no
 +    dnl Tracker SPARQL
 +    ac_cv_tracker_pkg_default=tracker-sparql-0.12
 +    AC_ARG_WITH([tracker-pkg-config],
 +      [AS_HELP_STRING([--with-tracker-pkg-config],[name of the Tracker SPARQL pkg in pkg-config])],
 +      [ac_cv_tracker_pkg=$withval],
 +      [ac_cv_tracker_pkg=$ac_cv_tracker_pkg_default])
 +
 +    PKG_CHECK_MODULES([TRACKER], [$ac_cv_tracker_pkg >= 0.12], [ac_cv_have_tracker_sparql=yes], [ac_cv_have_tracker_sparql=no])
 +
 +    if test x"$ac_cv_have_tracker_sparql" = x"no" ; then
 +        if test x"$need_tracker" = x"yes" ; then
 +            AC_MSG_ERROR([$ac_cv_tracker_pkg not found])
 +        fi
 +    else
 +        AC_DEFINE(HAVE_TRACKER, 1, [Define if Tracker is available])
 +        AC_DEFINE(HAVE_TRACKER_SPARQL, 1, [Define if Tracker SPARQL is available])
 +        ac_cv_tracker_prefix=`pkg-config --variable=prefix $ac_cv_tracker_pkg`
 +        AC_DEFINE_UNQUOTED(TRACKER_PREFIX, ["$ac_cv_tracker_prefix"], [Path to Tracker])
 +      fi
 +
 +    ac_cv_tracker_miner_pkg_default=tracker-miner-0.12
 +    AC_ARG_WITH([tracker-miner-pkg-config],
 +      [AS_HELP_STRING([--with-tracker-miner-pkg-config],[name of the Tracker miner pkg in pkg-config])],
 +      [ac_cv_tracker_miner_pkg=$withval],
 +      [ac_cv_tracker_miner_pkg=$ac_cv_tracker_miner_pkg_default])
 +
 +    PKG_CHECK_MODULES([TRACKER_MINER], [$ac_cv_tracker_miner_pkg >= 0.12], [ac_cv_have_tracker_miner=yes], [ac_cv_have_tracker_miner=no])
 +
 +    if test x"$ac_cv_have_tracker_miner" = x"yes" ; then
 +        AC_DEFINE(HAVE_TRACKER_MINER, 1, [Define if Tracker miner library is available])
 +        AC_SUBST(TRACKER_MINER_CFLAGS)
 +        AC_SUBST(TRACKER_MINER_LIBS)
 +      fi
 +
 +    dnl Test for Tracker 0.6 on Solaris and derived platforms
 +    if test x"$this_os" = x"solaris" ; then
 +        PKG_CHECK_MODULES([TRACKER], [tracker >= 0.6], [ac_cv_have_tracker_rdf=yes], [ac_cv_have_tracker_rdf=no])
 +        if test x"$ac_cv_have_tracker_rdf" = x"yes" ; then
 +            AC_DEFINE(HAVE_TRACKER, 1, [Define if Tracker is available])
 +            AC_DEFINE(HAVE_TRACKER_RDF, 1, [Define if Tracker 0.6 with support for RDF queries is available])
 +            ac_cv_tracker_prefix=`pkg-config --variable=prefix tracker`
 +            AC_DEFINE_UNQUOTED(TRACKER_RDF_PREFIX, ["$ac_cv_tracker_prefix"], [Path to Tracker])
 +          fi
 +    fi
 +
 +    if test x"$ac_cv_have_tracker_sparql" = x"yes" -o x"$ac_cv_have_tracker_rdf" = x"yes" ; then
 +       ac_cv_have_tracker=yes
 +    fi
 +    AC_SUBST(TRACKER_CFLAGS)
 +    AC_SUBST(TRACKER_LIBS)
 +    AM_CONDITIONAL(HAVE_TRACKER_SPARQL, [test x"$ac_cv_have_tracker_sparql" = x"yes"])
 +    AM_CONDITIONAL(HAVE_TRACKER_RDF, [test x"$ac_cv_have_tracker_rdf" = x"yes"])
 +])
 +
  dnl Whether to disable bundled libevent
  AC_DEFUN([AC_NETATALK_LIBEVENT], [
      AC_MSG_CHECKING([whether to use bundled libevent])
diff --combined macros/summary.m4
index f9b8891891fbc89a0504ae66ade17270b18cbec2,2b682a466c2d6d522a560db683260f003425887c..edb136c2e170a151c25e81617612e3fcd033cb2c
@@@ -14,7 -14,6 +14,7 @@@ AC_DEFUN([AC_NETATALK_CONFIG_SUMMARY], 
        AC_MSG_RESULT([    AFP:])
        AC_MSG_RESULT([         Extended Attributes: $neta_cv_eas])
        AC_MSG_RESULT([         ACL support: $with_acl_support])
 +      AC_MSG_RESULT([         Spotlight: $ac_cv_have_tracker])
        AC_MSG_RESULT([    CNID:])
        AC_MSG_RESULT([         backends: $compiled_backends])
        AC_MSG_RESULT([    UAMS:])
@@@ -56,6 -55,9 +56,9 @@@ dnl   AC_MSG_RESULT([         Samba share
        AC_MSG_RESULT([         ACL support:             $with_acl_support])
        AC_MSG_RESULT([         Kerberos support:        $with_kerberos])
        AC_MSG_RESULT([         LDAP support:            $netatalk_cv_ldap])
+       AC_MSG_RESULT([         dbus support:            $have_dbus_glib])
+       AC_MSG_RESULT([         dbus system directory:   $ac_cv_dbus_sysdir])
+       AC_MSG_RESULT([         dtrace probes:           $WDTRACE])
        if test x"$use_pam_so" = x"yes" -a x"$netatalk_cv_install_pam" = x"no"; then
                AC_MSG_RESULT([])
                AC_MSG_WARN([ PAM support was configured for your system, but the netatalk PAM configuration file])
diff --combined test/afpd/Makefile.am
index f7ed8a2715517c51ba679e0bff76d39d2752a34b,34e28f484a371874a1c5a2f57e0ed554980d78b9..6e7c2f46aec3620acd52822430fbcdeedb4cf126
@@@ -38,8 -38,6 +38,8 @@@ test_SOURCES =  test.c subtests.c afpfu
                                $(top_srcdir)/etc/afpd/ofork.c \
                                $(top_srcdir)/etc/afpd/quota.c \
                                $(top_srcdir)/etc/afpd/status.c \
 +                              $(top_srcdir)/etc/afpd/spotlight.c \
 +                              $(top_srcdir)/etc/afpd/spotlight_marshalling.c \
                                $(top_srcdir)/etc/afpd/switch.c \
                                $(top_srcdir)/etc/afpd/uam.c \
                                $(top_srcdir)/etc/afpd/unix.c \
@@@ -66,3 -64,12 +66,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