]> arthur.barton.de Git - netatalk.git/commitdiff
AFP statistics via dbus IPC
authorRalph Boehme <sloowfranklin@gmail.com>
Tue, 5 Feb 2013 16:25:27 +0000 (17:25 +0100)
committerRalph Boehme <sloowfranklin@gmail.com>
Tue, 19 Feb 2013 17:50:12 +0000 (18:50 +0100)
Fix PAM config installation. make distcheck was failing on Solaris
in uninstall, because the uninstall target ran some `rm -f PAMFILE`
where PAMFILE is hardcoded to /etc/pam.d. The resulting EPERM
causes the make target to fail.

30 files changed:
NEWS
config/Makefile.am
config/netatalk-dbus.conf [new file with mode: 0644]
config/pam/.gitignore
config/pam/Makefile.am
config/pam/netatalk.pam.tmpl [deleted file]
config/pam/netatalk.tmpl [new file with mode: 0644]
configure.ac
contrib/shell_utils/Makefile.am
contrib/shell_utils/afpstats [new file with mode: 0755]
etc/afpd/Makefile.am
etc/afpd/afp_dsi.c
etc/afpd/afpstats-service.xml [new file with mode: 0644]
etc/afpd/afpstats.c [new file with mode: 0644]
etc/afpd/afpstats.h [new file with mode: 0644]
etc/afpd/afpstats_obj.c [new file with mode: 0644]
etc/afpd/afpstats_obj.h [new file with mode: 0644]
etc/afpd/afpstats_service_glue.h [new file with mode: 0644]
etc/afpd/auth.c
etc/afpd/main.c
etc/afpd/volume.c
include/atalk/dsi.h
include/atalk/server_child.h
include/atalk/server_ipc.h
libatalk/dsi/dsi_stream.c
libatalk/util/server_child.c
libatalk/util/server_ipc.c
macros/netatalk.m4
macros/pam-check.m4
macros/summary.m4

diff --git a/NEWS b/NEWS
index 461cc85a3026d96afd005bf9931bc10e3ca2ab0d..df015fa52d5f62c271e270a78395dbc28dbff3b5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,13 @@ Changes in 3.0.3
 * 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.       
 
 Changes in 3.0.2
 ================
index 57c85ff3a67250cbcd3ec769f42c3461b5a6766a..e72c38f39f3044065f772f7e4c79e7562b1b0cf4 100644 (file)
@@ -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 (file)
index 0000000..1646efd
--- /dev/null
@@ -0,0 +1,17 @@
+<!DOCTYPE busconfig PUBLIC
+          "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+          "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+  <!-- Only root can own AFP stats service -->
+  <policy user="root">
+    <allow own="org.netatalk.AFPStats"/>
+  </policy>
+
+  <!-- Allow anyone to invoke methods on time-sliderd -->
+  <policy context="default">
+    <allow send_destination="org.netatalk.AFPStats"/>
+    <allow receive_sender="org.netatalk.AFPStats"/>
+  </policy>
+
+</busconfig>
index dbbab4b2b68881f9239845ac8595eec98f1272d7..d209ccf96dcf4b7da7c1d8ae5208136bbe3569a7 100644 (file)
@@ -1,5 +1,5 @@
 Makefile
 Makefile.in
 netatalk.pam
-.gitignore
+netatalk
 *.o
index e01d784c675d54261bdba14f05a5d0321d21c7ad..62affbdac21e5b18603b6cb3879352a3ebab74aa 100644 (file)
@@ -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.pam.tmpl
deleted file mode 100644 (file)
index 1eceba3..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#%PAM-1.0
-auth     @PAM_DIRECTIVE@ @PAM_AUTH@
-account  @PAM_DIRECTIVE@ @PAM_ACCOUNT@
-password @PAM_DIRECTIVE@ @PAM_PASSWORD@
-session  @PAM_DIRECTIVE@ @PAM_SESSION@
diff --git a/config/pam/netatalk.tmpl b/config/pam/netatalk.tmpl
new file mode 100644 (file)
index 0000000..1eceba3
--- /dev/null
@@ -0,0 +1,5 @@
+#%PAM-1.0
+auth     @PAM_DIRECTIVE@ @PAM_AUTH@
+account  @PAM_DIRECTIVE@ @PAM_ACCOUNT@
+password @PAM_DIRECTIVE@ @PAM_PASSWORD@
+session  @PAM_DIRECTIVE@ @PAM_SESSION@
index 3c8843d15bea9f3336cdfec0c42f6745b3ca0284..88f81aaf067b2ee0cbc6caf68e384774fcbd63c6 100644 (file)
@@ -189,6 +189,9 @@ AC_NETATALK_FHS
 dnl netatalk lockfile path, must come after AC_NETATALK_FHS
 AC_NETATALK_LOCKFILE
 
