diff --git a/autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch b/autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch new file mode 100644 index 0000000..17db1dc --- /dev/null +++ b/autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch @@ -0,0 +1,65 @@ +autofs-5.0.4 - always read file maps key lookup fixes + +From: Ian Kent + +Since we always read file maps at start we need to ensure that +we return a not found if the key isn't found in the cache. Also, +if we're looking through a "multi" map we can't use the cache +lookup optimisation because, in this case, there is a single map +source shared by the "multi" maps so we may not get correct results +from the lookup if a map later in the search has been modified. +--- + + CHANGELOG | 1 + + modules/lookup_file.c | 17 +++++++++++------ + 2 files changed, 12 insertions(+), 6 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 972ef63..5000f0c 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -48,6 +48,7 @@ + - improve manual umount recovery. + - dont fail on ipv6 address when adding host. + - always read file maps multi map fix. ++- always read file maps key lookup fixes. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/modules/lookup_file.c b/modules/lookup_file.c +index bd30bc5..a4ca39d 100644 +--- a/modules/lookup_file.c ++++ b/modules/lookup_file.c +@@ -1003,13 +1003,15 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + * If any map instances are present for this source + * then either we have plus included entries or we + * are looking through the list of nsswitch sources. +- * In either case we cannot avoid reading through the +- * map because we must preserve the key order over +- * multiple sources. But also, we can't know, at this +- * point, if a source instance has been changed since +- * the last time we checked it. ++ * In either case, or if it's a "multi" source, we ++ * cannot avoid reading through the map because we ++ * must preserve the key order over multiple sources ++ * or maps. But also, we can't know, at this point, ++ * if a source instance has been changed since the ++ * last time we checked it. + */ +- if (!source->instance) ++ if (!source->instance && ++ source->type && strcmp(source->type, "multi")) + goto do_cache_lookup; + } else + source->stale = 1; +@@ -1055,6 +1057,9 @@ do_cache_lookup: + } + cache_unlock(mc); + ++ if (!me) ++ return NSS_STATUS_NOTFOUND; ++ + if (!mapent) + return NSS_STATUS_TRYAGAIN; + diff --git a/autofs-5.0.4-always-read-file-maps-multi-map-fix.patch b/autofs-5.0.4-always-read-file-maps-multi-map-fix.patch new file mode 100644 index 0000000..bfa8b8b --- /dev/null +++ b/autofs-5.0.4-always-read-file-maps-multi-map-fix.patch @@ -0,0 +1,132 @@ +autofs-5.0.4 - always read file maps multi map fix + +From: Ian Kent + +Since "multi" map entries may contain file maps themselves and we +always want to read file maps we need to move the chack of whether +to read the map from lookup_nss_read_map() into the individual +map type lookup modules. +--- + + CHANGELOG | 1 + + daemon/lookup.c | 14 -------------- + modules/lookup_hosts.c | 8 ++++++++ + modules/lookup_ldap.c | 8 ++++++++ + modules/lookup_nisplus.c | 8 ++++++++ + modules/lookup_yp.c | 8 ++++++++ + 6 files changed, 33 insertions(+), 14 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 7e1012f..972ef63 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -47,6 +47,7 @@ + - fix incorrect shutdown introduced by library relaod fixes. + - improve manual umount recovery. + - dont fail on ipv6 address when adding host. ++- always read file maps multi map fix. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/daemon/lookup.c b/daemon/lookup.c +index bc94655..9d5a5c8 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -278,20 +278,6 @@ static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t a + map->lookup = lookup; + master_source_unlock(ap->entry); + +- /* If we don't need to create directories then there's no use +- * reading the map. We just need to test that the map is valid +- * for the fail cases to function correctly and to cache the +- * lookup handle. +- * +- * We always need to read the whole map for direct mounts in +- * order to mount the triggers. We also want to read the whole +- * map if it's a file map to avoid potentially lengthy linear +- * file scanning. +- */ +- if (strcmp(map->type, "file") && +- !(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT) +- return NSS_STATUS_SUCCESS; +- + if (!map->stale) + return NSS_STATUS_SUCCESS; + +diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c +index d3ae0e2..a213780 100644 +--- a/modules/lookup_hosts.c ++++ b/modules/lookup_hosts.c +@@ -89,6 +89,14 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + ap->entry->current = NULL; + master_source_current_signal(ap->entry); + ++ /* ++ * If we don't need to create directories then there's no use ++ * reading the map. We always need to read the whole map for ++ * direct mounts in order to mount the triggers. ++ */ ++ if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT) ++ return NSS_STATUS_SUCCESS; ++ + mc = source->mc; + + status = pthread_mutex_lock(&hostent_mutex); +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 8c6a8f2..a847622 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -2236,6 +2236,14 @@ static int read_one_map(struct autofs_point *ap, + ap->entry->current = NULL; + master_source_current_signal(ap->entry); + ++ /* ++ * If we don't need to create directories then there's no use ++ * reading the map. We always need to read the whole map for ++ * direct mounts in order to mount the triggers. ++ */ ++ if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT) ++ return NSS_STATUS_SUCCESS; ++ + sp.ap = ap; + sp.age = age; + +diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c +index 0c75905..ae53481 100644 +--- a/modules/lookup_nisplus.c ++++ b/modules/lookup_nisplus.c +@@ -180,6 +180,14 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + ap->entry->current = NULL; + master_source_current_signal(ap->entry); + ++ /* ++ * If we don't need to create directories then there's no use ++ * reading the map. We always need to read the whole map for ++ * direct mounts in order to mount the triggers. ++ */ ++ if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT) ++ return NSS_STATUS_SUCCESS; ++ + mc = source->mc; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); +diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c +index ce438e8..208f95e 100644 +--- a/modules/lookup_yp.c ++++ b/modules/lookup_yp.c +@@ -322,6 +322,14 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + ap->entry->current = NULL; + master_source_current_signal(ap->entry); + ++ /* ++ * If we don't need to create directories then there's no use ++ * reading the map. We always need to read the whole map for ++ * direct mounts in order to mount the triggers. ++ */ ++ if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT) ++ return NSS_STATUS_SUCCESS; ++ + ypcb_data.ap = ap; + ypcb_data.source = source; + ypcb_data.logopt = logopt; diff --git a/autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch b/autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch new file mode 100644 index 0000000..89f4790 --- /dev/null +++ b/autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch @@ -0,0 +1,68 @@ +autofs-5.0.4 - dont fail on ipv6 address adding host + +From: Ian Kent + +We don't have IPv6 support enabled in libtirpc yet. When we +perform name (or address) lookup and we get a mixture of IPv4 +and IPv6 addresses the lack of IPv6 support can cause the +parse_location() function to fail to add any valid hosts when +in fact it should. +--- + + CHANGELOG | 1 + + include/replicated.h | 1 + + modules/replicated.c | 9 ++++++++- + 3 files changed, 10 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 89aaa99..7e1012f 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -46,6 +46,7 @@ + - dont umount existing direct mount on master re-read. + - fix incorrect shutdown introduced by library relaod fixes. + - improve manual umount recovery. ++- dont fail on ipv6 address when adding host. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/include/replicated.h b/include/replicated.h +index e0133ff..fd87c08 100644 +--- a/include/replicated.h ++++ b/include/replicated.h +@@ -21,6 +21,7 @@ + #define PROXIMITY_SUBNET 0x0002 + #define PROXIMITY_NET 0x0004 + #define PROXIMITY_OTHER 0x0008 ++#define PROXIMITY_UNSUPPORTED 0x0010 + + #define NFS2_SUPPORTED 0x0010 + #define NFS3_SUPPORTED 0x0020 +diff --git a/modules/replicated.c b/modules/replicated.c +index 79845d0..a66de9f 100644 +--- a/modules/replicated.c ++++ b/modules/replicated.c +@@ -181,7 +181,7 @@ static unsigned int get_proximity(struct sockaddr *host_addr) + + case AF_INET6: + #ifndef INET6 +- return PROXIMITY_ERROR; ++ return PROXIMITY_UNSUPPORTED; + #else + addr6 = (struct sockaddr_in6 *) host_addr; + hst6_addr = (struct in6_addr *) &addr6->sin6_addr; +@@ -1048,6 +1048,13 @@ static int add_new_host(struct host **list, + int addr_len; + + prx = get_proximity(host_addr->ai_addr); ++ /* ++ * If we tried to add an IPv6 address and we don't have IPv6 ++ * support return success in the hope of getting an IPv4 ++ * address later. ++ */ ++ if (prx == PROXIMITY_UNSUPPORTED) ++ return 1; + if (prx == PROXIMITY_ERROR) + return 0; + diff --git a/autofs-5.0.4-dont-umount-existing-direct-mount-on-reread.patch b/autofs-5.0.4-dont-umount-existing-direct-mount-on-reread.patch new file mode 100644 index 0000000..6f76087 --- /dev/null +++ b/autofs-5.0.4-dont-umount-existing-direct-mount-on-reread.patch @@ -0,0 +1,368 @@ +autofs-5.0.4 - dont umount existing direct mount on master re-read + +From: Ian Kent + +Since direct mounts can have multiple entries in the master map they each +have an instance associated with them. If one entry changes, such as the +mount options, the instance comparison test fails and a new instance is +added. This causes autofs to get confused because there are now two +entries that contain the same mount information in different internal +caches. There are several consequences of this, most of which are just +noise in the log, but it also causes confuion for the expiration of mounts +since, for an active mount, the old cache entry can't be pruned until it's +umounted. Also, the map caches were not being properly pruned. +--- + + CHANGELOG | 1 + daemon/lookup.c | 160 ++++++++++++++++++++++++++++----------------------- + daemon/state.c | 90 +++++++++++++++++++++-------- + include/automount.h | 1 + 4 files changed, 156 insertions(+), 96 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 387af5e..7ca45fd 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -43,6 +43,7 @@ + - use percent hack for master map keys. + - use intr option as hosts mount default. + - fix kernel includes. ++- dont umount existing direct mount on master re-read. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/daemon/lookup.c b/daemon/lookup.c +index fd2ce55..bc94655 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -1016,96 +1016,114 @@ static char *make_fullpath(const char *root, const char *key) + return path; + } + +-int lookup_prune_cache(struct autofs_point *ap, time_t age) ++void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, time_t age) + { +- struct master_mapent *entry = ap->entry; +- struct map_source *map; +- struct mapent_cache *mc; + struct mapent *me, *this; + char *path; + int status = CHE_FAIL; + +- pthread_cleanup_push(master_source_lock_cleanup, entry); +- master_source_readlock(entry); ++ me = cache_enumerate(mc, NULL); ++ while (me) { ++ struct mapent *valid; ++ char *key = NULL, *next_key = NULL; + +- map = entry->maps; +- while (map) { +- /* Is the map stale */ +- if (!map->stale) { +- map = map->next; ++ if (me->age >= age) { ++ me = cache_enumerate(mc, me); + continue; + } +- mc = map->mc; +- pthread_cleanup_push(cache_lock_cleanup, mc); +- cache_readlock(mc); +- me = cache_enumerate(mc, NULL); +- while (me) { +- char *key = NULL, *next_key = NULL; + +- if (me->age >= age) { +- me = cache_enumerate(mc, me); +- continue; +- } ++ key = strdup(me->key); ++ me = cache_enumerate(mc, me); ++ if (!key || *key == '*') { ++ if (key) ++ free(key); ++ continue; ++ } + +- key = strdup(me->key); +- me = cache_enumerate(mc, me); +- if (!key || *key == '*') { +- if (key) +- free(key); +- continue; +- } ++ path = make_fullpath(ap->path, key); ++ if (!path) { ++ warn(ap->logopt, "can't malloc storage for path"); ++ free(key); ++ continue; ++ } + +- path = make_fullpath(ap->path, key); +- if (!path) { +- warn(ap->logopt, +- "can't malloc storage for path"); +- free(key); +- continue; +- } ++ /* ++ * If this key has another valid entry we want to prune it, ++ * even if it's a mount, as the valid entry will take the ++ * mount if it is a direct mount or it's just a stale indirect ++ * cache entry. ++ */ ++ valid = lookup_source_valid_mapent(ap, key, LKP_DISTINCT); ++ if (!valid && ++ is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { ++ debug(ap->logopt, ++ "prune check posponed, %s mounted", path); ++ free(key); ++ free(path); ++ continue; ++ } ++ if (valid) ++ cache_unlock(valid->mc); + +- if (is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { +- debug(ap->logopt, +- "prune check posponed, %s mounted", path); +- free(key); +- free(path); +- continue; +- } ++ if (me) ++ next_key = strdup(me->key); + +- if (me) +- next_key = strdup(me->key); ++ cache_unlock(mc); + ++ cache_writelock(mc); ++ this = cache_lookup_distinct(mc, key); ++ if (!this) { + cache_unlock(mc); ++ goto next; ++ } + +- cache_writelock(mc); +- this = cache_lookup_distinct(mc, key); +- if (!this) { +- cache_unlock(mc); +- goto next; +- } +- +- if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) { +- status = CHE_FAIL; +- if (this->ioctlfd == -1) +- status = cache_delete(mc, key); +- if (status != CHE_FAIL) { +- if (ap->type == LKP_INDIRECT) { +- if (ap->flags & MOUNT_FLAG_GHOST) +- rmdir_path(ap, path, ap->dev); +- } else +- rmdir_path(ap, path, this->dev); +- } ++ if (valid) ++ cache_delete(mc, key); ++ else if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) { ++ status = CHE_FAIL; ++ if (this->ioctlfd == -1) ++ status = cache_delete(mc, key); ++ if (status != CHE_FAIL) { ++ if (ap->type == LKP_INDIRECT) { ++ if (ap->flags & MOUNT_FLAG_GHOST) ++ rmdir_path(ap, path, ap->dev); ++ } else ++ rmdir_path(ap, path, this->dev); + } +- cache_unlock(mc); ++ } ++ cache_unlock(mc); + + next: +- cache_readlock(mc); +- if (next_key) { +- me = cache_lookup_distinct(mc, next_key); +- free(next_key); +- } +- free(key); +- free(path); ++ cache_readlock(mc); ++ if (next_key) { ++ me = cache_lookup_distinct(mc, next_key); ++ free(next_key); + } ++ free(key); ++ free(path); ++ } ++ ++ return; ++} ++ ++int lookup_prune_cache(struct autofs_point *ap, time_t age) ++{ ++ struct master_mapent *entry = ap->entry; ++ struct map_source *map; ++ ++ pthread_cleanup_push(master_source_lock_cleanup, entry); ++ master_source_readlock(entry); ++ ++ map = entry->maps; ++ while (map) { ++ /* Is the map stale */ ++ if (!map->stale) { ++ map = map->next; ++ continue; ++ } ++ pthread_cleanup_push(cache_lock_cleanup, map->mc); ++ cache_readlock(map->mc); ++ lookup_prune_one_cache(ap, map->mc, age); + pthread_cleanup_pop(1); + map->stale = 0; + map = map->next; +@@ -1124,7 +1142,6 @@ struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *k + struct mapent_cache *mc; + struct mapent *me = NULL; + +- master_source_readlock(entry); + map = entry->maps; + while (map) { + /* +@@ -1147,7 +1164,6 @@ struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *k + cache_unlock(mc); + map = map->next; + } +- master_source_unlock(entry); + + return me; + } +diff --git a/daemon/state.c b/daemon/state.c +index 533e241..84ccba3 100644 +--- a/daemon/state.c ++++ b/daemon/state.c +@@ -352,6 +352,68 @@ static void tree_mnts_cleanup(void *arg) + return; + } + ++static void do_readmap_mount(struct autofs_point *ap, struct mnt_list *mnts, ++ struct map_source *map, struct mapent *me, time_t now) ++{ ++ struct mapent_cache *nc; ++ struct mapent *ne, *nested, *valid; ++ ++ nc = ap->entry->master->nc; ++ ++ ne = cache_lookup_distinct(nc, me->key); ++ if (!ne) { ++ nested = cache_partial_match(nc, me->key); ++ if (nested) { ++ error(ap->logopt, ++ "removing invalid nested null entry %s", ++ nested->key); ++ nested = cache_partial_match(nc, me->key); ++ if (nested) ++ cache_delete(nc, nested->key); ++ } ++ } ++ ++ if (me->age < now || (ne && map->master_line > ne->age)) { ++ /* ++ * The map instance may have changed, such as the map name or ++ * the mount options, but the direct map entry may still exist ++ * in one of the other maps. If so then update the new cache ++ * entry device and inode so we can find it at lookup. Later, ++ * the mount for the new cache entry will just update the ++ * timeout. ++ * ++ * TODO: how do we recognise these orphaned map instances. We ++ * can't just delete these instances when the cache becomes ++ * empty because that is a valid state for a master map entry. ++ * This is becuase of the requirement to continue running with ++ * an empty cache awaiting a map re-load. ++ */ ++ valid = lookup_source_valid_mapent(ap, me->key, LKP_DISTINCT); ++ if (valid) { ++ struct mapent_cache *vmc = valid->mc; ++ cache_unlock(vmc); ++ debug(ap->logopt, ++ "updating cache entry for valid direct trigger %s", ++ me->key); ++ cache_writelock(vmc); ++ valid = cache_lookup_distinct(vmc, me->key); ++ /* Take over the mount if there is one */ ++ valid->ioctlfd = me->ioctlfd; ++ me->ioctlfd = -1; ++ /* Set device and inode number of the new mapent */ ++ cache_set_ino_index(vmc, me->key, me->dev, me->ino); ++ cache_unlock(vmc); ++ } else if (!tree_is_mounted(mnts, me->key, MNTS_REAL)) ++ do_umount_autofs_direct(ap, mnts, me); ++ else ++ debug(ap->logopt, ++ "%s is mounted", me->key); ++ } else ++ do_mount_autofs_direct(ap, mnts, me); ++ ++ return; ++} ++ + static void *do_readmap(void *arg) + { + struct autofs_point *ap; +@@ -398,7 +460,8 @@ static void *do_readmap(void *arg) + lookup_prune_cache(ap, now); + status = lookup_ghost(ap, ap->path); + } else { +- struct mapent *me, *ne, *nested; ++ struct mapent *me; ++ + mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/"); + pthread_cleanup_push(tree_mnts_cleanup, mnts); + pthread_cleanup_push(master_source_lock_cleanup, ap->entry); +@@ -418,31 +481,10 @@ static void *do_readmap(void *arg) + cache_readlock(mc); + me = cache_enumerate(mc, NULL); + while (me) { +- ne = cache_lookup_distinct(nc, me->key); +- if (!ne) { +- nested = cache_partial_match(nc, me->key); +- if (nested) { +- error(ap->logopt, +- "removing invalid nested null entry %s", +- nested->key); +- nested = cache_partial_match(nc, me->key); +- if (nested) +- cache_delete(nc, nested->key); +- } +- } +- +- /* TODO: check return of do_... */ +- if (me->age < now || (ne && map->master_line > ne->age)) { +- if (!tree_is_mounted(mnts, me->key, MNTS_REAL)) +- do_umount_autofs_direct(ap, mnts, me); +- else +- debug(ap->logopt, +- "%s is mounted", me->key); +- } else +- do_mount_autofs_direct(ap, mnts, me); +- ++ do_readmap_mount(ap, mnts, map, me, now); + me = cache_enumerate(mc, me); + } ++ lookup_prune_one_cache(ap, map->mc, now); + pthread_cleanup_pop(1); + map->stale = 0; + map = map->next; +diff --git a/include/automount.h b/include/automount.h +index d4675bd..ae517a7 100644 +--- a/include/automount.h ++++ b/include/automount.h +@@ -238,6 +238,7 @@ int lookup_enumerate(struct autofs_point *ap, + int lookup_ghost(struct autofs_point *ap, const char *root); + int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len); + void lookup_close_lookup(struct autofs_point *ap); ++void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, time_t age); + int lookup_prune_cache(struct autofs_point *ap, time_t age); + struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *key, unsigned int type); + struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, unsigned int type); diff --git a/autofs-5.0.4-fix-kernel-includes.patch b/autofs-5.0.4-fix-kernel-includes.patch new file mode 100644 index 0000000..5df38a8 --- /dev/null +++ b/autofs-5.0.4-fix-kernel-includes.patch @@ -0,0 +1,103 @@ +autofs-5.0.4 - fix kernel includes + +From: Valerie Aurora Henson + +autofs_dev-ioctl.h is included by both the kernel module and autofs, +and it includes two kernel header files. The compile worked if the +kernel headers were installed but failed otherwise. + +imk: there are a couple of other instances were we include kernel +headers. I've tried to fix that up too. +--- + + CHANGELOG | 1 + + include/automount.h | 3 +-- + include/dev-ioctl-lib.h | 3 +-- + include/linux/auto_dev-ioctl.h | 7 ++++++- + include/linux/auto_fs.h | 6 ++++-- + 5 files changed, 13 insertions(+), 7 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index a42dd14..387af5e 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -42,6 +42,7 @@ + - zero s_magic is valid. + - use percent hack for master map keys. + - use intr option as hosts mount default. ++- fix kernel includes. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/include/automount.h b/include/automount.h +index 615e07d..d4675bd 100644 +--- a/include/automount.h ++++ b/include/automount.h +@@ -8,12 +8,11 @@ + #ifndef AUTOMOUNT_H + #define AUTOMOUNT_H + +-#include + #include + #include + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/include/dev-ioctl-lib.h b/include/dev-ioctl-lib.h +index b7b8211..6d35da2 100644 +--- a/include/dev-ioctl-lib.h ++++ b/include/dev-ioctl-lib.h +@@ -21,8 +21,7 @@ + #ifndef AUTOFS_DEV_IOCTL_LIB_H + #define AUTOFS_DEV_IOCTL_LIB_H + +-#include +-#include "linux/auto_dev-ioctl.h" ++#include + + #define CONTROL_DEVICE "/dev/autofs" + +diff --git a/include/linux/auto_dev-ioctl.h b/include/linux/auto_dev-ioctl.h +index 91a7739..850f39b 100644 +--- a/include/linux/auto_dev-ioctl.h ++++ b/include/linux/auto_dev-ioctl.h +@@ -10,8 +10,13 @@ + #ifndef _LINUX_AUTO_DEV_IOCTL_H + #define _LINUX_AUTO_DEV_IOCTL_H + ++#include ++ ++#ifdef __KERNEL__ + #include +-#include ++#else ++#include ++#endif /* __KERNEL__ */ + + #define AUTOFS_DEVICE_NAME "autofs" + +diff --git a/include/linux/auto_fs.h b/include/linux/auto_fs.h +index bd39f09..91d414f 100644 +--- a/include/linux/auto_fs.h ++++ b/include/linux/auto_fs.h +@@ -17,11 +17,13 @@ + #ifdef __KERNEL__ + #include + #include ++#include ++#include ++#else + #include ++#include + #endif /* __KERNEL__ */ + +-#include +- + /* This file describes autofs v3 */ + #define AUTOFS_PROTO_VERSION 3 + diff --git a/autofs-5.0.4-improve-manual-umount-recovery.patch b/autofs-5.0.4-improve-manual-umount-recovery.patch new file mode 100644 index 0000000..8a055d3 --- /dev/null +++ b/autofs-5.0.4-improve-manual-umount-recovery.patch @@ -0,0 +1,161 @@ +autofs-5.0.4 - improve manual umount recovery + +From: Ian Kent + +The check for manually umounted mounts in the expire of direct mounts is +racy and the check itself is inadequate in that it can incorrectly clear +the descriptor of an active mount. Also, we do a similar test following +the expire which is a waste since we can catch this on the next expire. +So these two tests have been combined and the check done only prior to +the expire. In the indirect expire we don't have a check at all so we +add one. +--- + + CHANGELOG | 1 + + daemon/direct.c | 28 ++++++++++------------------ + daemon/indirect.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 57 insertions(+), 19 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 5e01812..89aaa99 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -45,6 +45,7 @@ + - fix kernel includes. + - dont umount existing direct mount on master re-read. + - fix incorrect shutdown introduced by library relaod fixes. ++- improve manual umount recovery. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/daemon/direct.c b/daemon/direct.c +index 4f4ff20..1ed2b15 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -881,13 +881,14 @@ void *expire_proc_direct(void *arg) + * avoid maintaining a file handle for control + * functions as once it's mounted all opens are + * directed to the mount not the trigger. +- * But first expire possible rootless offsets first. + */ + +- /* Offsets always have a real mount at their base */ ++ /* Check for manual umount */ + cache_writelock(me->mc); +- if (strstr(next->opts, "offset")) { +- ops->close(ap->logopt, me->ioctlfd); ++ if (me->ioctlfd != -1 && ++ fstat(ioctlfd, &st) != -1 && ++ !count_mounts(ap->logopt, next->path, st.st_dev)) { ++ ops->close(ap->logopt, ioctlfd); + me->ioctlfd = -1; + cache_unlock(me->mc); + pthread_setcancelstate(cur_state, NULL); +@@ -904,15 +905,6 @@ void *expire_proc_direct(void *arg) + continue; + } + +- cache_writelock(me->mc); +- if (me->ioctlfd != -1 && +- fstat(ioctlfd, &st) != -1 && +- !count_mounts(ap->logopt, next->path, st.st_dev)) { +- ops->close(ap->logopt, ioctlfd); +- me->ioctlfd = -1; +- } +- cache_unlock(me->mc); +- + pthread_setcancelstate(cur_state, NULL); + continue; + } +@@ -1068,7 +1060,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di + map = ap->entry->maps; + while (map) { + mc = map->mc; +- cache_readlock(mc); ++ cache_writelock(mc); + me = cache_lookup_ino(mc, pkt->dev, pkt->ino); + if (me) + break; +@@ -1345,7 +1337,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ + } + + mc = map->mc; +- cache_readlock(mc); ++ cache_writelock(mc); + me = cache_lookup_ino(mc, pkt->dev, pkt->ino); + if (me) + break; +@@ -1367,10 +1359,10 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ + + if (me->ioctlfd != -1) { + /* Maybe someone did a manual umount, clean up ! */ +- ioctlfd = me->ioctlfd; ++ close(me->ioctlfd); + me->ioctlfd = -1; +- } else +- ops->open(ap->logopt, &ioctlfd, me->dev, me->key); ++ } ++ ops->open(ap->logopt, &ioctlfd, me->dev, me->key); + + if (ioctlfd == -1) { + cache_unlock(mc); +diff --git a/daemon/indirect.c b/daemon/indirect.c +index 2539282..bc39e63 100644 +--- a/daemon/indirect.c ++++ b/daemon/indirect.c +@@ -428,8 +428,53 @@ void *expire_proc_indirect(void *arg) + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); + if (strstr(next->opts, "indirect")) + master_notify_submount(ap, next->path, ap->state); +- pthread_setcancelstate(cur_state, NULL); ++ else if (strstr(next->opts, "offset")) { ++ struct map_source *map; ++ struct mapent_cache *mc = NULL; ++ struct mapent *me = NULL; ++ struct stat st; ++ ++ master_source_readlock(ap->entry); ++ ++ map = ap->entry->maps; ++ while (map) { ++ mc = map->mc; ++ cache_writelock(mc); ++ me = cache_lookup_distinct(mc, next->path); ++ if (me) ++ break; ++ cache_unlock(mc); ++ map = map->next; ++ } + ++ if (!mc || !me) { ++ master_source_unlock(ap->entry); ++ pthread_setcancelstate(cur_state, NULL); ++ continue; ++ } ++ ++ /* Check for manual umount */ ++ if (me->ioctlfd != -1 && ++ (fstat(me->ioctlfd, &st) == -1 || ++ !count_mounts(ap->logopt, me->key, st.st_dev))) { ++ if (is_mounted(_PROC_MOUNTS, me->key, MNTS_REAL)) { ++ error(ap->logopt, ++ "error: possible mtab mismatch %s", ++ me->key); ++ cache_unlock(mc); ++ master_source_unlock(ap->entry); ++ pthread_setcancelstate(cur_state, NULL); ++ continue; ++ } ++ close(me->ioctlfd); ++ me->ioctlfd = -1; ++ } ++ ++ cache_unlock(mc); ++ master_source_unlock(ap->entry); ++ } ++ ++ pthread_setcancelstate(cur_state, NULL); + continue; + } + diff --git a/autofs-5.0.4-library-reload-fix-update-fix.patch b/autofs-5.0.4-library-reload-fix-update-fix.patch new file mode 100644 index 0000000..566c1e5 --- /dev/null +++ b/autofs-5.0.4-library-reload-fix-update-fix.patch @@ -0,0 +1,82 @@ +autofs-5.0.4 - library reload fix update fix + +From: Ian Kent + +The library reload fixes introduced a bug which causes autofs to +incorrectly shutdown. Previously the signal handling thread only +recieved signals either when they were explicity sent or it was +time to shutdown so continuing on to call the signal handling +routine was the correct thing to do. Now we need to join with +the mount handling thread at exit but, in this case, we don't +want to continue on to the signal handling routine as that will +incorrectly cause the signal to be passed on to other mount +handling threads. +--- + + CHANGELOG | 1 + + daemon/automount.c | 18 ++++++++++++++++-- + lib/master.c | 2 -- + 3 files changed, 17 insertions(+), 4 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 7ca45fd..5e01812 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -44,6 +44,7 @@ + - use intr option as hosts mount default. + - fix kernel includes. + - dont umount existing direct mount on master re-read. ++- fix incorrect shutdown introduced by library relaod fixes. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/daemon/automount.c b/daemon/automount.c +index 80691fa..3a0fe0b 100644 +--- a/daemon/automount.c ++++ b/daemon/automount.c +@@ -1332,8 +1332,22 @@ static void *statemachine(void *arg) + case SIGTERM: + case SIGINT: + case SIGUSR2: +- if (master_done(master_list)) +- return NULL; ++ master_mutex_lock(); ++ if (list_empty(&master_list->completed)) { ++ if (list_empty(&master_list->mounts)) { ++ master_mutex_unlock(); ++ return NULL; ++ } ++ } else { ++ if (master_done(master_list)) { ++ master_mutex_unlock(); ++ return NULL; ++ } ++ master_mutex_unlock(); ++ break; ++ } ++ master_mutex_unlock(); ++ + case SIGUSR1: + do_signals(master_list, sig); + break; +diff --git a/lib/master.c b/lib/master.c +index 762094f..e43f835 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -1182,7 +1182,6 @@ int master_done(struct master *master) + struct master_mapent *entry; + int res = 0; + +- master_mutex_lock(); + head = &master->completed; + p = head->next; + while (p != head) { +@@ -1195,7 +1194,6 @@ int master_done(struct master *master) + } + if (list_empty(&master->mounts)) + res = 1; +- master_mutex_unlock(); + + return res; + } diff --git a/autofs-5.0.4-use-intr-as-hosts-mount-default.patch b/autofs-5.0.4-use-intr-as-hosts-mount-default.patch new file mode 100644 index 0000000..94ae5cc --- /dev/null +++ b/autofs-5.0.4-use-intr-as-hosts-mount-default.patch @@ -0,0 +1,82 @@ +autofs-5.0.4 - use intr option as hosts mount default + +From: Ian Kent + +Use the "intr" option as default mount option for the hosts map +unless explicily overridden. +--- + + CHANGELOG | 1 + + man/auto.master.5.in | 5 +++-- + modules/parse_sun.c | 11 +++++++---- + 3 files changed, 11 insertions(+), 6 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 8258e00..a42dd14 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -41,6 +41,7 @@ + - reset flex scanner when setting buffer. + - zero s_magic is valid. + - use percent hack for master map keys. ++- use intr option as hosts mount default. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/man/auto.master.5.in b/man/auto.master.5.in +index aaa6324..7b7004f 100644 +--- a/man/auto.master.5.in ++++ b/man/auto.master.5.in +@@ -208,8 +208,9 @@ For example, with an entry in the master map of + accessing /net/myserver will mount exports from myserver on directories below + /net/myserver. + .P +-NOTE: mounts done from a hosts map will be mounted with the "nosuid" and "nodev" options +-unless the options "suid" and "dev" are explicitly given in the master map entry. ++NOTE: mounts done from a hosts map will be mounted with the "nosuid,nodev,intr" options ++unless overridden by explicily specifying the "suid", "dev" or "nointr" options in the ++master map entry. + .SH LDAP MAPS + If the map type \fBldap\fP is specified the mapname is of the form + \fB[//servername/]dn\fP, where the optional \fBservername\fP is +diff --git a/modules/parse_sun.c b/modules/parse_sun.c +index 65417e1..db36ae2 100644 +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -607,9 +607,10 @@ static int sun_mount(struct autofs_point *ap, const char *root, + int len = strlen(options); + int suid = strstr(options, "suid") ? 0 : 7; + int dev = strstr(options, "dev") ? 0 : 6; ++ int nointr = strstr(options, "nointr") ? 0 : 5; + +- if (suid || dev) { +- char *tmp = alloca(len + suid + dev + 1); ++ if (suid || dev || nointr) { ++ char *tmp = alloca(len + suid + dev + nointr + 1); + if (!tmp) { + error(ap->logopt, MODPREFIX + "alloca failed for options"); +@@ -623,10 +624,12 @@ static int sun_mount(struct autofs_point *ap, const char *root, + strcat(tmp, ",nosuid"); + if (dev) + strcat(tmp, ",nodev"); ++ if (nointr) ++ strcat(tmp, ",intr"); + options = tmp; + } + } else { +- char *tmp = alloca(13); ++ char *tmp = alloca(18); + if (!tmp) { + error(ap->logopt, + MODPREFIX "alloca failed for options"); +@@ -634,7 +637,7 @@ static int sun_mount(struct autofs_point *ap, const char *root, + return -1; + return 1; + } +- strcpy(tmp, "nosuid,nodev"); ++ strcpy(tmp, "nosuid,nodev,intr"); + options = tmp; + } + } diff --git a/autofs-5.0.4-use-srv-query-for-domain-dn.patch b/autofs-5.0.4-use-srv-query-for-domain-dn.patch new file mode 100644 index 0000000..6ab088e --- /dev/null +++ b/autofs-5.0.4-use-srv-query-for-domain-dn.patch @@ -0,0 +1,1097 @@ +autofs-5.0.4 - use srv query for domain dn + +From: Ian Kent + +Add the ability to use a domain dn in the LDAP_URI configuration +entry. If a domain dn is encountered in the LDAP_URI the list of +servers will be queried and used for the LDAP connection. The list +won't be queried again until the minimum ttl found in the SRV RR +records is reached or, if ttl isn't given in any SRV RR records, +after 1 hour. +--- + + CHANGELOG | 1 + include/dclist.h | 14 + + include/lookup_ldap.h | 3 + man/auto.master.5.in | 8 + modules/Makefile | 5 + modules/dclist.c | 785 ++++++++++++++++++++++++++++++++++++++++ + modules/lookup_ldap.c | 86 ++++ + redhat/autofs.sysconfig.in | 11 + + samples/autofs.conf.default.in | 11 + + 9 files changed, 911 insertions(+), 13 deletions(-) + create mode 100644 include/dclist.h + create mode 100644 modules/dclist.c + + +diff --git a/CHANGELOG b/CHANGELOG +index 5000f0c..f49784a 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -49,6 +49,7 @@ + - dont fail on ipv6 address when adding host. + - always read file maps multi map fix. + - always read file maps key lookup fixes. ++- use srv query for domain dn. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/include/dclist.h b/include/dclist.h +new file mode 100644 +index 0000000..ed89f97 +--- /dev/null ++++ b/include/dclist.h +@@ -0,0 +1,14 @@ ++#ifndef __DCLIST_H ++#define __DCLIST_H ++ ++#include ++ ++struct dclist { ++ time_t expire; ++ const char *uri; ++}; ++ ++struct dclist *get_dc_list(unsigned int logopt, const char *uri); ++void free_dclist(struct dclist *dclist); ++ ++#endif +diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h +index b47bf5d..dcae220 100644 +--- a/include/lookup_ldap.h ++++ b/include/lookup_ldap.h +@@ -10,6 +10,8 @@ + #include + #endif + ++#include "dclist.h" ++ + struct ldap_schema { + char *map_class; + char *map_attr; +@@ -57,6 +59,7 @@ struct lookup_context { + pthread_mutex_t uris_mutex; + struct list_head *uris; + struct ldap_uri *uri; ++ struct dclist *dclist; + char *cur_host; + struct ldap_searchdn *sdns; + +diff --git a/man/auto.master.5.in b/man/auto.master.5.in +index 7b7004f..71c4402 100644 +--- a/man/auto.master.5.in ++++ b/man/auto.master.5.in +@@ -271,6 +271,14 @@ Map entries that include a server name override this option and it is then + not used. Default is an empty list in which case either the server given + in a map entry or the LDAP configured default is used. This uri list is read at + startup and whenever the daemon receives a HUP signal. ++.P ++This configuration option can also be used to request autofs lookup SRV RRs ++for a domain of the form :///[]. Note that a trailing ++"/" is not allowed when using this form. If the domain dn is not specified ++the dns domain name (if any) is used to construct the domain dn for the ++SRV RR lookup. The server list returned from an SRV RR lookup is refreshed ++according to the minimum ttl found in the SRV RR records or after one hour, ++whichever is less. + .TP + .B SEARCH_BASE + The base dn to use when searching for amap base dn. This entry may be +diff --git a/modules/Makefile b/modules/Makefile +index 0d12f01..13b3bd8 100644 +--- a/modules/Makefile ++++ b/modules/Makefile +@@ -86,9 +86,10 @@ lookup_hesiod.so: lookup_hesiod.c + cyrus-sasl.o: cyrus-sasl.c + $(CC) $(CFLAGS) $(LDAP_FLAGS) -c $< + +-lookup_ldap.so: lookup_ldap.c $(SASL_OBJ) ++lookup_ldap.so: lookup_ldap.c dclist.o $(SASL_OBJ) + $(CC) $(SOLDFLAGS) $(CFLAGS) $(LDAP_FLAGS) -o lookup_ldap.so \ +- lookup_ldap.c $(SASL_OBJ) $(AUTOFS_LIB) $(LIBLDAP) ++ lookup_ldap.c dclist.o $(SASL_OBJ) \ ++ $(AUTOFS_LIB) $(LIBLDAP) $(LIBRESOLV) + $(STRIP) lookup_ldap.so + + mount_nfs.so: mount_nfs.c replicated.o +diff --git a/modules/dclist.c b/modules/dclist.c +new file mode 100644 +index 0000000..5b0e577 +--- /dev/null ++++ b/modules/dclist.c +@@ -0,0 +1,785 @@ ++/* ++ * Copyright 2009 Ian Kent ++ * Copyright 2009 Red Hat, Inc. ++ * ++ * This module was apapted from code contained in the Samba distribution ++ * file source/libads/dns.c which contained the following copyright ++ * information: ++ * ++ * Unix SMB/CIFS implementation. ++ * DNS utility library ++ * Copyright (C) Gerald (Jerry) Carter 2006. ++ * Copyright (C) Jeremy Allison 2007. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "automount.h" ++#include "dclist.h" ++ ++#define MAX_DNS_PACKET_SIZE 0xffff ++#define MAX_DNS_NAME_LENGTH MAXHOSTNAMELEN ++/* The longest time we will cache dns srv records */ ++#define MAX_TTL (60*60*1) /* 1 hours */ ++ ++#ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ ++#if !defined(C_IN) /* AIX 5.3 already defines C_IN */ ++# define C_IN ns_c_in ++#endif ++#if !defined(T_A) /* AIX 5.3 already defines T_A */ ++# define T_A ns_t_a ++#endif ++ ++# define T_SRV ns_t_srv ++#if !defined(T_NS) /* AIX 5.3 already defines T_NS */ ++# define T_NS ns_t_ns ++#endif ++#else ++# ifdef HFIXEDSZ ++# define NS_HFIXEDSZ HFIXEDSZ ++# else ++# define NS_HFIXEDSZ sizeof(HEADER) ++# endif /* HFIXEDSZ */ ++# ifdef PACKETSZ ++# define NS_PACKETSZ PACKETSZ ++# else /* 512 is usually the default */ ++# define NS_PACKETSZ 512 ++# endif /* PACKETSZ */ ++# define T_SRV 33 ++#endif ++ ++#define SVAL(buf, pos) (*(const uint16_t *)((const char *)(buf) + (pos))) ++#define IVAL(buf, pos) (*(const uint32_t *)((const char *)(buf) + (pos))) ++ ++#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) ++#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16))) ++ ++#define RSVAL(buf, pos) SREV(SVAL(buf, pos)) ++#define RIVAL(buf, pos) IREV(IVAL(buf, pos)) ++ ++#define QSORT_CAST (int (*)(const void *, const void *)) ++ ++/* DNS query section in replies */ ++ ++struct dns_query { ++ const char *hostname; ++ uint16_t type; ++ uint16_t in_class; ++}; ++ ++/* DNS RR record in reply */ ++ ++struct dns_rr { ++ const char *hostname; ++ uint16_t type; ++ uint16_t in_class; ++ uint32_t ttl; ++ uint16_t rdatalen; ++ uint8_t *rdata; ++}; ++ ++/* SRV records */ ++ ++struct dns_rr_srv { ++ const char *hostname; ++ uint16_t priority; ++ uint16_t weight; ++ uint16_t port; ++ uint32_t ttl; ++}; ++ ++static pthread_mutex_t dclist_mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++static void dclist_mutex_lock(void) ++{ ++ int status = pthread_mutex_lock(&dclist_mutex); ++ if (status) ++ fatal(status); ++ return; ++} ++ ++static void dclist_mutex_unlock(void) ++{ ++ int status = pthread_mutex_unlock(&dclist_mutex); ++ if (status) ++ fatal(status); ++ return; ++} ++ ++static int dns_parse_query(unsigned int logopt, ++ uint8_t *start, uint8_t *end, ++ uint8_t **ptr, struct dns_query *q) ++{ ++ uint8_t *p = *ptr; ++ char hostname[MAX_DNS_NAME_LENGTH]; ++ char buf[MAX_ERR_BUF]; ++ int namelen; ++ ++ if (!start || !end || !q || !*ptr) ++ return 0; ++ ++ memset(q, 0, sizeof(*q)); ++ ++ /* See RFC 1035 for details. If this fails, then return. */ ++ ++ namelen = dn_expand(start, end, p, hostname, sizeof(hostname)); ++ if (namelen < 0) { ++ error(logopt, "failed to expand query hostname"); ++ return 0; ++ } ++ ++ p += namelen; ++ q->hostname = strdup(hostname); ++ if (!q) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "strdup: %s", estr); ++ return 0; ++ } ++ ++ /* check that we have space remaining */ ++ ++ if (p + 4 > end) { ++ error(logopt, "insufficient buffer space for result"); ++ free((void *) q->hostname); ++ return 0; ++ } ++ ++ q->type = RSVAL(p, 0); ++ q->in_class = RSVAL(p, 2); ++ p += 4; ++ ++ *ptr = p; ++ ++ return 1; ++} ++ ++static int dns_parse_rr(unsigned int logopt, ++ uint8_t *start, uint8_t *end, ++ uint8_t **ptr, struct dns_rr *rr) ++{ ++ uint8_t *p = *ptr; ++ char hostname[MAX_DNS_NAME_LENGTH]; ++ char buf[MAX_ERR_BUF]; ++ int namelen; ++ ++ if (!start || !end || !rr || !*ptr) ++ return 0; ++ ++ memset(rr, 0, sizeof(*rr)); ++ ++ /* pull the name from the answer */ ++ ++ namelen = dn_expand(start, end, p, hostname, sizeof(hostname)); ++ if (namelen < 0) { ++ error(logopt, "failed to expand query hostname"); ++ return 0; ++ } ++ p += namelen; ++ rr->hostname = strdup(hostname); ++ if (!rr->hostname) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "strdup: %s", estr); ++ return 0; ++ } ++ ++ /* check that we have space remaining */ ++ ++ if (p + 10 > end) { ++ error(logopt, "insufficient buffer space for result"); ++ free((void *) rr->hostname); ++ return 0; ++ } ++ ++ /* pull some values and then skip onto the string */ ++ ++ rr->type = RSVAL(p, 0); ++ rr->in_class = RSVAL(p, 2); ++ rr->ttl = RIVAL(p, 4); ++ rr->rdatalen = RSVAL(p, 8); ++ ++ p += 10; ++ ++ /* sanity check the available space */ ++ ++ if (p + rr->rdatalen > end) { ++ error(logopt, "insufficient buffer space for data"); ++ free((void *) rr->hostname); ++ return 0; ++ } ++ ++ /* save a point to the rdata for this section */ ++ ++ rr->rdata = p; ++ p += rr->rdatalen; ++ ++ *ptr = p; ++ ++ return 1; ++} ++ ++static int dns_parse_rr_srv(unsigned int logopt, ++ uint8_t *start, uint8_t *end, ++ uint8_t **ptr, struct dns_rr_srv *srv) ++{ ++ struct dns_rr rr; ++ uint8_t *p; ++ char dcname[MAX_DNS_NAME_LENGTH]; ++ char buf[MAX_ERR_BUF]; ++ int namelen; ++ ++ if (!start || !end || !srv || !*ptr) ++ return 0; ++ ++ /* Parse the RR entry. Coming out of the this, ptr is at the beginning ++ of the next record */ ++ ++ if (!dns_parse_rr(logopt, start, end, ptr, &rr)) { ++ error(logopt, "Failed to parse RR record"); ++ return 0; ++ } ++ ++ if (rr.type != T_SRV) { ++ error(logopt, "Bad answer type (%d)", rr.type); ++ return 0; ++ } ++ ++ p = rr.rdata; ++ ++ srv->priority = RSVAL(p, 0); ++ srv->weight = RSVAL(p, 2); ++ srv->port = RSVAL(p, 4); ++ srv->ttl = rr.ttl; ++ ++ p += 6; ++ ++ namelen = dn_expand(start, end, p, dcname, sizeof(dcname)); ++ if (namelen < 0) { ++ error(logopt, "Failed to expand dcname"); ++ return 0; ++ } ++ ++ srv->hostname = strdup(dcname); ++ if (!srv->hostname) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "strdup: %s", estr); ++ return 0; ++ } ++ ++ debug(logopt, "Parsed %s [%u, %u, %u]", ++ srv->hostname, srv->priority, srv->weight, srv->port); ++ ++ return 1; ++} ++ ++/********************************************************************* ++ Sort SRV record list based on weight and priority. See RFC 2782. ++*********************************************************************/ ++ ++static int dnssrvcmp(struct dns_rr_srv *a, struct dns_rr_srv *b) ++{ ++ if (a->priority == b->priority) { ++ /* randomize entries with an equal weight and priority */ ++ if (a->weight == b->weight) ++ return 0; ++ ++ /* higher weights should be sorted lower */ ++ if (a->weight > b->weight) ++ return -1; ++ else ++ return 1; ++ } ++ ++ if (a->priority < b->priority) ++ return -1; ++ ++ return 1; ++} ++ ++#define DNS_FAILED_WAITTIME 30 ++ ++static int dns_send_req(unsigned int logopt, ++ const char *name, int q_type, uint8_t **rbuf, ++ int *resp_length) ++{ ++ uint8_t *buffer = NULL; ++ size_t buf_len = 0; ++ int resp_len = NS_PACKETSZ; ++ static time_t last_dns_check = 0; ++ static unsigned int last_dns_status = 0; ++ time_t now = time(NULL); ++ char buf[MAX_ERR_BUF]; ++ ++ /* Try to prevent bursts of DNS lookups if the server is down */ ++ ++ /* Protect against large clock changes */ ++ ++ if (last_dns_check > now) ++ last_dns_check = 0; ++ ++ /* IF we had a DNS timeout or a bad server and we are still ++ in the 30 second cache window, just return the previous ++ status and save the network timeout. */ ++ ++ if ((last_dns_status == ETIMEDOUT || ++ last_dns_status == ECONNREFUSED) && ++ ((last_dns_check + DNS_FAILED_WAITTIME) > now)) { ++ char *estr = strerror_r(last_dns_status, buf, MAX_ERR_BUF); ++ debug(logopt, "Returning cached status (%s)", estr); ++ return last_dns_status; ++ } ++ ++ /* Send the Query */ ++ do { ++ if (buffer) ++ free(buffer); ++ ++ buf_len = resp_len * sizeof(uint8_t); ++ ++ if (buf_len) { ++ buffer = malloc(buf_len); ++ if (!buffer) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ last_dns_status = ENOMEM; ++ last_dns_check = time(NULL); ++ return last_dns_status; ++ } ++ } ++ ++ resp_len = res_query(name, C_IN, q_type, buffer, buf_len); ++ if (resp_len < 0) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "Failed to resolve %s (%s)", name, estr); ++ free(buffer); ++ last_dns_status = ENOENT; ++ last_dns_check = time(NULL); ++ return last_dns_status; ++ } ++ ++ /* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8) ++ truncated replies never give back a resp_len > buflen ++ which ends up causing DNS resolve failures on large tcp DNS replies */ ++ ++ if (buf_len == resp_len) { ++ if (resp_len == MAX_DNS_PACKET_SIZE) { ++ error(logopt, ++ "DNS reply too large when resolving %s", ++ name); ++ free(buffer); ++ last_dns_status = EMSGSIZE; ++ last_dns_check = time(NULL); ++ return last_dns_status; ++ } ++ ++ resp_len = MIN(resp_len * 2, MAX_DNS_PACKET_SIZE); ++ } ++ } while (buf_len < resp_len && resp_len <= MAX_DNS_PACKET_SIZE); ++ ++ *rbuf = buffer; ++ *resp_length = resp_len; ++ ++ last_dns_check = time(NULL); ++ last_dns_status = 0; ++ ++ return 0; ++} ++ ++static int dns_lookup_srv(unsigned int logopt, const char *name, ++ struct dns_rr_srv **dclist, int *numdcs) ++{ ++ uint8_t *buffer = NULL; ++ int resp_len = 0; ++ struct dns_rr_srv *dcs = NULL; ++ int query_count, answer_count; ++ uint8_t *p = buffer; ++ int rrnum; ++ int idx = 0; ++ char buf[MAX_ERR_BUF]; ++ int ret; ++ ++ if (!name || !dclist) ++ return -EINVAL; ++ ++ /* Send the request. May have to loop several times in case ++ of large replies */ ++ ++ ret = dns_send_req(logopt, name, T_SRV, &buffer, &resp_len); ++ if (ret) { ++ error(logopt, "Failed to send DNS query"); ++ return ret; ++ } ++ p = buffer; ++ ++ /* For some insane reason, the ns_initparse() et. al. routines are only ++ available in libresolv.a, and not the shared lib. Who knows why.... ++ So we have to parse the DNS reply ourselves */ ++ ++ /* Pull the answer RR's count from the header. ++ * Use the NMB ordering macros */ ++ ++ query_count = RSVAL(p, 4); ++ answer_count = RSVAL(p, 6); ++ ++ debug(logopt, ++ "%d records returned in the answer section.", ++ answer_count); ++ ++ if (answer_count) { ++ dcs = malloc(sizeof(struct dns_rr_srv) * answer_count); ++ if (!dcs) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ free(buffer); ++ return ENOMEM; ++ } ++ } ++ ++ /* now skip the header */ ++ ++ p += NS_HFIXEDSZ; ++ ++ /* parse the query section */ ++ ++ for (rrnum = 0; rrnum < query_count; rrnum++) { ++ struct dns_query q; ++ ++ ret = dns_parse_query(logopt, buffer, buffer+resp_len, &p, &q); ++ if (!ret) { ++ error(logopt, ++ "Failed to parse query record [%d]", rrnum); ++ free(buffer); ++ free(dcs); ++ return EBADMSG; ++ } ++ } ++ ++ /* now we are at the answer section */ ++ ++ for (rrnum = 0; rrnum < answer_count; rrnum++) { ++ ret = dns_parse_rr_srv(logopt, ++ buffer, buffer+resp_len, ++ &p, &dcs[rrnum]); ++ if (!ret) { ++ error(logopt, ++ "Failed to parse answer record [%d]", rrnum); ++ free(buffer); ++ free(dcs); ++ return EBADMSG; ++ } ++ } ++ idx = rrnum; ++ ++ qsort(dcs, idx, sizeof(struct dns_rr_srv), QSORT_CAST dnssrvcmp); ++ ++ *dclist = dcs; ++ *numdcs = idx; ++ ++ return 0; ++} ++ ++static char *escape_dn_commas(const char *uri) ++{ ++ size_t len = strlen(uri); ++ char *new, *tmp, *ptr; ++ ++ ptr = (char *) uri; ++ while (*ptr) { ++ if (*ptr == '\\') ++ ptr += 2; ++ if (*ptr == ',') ++ len += 2; ++ ptr++; ++ } ++ ++ new = malloc(len + 1); ++ if (!new) ++ return NULL; ++ memset(new, 0, len + 1); ++ ++ ptr = (char *) uri; ++ tmp = new; ++ while (*ptr) { ++ if (*ptr == '\\') { ++ ptr++; ++ *tmp++ = *ptr++; ++ continue; ++ } ++ if (*ptr == ',') { ++ strcpy(tmp, "%2c"); ++ ptr++; ++ tmp += 3; ++ continue; ++ } ++ *tmp++ = *ptr++; ++ } ++ ++ return new; ++} ++ ++void free_dclist(struct dclist *dclist) ++{ ++ if (dclist->uri) ++ free((void *) dclist->uri); ++ free(dclist); ++} ++ ++static char *getdnsdomainname(unsigned int logopt) ++{ ++ struct addrinfo hints, *ni; ++ char name[MAX_DNS_NAME_LENGTH + 1]; ++ char buf[MAX_ERR_BUF]; ++ char *dnsdomain = NULL; ++ char *ptr; ++ int ret; ++ ++ memset(name, 0, sizeof(name)); ++ if (gethostname(name, MAX_DNS_NAME_LENGTH) == -1) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "gethostname: %s", estr); ++ return NULL; ++ } ++ ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_flags = AI_CANONNAME; ++ hints.ai_family = AF_UNSPEC; ++ hints.ai_socktype = SOCK_DGRAM; ++ ++ ret = getaddrinfo(name, NULL, &hints, &ni); ++ if (ret) { ++ error(logopt, "hostname lookup failed: %s", gai_strerror(ret)); ++ return NULL; ++ } ++ ++ ptr = ni->ai_canonname; ++ while (*ptr && *ptr != '.') ++ ptr++; ++ ++ if (*++ptr) ++ dnsdomain = strdup(ptr); ++ ++ freeaddrinfo(ni); ++ ++ return dnsdomain; ++} ++ ++struct dclist *get_dc_list(unsigned int logopt, const char *uri) ++{ ++ LDAPURLDesc *ludlist = NULL; ++ LDAPURLDesc **ludp; ++ struct dns_rr_srv *dcs; ++ unsigned int min_ttl = MAX_TTL; ++ struct dclist *dclist = NULL;; ++ char buf[MAX_ERR_BUF]; ++ char *dn_uri, *esc_uri; ++ char *domain; ++ char *list; ++ int numdcs; ++ int ret; ++ ++ if (strcmp(uri, "ldap:///") && strcmp(uri, "ldaps:///")) { ++ dn_uri = strdup(uri); ++ if (!dn_uri) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "strdup: %s", estr); ++ return NULL; ++ } ++ } else { ++ char *dnsdomain; ++ char *hdn; ++ ++ dnsdomain = getdnsdomainname(logopt); ++ if (!dnsdomain) { ++ error(logopt, "failed to get dns domainname"); ++ return NULL; ++ } ++ ++ if (ldap_domain2dn(dnsdomain, &hdn) || hdn == NULL) { ++ error(logopt, ++ "Could not turn domain \"%s\" into a dn\n", ++ dnsdomain); ++ free(dnsdomain); ++ return NULL; ++ } ++ free(dnsdomain); ++ ++ dn_uri = malloc(strlen(uri) + strlen(hdn) + 1); ++ if (!dn_uri) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ ber_memfree(hdn); ++ return NULL; ++ } ++ ++ strcpy(dn_uri, uri); ++ strcat(dn_uri, hdn); ++ ber_memfree(hdn); ++ } ++ ++ esc_uri = escape_dn_commas(dn_uri); ++ if (!esc_uri) { ++ error(logopt, "Could not escape commas in uri %s", dn_uri); ++ free(dn_uri); ++ return NULL; ++ } ++ ++ ret = ldap_url_parse(esc_uri, &ludlist); ++ if (ret != LDAP_URL_SUCCESS) { ++ error(logopt, "Could not parse uri %s (%d)", dn_uri, ret); ++ free(esc_uri); ++ free(dn_uri); ++ return NULL; ++ } ++ ++ free(esc_uri); ++ ++ if (!ludlist) { ++ error(logopt, "No dn found in uri %s", dn_uri); ++ free(dn_uri); ++ return NULL; ++ } ++ ++ free(dn_uri); ++ ++ dclist = malloc(sizeof(struct dclist)); ++ if (!dclist) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ ldap_free_urldesc(ludlist); ++ return NULL; ++ } ++ memset(dclist, 0, sizeof(struct dclist)); ++ ++ list = NULL; ++ for (ludp = &ludlist; *ludp != NULL;) { ++ LDAPURLDesc *lud = *ludp; ++ size_t req_len, len; ++ char *request = NULL; ++ char *tmp; ++ int i; ++ ++ if (!lud->lud_dn && !lud->lud_dn[0] && ++ (!lud->lud_host || !lud->lud_host[0])) { ++ *ludp = lud->lud_next; ++ continue; ++ } ++ ++ domain = NULL; ++ if (ldap_dn2domain(lud->lud_dn, &domain) || domain == NULL) { ++ error(logopt, ++ "Could not turn dn \"%s\" into a domain", ++ lud->lud_dn); ++ *ludp = lud->lud_next; ++ continue; ++ } ++ ++ debug(logopt, "doing lookup of SRV RRs for domain %s", domain); ++ ++ req_len = sizeof("_ldap._tcp.") + strlen(domain); ++ request = malloc(req_len); ++ if (!request) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ goto out_error; ++ } ++ ++ ret = snprintf(request, req_len, "_ldap._tcp.%s", domain); ++ if (ret >= req_len) { ++ free(request); ++ goto out_error; ++ } ++ ++ dclist_mutex_lock(); ++ if (dns_lookup_srv(logopt, request, &dcs, &numdcs)) { ++ error(logopt, ++ "DNS SRV query failed for domain %s", domain); ++ dclist_mutex_unlock(); ++ free(request); ++ goto out_error; ++ } ++ dclist_mutex_unlock(); ++ free(request); ++ ++ len = strlen(lud->lud_scheme); ++ len += sizeof("://"); ++ len *= numdcs; ++ ++ for (i = 0; i < numdcs; i++) { ++ if (dcs[i].ttl > 0 && dcs[i].ttl < min_ttl) ++ min_ttl = dcs[i].ttl; ++ len += strlen(dcs[i].hostname); ++ if (dcs[i].port > 0) ++ len += sizeof(":65535"); ++ } ++ ++ tmp = realloc(list, len); ++ if (!tmp) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "realloc: %s", estr); ++ goto out_error; ++ } ++ ++ if (!list) ++ memset(tmp, 0, len); ++ else ++ strcat(tmp, " "); ++ ++ for (i = 0; i < numdcs; i++) { ++ if (i > 0) ++ strcat(tmp, " "); ++ strcat(tmp, lud->lud_scheme); ++ strcat(tmp, "://"); ++ strcat(tmp, dcs[i].hostname); ++ if (dcs[i].port > 0) { ++ char port[7]; ++ ret = snprintf(port, 7, ":%d", dcs[i].port); ++ if (ret > 6) { ++ error(logopt, ++ "invalid port: %u", dcs[i].port); ++ goto out_error; ++ } ++ strcat(tmp, port); ++ } ++ } ++ list = tmp; ++ ++ *ludp = lud->lud_next; ++ ber_memfree(domain); ++ } ++ ++ ldap_free_urldesc(ludlist); ++ ++ dclist->expire = time(NULL) + min_ttl; ++ dclist->uri = list; ++ ++ return dclist; ++ ++out_error: ++ if (list) ++ free(list); ++ if (domain) ++ ber_memfree(domain); ++ ldap_free_urldesc(ludlist); ++ free_dclist(dclist); ++ return NULL; ++} +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index a847622..f6b3f42 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -643,14 +643,26 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + LDAP *ldap = NULL; + struct ldap_uri *this; + struct list_head *p, *first; ++ struct dclist *dclist = NULL; ++ char *uri = NULL; + +- /* Try each uri in list, add connect fails to tmp list */ + uris_mutex_lock(ctxt); ++ if (ctxt->dclist) { ++ dclist = ctxt->dclist; ++ if (ctxt->dclist->expire < time(NULL)) { ++ free_dclist(ctxt->dclist); ++ ctxt->dclist = NULL; ++ dclist = NULL; ++ } ++ } + if (!ctxt->uri) + first = ctxt->uris; + else + first = &ctxt->uri->list; + uris_mutex_unlock(ctxt); ++ ++ ++ /* Try each uri, save point in server list upon success */ + p = first->next; + while(p != first) { + /* Skip list head */ +@@ -659,25 +671,62 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + continue; + } + this = list_entry(p, struct ldap_uri, list); +- debug(logopt, "trying server %s", this->uri); +- ldap = connect_to_server(logopt, this->uri, ctxt); ++ if (!strstr(this->uri, ":///")) ++ uri = strdup(this->uri); ++ else { ++ if (dclist) ++ uri = strdup(dclist->uri); ++ else { ++ struct dclist *tmp; ++ tmp = get_dc_list(logopt, this->uri); ++ if (!tmp) { ++ p = p->next; ++ continue; ++ } ++ dclist = tmp; ++ uri = strdup(dclist->uri); ++ } ++ } ++ if (!uri) { ++ p = p->next; ++ continue; ++ } ++ debug(logopt, "trying server uri %s", uri); ++ ldap = connect_to_server(logopt, uri, ctxt); + if (ldap) { +- info(logopt, "connected to uri %s", this->uri); +- uris_mutex_lock(ctxt); +- ctxt->uri = this; +- uris_mutex_unlock(ctxt); ++ info(logopt, "connected to uri %s", uri); ++ free(uri); + break; + } ++ free(uri); ++ uri = NULL; ++ free_dclist(dclist); ++ dclist = NULL; + p = p->next; + } + ++ uris_mutex_lock(ctxt); ++ if (ldap) ++ ctxt->uri = this; ++ if (dclist) { ++ if (!ctxt->dclist) ++ ctxt->dclist = dclist; ++ else { ++ if (ctxt->dclist != dclist) { ++ free_dclist(ctxt->dclist); ++ ctxt->dclist = dclist; ++ } ++ } ++ } ++ uris_mutex_unlock(ctxt); ++ + return ldap; + } + + static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + { +- struct ldap_uri *this; + LDAP *ldap; ++ char *uri; + + if (ctxt->server || !ctxt->uris) { + ldap = do_connect(logopt, ctxt->server, ctxt); +@@ -692,9 +741,20 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + } + + uris_mutex_lock(ctxt); +- this = ctxt->uri; ++ if (ctxt->dclist) ++ uri = strdup(ctxt->dclist->uri); ++ else ++ uri = strdup(ctxt->uri->uri); + uris_mutex_unlock(ctxt); +- ldap = do_connect(logopt, this->uri, ctxt); ++ ++ if (!uri) { ++ char buf[MAX_ERR_BUF]; ++ char *estr = strerror_r(errno, buf, sizeof(buf)); ++ crit(logopt, MODPREFIX "strdup: %s", estr); ++ return NULL; ++ } ++ ++ ldap = do_connect(logopt, uri, ctxt); + #ifdef WITH_SASL + /* + * Dispose of the sasl authentication connection and try the +@@ -702,9 +762,11 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + */ + if (!ldap) { + autofs_sasl_dispose(ctxt); +- ldap = connect_to_server(logopt, this->uri, ctxt); ++ ldap = connect_to_server(logopt, uri, ctxt); + } + #endif ++ free(uri); ++ + if (ldap) + return ldap; + +@@ -1296,6 +1358,8 @@ static void free_context(struct lookup_context *ctxt) + fatal(ret); + if (ctxt->sdns) + defaults_free_searchdns(ctxt->sdns); ++ if (ctxt->dclist) ++ free_dclist(ctxt->dclist); + free(ctxt); + + return; +diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in +index 97e20fe..37448ea 100644 +--- a/redhat/autofs.sysconfig.in ++++ b/redhat/autofs.sysconfig.in +@@ -50,6 +50,17 @@ BROWSE_MODE="no" + # Map entries that include a server name override + # this option. + # ++# This configuration option can also be used to ++# request autofs lookup SRV RRs for a domain of ++# the form :///[]. Note that a ++# trailing "/" is not allowed when using this form. ++# If the domain dn is not specified the dns domain ++# name (if any) is used to construct the domain dn ++# for the SRV RR lookup. The server list returned ++# from an SRV RR lookup is refreshed according to ++# the minimum ttl found in the SRV RR records or ++# after one hour, whichever is less. ++# + #LDAP_URI="" + # + # LDAP__TIMEOUT - timeout value for the synchronous API calls +diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in +index 62084c2..7dee5fd 100644 +--- a/samples/autofs.conf.default.in ++++ b/samples/autofs.conf.default.in +@@ -48,6 +48,17 @@ BROWSE_MODE="no" + # Map entries that include a server name override + # this option. + # ++# This configuration option can also be used to ++# request autofs lookup SRV RRs for a domain of ++# the form :///[]. Note that a ++# trailing "/" is not allowed when using this form. ++# If the domain dn is not specified the dns domain ++# name (if any) is used to construct the domain dn ++# for the SRV RR lookup. The server list returned ++# from an SRV RR lookup is refreshed according to ++# the minimum ttl found in the SRV RR records or ++# after one hour, whichever is less. ++# + #LDAP_URI="" + # + # LDAP__TIMEOUT - timeout value for the synchronous API calls diff --git a/autofs.spec b/autofs.spec index e110d4b..bc0a1ff 100644 --- a/autofs.spec +++ b/autofs.spec @@ -4,7 +4,7 @@ Summary: A tool for automatically mounting and unmounting filesystems Name: autofs Version: 5.0.4 -Release: 26 +Release: 28 Epoch: 1 License: GPLv2+ Group: System Environment/Daemons @@ -51,6 +51,15 @@ Patch38: autofs-5.0.4-fix-st_remove_tasks-locking.patch Patch39: autofs-5.0.4-reset-flex-scanner-when-setting-buffer.patch Patch40: autofs-5.0.4-zero-s_magic-is-valid.patch Patch41: autofs-5.0.4-use-percent-hack-for-master.patch +Patch42: autofs-5.0.4-use-intr-as-hosts-mount-default.patch +Patch43: autofs-5.0.4-fix-kernel-includes.patch +Patch44: autofs-5.0.4-dont-umount-existing-direct-mount-on-reread.patch +Patch45: autofs-5.0.4-library-reload-fix-update-fix.patch +Patch46: autofs-5.0.4-improve-manual-umount-recovery.patch +Patch47: autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch +Patch48: autofs-5.0.4-always-read-file-maps-multi-map-fix.patch +Patch49: autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch +Patch50: autofs-5.0.4-use-srv-query-for-domain-dn.patch Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: autoconf, hesiod-devel, openldap-devel, bison, flex, libxml2-devel, cyrus-sasl-devel, openssl-devel module-init-tools util-linux nfs-utils e2fsprogs libtirpc-devel Requires: kernel >= 2.6.17 @@ -133,6 +142,15 @@ echo %{version}-%{release} > .version %patch39 -p1 %patch40 -p1 %patch41 -p1 +%patch42 -p1 +%patch43 -p1 +%patch44 -p1 +%patch45 -p1 +%patch46 -p1 +%patch47 -p1 +%patch48 -p1 +%patch49 -p1 +%patch50 -p1 %build #CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir} @@ -185,6 +203,17 @@ fi %{_libdir}/autofs/ %changelog +* Mon May 18 2009 Ian Kent - 1:5.0.4-28 +- use intr option as hosts mount default. +- sync kernel includes with upstream kernel. +- dont umount existing direct mount on master re-read. +- fix incorrect shutdown introduced by library relaod fixes. +- improve manual umount recovery. +- dont fail on ipv6 address when adding host. +- always read file maps multi map fix. +- always read file maps key lookup fixes. +- add support for LDAP_URI="ldap:///" SRV RR lookup. + * Thu Apr 16 2009 Ian Kent - 1:5.0.4-26 - fix lsb init script header. - fix memory leak reading ldap master map.