3090 lines
83 KiB
Diff
3090 lines
83 KiB
Diff
ddiss: rebase atop 37fda2c ("autofs-5.1.8 - add soucre parameter to
|
|
module functions")
|
|
Fix xmlStructuredErrorFunc callback parameter type (bsc#1221682)
|
|
|
|
---
|
|
Makefile.conf.in | 3
|
|
daemon/lookup.c | 4
|
|
daemon/master_tok.l | 2
|
|
include/lookup_udisks.h | 381 +++++++
|
|
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(-)
|
|
|
|
Index: autofs-5.1.9/Makefile.conf.in
|
|
===================================================================
|
|
--- autofs-5.1.9.orig/Makefile.conf.in
|
|
+++ autofs-5.1.9/Makefile.conf.in
|
|
@@ -46,6 +46,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@
|
|
|
|
Index: autofs-5.1.9/daemon/lookup.c
|
|
===================================================================
|
|
--- autofs-5.1.9.orig/daemon/lookup.c
|
|
+++ autofs-5.1.9/daemon/lookup.c
|
|
@@ -200,6 +200,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) &&
|
|
Index: autofs-5.1.9/daemon/master_tok.l
|
|
===================================================================
|
|
--- autofs-5.1.9.orig/daemon/master_tok.l
|
|
+++ autofs-5.1.9/daemon/master_tok.l
|
|
@@ -123,7 +123,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})
|
|
Index: autofs-5.1.9/include/lookup_udisks.h
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ autofs-5.1.9/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
|
|
Index: autofs-5.1.9/lib/parse_subs.c
|
|
===================================================================
|
|
--- autofs-5.1.9.orig/lib/parse_subs.c
|
|
+++ autofs-5.1.9/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 },
|
|
Index: autofs-5.1.9/man/autofs.udisks.5.in
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ autofs-5.1.9/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>.
|
|
Index: autofs-5.1.9/modules/Makefile
|
|
===================================================================
|
|
--- autofs-5.1.9.orig/modules/Makefile
|
|
+++ autofs-5.1.9/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)\"
|
|
@@ -145,6 +153,10 @@ lookup_ldap.so: lookup_ldap.c dclist.o b
|
|
$(LDFLAGS) $(LIBLDAP) $(LIBRESOLV) $(LIBS) $(AUTOFS_LIB_LINK)
|
|
$(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) $(LIBS) $(AUTOFS_LIB_LINK)
|
|
Index: autofs-5.1.9/modules/lookup_multi.c
|
|
===================================================================
|
|
--- autofs-5.1.9.orig/modules/lookup_multi.c
|
|
+++ autofs-5.1.9/modules/lookup_multi.c
|
|
@@ -189,6 +189,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) ||
|
|
Index: autofs-5.1.9/modules/lookup_udisks.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ autofs-5.1.9/modules/lookup_udisks.c
|
|
@@ -0,0 +1,2411 @@
|
|
+/*
|
|
+ * 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, const xmlError *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;
|
|
+ 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, struct map_source *source, time_t age, void *context)
|
|
+{
|
|
+ struct lookup_context *ctxt = (struct lookup_context *)context;
|
|
+ struct mapent_cache *mc = source->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
|
|
+
|
|
+ /*
|
|
+ * 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;
|
|
+ }
|
|
+
|
|
+ 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,
|
|
+ struct map_source *source,
|
|
+ char *key, int key_len,
|
|
+ struct lookup_context *ctxt)
|
|
+{
|
|
+ struct mapent_cache *mc = source->mc;
|
|
+ time_t age = time(NULL);
|
|
+ int ret, cur_state;
|
|
+ entry_t *entry;
|
|
+ list_t *ptr;
|
|
+
|
|
+
|
|
+ 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,
|
|
+ struct map_source *source,
|
|
+ char *key, int key_len,
|
|
+ struct lookup_context *ctxt)
|
|
+{
|
|
+ struct mapent_cache *mc = source->mc;
|
|
+ struct mapent *me;
|
|
+ time_t now = time(NULL);
|
|
+ time_t t_last_read;
|
|
+ int ret, cur_state;
|
|
+
|
|
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
|
|
+ ret = lookup_one(ap, source, 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, struct map_source *source, const char *name, int name_len, void *context)
|
|
+{
|
|
+ struct lookup_context *ctxt = (struct lookup_context *) context;
|
|
+ struct mapent_cache *mc = source->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;
|
|
+
|
|
+ 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);
|
|
+ lkp_key = strdup(key);
|
|
+ cache_unlock(mc);
|
|
+
|
|
+ if (!lkp_key)
|
|
+ return NSS_STATUS_UNKNOWN;
|
|
+
|
|
+ status = check_map_indirect(ap, source, 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;
|
|
+
|
|
+ debug(ap->logopt, MODPREFIX "%s -> %s", key, mapent);
|
|
+ ret = ctxt->parse->parse_mount(ap, source, 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;
|
|
+}
|
|
Index: autofs-5.1.9/modules/parse_sun.c
|
|
===================================================================
|
|
--- autofs-5.1.9.orig/modules/parse_sun.c
|
|
+++ autofs-5.1.9/modules/parse_sun.c
|
|
@@ -965,6 +965,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;
|
|
Index: autofs-5.1.9/samples/autofs.udisks
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ autofs-5.1.9/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>
|