+dnl Check for dbus-glib, for AFP stats on dbus
+AC_NETATALK_DBUS_GLIB
+
 CFLAGS="-I\$(top_srcdir)/include -I\$(top_srcdir)/sys $CFLAGS"
 UAMS_PATH="${uams_path}"
 
index bb4d9cbf0637381a924e0a0d2f41b8364381ce72..dc4c7db7076b6f2b1de73ed7546a2acb1c3a182c 100644 (file)
@@ -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 (executable)
index 0000000..8c5413c
--- /dev/null
@@ -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()
index 2404ad7dbf8fb5df1dd3b707ee7ebe76d9460ebb..1612344a5132232ba3b06262d6e31c4762022f39 100644 (file)
@@ -1,6 +1,10 @@
 # Makefile.am for etc/afpd/
 
 pkgconfdir = @PKGCONFDIR@
+BUILT_SOURCES =
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
 
 sbin_PROGRAMS = afpd
 noinst_PROGRAMS = hash fce
@@ -61,11 +65,28 @@ if HAVE_ACLS
 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) -DDBUS_COMPILATION
+afpd_LDFLAGS += $(DBUS_LIBS) $(DBUS_GLIB_LIBS) -ldbus-glib-1
+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
index 77918c56baa68b343eedd8546bd65f9a612d8ac6..646e8d12f4e3bd555ef9bf9d9a8564b4ee025be1 100644 (file)
@@ -473,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)
@@ -497,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);
@@ -516,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  */
         }
@@ -526,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) {
diff --git a/etc/afpd/afpstats-service.xml b/etc/afpd/afpstats-service.xml
new file mode 100644 (file)
index 0000000..099c778
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<node name="/org/netatalk/AFPStats">
+  <interface name="org.netatalk.AFPStats">
+    <method name="GetUsers">
+       <arg name="ret" type="as" direction="out"/>
+    </method>
+  </interface>
+</node>
diff --git a/etc/afpd/afpstats.c b/etc/afpd/afpstats.c
new file mode 100644 (file)
index 0000000..1dbacdf
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013 Frank Lahm <franklahm@gmail.com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <dbus/dbus-glib.h>
+
+#include <atalk/logger.h>
+#include <atalk/compat.h>
+#include <atalk/errchk.h>
+#include <atalk/server_child.h>
+
+#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;
+    GMainLoop *thread_loop;
+    guint request_name_result;
+    sigset_t sigs;
+
+    /* Block all signals in this thread */
+    sigfillset(&sigs);
+    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
+
+    dbus_g_object_type_install_info(AFPSTATS_TYPE_OBJECT, &dbus_glib_afpstats_obj_object_info);
+
+    thread_loop = g_main_loop_new(NULL, FALSE);
+   
+    if (!(bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &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();
+    (void)g_log_set_default_handler(my_glib_log, NULL);
+    g_thread_init(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 (file)
index 0000000..9f742ad
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Frank Lahm <franklahm@gmail.com>
+ *
+ * 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 <atalk/server_child.h>
+
+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 (file)
index 0000000..755d7a5
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013 Frank Lahm <franklahm@gmail.com>
+ *
+ * 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 <strings.h>
+#include <pwd.h>
+
+#include <glib-object.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include <atalk/logger.h>
+#include <atalk/dsi.h>
+
+#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 (file)
index 0000000..9d83000
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef AFPSTATS_OBJ_H
+#define AFPSTATS_OBJ_H
+
+#include <glib.h>
+
+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 (file)
index 0000000..65081c4
--- /dev/null
@@ -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       <glib-object.h>
+
+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 <dbus/dbus-glib.h>
+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"
+};
+
index 5246d4360f39e34925693de82c058704067d00ef..fa60b192796739d2f3ab1fd50cf0d136928d2cd6 100644 (file)
@@ -375,6 +375,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 +383,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);
         }
     }
 
