File autofs-5.1.1-dbus-udisks-monitor.patch of Package autofs.23455
---
Makefile.conf.in | 3
daemon/lookup.c | 4
include/lookup_udisks.h | 381 +++++++
lib/master_tok.l | 2
lib/parse_subs.c | 2
man/autofs.udisks.5.in | 121 ++
modules/Makefile | 12
modules/lookup_multi.c | 2
modules/lookup_udisks.c | 2449 ++++++++++++++++++++++++++++++++++++++++++++++++
modules/parse_sun.c | 1
samples/autofs.udisks | 28
11 files changed, 3004 insertions(+), 1 deletion(-)
--- a/Makefile.conf.in
+++ b/Makefile.conf.in
@@ -40,6 +40,9 @@ KRB5_FLAGS=@KRB5_FLAGS@
# NIS+ support: yes (1) no (0)
NISPLUS = @HAVE_NISPLUS@
+# Udisks support
+UDISKS = 1
+
# SMBFS support: yes (1) no (0)
SMBFS = @HAVE_SMBMOUNT@
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -239,6 +239,10 @@ int lookup_nss_read_master(struct master
(name[3] == ',' || name[3] == ':')) ||
(!strncmp(name, "nisplus", 7) &&
(name[7] == ',' || name[7] == ':')) ||
+ (!strncmp(name, "udisks", 6) &&
+ (name[6] == ',' || name[6] == ':')) ||
+ (!strncmp(name, "udisks2", 7) &&
+ (name[7] == ',' || name[7] == ':')) ||
(!strncmp(name, "ldap", 4) &&
(name[4] == ',' || name[4] == ':')) ||
(!strncmp(name, "ldaps", 5) &&
--- /dev/null
+++ b/include/lookup_udisks.h
@@ -0,0 +1,381 @@
+/*
+ * loopup_udisks.h - Header file for lookup_udisks automount module
+ *
+ * Copyright 2012 SuSE LINUX Products GmbH - All Rights Reserved
+ * Copyright 2012 Werner Fink <werner@suse.de>
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; 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 LOOKUP_UDISKS_H
+#define LOOKUP_UDISKS_H
+
+#include "list.h"
+typedef struct list_head list_t;
+
+#ifndef list_for_each_safe
+#define list_for_each_safe(pos, safe, head) \
+ for (pos = (head)->next, safe = pos->next; pos != (head); pos = safe, safe = pos->next)
+#endif
+#ifdef offsetof
+# undef list_entry
+# define list_entry(ptr, type, member) (__extension__ ({ \
+ __const__ __typeof__( ((type*)0)->member ) *__mptr = (ptr); \
+ ((type *)( (char *)__mptr - offsetof(type,member) ));}))
+#endif
+
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+# ifndef inline
+# define inline __inline__
+# endif
+# ifndef restrict
+# define restrict __restrict__
+# endif
+# ifndef volatile
+# define volatile __volatile__
+# endif
+# ifndef extension
+# define extension __extension__
+# endif
+# ifndef typeof
+# define typeof __typeof__
+# endif
+#endif
+#ifndef attribute
+# define attribute(attr) __attribute__(attr)
+#endif
+#define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
+#define strsize(string) ((strlen(string)+1)*sizeof(char))
+#define MODPREFIX "lookup(udisks): "
+
+typedef struct property_s {
+ list_t handle;
+ int type;
+ char *name;
+ void *value;
+} property_t;
+
+typedef struct array_s {
+ list_t handle;
+ char *value;
+} array_t;
+
+typedef struct filter_s {
+ char *property;
+#define DBUS_TYPE_OBJECT DBUS_TYPE_OBJECT_PATH
+ int type;
+} filter_t;
+
+typedef struct option_s {
+ int error;
+ union {
+ dbus_bool_t boolean;
+ dbus_int32_t int32;
+ dbus_uint32_t uint32;
+ dbus_int64_t int64;
+ dbus_uint64_t uint64;
+ double number;
+ const char *string;
+ const list_t *array;
+ };
+} option_t;
+
+typedef struct entry_s {
+ time_t age;
+ size_t key_len;
+ size_t mapent_len;
+ char *key;
+ char *mapent;
+} entry_t;
+
+typedef struct device_s {
+ list_t handle;
+ list_t properties;
+ list_t *head;
+ filter_t *opts;
+ entry_t *entry;
+ char* identify;
+ char* node;
+} device_t;
+
+typedef struct session_s {
+ list_t handle;
+ list_t properties;
+ list_t *head;
+ filter_t *opts;
+ char* identify;
+ char* node;
+} session_t;
+
+typedef struct mntopt_s {
+ list_t handle;
+ char* identify;
+ char* options;
+} mntopt_t;
+
+typedef struct config_s {
+ int enabled;
+ char* common;
+ list_t fstypes;
+ list_t byid;
+ list_t label;
+} config_t;
+
+struct lookup_context {
+ pthread_mutex_t mtx;
+ pthread_t watchdog;
+ dbus_bool_t monitor;
+ volatile int active;
+ volatile int running;
+ const char *mapname;
+ list_t devices;
+ list_t sessions;
+ config_t config;
+ DBusConnection *conn;
+ DBusError *error;
+ struct autofs_point *ap;
+ struct map_source *map;
+ struct parse_mod *parse;
+};
+
+static inline void lock(struct lookup_context *ctxt)
+{
+ int status = pthread_mutex_lock(&ctxt->mtx);
+ if (status)
+ fatal(status);
+ return;
+}
+
+static inline void unlock(struct lookup_context *ctxt)
+{
+ int status = pthread_mutex_unlock(&ctxt->mtx);
+ if (status)
+ fatal(status);
+ return;
+}
+
+/*
+ * Use posix_memalign for a well aligned container which not only has
+ * the required amount of space for the structure of a list member but
+ * also for the used strings therein. With this such a container can
+ * be freed at once.
+ */
+extern void* newaligned(size_t size) attribute((__warn_unused_result__,__always_inline__));
+extern inline void* newaligned(size_t size)
+{
+ void *restrict new;
+ if (posix_memalign((void**)&new, sizeof(void*), size) != 0) {
+ char buf[MAX_ERR_BUF];
+ const char *const estr = strerror_r(errno, buf, sizeof(buf));
+ logerr(MODPREFIX "memory allocation: %s", estr);
+ return (void*)0;
+ }
+ return new;
+}
+
+/*
+ * Sorted with same order as found in the response of the dbus call
+ * org.freedesktop.DBus.Properties.GetAll, e.g.
+ * dbus-send --system --print-reply --dest=org.freedesktop.UDisks \
+ * /org/freedesktop/UDisks/devices/sda \
+ * org.freedesktop.DBus.Properties.GetAll \
+ * string:org.freedesktop.UDisks.Device | \
+ * sed -rn '/dict entry\(/,/\)/ {
+ * H
+ * x
+ * s@\n*@@g
+ * s@^\s+string\s"(\w+)"\s+.*@\t\1,@p
+ * }'
+ *
+ * compare with filter[] found in lookup_udisks.c
+ */
+
+typedef enum {
+ NativePath = 0,
+ DeviceDetectionTime,
+ DeviceMediaDetectionTime,
+ DeviceMajor,
+ DeviceMinor,
+ DeviceFile,
+ DeviceFilePresentation,
+ DeviceFileById,
+ DeviceFileByPath,
+ DeviceIsSystemInternal,
+ DeviceIsPartition,
+ DeviceIsPartitionTable,
+ DeviceIsRemovable,
+ DeviceIsMediaAvailable,
+ DeviceIsMediaChangeDetected,
+ DeviceIsMediaChangeDetectionPolling,
+ DeviceIsMediaChangeDetectionInhibitable,
+ DeviceIsMediaChangeDetectionInhibited,
+ DeviceIsReadOnly,
+ DeviceIsDrive,
+ DeviceIsOpticalDisc,
+ DeviceIsMounted,
+ DeviceMountPaths,
+ DeviceMountedByUid,
+ DeviceIsLuks,
+ DeviceIsLuksCleartext,
+ DeviceIsLinuxMdComponent,
+ DeviceIsLinuxMd,
+ DeviceIsLinuxLvm2LV,
+ DeviceIsLinuxLvm2PV,
+ DeviceIsLinuxDmmpComponent,
+ DeviceIsLinuxDmmp,
+ DeviceIsLinuxLoop,
+ DeviceSize,
+ DeviceBlockSize,
+ DevicePresentationHide,
+ DevicePresentationNopolicy,
+ DevicePresentationName,
+ DevicePresentationIconName,
+ DeviceAutomountHint,
+ JobInProgress,
+ JobId,
+ JobInitiatedByUid,
+ JobIsCancellable,
+ JobPercentage,
+ IdUsage,
+ IdType,
+ IdVersion,
+ IdUuid,
+ IdLabel,
+ LuksHolder,
+ LuksCleartextSlave,
+ LuksCleartextUnlockedByUid,
+ PartitionSlave,
+ PartitionScheme,
+ PartitionType,
+ PartitionLabel,
+ PartitionUuid,
+ PartitionFlags,
+ PartitionNumber,
+ PartitionOffset,
+ PartitionSize,
+ PartitionAlignmentOffset,
+ PartitionTableScheme,
+ PartitionTableCount,
+ DriveVendor,
+ DriveModel,
+ DriveRevision,
+ DriveSerial,
+ DriveWwn,
+ DriveRotationRate,
+ DriveWriteCache,
+ DriveConnectionInterface,
+ DriveConnectionSpeed,
+ DriveMediaCompatibility,
+ DriveMedia,
+ DriveIsMediaEjectable,
+ DriveCanDetach,
+ DriveCanSpindown,
+ DriveIsRotational,
+ DriveAdapter,
+ DrivePorts,
+ DriveSimilarDevices,
+ OpticalDiscIsBlank,
+ OpticalDiscIsAppendable,
+ OpticalDiscIsClosed,
+ OpticalDiscNumTracks,
+ OpticalDiscNumAudioTracks,
+ OpticalDiscNumSessions,
+ DriveAtaSmartIsAvailable,
+ DriveAtaSmartTimeCollected,
+ DriveAtaSmartStatus,
+ DriveAtaSmartBlob,
+ LinuxMdComponentLevel,
+ LinuxMdComponentPosition,
+ LinuxMdComponentNumRaidDevices,
+ LinuxMdComponentUuid,
+ LinuxMdComponentName,
+ LinuxMdComponentHomeHost,
+ LinuxMdComponentVersion,
+ LinuxMdComponentHolder,
+ LinuxMdComponentState,
+ LinuxMdState,
+ LinuxMdLevel,
+ LinuxMdUuid,
+ LinuxMdHomeHost,
+ LinuxMdName,
+ LinuxMdNumRaidDevices,
+ LinuxMdVersion,
+ LinuxMdSlaves,
+ LinuxMdIsDegraded,
+ LinuxMdSyncAction,
+ LinuxMdSyncPercentage,
+ LinuxMdSyncSpeed,
+ LinuxLvm2PVUuid,
+ LinuxLvm2PVNumMetadataAreas,
+ LinuxLvm2PVGroupName,
+ LinuxLvm2PVGroupUuid,
+ LinuxLvm2PVGroupSize,
+ LinuxLvm2PVGroupUnallocatedSize,
+ LinuxLvm2PVGroupSequenceNumber,
+ LinuxLvm2PVGroupExtentSize,
+ LinuxLvm2PVGroupPhysicalVolumes,
+ LinuxLvm2PVGroupLogicalVolumes,
+ LinuxLvm2LVName,
+ LinuxLvm2LVUuid,
+ LinuxLvm2LVGroupName,
+ LinuxLvm2LVGroupUuid,
+ LinuxDmmpComponentHolder,
+ LinuxDmmpName,
+ LinuxDmmpSlaves,
+ LinuxDmmpParameters,
+ LinuxLoopFilename,
+ NullDict
+} devdict_t;
+
+/*
+ * Sorted with same order as found in the response of the dbus call
+ * org.freedesktop.DBus.Properties.GetAll, e.g.
+ * dbus-send --print-reply --system --dest=org.freedesktop.ConsoleKit \
+ * /org/freedesktop/ConsoleKit/Session1 \
+ * org.freedesktop.DBus.Properties.GetAll \
+ * string:org.freedesktop.ConsoleKit.Session | \
+ * sed -rn '/dict entry\(/,/\)/{
+ * H
+ * x
+ * s@\n*@@g
+ * s@^\s+string\s"([a-z0-9-]+)"\s+.*@\t\1,@p
+ * }'
+ *
+ * compare with sessions[] found in lookup_udisks.c
+ */
+
+typedef enum {
+ unix_user = 0,
+ user,
+ session_type,
+ remote_host_name,
+ display_device,
+ x11_display,
+ x11_display_device,
+ active,
+ is_local,
+ idle_hint,
+ NullCk
+} ckdict_t;
+
+typedef enum {
+ AutofsUdisks = 0,
+ MountOptions,
+ Common,
+ DiskById,
+ DiskByLabel,
+ FSType,
+ NullCnf
+} cnfxml_t;
+
+#endif
--- a/lib/master_tok.l
+++ b/lib/master_tok.l
@@ -119,7 +119,7 @@ DNNAMESTR2 ([[:alnum:]_.\-]+)
INTMAP (-hosts|-null)
MULTI ((multi)(,(sun|hesiod))?(:{OPTWS}|{WS}))
MULTISEP ([\-]{2}[[:blank:]]+)
-MTYPE ((file|program|exec|sss|yp|nis|nisplus|ldap|ldaps|hesiod|userdir)(,(sun|hesiod|amd))?(:{OPTWS}|{WS}))
+MTYPE ((file|program|exec|sss|yp|nis|nisplus|udisks|udisks2|ldap|ldaps|hesiod|userdir)(,(sun|hesiod|amd))?(:{OPTWS}|{WS}))
OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
--- a/lib/parse_subs.c
+++ b/lib/parse_subs.c
@@ -98,6 +98,8 @@ static struct types map_type[] = {
{ "yp", 2 },
{ "nis", 3 },
{ "nisplus", 7 },
+ { "udisks", 6 },
+ { "udisks2", 7 },
{ "ldap", 4 },
{ "ldaps", 5 },
{ "hesiod", 6 },
--- /dev/null
+++ b/man/autofs.udisks.5.in
@@ -0,0 +1,121 @@
+.\" t
+.TH AUTOFS.UDISKS 5 "22 Aug 2012"
+.SH NAME
+autofs.udisks \- autofs configuration for local removable devices
+.SH "DESCRIPTION"
+The automount udisks module is able to manage removable devices on the
+local system by connecting to the message bus daemon
+.BR dbus\-daemon (1)
+to monitor all device events of the
+.BR udisks\-daemon (8).
+To grant access for local users the automount
+udisks module also monitors users sessions hold by the ConsoleKit
+daemon, compare with description of the PAM module
+.BR pam_ck_connector (8).
+.P
+To use the automount udisks module an entry in the Master Map
+.BR auto.master (5)
+has to added, like this:
+.sp
+.RS +.2i
+.ta 1.0i
+.nf
+.I /media/autofs udisks:@@autofsmapdir@@/autofs.udisks \-\-timeout=5 \-\-ghost
+.fi
+.RE
+.sp
+Please be aware that format of the file
+.R autofs.udisks
+does
+.B not
+follow the common format of the automounter maps but is an XML
+configuration file. This file is used by the automount udisks module
+to generate the automounter map on the fly.
+.P
+An example of this file is:
+.sp
+.RS +.2i
+.ta 1.0i
+.nf
+<?xml version=\[dq]1.0\[dq] ?>
+<AutofsUdisks enable=\[dq]true\[dq]>
+ <MountOptions>
+ <Common>uid=$UID,gid=$GID,nosuid,nodev</Common>
+ <DiskById value=\[dq]usb\-USB_Flash_Disk_XXXXXXXXXXXX\-0:0\-part1\[dq]>
+ uid=1002,gid=501,user,nosuid,nodev,exec
+ </DiskById>
+ <DiskByLabel value=\[dq]MyPersonal\-DVD\-x86_64XXXX\[dq]>
+ unhide
+ </DiskByLabel>
+ <FSType value=\[dq]vfat\[dq]>fmask=0132,dmask=0022,showexec</FSType>
+ <FSType value=\[dq]ntfs\[dq]>umask=0022</FSType>
+ <FSType value=\[dq]iso9660\[dq]>ro</FSType>
+ <FSType value=\[dq]ext4\[dq]>check=none,noatime,nodiratime,data=journal</FSType>
+ <FSType value=\[dq]ext3\[dq]>check=none,noatime,nodiratime,data=journal</FSType>
+ <FSType value=\[dq]ext2\[dq]>check=none,noatime</FSType>
+ <FSType>ro,nosuid,nodev,noexec</FSType>
+ </MountOptions>
+</AutofsUdisks>
+.fi
+.RE
+.sp
+The entries of such a XML configuration file are
+.TP
+.RB < AutofsUdisks >
+as the outer envelop. This level has exactly one attribute
+.BR enable =\[dq] true \[dq]|\[dq] false \[dq]
+which allows disabling the automount udisks module without
+removing the module its self.
+.TP
+.RB < MountOptions >
+is the only known entry below which is used to list the
+possible mount options, compare with
+.BR mount (8)
+as well as the variable substitutions mentioned in the manual
+page
+.BR autofs (5)
+for the format of the automounter maps.
+.P
+There are four possible entries below
+.RB < MountOptions >
+to help the the automount udisks module to generate the automounter
+map.
+.TP
+.RB < Common >
+is the entry which provides mount options applied to
+nearly all generated maps.
+This entry will be overwritten by the next entry.
+.TP
+.RB < DiskById\ value =\[dq] \fIID\fR \[dq]>
+is the entry which provides mount options which are applied
+instead of the
+.RB < Common >
+entry if a device is found with an
+.I ID
+listed below
+.IR /dev/disk/by\-id/ .
+This entry will be overwritten by the next entry.
+.TP
+.RB < DiskByLabel\ value =\[dq] \fILABEL\fR \[dq]>
+is the entry which provides mount options which are applied
+instead of the
+.RB < Common >
+or
+.RB < DiskByLabel >
+entries if a device is found labeled with
+.IR LABEL .
+Such labels can be detected by the super user with the
+.BR blkid (8)
+command.
+.TP
+.RB < FSType\ [ value =\[dq] \fIFSTYPE\fR \[dq]]>
+those entries are used to apply file system \fIFSTYPE\fR specific mount
+options to a generated automounter map entry. There can be one
+.RB < FSType >
+entry without any file system value as a fallback for file systems
+not specified in the configuration file.
+.SH "SEE ALSO"
+.BR auto.master (5),
+.BR udisks\-daemon (8)
+.SH AUTHOR
+This manual page was written by Werner Fink <werner@suse.com>.
--- a/modules/Makefile
+++ b/modules/Makefile
@@ -62,6 +62,14 @@ ifeq ($(SSSD), 1)
MODS += lookup_sss.so
endif
+ifeq ($(UDISKS), 1)
+ UDISKS_FLAGS += $(shell pkg-config --cflags dbus-1)
+ UDISKS_LIBS += $(shell pkg-config --libs dbus-1)
+ UDISKS_LIBS += $(AUTOFS_LIB)
+ SRCS += lookup_udisks.c
+ MODS += lookup_udisks.so
+endif
+
CFLAGS += -I../include -I../lib -fPIC -D_GNU_SOURCE
CFLAGS += -DAUTOFS_LIB_DIR=\"$(autofslibdir)\"
CFLAGS += -DAUTOFS_MAP_DIR=\"$(autofsmapdir)\"
@@ -133,6 +141,10 @@ lookup_ldap.so: lookup_ldap.c dclist.o b
$(LDFLAGS) $(AUTOFS_LIB) $(LIBLDAP) $(LIBRESOLV) $(LIBS)
$(STRIP) lookup_ldap.so
+lookup_udisks.so: lookup_udisks.c ../include/lookup_udisks.h
+ $(CC) $(SOLDFLAGS) $(CFLAGS) $(UDISKS_FLAGS) -o $@ $< $(UDISKS_LIBS)
+ $(STRIP) $@
+
mount_nfs.so: mount_nfs.c replicated.o
$(CC) $(SOLDFLAGS) $(CFLAGS) -o mount_nfs.so \
mount_nfs.c replicated.o $(LDFLAGS) $(AUTOFS_LIB) $(LIBS)
--- a/modules/lookup_multi.c
+++ b/modules/lookup_multi.c
@@ -56,6 +56,8 @@ static struct lookup_mod *nss_open_looku
if (!strncmp(argv[0], "file", 4) ||
!strncmp(argv[0], "yp", 2) ||
!strncmp(argv[0], "nisplus", 7) ||
+ !strncmp(argv[0], "udisks", 6) ||
+ !strncmp(argv[0], "udisks2", 7) ||
!strncmp(argv[0], "nis", 3) ||
!strncmp(argv[0], "ldaps", 5) ||
!strncmp(argv[0], "ldap", 4) ||
--- /dev/null
+++ b/modules/lookup_udisks.c
@@ -0,0 +1,2449 @@
+/*
+ * lookup_udisks.c - Module for Linux automount to access removable devices
+ * listed by the dbus based udisks-daemon
+ *
+ * Copyright 2012 SuSE LINUX Products GmbH - All Rights Reserved
+ * Copyright 2012 Werner Fink <werner@suse.de>
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; 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.
+ *
+ */
+
+#include <dbus/dbus.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlerror.h>
+
+#define MODULE_LOOKUP
+#include "automount.h"
+#include "nsswitch.h"
+#include "lookup_udisks.h"
+
+extern pthread_attr_t th_attr_detached;
+
+#define MAPFMT_DEFAULT "sun"
+
+#define DBUS_COMMON_NAME_UDISKS "org.freedesktop.UDisks"
+#define DBUS_INTERFACE_UDISKS "org.freedesktop.UDisks"
+#define DBUS_OBJECT_PATH_UDISKS_ROOT "/org/freedesktop/UDisks"
+
+/*
+ * Sorted with same order as found in the response of the dbus call
+ * org.freedesktop.DBus.Properties.GetAll, e.g.
+ * dbus-send --system --print-reply --dest=org.freedesktop.UDisks \
+ * /org/freedesktop/UDisks/devices/sda \
+ * org.freedesktop.DBus.Properties.GetAll \
+ * string:org.freedesktop.UDisks.Device | \
+ * sed -rn '/dict entry\(/,/\)/ {
+ * H
+ * x
+ * s@\n*@@g
+ * s@^\s+string\s("\w+")\s+variant\s+(\w+).*@FILTER\(\U\2\E,\t\1\)@p
+ * }'
+ *
+ * compare with enum type devdict_t in ../include/lookup_udisks.h
+ * that is if add here a hash key you have to extend dict_t!
+ */
+#define FILTER(name, property) { property, DBUS_TYPE_ ## name }
+static filter_t devproperpty[] = {
+ FILTER(STRING, "NativePath"),
+ FILTER(UINT64, "DeviceDetectionTime"),
+ FILTER(UINT64, "DeviceMediaDetectionTime"),
+ FILTER(INT64, "DeviceMajor"),
+ FILTER(INT64, "DeviceMinor"),
+ FILTER(STRING, "DeviceFile"),
+ FILTER(STRING, "DeviceFilePresentation"),
+ FILTER(ARRAY, "DeviceFileById"),
+ FILTER(ARRAY, "DeviceFileByPath"),
+ FILTER(BOOLEAN, "DeviceIsSystemInternal"),
+ FILTER(BOOLEAN, "DeviceIsPartition"),
+ FILTER(BOOLEAN, "DeviceIsPartitionTable"),
+ FILTER(BOOLEAN, "DeviceIsRemovable"),
+ FILTER(BOOLEAN, "DeviceIsMediaAvailable"),
+ FILTER(BOOLEAN, "DeviceIsMediaChangeDetected"),
+ FILTER(BOOLEAN, "DeviceIsMediaChangeDetectionPolling"),
+ FILTER(BOOLEAN, "DeviceIsMediaChangeDetectionInhibitable"),
+ FILTER(BOOLEAN, "DeviceIsMediaChangeDetectionInhibited"),
+ FILTER(BOOLEAN, "DeviceIsReadOnly"),
+ FILTER(BOOLEAN, "DeviceIsDrive"),
+ FILTER(BOOLEAN, "DeviceIsOpticalDisc"),
+ FILTER(BOOLEAN, "DeviceIsMounted"),
+ FILTER(ARRAY, "DeviceMountPaths"),
+ FILTER(UINT32, "DeviceMountedByUid"),
+ FILTER(BOOLEAN, "DeviceIsLuks"),
+ FILTER(BOOLEAN, "DeviceIsLuksCleartext"),
+ FILTER(BOOLEAN, "DeviceIsLinuxMdComponent"),
+ FILTER(BOOLEAN, "DeviceIsLinuxMd"),
+ FILTER(BOOLEAN, "DeviceIsLinuxLvm2LV"),
+ FILTER(BOOLEAN, "DeviceIsLinuxLvm2PV"),
+ FILTER(BOOLEAN, "DeviceIsLinuxDmmpComponent"),
+ FILTER(BOOLEAN, "DeviceIsLinuxDmmp"),
+ FILTER(BOOLEAN, "DeviceIsLinuxLoop"),
+ FILTER(UINT64, "DeviceSize"),
+ FILTER(UINT64, "DeviceBlockSize"),
+ FILTER(BOOLEAN, "DevicePresentationHide"),
+ FILTER(BOOLEAN, "DevicePresentationNopolicy"),
+ FILTER(STRING, "DevicePresentationName"),
+ FILTER(STRING, "DevicePresentationIconName"),
+ FILTER(STRING, "DeviceAutomountHint"),
+ FILTER(BOOLEAN, "JobInProgress"),
+ FILTER(STRING, "JobId"),
+ FILTER(UINT32, "JobInitiatedByUid"),
+ FILTER(BOOLEAN, "JobIsCancellable"),
+ FILTER(DOUBLE, "JobPercentage"),
+ FILTER(STRING, "IdUsage"),
+ FILTER(STRING, "IdType"),
+ FILTER(STRING, "IdVersion"),
+ FILTER(STRING, "IdUuid"),
+ FILTER(STRING, "IdLabel"),
+ FILTER(OBJECT, "LuksHolder"),
+ FILTER(OBJECT, "LuksCleartextSlave"),
+ FILTER(UINT32, "LuksCleartextUnlockedByUid"),
+ FILTER(OBJECT, "PartitionSlave"),
+ FILTER(STRING, "PartitionScheme"),
+ FILTER(STRING, "PartitionType"),
+ FILTER(STRING, "PartitionLabel"),
+ FILTER(STRING, "PartitionUuid"),
+ FILTER(ARRAY, "PartitionFlags"),
+ FILTER(INT32, "PartitionNumber"),
+ FILTER(UINT64, "PartitionOffset"),
+ FILTER(UINT64, "PartitionSize"),
+ FILTER(UINT64, "PartitionAlignmentOffset"),
+ FILTER(STRING, "PartitionTableScheme"),
+ FILTER(INT32, "PartitionTableCount"),
+ FILTER(STRING, "DriveVendor"),
+ FILTER(STRING, "DriveModel"),
+ FILTER(STRING, "DriveRevision"),
+ FILTER(STRING, "DriveSerial"),
+ FILTER(STRING, "DriveWwn"),
+ FILTER(UINT32, "DriveRotationRate"),
+ FILTER(STRING, "DriveWriteCache"),
+ FILTER(STRING, "DriveConnectionInterface"),
+ FILTER(UINT64, "DriveConnectionSpeed"),
+ FILTER(ARRAY, "DriveMediaCompatibility"),
+ FILTER(STRING, "DriveMedia"),
+ FILTER(BOOLEAN, "DriveIsMediaEjectable"),
+ FILTER(BOOLEAN, "DriveCanDetach"),
+ FILTER(BOOLEAN, "DriveCanSpindown"),
+ FILTER(BOOLEAN, "DriveIsRotational"),
+ FILTER(OBJECT, "DriveAdapter"),
+ FILTER(ARRAY, "DrivePorts"),
+ FILTER(ARRAY, "DriveSimilarDevices"),
+ FILTER(BOOLEAN, "OpticalDiscIsBlank"),
+ FILTER(BOOLEAN, "OpticalDiscIsAppendable"),
+ FILTER(BOOLEAN, "OpticalDiscIsClosed"),
+ FILTER(UINT32, "OpticalDiscNumTracks"),
+ FILTER(UINT32, "OpticalDiscNumAudioTracks"),
+ FILTER(UINT32, "OpticalDiscNumSessions"),
+ FILTER(BOOLEAN, "DriveAtaSmartIsAvailable"),
+ FILTER(UINT64, "DriveAtaSmartTimeCollected"),
+ FILTER(STRING, "DriveAtaSmartStatus"),
+ FILTER(ARRAY, "DriveAtaSmartBlob"),
+ FILTER(STRING, "LinuxMdComponentLevel"),
+ FILTER(INT32, "LinuxMdComponentPosition"),
+ FILTER(INT32, "LinuxMdComponentNumRaidDevices"),
+ FILTER(STRING, "LinuxMdComponentUuid"),
+ FILTER(STRING, "LinuxMdComponentName"),
+ FILTER(STRING, "LinuxMdComponentHomeHost"),
+ FILTER(STRING, "LinuxMdComponentVersion"),
+ FILTER(OBJECT, "LinuxMdComponentHolder"),
+ FILTER(ARRAY, "LinuxMdComponentState"),
+ FILTER(STRING, "LinuxMdState"),
+ FILTER(STRING, "LinuxMdLevel"),
+ FILTER(STRING, "LinuxMdUuid"),
+ FILTER(STRING, "LinuxMdHomeHost"),
+ FILTER(STRING, "LinuxMdName"),
+ FILTER(INT32, "LinuxMdNumRaidDevices"),
+ FILTER(STRING, "LinuxMdVersion"),
+ FILTER(ARRAY, "LinuxMdSlaves"),
+ FILTER(BOOLEAN, "LinuxMdIsDegraded"),
+ FILTER(STRING, "LinuxMdSyncAction"),
+ FILTER(DOUBLE, "LinuxMdSyncPercentage"),
+ FILTER(UINT64, "LinuxMdSyncSpeed"),
+ FILTER(STRING, "LinuxLvm2PVUuid"),
+ FILTER(UINT32, "LinuxLvm2PVNumMetadataAreas"),
+ FILTER(STRING, "LinuxLvm2PVGroupName"),
+ FILTER(STRING, "LinuxLvm2PVGroupUuid"),
+ FILTER(UINT64, "LinuxLvm2PVGroupSize"),
+ FILTER(UINT64, "LinuxLvm2PVGroupUnallocatedSize"),
+ FILTER(UINT64, "LinuxLvm2PVGroupSequenceNumber"),
+ FILTER(UINT64, "LinuxLvm2PVGroupExtentSize"),
+ FILTER(ARRAY, "LinuxLvm2PVGroupPhysicalVolumes"),
+ FILTER(ARRAY, "LinuxLvm2PVGroupLogicalVolumes"),
+ FILTER(STRING, "LinuxLvm2LVName"),
+ FILTER(STRING, "LinuxLvm2LVUuid"),
+ FILTER(STRING, "LinuxLvm2LVGroupName"),
+ FILTER(STRING, "LinuxLvm2LVGroupUuid"),
+ FILTER(OBJECT, "LinuxDmmpComponentHolder"),
+ FILTER(STRING, "LinuxDmmpName"),
+ FILTER(ARRAY, "LinuxDmmpSlaves"),
+ FILTER(STRING, "LinuxDmmpParameters"),
+ FILTER(STRING, "LinuxLoopFilename"),
+ FILTER(BOOLEAN, (char*)0)
+};
+
+/*
+ * Sorted with same order as found in the response of the dbus call
+ * org.freedesktop.DBus.Properties.GetAll, e.g.
+ * dbus-send --print-reply --system --dest=org.freedesktop.ConsoleKit \
+ * /org/freedesktop/ConsoleKit/Session2 \
+ * org.freedesktop.DBus.Properties.GetAll \
+ * string:org.freedesktop.ConsoleKit.Session | \
+ * sed -rn '/dict entry\(/,/\)/ {
+ * H
+ * x
+ * s@\n*@@g
+ * s@^\s+string\s("[a-z0-9-]+")\s+variant\s+(\w+).*@FILTER\(\U\2\E,\t\1\)@p
+ * }'
+ *
+ * compare with enum type ckdict_t in ../include/lookup_udisks.h
+ * that is if add here a hash key you have to extend ckdict_t!
+ */
+static filter_t sessproperty[] = {
+ FILTER(UINT32, "unix-user"),
+ FILTER(UINT32, "user"),
+ FILTER(STRING, "session-type"),
+ FILTER(STRING, "remote-host-name"),
+ FILTER(STRING, "display-device"),
+ FILTER(STRING, "x11-display"),
+ FILTER(STRING, "x11-display-device"),
+ FILTER(BOOLEAN, "active"),
+ FILTER(BOOLEAN, "is-local"),
+ FILTER(BOOLEAN, "idle-hint"),
+ FILTER(BOOLEAN, (char*)0)
+};
+
+#undef FILTER
+
+static inline device_t* add_device(list_t *head, const char *node)
+{
+ const char* identify;
+ device_t *restrict new;
+ list_t *ptr;
+
+ if ((identify = strrchr(node, '/')))
+ identify++;
+ else identify = node;
+
+ list_for_each(ptr, head) {
+ device_t *this = list_entry(ptr, device_t, handle);
+ if (strcmp(this->identify, identify) == 0)
+ return this;
+ }
+
+ new = newaligned(alignof(device_t)+strsize(node));
+ if (!new)
+ return (device_t*)0;
+ memset(new, 0, alignof(device_t));
+
+ list_add_tail(&new->handle, head);
+ INIT_LIST_HEAD(&new->properties);
+ new->head = head;
+
+ new->node = ((typeof(new->node))new)+alignof(device_t);
+ strcpy(new->node, node);
+ new->identify = new->node+(identify-node);
+ return new;
+}
+
+static inline device_t* find_device(list_t *head, const char *node)
+{
+ const char* identify;
+ list_t *ptr;
+
+ if ((identify = strrchr(node, '/')))
+ identify++;
+ else identify = node;
+
+ list_for_each(ptr, head) {
+ device_t *this = list_entry(ptr, device_t, handle);
+ if (strcmp(this->identify, identify) == 0)
+ return this;
+ }
+ return (device_t*)0;
+}
+
+static inline void delete_device(device_t *this)
+{
+ list_t *ptr, *safe;
+ list_for_each_safe(ptr, safe, &this->properties) {
+ property_t *obj = list_entry(ptr, property_t, handle);
+ if (obj->type == DBUS_TYPE_ARRAY) {
+ list_t *ap, *as;
+ list_for_each_safe(ap, as, (list_t*)obj->value) {
+ array_t *array = list_entry(ap, array_t, handle);
+ list_del(ap);
+ free(array);
+ }
+ }
+ list_del(ptr);
+ free(obj);
+ }
+ list_del(&this->handle);
+ this->head = (list_t*)0;
+ if (this->opts) free(this->opts);
+ if (this->entry) free(this->entry);
+ free(this);
+}
+
+static inline void remove_device(list_t *head, const char *node)
+{
+ list_t *ptr;
+ device_t *this = (device_t*)0;
+ const char* identify;
+
+ if ((identify = strrchr(node, '/')))
+ identify++;
+ else identify = node;
+
+ list_for_each(ptr, head) {
+ this = list_entry(ptr, device_t, handle);
+ if (strcmp(this->identify, identify) == 0)
+ break;
+ }
+ if (this) delete_device(this);
+}
+
+static inline void clear_devices(list_t *head)
+{
+ list_t *ptr, *safe;
+ list_for_each_safe(ptr, safe, head) {
+ device_t *this = list_entry(ptr, device_t, handle);
+ delete_device(this);
+ }
+}
+
+static inline session_t* add_session(list_t *head, const char *node)
+{
+ const char* identify;
+ session_t *restrict new;
+ list_t *ptr;
+
+ if ((identify = strrchr(node, '/')))
+ identify++;
+ else identify = node;
+
+ list_for_each(ptr, head) {
+ session_t *this = list_entry(ptr, session_t, handle);
+ if (strcmp(this->identify, identify) == 0)
+ return this;
+ }
+
+ new = newaligned(alignof(session_t)+strsize(node));
+ if (!new)
+ return (session_t*)0;
+ memset(new, 0, alignof(session_t));
+
+ list_add_tail(&new->handle, head);
+ INIT_LIST_HEAD(&new->properties);
+ new->head = head;
+
+ new->node = ((typeof(new->node))new)+alignof(session_t);
+ strcpy(new->node, node);
+ new->identify = new->node+(identify-node);
+ return new;
+}
+
+static inline session_t* find_session(list_t *head, const char *node)
+{
+ const char* identify;
+ list_t *ptr;
+
+ if ((identify = strrchr(node, '/')))
+ identify++;
+ else identify = node;
+
+ list_for_each(ptr, head) {
+ session_t *this = list_entry(ptr, session_t, handle);
+ if (strcmp(this->identify, identify) == 0)
+ return this;
+ }
+ return (session_t*)0;
+}
+
+static inline void delete_session(session_t *this)
+{
+ list_t *ptr, *safe;
+ list_for_each_safe(ptr, safe, &this->properties) {
+ property_t *obj = list_entry(ptr, property_t, handle);
+ if (obj->type == DBUS_TYPE_ARRAY) {
+ list_t *ap, *as;
+ list_for_each_safe(ap, as, (list_t*)obj->value) {
+ array_t *array = list_entry(ap, array_t, handle);
+ list_del(ap);
+ free(array);
+ }
+ }
+ list_del(ptr);
+ free(obj);
+ }
+ list_del(&this->handle);
+ this->head = (list_t*)0;
+ if (this->opts) free(this->opts);
+ free(this);
+}
+
+static inline void remove_session(list_t *head, const char *node)
+{
+ list_t *ptr;
+ session_t *this = (session_t*)0;
+ const char* identify;
+
+ if ((identify = strrchr(node, '/')))
+ identify++;
+ else identify = node;
+
+ list_for_each(ptr, head) {
+ this = list_entry(ptr, session_t, handle);
+ if (strcmp(this->identify, identify) == 0)
+ break;
+ }
+ if (this) delete_session(this);
+}
+
+static inline void clear_sessions(list_t *head)
+{
+ list_t *ptr, *safe;
+ list_for_each_safe(ptr, safe, head) {
+ session_t *this = list_entry(ptr, session_t, handle);
+ delete_session(this);
+ }
+}
+
+static filter_t *property;
+static inline property_t *add_property(list_t *head,
+ const char* name,
+ int type,
+ const void *value,
+ size_t len)
+{
+ property_t *restrict new;
+ filter_t *flt;
+ list_t *ptr;
+ size_t slen;
+
+ if (!property) {
+ logerr(MODPREFIX "property not specified");
+ return (property_t*)0;
+ }
+
+ flt = property;
+ do {
+ if (flt->property == (char*)0)
+ break;
+ if (strcmp(flt->property, name) == 0)
+ break;
+ } while (flt++);
+
+ if (flt->property == (char*)0) {
+ warn(LOGOPT_NONE, MODPREFIX "udisks reply property `%s' not known", name);
+ slen = strsize(name);
+ } else {
+ slen = 0;
+ if (flt->type != type)
+ warn(LOGOPT_NONE, MODPREFIX "udisks reply type `%c' not known", type);
+ }
+
+ list_for_each(ptr, head) {
+ property_t *this = list_entry(ptr, property_t, handle);
+ if (strcmp(this->name, name) == 0)
+ return this;
+ }
+ if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH)
+ len++;
+
+ new = newaligned(alignof(property_t)+slen+len);
+ if (!new)
+ return (property_t*)0;
+ memset(new, 0, alignof(property_t));
+
+ list_add_tail(&new->handle, head);
+
+ new->type = type;
+
+ if (flt->property == (char*)0) {
+ new->name = ((typeof(new->name))new)+alignof(property_t);
+ strcpy(new->name, name);
+ } else
+ new->name = flt->property; /* hash key */
+
+ new->value = ((typeof(new->value))new)+alignof(property_t)+slen;
+ if (type == DBUS_TYPE_ARRAY)
+ INIT_LIST_HEAD(((list_t*)new->value));
+ else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH)
+ strcpy(new->value, value);
+ else
+ memcpy(new->value, value, len);
+
+ return new;
+}
+
+static void append_array(list_t *head, const char *value)
+{
+ array_t *restrict new;
+ const char *string;
+
+ if ((string = strrchr(value, '/')))
+ string++;
+ else string = value;
+
+ new = newaligned(alignof(array_t)+strsize(string));
+ if (!new)
+ return;
+ memset(new, 0, alignof(array_t));
+ list_add_tail(&new->handle, head);
+
+ new->value = ((typeof(new->value))new)+alignof(array_t);
+ strcpy(new->value, string);
+}
+
+static inline option_t map_property(const list_t *head, const char *restrict property)
+{
+ option_t ret;
+ list_t *ptr;
+
+ list_for_each(ptr, head) {
+ property_t *prop = list_entry(ptr, property_t, handle);
+ if (property == prop->name) {
+ ret.error = 0;
+ switch (prop->type) {
+ case DBUS_TYPE_BOOLEAN:
+ ret.boolean = *(dbus_bool_t*)(prop->value);
+ break;
+ case DBUS_TYPE_INT32:
+ ret.int32 = *(dbus_int32_t*)(prop->value);
+ break;
+ case DBUS_TYPE_UINT32:
+ ret.uint32 = *(dbus_uint32_t*)(prop->value);
+ break;
+ case DBUS_TYPE_INT64:
+ ret.int64 = *(dbus_int64_t*)(prop->value);
+ break;
+ case DBUS_TYPE_UINT64:
+ ret.uint64 = *(dbus_uint64_t*)(prop->value);
+ break;
+ case DBUS_TYPE_DOUBLE:
+ ret.number = *(double*)(prop->value);
+ break;
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT:
+ ret.string = (char*)(prop->value);
+ break;
+ case DBUS_TYPE_ARRAY:
+ ret.array = (list_t*)(prop->value);
+ break;
+ default:
+ ret.error = 1;
+ warn(LOGOPT_NONE, MODPREFIX
+ "udisks dbus type `%c' not handled", prop->type);
+ break;
+ }
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static option_t get_option(const device_t *this, const devdict_t opt)
+{
+ filter_t *flt;
+ option_t ret;
+
+ memset(&ret, 0, sizeof(ret));
+ ret.error = 1;
+ if (sizeof(devproperpty)/sizeof(filter_t) < opt) {
+ logerr(MODPREFIX "udisks option `%d' not known", opt);
+ goto out;
+ }
+ flt = &devproperpty[opt];
+ if (flt->property == (char*)0) {
+ warn(LOGOPT_NONE, MODPREFIX "udisks option `%d' not known", opt);
+ goto out;
+ }
+ ret = map_property(&this->properties, flt->property);
+out:
+ return ret;
+}
+
+static option_t get_session(const session_t *this, const ckdict_t opt)
+{
+ filter_t *flt;
+ option_t ret;
+
+ memset(&ret, 0, sizeof(ret));
+ ret.error = 1;
+ if (sizeof(sessproperty)/sizeof(filter_t) < opt) {
+ logerr(MODPREFIX "udisks option `%d' not known", opt);
+ goto out;
+ }
+ flt = &sessproperty[opt];
+ if (flt->property == (char*)0) {
+ warn(LOGOPT_NONE, MODPREFIX "udisks option `%d' not known", opt);
+ goto out;
+ }
+ ret = map_property(&this->properties, flt->property);
+out:
+ return ret;
+}
+
+static entry_t *do_map_entry(struct lookup_context *ctxt, device_t *this)
+{
+ const int labels[] = {IdLabel, DriveModel, DriveVendor, DriveSerial, -1};
+ const config_t *const config = &ctxt->config;
+ entry_t *restrict entry = (entry_t*)0;
+ char mapent[MAPENT_MAX_LEN+1];
+ const char *fstype;
+ const char *fallbck;
+ const char *common;
+ const char *device;
+ option_t option;
+ size_t maplen;
+ int offset;
+ list_t *ptr;
+ char *key;
+
+ if (!config->enabled)
+ goto out;
+
+ option = get_option(this, DeviceIsSystemInternal);
+ if (option.error || option.boolean == TRUE)
+ goto out;
+
+ option = get_option(this, JobInProgress);
+ if (option.error || option.boolean == TRUE)
+ goto out;
+
+ option = get_option(this, DeviceIsRemovable);
+ if (option.error || option.boolean == FALSE) {
+ /*
+ * Check for removable master device!
+ */
+ option = get_option(this, DeviceIsDrive);
+ if (option.error)
+ goto out;
+ if (option.boolean == FALSE) {
+ device_t *master;
+ option = get_option(this, PartitionSlave);
+ if (option.error || strlen(option.string) <= 1)
+ goto out;
+ master = find_device(this->head, option.string);
+ option = get_option(master, DeviceIsRemovable);
+ if (option.error || option.boolean == FALSE)
+ goto out;
+ }
+ }
+
+ option = get_option(this, DeviceIsPartition);
+ if (option.error || option.boolean == FALSE) {
+ /*
+ * Check for optical device with media!
+ */
+ option = get_option(this, DeviceIsOpticalDisc);
+ if (option.error || option.boolean == FALSE)
+ goto out;
+ option = get_option(this, OpticalDiscNumAudioTracks);
+ if (option.error || option.uint32 > 0)
+ goto out;
+ }
+
+ option = get_option(this, IdUsage);
+ if (option.error || strcmp(option.string, "filesystem") != 0)
+ goto out;
+
+ option = get_option(this, IdType);
+ if (option.error)
+ goto out;
+ fstype = option.string;
+ if (*fstype == '\0')
+ fstype = "auto";
+
+ option = get_option(this, DeviceFilePresentation);
+ if (option.error)
+ goto out;
+ device = option.string;
+
+ maplen = sizeof(mapent);
+ offset = snprintf(&mapent[0], maplen, "-fstype=%s", fstype);
+ if (offset < 0 || offset >= maplen)
+ goto out;
+ maplen -= offset;
+
+ fallbck = (char*)0;
+ list_for_each(ptr, &config->fstypes) {
+ mntopt_t *fs = list_entry(ptr, mntopt_t, handle);
+ if (strcmp(fstype, fs->identify) == 0) {
+ int len = snprintf(&mapent[offset], maplen, ",%s", fs->options);
+ if (len < 0 || len >= maplen)
+ goto out;
+ offset += len;
+ maplen -= len;
+ fallbck = (char*)0;
+ break;
+ }
+ if (strcmp("auto", fs->identify) == 0)
+ fallbck = fs->identify;
+ }
+
+ if (fallbck) {
+ int len = snprintf(&mapent[offset], maplen, ",%s", fallbck);
+ if (len < 0 || len >= maplen)
+ goto out;
+ offset += len;
+ maplen -= len;
+ }
+
+ /*
+ * Determine common mount options in order of <DiskByLabel>
+ * <DiskById>, and last but not least <Common> from the
+ * configuration file for the current map.
+ */
+ common = (char*)0;
+ option = get_option(this, IdLabel);
+ if (option.error)
+ goto out;
+ if (*option.string) {
+ list_for_each(ptr, &config->label) {
+ mntopt_t *lb = list_entry(ptr, mntopt_t, handle);
+ if (strcmp(option.string, lb->identify) == 0) {
+ common = lb->options;
+ break;
+ }
+ }
+ }
+ if (!common) {
+ list_t *tmp;
+ option = get_option(this, DeviceFileById);
+ if (option.error)
+ goto out;
+ list_for_each(tmp, option.array) {
+ array_t *str = list_entry(tmp, array_t, handle);
+ list_for_each(ptr, &config->byid) {
+ mntopt_t *id = list_entry(ptr, mntopt_t, handle);
+ if (strcmp(str->value, id->identify) == 0) {
+ common = id->options;
+ break;
+ }
+ }
+ if (common) break;
+ }
+ }
+ if (!common) common = config->common;
+
+ if (common) {
+ int len = snprintf(&mapent[offset], maplen, ",%s", common);
+ if (len < 0 || len >= maplen)
+ goto out;
+ offset += len;
+ maplen -= len;
+ }
+
+ /*
+ * Now add the device after a colon
+ */
+ offset = snprintf(&mapent[offset], maplen, " :%s", device);
+ if (offset < 0 || offset >= maplen)
+ goto out;
+ maplen -= offset;
+
+ /*
+ * The key of the entry
+ */
+ key = (char*)0;
+ for (offset = 0; labels[offset] >= 0; offset++) {
+ char *ptr;
+
+ option = get_option(this, labels[offset]);
+ if (option.error)
+ continue;
+ if (*option.string == '\0')
+ continue;
+ if (strcasecmp(option.string, "usb") == 0)
+ continue;
+
+ key = strdup(option.string);
+ if (key == (char*)0)
+ goto out;
+
+ for (ptr = key; *ptr; ptr++) {
+ if (*ptr == ' ') *ptr = '_';
+ else if (*ptr == '/') *ptr = '_';
+ else if (*ptr < 32) *ptr = '?';
+ else if (*ptr > 127) *ptr = '?';
+ }
+
+ break;
+ }
+ if (key == (char*)0)
+ goto out;
+
+ /*
+ * Allocate the entry and return this.
+ */
+ entry = newaligned(alignof(entry_t)+strsize(key)+strsize(mapent));
+ if (!entry)
+ goto out;
+ memset(entry, 0, alignof(entry_t));
+
+ entry->key = ((typeof(entry->key))entry)+alignof(entry_t);
+ entry->key_len = strlen(key);
+ strcpy(entry->key, key);
+
+ entry->mapent = ((typeof(entry->mapent))entry)+alignof(entry_t)+strsize(key);
+ entry->mapent_len = strlen(mapent);
+ strcpy(entry->mapent, mapent);
+
+ if (this->entry)
+ free(this->entry);
+ this->entry = entry;
+ free(key);
+out:
+ return entry;
+}
+
+/*
+ * We parse dbus messages structure as response of org.freedesktop.DBus.Properties.GetAll
+ * which looks like this one:
+ *
+ * array [
+ * dict_entry(
+ * string "DictName"
+ * variant [array:string|boolean|double|int32|int64|object_path|string|uint32|uint64]
+ * )
+ * ...
+ * ]
+ *
+ */
+static void __iterate_reply(DBusMessageIter *iter, list_t *head, const char** name)
+{
+ do {
+ int type = dbus_message_iter_get_arg_type(iter);
+ if (type == DBUS_TYPE_INVALID)
+ break;
+ switch (type) {
+ case DBUS_TYPE_STRING: {
+ char *value;
+ dbus_message_iter_get_basic(iter, &value);
+ if (*name == (char*)0) {
+ *name = value;
+ break;
+ }
+ add_property(head, *name, DBUS_TYPE_STRING, value, strlen(value));
+ break;
+ }
+ case DBUS_TYPE_OBJECT_PATH: {
+ char *value;
+ if (*name == (char*)0)
+ goto err;
+ dbus_message_iter_get_basic(iter, &value);
+ add_property(head, *name, DBUS_TYPE_OBJECT_PATH, value, strlen(value));
+ break;
+ }
+ case DBUS_TYPE_INT32: {
+ dbus_int32_t value;
+ if (*name == (char*)0)
+ goto err;
+ dbus_message_iter_get_basic(iter, &value);
+ add_property(head, *name, DBUS_TYPE_INT32, &value, sizeof(dbus_int32_t));
+ break;
+ }
+ case DBUS_TYPE_UINT32: {
+ dbus_uint32_t value;
+ if (*name == (char*)0)
+ goto err;
+ dbus_message_iter_get_basic(iter, &value);
+ add_property(head, *name, DBUS_TYPE_UINT32, &value, sizeof(dbus_uint32_t));
+ break;
+ }
+ case DBUS_TYPE_INT64: {
+ dbus_int64_t value;
+ if (*name == (char*)0)
+ goto err;
+ dbus_message_iter_get_basic(iter, &value);
+ add_property(head, *name, DBUS_TYPE_INT64, &value, sizeof(dbus_int64_t));
+ break;
+ }
+ case DBUS_TYPE_UINT64: {
+ dbus_uint64_t value;
+ if (*name == (char*)0)
+ goto err;
+ dbus_message_iter_get_basic(iter, &value);
+ add_property(head, *name, DBUS_TYPE_UINT64, &value, sizeof(dbus_uint64_t));
+ break;
+ }
+ case DBUS_TYPE_DOUBLE: {
+ double value;
+ if (*name == (char*)0)
+ goto err;
+ dbus_message_iter_get_basic(iter, &value);
+ add_property(head, *name, DBUS_TYPE_DOUBLE, &value, sizeof(double));
+ break;
+ }
+ case DBUS_TYPE_BOOLEAN: {
+ dbus_bool_t value;
+ if (*name == (char*)0)
+ goto err;
+ dbus_message_iter_get_basic(iter, &value);
+ add_property(head, *name, DBUS_TYPE_BOOLEAN, &value, sizeof(dbus_bool_t));
+ break;
+ }
+ case DBUS_TYPE_ARRAY: {
+ int tsub;
+ property_t *prop;
+ DBusMessageIter isub;
+
+ if (name == (const char**)0) {
+ /*
+ * The outer array of the message, check for first entry which
+ * should be a dict container, anything else is a bug.
+ */
+ dbus_message_iter_recurse (iter, &isub);
+ if (dbus_message_iter_get_arg_type(&isub) != DBUS_TYPE_DICT_ENTRY)
+ goto err;
+ __iterate_reply(&isub, head, (const char**)0);
+ break;
+ }
+
+ dbus_message_iter_recurse(iter, &isub);
+ tsub = dbus_message_iter_get_arg_type(&isub);
+ prop = add_property(head, *name, DBUS_TYPE_ARRAY, 0, sizeof(list_t));
+
+ while (tsub == DBUS_TYPE_STRING) {
+ char *value;
+ dbus_message_iter_get_basic(&isub, &value);
+ append_array(((list_t*)prop->value), value);
+
+ dbus_message_iter_next(&isub);
+ tsub = dbus_message_iter_get_arg_type(&isub);
+ }
+ break;
+ }
+ case DBUS_TYPE_VARIANT: {
+ DBusMessageIter isub;
+ if (*name == (char*)0)
+ goto err;
+ dbus_message_iter_recurse(iter, &isub);
+ __iterate_reply(&isub, head, name);
+ break;
+ }
+ case DBUS_TYPE_DICT_ENTRY: {
+ const char *dict;
+ DBusMessageIter isub;
+ dbus_message_iter_recurse(iter, &isub);
+ dict = (const char*)0;
+ __iterate_reply(&isub, head, &dict);
+ dbus_message_iter_next(&isub);
+ __iterate_reply(&isub, head, &dict);
+ break;
+ }
+ default:
+ err:
+ warn(LOGOPT_NONE, MODPREFIX "udisks reply type `%c' not handled", type);
+ break;
+ }
+ } while (dbus_message_iter_next(iter));
+}
+
+static inline void iterate_device_reply(DBusMessageIter *iter, list_t *head)
+{
+ property = &devproperpty[0];
+ __iterate_reply(iter, head, (const char**)0);
+ property = (filter_t*)0;
+}
+
+static int read_device_properties(struct lookup_context *ctxt, device_t *obj)
+{
+ const char *device = "org.freedesktop.UDisks.Device";
+ DBusMessage *reply, *send;
+ DBusMessageIter iter;
+ const char *signature;
+ int ret = NSS_STATUS_UNAVAIL;
+
+ send = dbus_message_new_method_call("org.freedesktop.UDisks",
+ obj->node,
+ "org.freedesktop.DBus.Properties",
+ "GetAll");
+ if (!send)
+ goto out;
+ dbus_message_set_auto_start(send, TRUE);
+ if (!dbus_message_set_destination(send, "org.freedesktop.UDisks"))
+ goto out;
+
+ dbus_message_iter_init_append(send, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device);
+
+ reply = dbus_connection_send_with_reply_and_block(ctxt->conn, send, 50000, ctxt->error);
+ dbus_message_unref(send);
+
+ if (dbus_error_is_set(ctxt->error)) {
+ warn(LOGOPT_NONE, MODPREFIX
+ "udisks map %s, can not connect system dbus: %s", ctxt->mapname, ctxt->error->message);
+ dbus_error_free(ctxt->error);
+ goto out;
+ }
+ if (!reply)
+ goto out;
+ if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ goto unref;
+ signature = dbus_message_get_signature(reply);
+ if ((int)*signature != DBUS_TYPE_ARRAY)
+ goto unref;
+ dbus_message_iter_init(reply, &iter);
+ iterate_device_reply(&iter, &obj->properties);
+ ret = NSS_STATUS_SUCCESS;
+unref:
+ dbus_message_unref(reply);
+out:
+ if (ret != NSS_STATUS_SUCCESS)
+ logerr(MODPREFIX "%s failed", __FUNCTION__);
+ return ret;
+}
+
+static inline void iterate_session_reply(DBusMessageIter *iter, list_t *head)
+{
+ property = &sessproperty[0];
+ __iterate_reply(iter, head, (const char**)0);
+ property = (filter_t*)0;
+}
+
+static int read_session_properties(struct lookup_context *ctxt, session_t *obj)
+{
+ const char *session = "org.freedesktop.ConsoleKit.Session";
+ DBusMessage *reply, *send;
+ DBusMessageIter iter;
+ const char *signature;
+ int ret = NSS_STATUS_UNAVAIL;
+
+ send = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
+ obj->node,
+ "org.freedesktop.DBus.Properties",
+ "GetAll");
+ if (!send)
+ goto out;
+ dbus_message_set_auto_start(send, TRUE);
+ if (!dbus_message_set_destination(send, "org.freedesktop.ConsoleKit"))
+ goto out;
+
+ dbus_message_iter_init_append(send, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &session);
+
+ reply = dbus_connection_send_with_reply_and_block(ctxt->conn, send, 50000, ctxt->error);
+ dbus_message_unref(send);
+
+ if (dbus_error_is_set(ctxt->error)) {
+ warn(LOGOPT_NONE, MODPREFIX
+ "udisks sessions %s, can not connect system dbus: %s", ctxt->mapname, ctxt->error->message);
+ dbus_error_free(ctxt->error);
+ goto out;
+ }
+ if (!reply)
+ goto out;
+ if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ goto unref;
+ signature = dbus_message_get_signature(reply);
+ if ((int)*signature != DBUS_TYPE_ARRAY)
+ goto unref;
+ dbus_message_iter_init(reply, &iter);
+ iterate_session_reply(&iter, &obj->properties);
+ ret = NSS_STATUS_SUCCESS;
+unref:
+ dbus_message_unref(reply);
+out:
+ if (ret != NSS_STATUS_SUCCESS)
+ logerr(MODPREFIX "%s failed", __FUNCTION__);
+ return ret;
+}
+
+typedef enum member_e {
+ DeviceAdded = 0,
+ DeviceChanged,
+ DeviceRemoved,
+ SessionAdded,
+ SessionRemoved,
+ UnkownMember
+} member_t;
+
+static time_t do_cache_update(struct lookup_context *ctxt,
+ const char *key, const char *mapent,
+ const int update)
+{
+ struct autofs_point *ap = ctxt->ap;
+ struct map_source *map = ctxt->map;
+ struct mapent_cache *mc;
+ time_t age = time(NULL);
+ char path[PATH_MAX+1];
+ int manage = 0;
+
+ if (!ap || !map->mc)
+ return 0;
+ mc = map->mc;
+
+ if ((ap->flags & MOUNT_FLAG_GHOST) && strlen(key)) {
+ int len = snprintf(path, PATH_MAX, "%s/%s", ap->path, key);
+ if (len < 0 || len >= PATH_MAX)
+ return 0;
+ manage = 1;
+ }
+
+ cache_writelock(mc);
+ switch (update) {
+ case DeviceRemoved:
+ debug(LOGOPT_NONE, MODPREFIX "%s %d remove %s -> %s", __FUNCTION__, __LINE__, key, mapent);
+ cache_delete(mc, key);
+ if (manage)
+ rmdir_path(ap, path, ap->dev);
+ break;
+ default:
+ case DeviceAdded:
+ debug(LOGOPT_NONE, MODPREFIX "%s %d added %s -> %s", __FUNCTION__, __LINE__, key, mapent);
+ cache_update(mc, map, key, mapent, age);
+ if (manage)
+ mkdir_path(path, 0555);
+ break;
+ }
+ cache_unlock(mc);
+
+ map->age = age;
+ return age;
+}
+
+static DBusHandlerResult dbusfilter(DBusConnection *connection,
+ DBusMessage *message,
+ void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *)context;
+ DBusMessageIter iter;
+ const char *interface;
+ const char *member;
+ const char *path;
+ int type, state;
+ member_t memb;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
+
+ type = dbus_message_get_type(message);
+ switch (type) {
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ path = dbus_message_get_path(message);
+ if (!path)
+ break;
+ if (strncmp("/org/freedesktop/", path, 17))
+ break;
+ interface = dbus_message_get_interface(message);
+ if (!interface)
+ break;
+ if (strncmp("org.freedesktop.", interface, 16))
+ break;
+ member = dbus_message_get_member(message);
+ if (!member) {
+ warn(LOGOPT_NONE, MODPREFIX
+ "udisks member of `%s' is missed known", path);
+ break;
+ }
+
+ memb = UnkownMember;
+ if (strcmp("UDisks", path+17) == 0) {
+ if (strcmp("UDisks", interface+16))
+ break;
+ if (strncmp(member, "Device", 6)) {
+ warn(LOGOPT_NONE, MODPREFIX
+ "udisks member `%s' not known", member);
+ break;
+ }
+ member += 6;
+
+ if (strcmp(member, "Added") == 0)
+ memb = DeviceAdded;
+ else if (strcmp(member, "Changed") == 0)
+ memb = DeviceChanged;
+ else if (strcmp(member, "Removed") == 0)
+ memb = DeviceRemoved;
+
+ } else if (strncmp("ConsoleKit/Seat", path+17, 4) == 0) {
+ if (strcmp("ConsoleKit.Seat", interface+16))
+ break;
+ if (strncmp(member, "Session", 7)) {
+ warn(LOGOPT_NONE, MODPREFIX
+ "udisks member `%s' not known", member);
+ break;
+ }
+ member += 7;
+
+ if (strcmp(member, "Added") == 0)
+ memb = SessionAdded;
+ else if (strcmp(member, "Removed") == 0)
+ memb = SessionRemoved;
+
+ } else
+ break;
+
+ dbus_message_iter_init(message, &iter);
+ type = dbus_message_iter_get_arg_type(&iter);
+ if (type != DBUS_TYPE_OBJECT_PATH) {
+ warn(LOGOPT_NONE, MODPREFIX
+ "udisks member `Device%s' without object path", member);
+ break;
+ }
+ dbus_message_iter_get_basic(&iter, &path);
+ lock(ctxt);
+ switch (memb) {
+ case DeviceAdded: {
+ device_t *this = add_device(&ctxt->devices, path);
+ if (this) {
+ entry_t *entry;
+ int ret = read_device_properties(ctxt, this);
+ if (ret != NSS_STATUS_SUCCESS) {
+ remove_device(&ctxt->devices, path);
+ break;
+ }
+ entry = do_map_entry(ctxt, this);
+ if (entry)
+ entry->age = do_cache_update(ctxt, entry->key, entry->mapent, DeviceAdded);
+ }
+ break;
+ }
+ case DeviceChanged: {
+ char *key = (char*)0;
+ device_t *this = find_device(&ctxt->devices, path);
+ if (this) {
+ entry_t *entry = this->entry;
+ if (entry)
+ key = strdup(entry->key);
+ delete_device(this);
+ }
+ this = add_device(&ctxt->devices, path);
+ if (this) {
+ entry_t *entry;
+ int ret = read_device_properties(ctxt, this);
+ if (ret != NSS_STATUS_SUCCESS) {
+ remove_device(&ctxt->devices, path);
+ if (key)
+ free(key);
+ break;
+ }
+ entry = do_map_entry(ctxt, this);
+ if (entry) {
+ if (key == (char*)0)
+ entry->age = do_cache_update(ctxt, entry->key, entry->mapent, DeviceAdded);
+ else if (strcmp(key, entry->key) != 0) {
+ entry->age = do_cache_update(ctxt, entry->key, entry->mapent, DeviceAdded);
+ free(key);
+ }
+ } else {
+ if (key) {
+ (void)do_cache_update(ctxt, key, (char*)0, DeviceRemoved);
+ free(key);
+ }
+ }
+ break;
+ }
+ if (!key)
+ break;
+ do_cache_update(ctxt, key, (char*)0, DeviceRemoved);
+ free(key);
+ break;
+ }
+ case DeviceRemoved: {
+ device_t *this = find_device(&ctxt->devices, path);
+ if (this) {
+ entry_t *entry = this->entry;
+ if (entry)
+ (void)do_cache_update(ctxt, entry->key, (char*)0, DeviceRemoved);
+ delete_device(this);
+ }
+ break;
+ }
+ case SessionAdded: {
+ session_t *this = add_session(&ctxt->sessions, path);
+ if (this) {
+ int ret = read_session_properties(ctxt, this);
+ if (ret == NSS_STATUS_SUCCESS) {
+ debug(LOGOPT_NONE, MODPREFIX "%s %d added session %s", __FUNCTION__, __LINE__, path);
+ break;
+ }
+ remove_session(&ctxt->sessions, path);
+ }
+ break;
+ }
+ case SessionRemoved: {
+ session_t *this = find_session(&ctxt->sessions, path);
+ if (this) {
+ debug(LOGOPT_NONE, MODPREFIX "%s %d removed session %s", __FUNCTION__, __LINE__, path);
+ delete_session(this);
+ }
+ break;
+ }
+ default:
+ warn(LOGOPT_NONE, MODPREFIX "udisks member `Device%s' not known", member);
+ break;
+ }
+ unlock(ctxt);
+ default:
+ break;
+ }
+
+ pthread_setcancelstate(state, NULL);
+
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
+ if (ctxt->active) {
+ lock(ctxt);
+ ctxt->active = 0;
+ unlock(ctxt);
+ pthread_exit(NULL);
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void free_config(struct lookup_context *ctxt)
+{
+ list_t *ptr, *safe;
+ if (ctxt->config.common)
+ free(ctxt->config.common);
+ list_for_each_safe(ptr, safe, &ctxt->config.fstypes) {
+ mntopt_t *this = list_entry(ptr, mntopt_t, handle);
+ list_del(ptr);
+ free(this);
+ }
+ list_for_each_safe(ptr, safe, &ctxt->config.byid) {
+ mntopt_t *this = list_entry(ptr, mntopt_t, handle);
+ list_del(ptr);
+ free(this);
+ }
+ list_for_each_safe(ptr, safe, &ctxt->config.label) {
+ mntopt_t *this = list_entry(ptr, mntopt_t, handle);
+ list_del(ptr);
+ free(this);
+ }
+}
+
+#ifdef LIBXML_TREE_ENABLED
+static void xmlerror(void *context, xmlErrorPtr err)
+{
+ struct lookup_context *ctxt = (struct lookup_context*)context;
+ char *message = err->message;
+ char *nl = strrchr(message, '\n');
+ if (nl) *nl = '\0';
+ logerr(MODPREFIX "in %s at line %d: %s", ctxt->mapname, err->line, err->message);
+ xmlResetError(err);
+ ctxt->config.enabled = 0;
+}
+
+#define FILTER(property) { #property, property }
+static filter_t cnfproperpty[] = {
+ FILTER(AutofsUdisks),
+ FILTER(MountOptions),
+ FILTER(Common),
+ FILTER(DiskById),
+ FILTER(DiskByLabel),
+ FILTER(FSType),
+ { (char*)0, 0 }
+};
+#undef FILTER
+
+static filter_t *check_config(struct lookup_context *ctxt, const xmlChar *name, const int depth)
+{
+ filter_t *flt;
+ cnfxml_t obj = 0;
+
+ flt = &cnfproperpty[obj];
+
+ do {
+ if (flt->property == (char*)0)
+ break;
+ if (strcmp(flt->property, (char*)name) == 0)
+ break;
+ } while (flt++);
+
+ switch (flt->type) {
+ case AutofsUdisks:
+ case MountOptions:
+ if (depth == flt->type)
+ break;
+ logerr(MODPREFIX "broken xml configuration file %s", ctxt->mapname);
+ ctxt->config.enabled = 0;
+ default:
+ break;
+ }
+
+ return flt;
+}
+
+static void add_config(struct lookup_context *ctxt, list_t *head, const char *fs, const char* opts)
+{
+ mntopt_t *restrict new;
+
+ new = newaligned(alignof(mntopt_t)+strsize(fs)+strsize(opts));
+ if (!new) {
+ ctxt->config.enabled = 0;
+ return;
+ }
+ memset(new, 0, alignof(mntopt_t));
+
+ list_add_tail(&new->handle, head);
+
+ new->identify = ((typeof(new->identify))new)+alignof(mntopt_t);
+ strcpy(new->identify, fs);
+
+ new->options = ((typeof(new->options))new)+alignof(mntopt_t)+strsize(fs);
+ strcpy(new->options, opts);
+}
+
+static void iterate_config(struct lookup_context *ctxt, const xmlNode *node, int depth)
+{
+ const xmlNode *curr;
+
+ for (curr = node; curr; curr = curr->next) {
+ const xmlAttr *attr;
+ xmlNode *child;
+ xmlChar *entry;
+ xmlChar *opts;
+ filter_t *flt;
+ list_t *head;
+ int cnt;
+
+ if (curr->type != XML_ELEMENT_NODE)
+ continue;
+ child = curr->children;
+ flt = check_config(ctxt, curr->name, depth);
+ head = (list_t*)0;
+ opts = (xmlChar*)0;
+
+ entry = xmlNodeListGetString(curr->doc, child, 1);
+ if (entry) {
+ char *nl;
+ opts = entry;
+ while (*opts == ' ' || *opts == '\n')
+ opts++;
+ if ((nl = strchr((char*)opts, '\n')))
+ *nl = '\0';
+ switch (flt->type) {
+ case AutofsUdisks:
+ case MountOptions:
+ if (*opts == '\0')
+ break;
+ goto err;
+ case Common:
+ if (ctxt->config.common)
+ goto err;
+ ctxt->config.common = strdup((char*)opts);
+ break;
+ case DiskById:
+ if (!curr->properties)
+ goto err;
+ head = &ctxt->config.byid;
+ break;
+ case DiskByLabel:
+ if (!curr->properties)
+ goto err;
+ head = &ctxt->config.label;
+ break;
+ case FSType:
+ head = &ctxt->config.fstypes;
+ if (!curr->properties)
+ add_config(ctxt, head, "auto", (const char*)opts);
+ break;
+ default:
+ goto err;
+ }
+ }
+
+ for (attr = curr->properties, cnt = 0; attr; attr = attr->next, cnt++) {
+ xmlChar *key;
+ if (!attr->name)
+ continue;
+ switch (flt->type) {
+ case MountOptions:
+ case Common:
+ goto err;
+ default:
+ if (!cnt)
+ break;
+ goto err;
+ }
+ key = xmlNodeListGetString(attr->doc, attr->children, 1);
+ if (key) {
+ char *nl;
+ xmlChar *ptr = key;
+ while (*ptr == ' ' || *ptr == '\n')
+ ptr++;
+ if ((nl = strchr((char*)opts, '\n')))
+ *nl = '\0';
+ switch (flt->type) {
+ case AutofsUdisks:
+ if (strcmp("enable", (char*)attr->name))
+ goto err;
+ if (strcasecmp("true", (char*)ptr) == 0 ||
+ strcasecmp("yes", (char*)ptr) == 0)
+ ctxt->config.enabled = 1; /* Here we go */
+ break;
+ default:
+ if (strcmp("value", (char*)attr->name))
+ goto err;
+ if (!head || !opts)
+ goto err;
+ add_config(ctxt, head, (const char*)ptr, (const char*)opts);
+ break;
+ }
+ xmlFree(key);
+ }
+ }
+ if (entry)
+ xmlFree(entry);
+
+ iterate_config(ctxt, child, ++depth);
+ }
+ return;
+err:
+ logerr(MODPREFIX "broken xml configuration file %s", ctxt->mapname);
+ ctxt->config.enabled = 0;
+}
+
+static void parse_config(struct lookup_context *ctxt, const char* path)
+{
+ xmlNode *root = (xmlNode*)0;
+ xmlDoc *doc;
+
+ xmlSetStructuredErrorFunc(ctxt, &xmlerror);
+
+ doc = xmlReadFile(path, (const char*)0, XML_PARSE_NONET | XML_PARSE_PEDANTIC);
+ if (!doc)
+ return;
+ root = xmlDocGetRootElement(doc);
+ if (!root) {
+ xmlFreeDoc(doc);
+ return;
+ }
+
+ iterate_config(ctxt, root, 0);
+
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+}
+#else /* !LIBXML_TREE_ENABLED */
+static void parse_config(struct lookup_context ctxt, const char* path)
+{
+ ctxt->config.enabled = 0;
+}
+#endif /* !LIBXML_TREE_ENABLED */
+
+static void free_context(struct lookup_context *ctxt)
+{
+ if (ctxt->active) {
+ lock(ctxt);
+ ctxt->active = 0;
+ unlock(ctxt);
+ pthread_yield();
+ if (ctxt->running && ctxt->watchdog)
+ pthread_cancel(ctxt->watchdog);
+ }
+
+ lock(ctxt);
+ if (!list_empty(&ctxt->devices)) {
+ list_t *ptr;
+ list_for_each(ptr, &ctxt->devices) {
+ entry_t *entry;
+ device_t *this = list_entry(ptr, device_t, handle);
+ if (!this)
+ continue;
+ entry = do_map_entry(ctxt, this);
+ if (!entry)
+ continue;
+ do_cache_update(ctxt, entry->key, entry->mapent, DeviceRemoved);
+ }
+ clear_devices(&ctxt->devices);
+ }
+ if (!list_empty(&ctxt->sessions))
+ clear_sessions(&ctxt->sessions);
+ unlock(ctxt);
+ pthread_mutex_destroy(&ctxt->mtx);
+
+ free_config(ctxt);
+
+ if (ctxt->error && dbus_error_is_set(ctxt->error))
+ dbus_error_free(ctxt->error);
+ if (ctxt->conn) {
+ dbus_connection_close(ctxt->conn);
+ dbus_connection_unref(ctxt->conn);
+ }
+ dbus_shutdown();
+
+ free(ctxt);
+}
+
+int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **context)
+{
+ struct lookup_context *restrict ctxt;
+ const char *address;
+ struct stat st;
+ int ret;
+
+ *context = NULL;
+
+ debug(LOGOPT_NONE, MODPREFIX "lookup init with argv[0] == %s", argv[0]);
+
+ if (sizeof(devproperpty)/sizeof(filter_t) != NullDict+1) {
+ logerr(MODPREFIX "size of hash array does not fit numbers of symbols");
+ goto err;
+ }
+ if (sizeof(sessproperty)/sizeof(filter_t) != NullCk+1) {
+ logerr(MODPREFIX "size of hash array does not fit numbers of symbols");
+ goto err;
+ }
+
+#ifdef LIBXML_TREE_ENABLED
+ if (sizeof(cnfproperpty)/sizeof(filter_t) != NullCnf+1) {
+ logerr(MODPREFIX "size of hash array does not fit numbers of symbols");
+ goto err;
+ }
+ xmlInitParser();
+
+ /*
+ * This initialize the library and check potential ABI mismatches
+ * between the version it was compiled for and the actual shared
+ * library used.
+ */
+ LIBXML_TEST_VERSION
+#else /* !LIBXML_TREE_ENABLED */
+ logerr(MODPREFIX "there was no XML support compiled in");
+ goto err;
+#endif /* !LIBXML_TREE_ENABLED */
+ ctxt = newaligned(alignof(struct lookup_context)+sizeof(struct DBusError));
+ if (!ctxt)
+ goto err;
+ memset(ctxt, 0, alignof(struct lookup_context));
+
+ INIT_LIST_HEAD(&ctxt->devices);
+ INIT_LIST_HEAD(&ctxt->sessions);
+ INIT_LIST_HEAD(&ctxt->config.fstypes);
+ INIT_LIST_HEAD(&ctxt->config.byid);
+ INIT_LIST_HEAD(&ctxt->config.label);
+ ctxt->config.enabled = 0;
+ ctxt->error = (struct DBusError*)((void*)ctxt+alignof(struct lookup_context));
+ dbus_error_init(ctxt->error);
+
+ ret = pthread_mutex_init(&ctxt->mtx, NULL);
+ if (ret) {
+ error(LOGOPT_ANY, MODPREFIX "failed to init mutex");
+ goto ferr;
+ }
+
+ /* If a map type isn't explicitly given, parse it like sun entries. */
+ if (mapfmt == NULL)
+ mapfmt = MAPFMT_DEFAULT;
+
+ if (argc < 1) {
+ logerr(MODPREFIX "No map name");
+ goto ferr;
+ }
+ ctxt->mapname = argv[0];
+ if (ctxt->mapname[0] != '/') {
+ logmsg(MODPREFIX
+ "udisks autofs %s is not an absolute pathname", argv[0]);
+ goto ferr;
+ }
+ if (access(ctxt->mapname, R_OK)) {
+ logerr(MODPREFIX
+ "udisks autofs %s missing or not readable", argv[0]);
+ goto ferr;
+ }
+ if (stat(ctxt->mapname, &st)) {
+ logerr(MODPREFIX
+ "udisks autofs %s, could not stat", argv[0]);
+ goto ferr;
+ }
+
+ if (S_ISREG(st.st_mode) == 0) {
+ logerr(MODPREFIX
+ "udisks autofs %s, is not a regular file", argv[0]);
+ goto ferr;
+ }
+ parse_config(ctxt, ctxt->mapname);
+
+ if (dbus_threads_init_default() == FALSE) {
+ char buf[MAX_ERR_BUF];
+ const char *const estr = strerror_r(errno, buf, sizeof(buf));
+ logerr(MODPREFIX "memory allocation: %s", estr);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ ctxt->conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, ctxt->error);
+ if (!ctxt->conn) {
+ logerr(MODPREFIX "udisks map %s, can not connect system dbus: %s",
+ ctxt->mapname, ctxt->error->message);
+ goto ferr;
+ }
+ dbus_connection_set_exit_on_disconnect(ctxt->conn, FALSE);
+
+ ret = dbus_bus_start_service_by_name(ctxt->conn, "org.freedesktop.UDisks", 0, 0, ctxt->error);
+ if ((dbus_bool_t)ret == FALSE) {
+ warn(LOGOPT_NONE, MODPREFIX
+ "udisks map %s, can not start system udisks service: %s", argv[0], ctxt->error->message);
+ goto ferr;
+ }
+
+ ret = dbus_bus_request_name(ctxt->conn, "org.freedesktop.AutoMount", DBUS_NAME_FLAG_REPLACE_EXISTING, ctxt->error);
+ if ((dbus_bool_t)ret == FALSE) {
+ logerr(MODPREFIX "udisks map %s, can not connect system dbus: %s",
+ ctxt->mapname, ctxt->error->message);
+ goto ferr;
+ }
+
+ /* Open the parser, if we can. */
+ ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
+ if (!ctxt->parse) {
+ logerr(MODPREFIX "failed to open parse context");
+ goto ferr;
+ }
+
+ ctxt->ap = (struct autofs_point*)0;
+ *context = ctxt;
+ return NSS_STATUS_SUCCESS;
+ferr:
+ free_context(ctxt);
+err:
+ logerr(MODPREFIX "%s failed", __FUNCTION__);
+ return NSS_STATUS_NOTFOUND;
+}
+
+int lookup_read_master(struct master *master, time_t age, void *context)
+{
+ logmsg(MODPREFIX "%s master not supported", __FUNCTION__);
+ return NSS_STATUS_UNKNOWN;
+}
+
+static int read_current_map(struct lookup_context *ctxt)
+{
+ DBusMessage *reply, *send;
+ DBusMessageIter iter, isub;
+ int type, ret = NSS_STATUS_UNAVAIL;
+
+ send = dbus_message_new_method_call("org.freedesktop.UDisks",
+ "/org/freedesktop/UDisks",
+ "org.freedesktop.UDisks",
+ "EnumerateDevices");
+ if (!send)
+ goto err;
+ dbus_message_set_auto_start(send, TRUE);
+ if (!dbus_message_set_destination(send, "org.freedesktop.UDisks"))
+ goto err;
+
+ reply = dbus_connection_send_with_reply_and_block(ctxt->conn, send, 50000, ctxt->error);
+ dbus_message_unref(send);
+
+ if (dbus_error_is_set(ctxt->error)) {
+ logerr(MODPREFIX "udisks map %s, can not connect system dbus: %s",
+ ctxt->mapname, ctxt->error->message);
+ dbus_error_free(ctxt->error);
+ goto err;
+ }
+ if (!reply)
+ goto err;
+ if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ goto unref;
+
+ /*
+ * As reply we assume an array of strings here,
+ * each of them a device path
+ */
+ dbus_message_iter_init(reply, &iter);
+ type = dbus_message_iter_get_arg_type(&iter);
+ if (type != DBUS_TYPE_ARRAY)
+ goto unref;
+
+ dbus_message_iter_recurse (&iter, &isub);
+ type = dbus_message_iter_get_arg_type(&isub);
+ if (type == DBUS_TYPE_BYTE)
+ goto unref;
+
+ while (type == DBUS_TYPE_OBJECT_PATH) {
+ char *path;
+
+ dbus_message_iter_get_basic(&isub, &path);
+ if (add_device(&ctxt->devices, path) == (device_t*)0)
+ goto unref;
+
+ dbus_message_iter_next (&isub);
+ type = dbus_message_iter_get_arg_type(&isub);
+ }
+ ret = NSS_STATUS_SUCCESS;
+unref:
+ dbus_message_unref(reply);
+err:
+ if (ret != NSS_STATUS_SUCCESS)
+ logerr(MODPREFIX "%s faild", __FUNCTION__);
+ return ret;
+}
+
+static int read_current_sessions(struct lookup_context *ctxt, const char* seat)
+{
+ DBusMessage *reply, *send;
+ DBusMessageIter iter, isub;
+ int type, ret = NSS_STATUS_UNAVAIL;
+
+
+ send = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
+ seat,
+ "org.freedesktop.ConsoleKit.Seat",
+ "GetSessions");
+ if (!send)
+ goto err;
+ dbus_message_set_auto_start(send, TRUE);
+ if (!dbus_message_set_destination(send, "org.freedesktop.ConsoleKit"))
+ goto err;
+
+ reply = dbus_connection_send_with_reply_and_block(ctxt->conn, send, 50000, ctxt->error);
+ dbus_message_unref(send);
+
+ if (dbus_error_is_set(ctxt->error)) {
+ logerr(MODPREFIX "udisks sessions %s, can not connect system dbus: %s",
+ ctxt->mapname, ctxt->error->message);
+ dbus_error_free(ctxt->error);
+ goto err;
+ }
+ if (!reply)
+ goto err;
+ if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ goto unref;
+
+ /*
+ * As reply we assume an array of strings here,
+ * each of them a seat path
+ */
+ dbus_message_iter_init(reply, &iter);
+ type = dbus_message_iter_get_arg_type(&iter);
+ if (type != DBUS_TYPE_ARRAY)
+ goto unref;
+
+ dbus_message_iter_recurse (&iter, &isub);
+ type = dbus_message_iter_get_arg_type(&isub);
+ if (type == DBUS_TYPE_BYTE)
+ goto unref;
+
+ while (type == DBUS_TYPE_OBJECT_PATH) {
+ char *path;
+
+ dbus_message_iter_get_basic(&isub, &path);
+ if (add_session(&ctxt->sessions, path) == (session_t*)0)
+ goto unref;
+
+ dbus_message_iter_next (&isub);
+ type = dbus_message_iter_get_arg_type(&isub);
+ }
+ ret = NSS_STATUS_SUCCESS;
+unref:
+ dbus_message_unref(reply);
+err:
+ if (ret != NSS_STATUS_SUCCESS)
+ logerr(MODPREFIX "%s faild", __FUNCTION__);
+ return ret;
+}
+
+static int read_current_seats(struct lookup_context *ctxt)
+{
+ DBusMessage *reply, *send;
+ DBusMessageIter iter, isub;
+ int type, ret = NSS_STATUS_UNAVAIL;
+
+ send = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
+ "/org/freedesktop/ConsoleKit/Manager",
+ "org.freedesktop.ConsoleKit.Manager",
+ "GetSeats");
+ if (!send)
+ goto err;
+ dbus_message_set_auto_start(send, TRUE);
+ if (!dbus_message_set_destination(send, "org.freedesktop.ConsoleKit"))
+ goto err;
+
+ reply = dbus_connection_send_with_reply_and_block(ctxt->conn, send, 50000, ctxt->error);
+ dbus_message_unref(send);
+
+ if (dbus_error_is_set(ctxt->error)) {
+ logerr(MODPREFIX "udisks seats %s, can not connect system dbus: %s",
+ ctxt->mapname, ctxt->error->message);
+ dbus_error_free(ctxt->error);
+ goto err;
+ }
+ if (!reply)
+ goto err;
+ if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ goto unref;
+
+ /*
+ * As reply we assume an array of strings here,
+ * each of them a seat path
+ */
+ dbus_message_iter_init(reply, &iter);
+ type = dbus_message_iter_get_arg_type(&iter);
+ if (type != DBUS_TYPE_ARRAY)
+ goto unref;
+
+ dbus_message_iter_recurse (&iter, &isub);
+ type = dbus_message_iter_get_arg_type(&isub);
+ if (type == DBUS_TYPE_BYTE)
+ goto unref;
+
+ while (type == DBUS_TYPE_OBJECT_PATH) {
+ char *seat;
+
+ dbus_message_iter_get_basic(&isub, &seat);
+ if (read_current_sessions(ctxt, seat) != NSS_STATUS_SUCCESS)
+ goto unref;
+
+ dbus_message_iter_next (&isub);
+ type = dbus_message_iter_get_arg_type(&isub);
+ }
+ ret = NSS_STATUS_SUCCESS;
+unref:
+ dbus_message_unref(reply);
+err:
+ if (ret != NSS_STATUS_SUCCESS)
+ logerr(MODPREFIX "%s faild", __FUNCTION__);
+ return ret;
+}
+
+static void *udisks_dispatcher(void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *)context;
+
+ lock(ctxt);
+ ctxt->active = 1;
+ ctxt->running = 1;
+ unlock(ctxt);
+ while (dbus_connection_read_write_dispatch(ctxt->conn, -1)) {
+ if (!ctxt->active)
+ break;
+ }
+ lock(ctxt);
+ ctxt->running = 0;
+ unlock(ctxt);
+ return NULL;
+}
+
+static int enable_udisks_watchdog(struct lookup_context *ctxt)
+{
+ int policy = SCHED_RR, ret;
+ struct sched_param param;
+ char match[128] = "eavesdrop='true',type='signal',sender='org.freedesktop.%s',interface='org.freedesktop.%s'";
+ char *restrict mptr;
+ int offset;
+
+ if (ctxt->monitor)
+ goto dog;
+ offset = 0;
+ckretry:
+ ret = asprintf((char**)&mptr, &match[offset], "ConsoleKit", "ConsoleKit.Seat");
+ if (ret < 0) {
+ char buf[MAX_ERR_BUF];
+ const char *const estr = strerror_r(errno, buf, sizeof(buf));
+ logerr(MODPREFIX "memory allocation: %s", estr);
+ goto err;
+ }
+ dbus_bus_add_match(ctxt->conn, mptr, ctxt->error);
+ free(mptr);
+ if (dbus_error_is_set(ctxt->error)) {
+ if (!offset && strcmp(ctxt->error->name, DBUS_ERROR_MATCH_RULE_INVALID) == 0) {
+ offset = strlen("eavesdrop='true',");
+ dbus_error_free(ctxt->error);
+ goto ckretry;
+ }
+ logerr(MODPREFIX "udisks sessions %s, can not listen system ConsoleKit: %s",
+ ctxt->mapname, ctxt->error->message);
+ dbus_error_free(ctxt->error);
+ goto err;
+ }
+ offset = 0;
+uretry:
+ ret = asprintf((char**)&mptr, &match[offset], "UDisks", "UDisks");
+ if (ret < 0) {
+ char buf[MAX_ERR_BUF];
+ const char *const estr = strerror_r(errno, buf, sizeof(buf));
+ logerr(MODPREFIX "memory allocation: %s", estr);
+ goto err;
+ }
+ dbus_bus_add_match(ctxt->conn, mptr, ctxt->error);
+ free(mptr);
+ if (dbus_error_is_set(ctxt->error)) {
+ if (!offset && strcmp(ctxt->error->name, DBUS_ERROR_MATCH_RULE_INVALID) == 0) {
+ offset = strlen("eavesdrop='true',");
+ dbus_error_free(ctxt->error);
+ goto uretry;
+ }
+ logerr(MODPREFIX "udisks map %s, can not listen system UDisks: %s",
+ ctxt->mapname, ctxt->error->message);
+ dbus_error_free(ctxt->error);
+ goto err;
+ }
+ if ((ctxt->monitor = dbus_connection_add_filter(ctxt->conn, dbusfilter, (void *)ctxt, NULL)) != TRUE) {
+ logerr(MODPREFIX "udisks %s, could not add device and session filters: %s", ctxt->mapname, ctxt->error->message);
+ dbus_error_free(ctxt->error);
+ goto err;
+ }
+dog:
+ if (ctxt->watchdog)
+ goto out;
+ ret = pthread_getschedparam(pthread_self(), &policy, ¶m);
+ if (pthread_create(&ctxt->watchdog, &th_attr_detached, &udisks_dispatcher, (void *)ctxt) != 0) {
+ ctxt->watchdog = (pthread_t)0;
+ goto err;
+ }
+ if (ret == 0) pthread_setschedparam(ctxt->watchdog, policy, ¶m);
+out:
+ return NSS_STATUS_SUCCESS;
+err:
+ return NSS_STATUS_UNAVAIL;
+}
+
+int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *)context;
+ struct map_source *source;
+ struct mapent_cache *mc;
+ int ret, cur_state;
+ list_t *ptr;
+
+ ctxt->ap = ap;
+ ctxt->map = ap->entry->current;
+#if defined(DEBUG) && (DEBUG > 0)
+ ctxt->ap->logopt = LOGOPT_DEBUG;
+#endif
+
+ source = ap->entry->current;
+ ap->entry->current = NULL;
+ master_source_current_signal(ap->entry);
+
+ /*
+ * If we don't need to create directories then there's no use
+ * reading the map. We always need to read the whole map for
+ * direct mounts in order to mount the triggers.
+ */
+ ret = NSS_STATUS_SUCCESS;
+ if ((ap->flags & MOUNT_FLAG_GHOST) == 0 && ap->type != LKP_DIRECT) {
+ debug(ap->logopt, "map read not needed, so not done");
+ goto out;
+ }
+
+ if (sizeof(devproperpty)/sizeof(filter_t) != NullDict+1) {
+ logerr(MODPREFIX "size of hash array does not fit numbers of symbols");
+ goto out;
+ }
+
+ mc = source->mc;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+ ret = enable_udisks_watchdog(context);
+ if (ret != NSS_STATUS_SUCCESS) {
+ warn(LOGOPT_NONE, MODPREFIX "udisks map %s, could not start watchdog",
+ ctxt->mapname);
+ goto cancel;
+ }
+
+ lock(ctxt);
+ if (list_empty(&ctxt->devices)) {
+ ret = read_current_map(ctxt);
+ if (ret != NSS_STATUS_SUCCESS) {
+ unlock(ctxt);
+ goto cancel;
+ }
+ list_for_each(ptr, &ctxt->devices) {
+ device_t *this = list_entry(ptr, device_t, handle);
+ ret = read_device_properties(ctxt, this);
+ if (ret != NSS_STATUS_SUCCESS) {
+ unlock(ctxt);
+ goto cancel;
+ }
+ }
+ }
+ if (list_empty(&ctxt->sessions)) {
+ ret = read_current_seats(ctxt);
+ if (ret != NSS_STATUS_SUCCESS) {
+ unlock(ctxt);
+ goto cancel;
+ }
+ list_for_each(ptr, &ctxt->sessions) {
+ session_t *this = list_entry(ptr, session_t, handle);
+ ret = read_session_properties(ctxt, this);
+ if (ret != NSS_STATUS_SUCCESS) {
+ unlock(ctxt);
+ goto cancel;
+ }
+ }
+ }
+ list_for_each(ptr, &ctxt->devices) {
+ device_t *this = list_entry(ptr, device_t, handle);
+ entry_t *entry = do_map_entry(ctxt, this);
+ char *key;
+
+ if (entry == (entry_t*)0)
+ continue;
+ if (entry->key == (char*)0)
+ continue;
+
+ key = sanitize_path(entry->key, entry->key_len, ap->type, ap->logopt);
+ if (key == (char*)0)
+ continue;
+
+ entry->age = age;
+
+ cache_writelock(mc);
+ cache_update(mc, source, key, entry->mapent, age);
+ cache_unlock(mc);
+
+ free(key);
+ }
+ unlock(ctxt);
+ source->age = age;
+cancel:
+ pthread_setcancelstate(cur_state, NULL);
+out:
+ return ret;
+}
+
+static int lookup_one(struct autofs_point *ap,
+ char *key, int key_len,
+ struct lookup_context *ctxt)
+{
+ struct map_source *source;
+ struct mapent_cache *mc;
+ time_t age = time(NULL);
+ int ret, cur_state;
+ entry_t *entry;
+ list_t *ptr;
+
+ source = ap->entry->current;
+ ap->entry->current = NULL;
+ master_source_current_signal(ap->entry);
+
+ mc = source->mc;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+
+ lock(ctxt);
+ entry = (entry_t*)0;
+ list_for_each(ptr, &ctxt->devices) {
+ device_t *this = list_entry(ptr, device_t, handle);
+ entry = this->entry;
+
+ if (entry == (entry_t*)0)
+ continue;
+ if (entry->key == (char*)0)
+ continue;
+
+ if (entry->key_len != key_len)
+ continue;
+
+ if (strcmp(entry->key, key) == 0)
+ break;
+ entry = (entry_t*)0;
+ }
+ unlock(ctxt);
+
+ ret = CHE_MISSING;
+ if (entry == (entry_t*)0)
+ goto out;
+
+ entry->age = age;
+
+ cache_writelock(mc);
+ ret = cache_update(mc, source, key, entry->mapent, age);
+ cache_unlock(mc);
+out:
+ pthread_setcancelstate(cur_state, NULL);
+ return ret;
+}
+
+static int check_map_indirect(struct autofs_point *ap,
+ char *key, int key_len,
+ struct lookup_context *ctxt)
+{
+ struct map_source *source;
+ struct mapent_cache *mc;
+ struct mapent *me;
+ time_t now = time(NULL);
+ time_t t_last_read;
+ int ret, cur_state;
+
+ source = ap->entry->current;
+ ap->entry->current = NULL;
+ master_source_current_signal(ap->entry);
+
+ mc = source->mc;
+
+ master_source_current_wait(ap->entry);
+ ap->entry->current = source;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+ ret = lookup_one(ap, key, key_len, ctxt);
+ if (ret == CHE_FAIL) {
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_NOTFOUND;
+ }
+ if (ret == CHE_UNAVAIL) {
+ /*
+ * If the server is down and the entry exists in the cache
+ * and belongs to this map return success and use the entry.
+ */
+ struct mapent *exists = cache_lookup(mc, key);
+ if (exists && exists->source == source) {
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_SUCCESS;
+ }
+
+ warn(ap->logopt,
+ MODPREFIX "lookup for %s failed: connection failed", key);
+
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_UNAVAIL;
+ }
+ if (ret == CHE_COMPLETED) {
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_COMPLETED;
+ }
+ pthread_setcancelstate(cur_state, NULL);
+
+ /*
+ * Check for map change and update as needed for
+ * following cache lookup.
+ */
+ cache_readlock(mc);
+ t_last_read = ap->exp_runfreq + 1;
+ me = cache_lookup_first(mc);
+ while (me) {
+ if (me->source == source) {
+ t_last_read = now - me->age;
+ break;
+ }
+ me = cache_lookup_next(mc, me);
+ }
+ cache_unlock(mc);
+
+ if (t_last_read > ap->exp_runfreq && ret & CHE_UPDATED)
+ source->stale = 1;
+
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, "*");
+ if (ret == CHE_MISSING && (!me || me->source != source)) {
+ cache_unlock(mc);
+ return NSS_STATUS_NOTFOUND;
+ }
+ cache_unlock(mc);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static int check_permsission(struct autofs_point *ap, struct lookup_context *ctxt)
+{
+ struct thread_stdenv_vars *tsv;
+ int state, ret;
+
+ ret = NSS_STATUS_UNAVAIL;
+ if (list_empty(&ctxt->sessions))
+ goto out;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
+
+ tsv = pthread_getspecific(key_thread_stdenv_vars);
+ if (tsv) {
+ list_t *ptr;
+ list_for_each(ptr, &ctxt->sessions) {
+ session_t *session = list_entry(ptr, session_t, handle);
+ option_t opt = get_session(session, unix_user);
+ if (opt.error)
+ break;
+ if (opt.uint32 == (unsigned int)tsv->uid) {
+ option_t opt = get_session(session, is_local);
+ if (opt.error)
+ break;
+ if (opt.boolean) {
+ ret = NSS_STATUS_SUCCESS;
+ break;
+ }
+#if defined(DEBUG) && (DEBUG > 0)
+ opt = get_session(session, x11_display);
+ if (opt.error)
+ break;
+ if (*opt.string == ':')
+ ret = NSS_STATUS_SUCCESS;
+#endif
+ break;
+ }
+ }
+ }
+
+ pthread_setcancelstate(state, NULL);
+out:
+ debug(ap->logopt, MODPREFIX "mount not allowed");
+ return ret;
+}
+
+int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ struct map_source *source;
+ struct mapent_cache *mc;
+ struct mapent *me;
+ char key[KEY_MAX_LEN + 1];
+ int key_len;
+ char *mapent = NULL;
+ char mapent_buf[MAPENT_MAX_LEN + 1];
+ int status = 0;
+ int ret = 1;
+
+ source = ap->entry->current;
+ ap->entry->current = NULL;
+ master_source_current_signal(ap->entry);
+
+ mc = source->mc;
+
+ debug(ap->logopt, MODPREFIX "looking up %s", name);
+
+ status = check_permsission(ap, ctxt);
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+
+ key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name);
+ if (key_len < 0 || key_len > KEY_MAX_LEN)
+ return NSS_STATUS_NOTFOUND;
+
+ if (sizeof(sessproperty)/sizeof(filter_t) != NullCk+1) {
+ logerr(MODPREFIX "size of hash array does not fit numbers of symbols");
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Check if we recorded a mount fail for this key anywhere */
+ me = lookup_source_mapent(ap, key, LKP_DISTINCT);
+ if (me) {
+ if (me->status >= time(NULL)) {
+ cache_unlock(me->mc);
+ return NSS_STATUS_NOTFOUND;
+ } else {
+ struct mapent_cache *smc = me->mc;
+ struct mapent *sme;
+
+ if (me->mapent)
+ cache_unlock(smc);
+ else {
+ cache_unlock(smc);
+ cache_writelock(smc);
+ sme = cache_lookup_distinct(smc, key);
+ /* Negative timeout expired for non-existent entry. */
+ if (sme && !sme->mapent)
+ cache_delete(smc, key);
+ cache_unlock(smc);
+ }
+ }
+ }
+
+ /*
+ * We can't check the direct mount map as if it's not in
+ * the map cache already we never get a mount lookup, so
+ * we never know about it.
+ */
+ if (ap->type == LKP_INDIRECT && *key != '/') {
+ char *lkp_key;
+
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, key);
+ if (me && me->multi)
+ lkp_key = strdup(me->multi->key);
+ else
+ lkp_key = strdup(key);
+ cache_unlock(mc);
+
+ if (!lkp_key)
+ return NSS_STATUS_UNKNOWN;
+
+ master_source_current_wait(ap->entry);
+ ap->entry->current = source;
+
+ status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt);
+ free(lkp_key);
+ if (status) {
+ if (status == NSS_STATUS_COMPLETED)
+ return NSS_STATUS_SUCCESS;
+ return NSS_STATUS_NOTFOUND;
+ }
+ }
+
+ cache_readlock(mc);
+ me = cache_lookup(mc, key);
+ /* Stale mapent => check for entry in alternate source or wildcard */
+ if (me && !me->mapent) {
+ while ((me = cache_lookup_key_next(me)))
+ if (me->source == source)
+ break;
+ if (!me)
+ me = cache_lookup_distinct(mc, "*");
+ }
+ if (me && me->mapent && (me->source == source || *me->key == '/')) {
+ pthread_cleanup_push(cache_lock_cleanup, mc);
+ strcpy(mapent_buf, me->mapent);
+ mapent = &mapent_buf[0];
+ pthread_cleanup_pop(0);
+ }
+ cache_unlock(mc);
+
+ if (!me)
+ return NSS_STATUS_NOTFOUND;
+
+ if (!mapent)
+ return NSS_STATUS_TRYAGAIN;
+
+ master_source_current_wait(ap->entry);
+ ap->entry->current = source;
+
+ debug(ap->logopt, MODPREFIX "%s -> %s", key, mapent);
+ ret = ctxt->parse->parse_mount(ap, key, key_len,
+ mapent, ctxt->parse->context);
+ if (ret) {
+ time_t now = time(NULL);
+ int rv = CHE_OK;
+
+ /* Record the the mount fail in the cache */
+ cache_writelock(mc);
+ me = cache_lookup_distinct(mc, key);
+ if (!me)
+ rv = cache_update(mc, source, key, NULL, now);
+ if (rv != CHE_FAIL) {
+ me = cache_lookup_distinct(mc, key);
+ me->status = now + ap->negative_timeout;
+ }
+ cache_unlock(mc);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+int lookup_done(void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *)context;
+ int ret = NSS_STATUS_UNAVAIL;
+ if (!ctxt)
+ goto out;
+ ret = close_parse(ctxt->parse);
+ free_context(ctxt);
+out:
+ return ret;
+}
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -847,6 +847,7 @@ static int validate_location(unsigned in
((esc = strchr(ptr, '\\')) && *(esc + 1) == ':') ||
!strncmp(ptr, "file:", 5) || !strncmp(ptr, "yp:", 3) ||
!strncmp(ptr, "nis:", 4) || !strncmp(ptr, "nisplus:", 8) ||
+ !strncmp(ptr, "udisks:", 7) || !strncmp(ptr, "udisks2:", 8) ||
!strncmp(ptr, "ldap:", 5) || !strncmp(ptr, "ldaps:", 6) ||
!strncmp(ptr, "sss:", 4) || !strncmp(ptr, "dir:", 4))
return 1;
--- /dev/null
+++ b/samples/autofs.udisks
@@ -0,0 +1,28 @@
+<?xml version="1.0" ?>
+<!--
+ This files contains a several entries. The upper envelop AutofsUdisks can be
+ disabled. The inner envelop MountOptions includes one or more mount options.
+ Those options are split into DiskByLabel, DiskById, and Common entries, which
+ are applied in matching order. And the options for several file system types
+ with a fallback. See autofs.udisks(5) for more information.
+-->
+<AutofsUdisks enable="true">
+ <MountOptions>
+ <Common>uid=$UID,gid=$GID,nosuid,nodev</Common>
+ <!--
+ <DiskById value="usb-USB_Flash_Disk_XXXXXXXXXXXX-0:0-part1">
+ uid=1002,gid=501,user,nosuid,nodev,exec
+ </DiskById>
+ <DiskByLabel value="MyPersonal-DVD-x86_64XXXX">
+ unhide
+ </DiskByLabel>
+ -->
+ <FSType value="vfat">fmask=0132,dmask=0022,showexec</FSType>
+ <FSType value="ntfs">umask=0022</FSType>
+ <FSType value="iso9660">ro</FSType>
+ <FSType value="ext4">check=none,noatime,nodiratime,data=journal</FSType>
+ <FSType value="ext3">check=none,noatime,nodiratime,data=journal</FSType>
+ <FSType value="ext2">check=none,noatime</FSType>
+ <FSType>ro,nosuid,nodev,noexec</FSType>
+ </MountOptions>
+</AutofsUdisks>