index a66e4a86f47dae01bd3a23d6a05a5db8bbc2b07e..2265047958dc35f5b56512f272b129d0984652fd 100644 (file)
@@ -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
@@ -326,6 +327,11 @@ int main(int ac, char **av)
     /* 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;
index 9c7eb2bd8bc7537f519a291380ddcb4dc31e5b9d..f51223730c32a5047eedd749d935315613e24ff9 100644 (file)
@@ -39,6 +39,7 @@
 #include <atalk/iniparser.h>
 #include <atalk/unix.h>
 #include <atalk/netatalk_conf.h>
+#include <atalk/server_ipc.h>
 
 #ifdef CNID_DB
 #include <atalk/cnid.h>
@@ -659,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
  */
@@ -834,6 +860,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
             setmessage(msg);
 
         free(vol_mname);
+        server_ipc_volumes(obj);
         return( AFP_OK );
     }
 
@@ -906,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 );
 }
index 4197dba5df563726fbd71ca0041ee708c4b652c9..fc1af468ac3156934f4ce1771bb19e7ed18591b4 100644 (file)
@@ -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);
index 6f8f18a0b7933837cf03f656f8cda51c6721081e..5e69401886dc7856287248f3e6df11bc1e99621e 100644 (file)
@@ -20,10 +20,13 @@ typedef struct afp_child {
     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_time;        /* client boot time (from the mac 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;
@@ -34,7 +37,6 @@ typedef struct {
     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 */
-    void          (*servch_cleanup)(const pid_t);   /* Cleanup handler */
 } server_child_t;
 
 /* server_child.c */
@@ -42,6 +44,7 @@ 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,
index 0765c73c62f5da7e7ac493ed5c0c13b7d51ccf05..50eb7edccc2b303f3611a9d742b7affbb58a661e 100644 (file)
@@ -6,8 +6,11 @@
 
 #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_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 */
index 711a037b5098925c59c77198bb6350d390d9b5a3..6c502b0bcea37796af1c71fe03c5aaa05b0b1442 100644 (file)
@@ -471,10 +471,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",
index 6c86f48375a2ffbd848d46393ae1eb5747074800..da78c6a064bd637418b40f5495653b2f77f5ebdf 100644 (file)
@@ -70,11 +70,11 @@ static inline void unhash_child(afp_child_t *child)
     }
 }
 
-static afp_child_t *resolve_child(afp_child_t **table, pid_t pid)
+afp_child_t *server_child_resolve(server_child_t *childs, id_t pid)
 {
     afp_child_t *child;
 
-    for (child = table[HASH(pid)]; child; child = child->afpch_next) {
+    for (child = childs->servch_table[HASH(pid)]; child; child = child->afpch_next) {
         if (child->afpch_pid == pid)
             break;
     }
@@ -113,7 +113,7 @@ afp_child_t *server_child_add(server_child_t *children, pid_t pid, int ipc_fd)
     }
 
     /* if we already have an entry. just return. */
-    if ((child = resolve_child(children->servch_table, pid)))
+    if ((child = server_child_resolve(children, pid)))
         goto exit;
 
     if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
@@ -121,6 +121,7 @@ afp_child_t *server_child_add(server_child_t *children, pid_t pid, int ipc_fd)
 
     child->afpch_pid = pid;
     child->afpch_ipc_fd = ipc_fd;
+    child->afpch_logintime = time(NULL);
 
     hash_child(children->servch_table, child);
     children->servch_count++;
@@ -136,9 +137,11 @@ int server_child_remove(server_child_t *children, pid_t pid)
     int fd;
     afp_child_t *child;
 
-    if (!(child = resolve_child(children->servch_table, pid)))
+    if (!(child = server_child_resolve(children, pid)))
         return -1;
 
+    pthread_mutex_lock(&children->servch_lock);
+
     unhash_child(child);
     if (child->afpch_clientid) {
         free(child->afpch_clientid);
@@ -153,8 +156,7 @@ int server_child_remove(server_child_t *children, pid_t pid)
     free(child);
     children->servch_count--;
 
-    if (children->servch_cleanup)
-        children->servch_cleanup(pid);
+    pthread_mutex_unlock(&children->servch_lock);
 
     return fd;
 }
@@ -173,6 +175,8 @@ void server_child_free(server_child_t *children)
             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;
         }
@@ -225,7 +229,7 @@ int server_child_transfer_session(server_child_t *children,
     EC_INIT;
     afp_child_t *child;
 
-    if ((child = resolve_child(children->servch_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);
@@ -274,13 +278,15 @@ void server_child_kill_one_by_id(server_child_t *children, pid_t pid,
     afp_child_t *child, *tmp;
     int i;
 
+    pthread_mutex_lock(&children->servch_lock);
+    
     for (i = 0; i < CHILD_HASHSIZE; i++) {
         child = children->servch_table[i];
         while (child) {
             tmp = child->afpch_next;
             if (child->afpch_pid != pid) {
                 if (child->afpch_idlen == idlen && memcmp(child->afpch_clientid, id, idlen) == 0) {
-                    if ( child->afpch_time != boottime ) {
+                    if ( child->afpch_boottime != boottime ) {
                         /* Client rebooted */
                         if (uid == child->afpch_uid) {
                             kill_child(child);
@@ -299,7 +305,7 @@ void server_child_kill_one_by_id(server_child_t *children, pid_t pid,
                 }
             } else {
                 /* update childs own slot */
-                child->afpch_time = boottime;
+                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);
@@ -311,6 +317,8 @@ void server_child_kill_one_by_id(server_child_t *children, pid_t pid,
             child = tmp;
         }
     }
+
+    pthread_mutex_unlock(&children->servch_lock);
 }
 
 /* ---------------------------
index 838cece7253dbf75ff832b02ab64d0c2caae573f..fa1778e9c99cd251c77f336fc6788121b849a888 100644 (file)
@@ -18,6 +18,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <time.h>
+#include <pthread.h>
 
 #include <atalk/server_child.h>
 #include <atalk/server_ipc.h>
@@ -104,6 +105,45 @@ static int ipc_get_session(struct ipc_header *ipc, server_child_t *children)
     return 0;
 }
 
+static int ipc_set_state(struct ipc_header *ipc, server_child_t *children)
+{
+    EC_INIT;
+    afp_child_t *child;
+
+    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));
+
+EC_CLEANUP:
+    pthread_mutex_unlock(&children->servch_lock);
+    EC_EXIT;
+}
+
+static int ipc_set_volumes(struct ipc_header *ipc, server_child_t *children)
+{
+    EC_INIT;
+    afp_child_t *child;
+
+    pthread_mutex_lock(&children->servch_lock);
+
+    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:
+    pthread_mutex_unlock(&children->servch_lock);
+    EC_EXIT;
+}
+
 /***********************************************************************************
  * Public functions
  ***********************************************************************************/
@@ -201,6 +241,16 @@ int ipc_server_read(server_child_t *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;
@@ -252,3 +302,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);
+}
index 72cbaebd091996929daafc23a95523114d0ba16f..b0f3d8e2396b5359171086a9fabe1814bb27b5fa 100644 (file)
@@ -1,5 +1,29 @@
 dnl Kitchen sink for configuration macros
 
+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)
+    AC_SUBST(DBUS_CFLAGS)
+    AC_SUBST(DBUS_LIBS)
+    AC_SUBST(DBUS_GLIB_CFLAGS)
+    AC_SUBST(DBUS_GLIB_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])
index 17a92898c6d7b4c8e7161c298c81ddb04f5044c4..26d14b850482e09331cc1ec46227d32a3e8128f9 100644 (file)
@@ -138,6 +138,13 @@ 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)])],
+        PAMDIR=$withval,
+        PAMDIR='${sysconfdir}/pam.d'
+    )
+
     LIB_REMOVE_USR_LIB(PAM_LIBS)
     CFLAGS_REMOVE_USR_INCLUDE(PAM_CFLAGS)
        AC_SUBST(PAMDIR)
index f4d99863f2cc69d8904eb831b516a7e1867e0ba9..460efc6671f25b8af40f63c48258696854fbb778 100644 (file)
@@ -55,6 +55,8 @@ 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])
+       AC_MSG_RESULT([         dbus support:            $have_dbus_glib])
+       AC_MSG_RESULT([         dbus system directory:   $ac_cv_dbus_sysdir])
        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])