autofs-5.1.6 - move lib/master.c to daemon/master.c From: Ian Kent The lib subdirectory isn't really the right place for master.c, move it to the deamon subdirectory. Signed-off-by: Ian Kent --- CHANGELOG | 1 daemon/Makefile | 19 daemon/master.c | 1885 +++++++++++++++++++++++++++++++++++++++++++++++++ daemon/master_parse.y | 983 ++++++++++++++++++++++++++ daemon/master_tok.l | 504 +++++++++++++ lib/Makefile | 23 - lib/master.c | 1885 ------------------------------------------------- lib/master_parse.y | 983 -------------------------- lib/master_tok.l | 504 ------------- 9 files changed, 3394 insertions(+), 3393 deletions(-) create mode 100644 daemon/master.c create mode 100644 daemon/master_parse.y create mode 100644 daemon/master_tok.l delete mode 100644 lib/master.c delete mode 100644 lib/master_parse.y delete mode 100644 lib/master_tok.l diff --git a/CHANGELOG b/CHANGELOG index d12a9cad..5db1d7df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -67,6 +67,7 @@ xx/xx/2020 autofs-5.1.7 - remove unused function tree_get_mnt_list(). - only add expre alarm for active mounts. - move submount check into conditional_alarm_add(). +- move lib/master.c to daemon/master.c. 07/10/2019 autofs-5.1.6 - support strictexpire mount option. diff --git a/daemon/Makefile b/daemon/Makefile index d8e2d6a4..c602a915 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -6,9 +6,12 @@ include ../Makefile.rules SRCS = automount.c indirect.c direct.c spawn.c module.c mount.c \ - lookup.c state.c flag.c + master.c master_tok.l master_parse.y lookup.c state.c flag.c OBJS = automount.o indirect.o direct.o spawn.o module.o mount.o \ - lookup.o state.o flag.o + master.o master_tok.o master_parse.tab.o lookup.o state.o \ + flag.o + +YACCSRC = master_tok.c master_parse.tab.c master_parse.tab.h version := $(shell cat ../.version) @@ -38,8 +41,18 @@ automount: $(OBJS) $(AUTOFS_LIB) $(CC) $(DAEMON_LDFLAGS) -o automount $(OBJS) $(LDFLAGS) $(AUTOFS_LIB) $(LIBS) $(STRIP) automount +master_tok.c: master_tok.l + $(LEX) -o$@ -Pmaster_ $? + +master_parse.tab.c master_parse.tab.h: master_parse.y + $(YACC) -v -d -p master_ -b master_parse $? + +master_tok.o: master_tok.c master_parse.tab.h + +master_parse.tab.o: master_parse.tab.c master_parse.tab.h + clean: - rm -f *.o *.s *~ automount + rm -f *.o *.s *~ $(YACCSRC) *.output *~ automount install: all install -d -m 755 $(INSTALLROOT)$(sbindir) diff --git a/daemon/master.c b/daemon/master.c new file mode 100644 index 00000000..5ce7aed6 --- /dev/null +++ b/daemon/master.c @@ -0,0 +1,1885 @@ +/* ----------------------------------------------------------------------- * + * + * master.c - master map utility routines. + * + * Copyright 2006 Ian Kent + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "automount.h" + +/* The root of the map entry tree */ +struct master *master_list = NULL; + +extern const char *global_options; +extern long global_negative_timeout; + +/* Attribute to create a joinable thread */ +extern pthread_attr_t th_attr; + +extern struct startup_cond suc; + +static struct map_source * +__master_find_map_source(struct master_mapent *, + const char *, const char *, int, const char **); + +static pthread_mutex_t master_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER; + +void master_mutex_lock(void) +{ + int status = pthread_mutex_lock(&master_mutex); + if (status) + fatal(status); +} + +void master_mutex_unlock(void) +{ + int status = pthread_mutex_unlock(&master_mutex); + if (status) + fatal(status); +} + +void master_mutex_lock_cleanup(void *arg) +{ + master_mutex_unlock(); + return; +} + +int master_add_autofs_point(struct master_mapent *entry, unsigned logopt, + unsigned nobind, unsigned ghost, int submount) +{ + struct autofs_point *ap; + int status; + + ap = malloc(sizeof(struct autofs_point)); + if (!ap) + return 0; + + ap->state = ST_INIT; + + ap->state_pipe[0] = -1; + ap->state_pipe[1] = -1; + ap->logpri_fifo = -1; + + ap->path = strdup(entry->path); + if (!ap->path) { + free(ap); + return 0; + } + ap->pref = NULL; + + ap->entry = entry; + ap->exp_thread = 0; + ap->readmap_thread = 0; + /* + * Program command line option overrides config. + * We can't use 0 negative timeout so use default. + */ + if (global_negative_timeout <= 0) + ap->negative_timeout = defaults_get_negative_timeout(); + else + ap->negative_timeout = global_negative_timeout; + ap->exp_timeout = defaults_get_timeout(); + ap->exp_runfreq = 0; + ap->flags = 0; + + if (defaults_get_use_ignore_mount_option()) + ap->flags = MOUNT_FLAG_IGNORE; + if (ghost) + ap->flags |= MOUNT_FLAG_GHOST; + + if (nobind) + ap->flags |= MOUNT_FLAG_NOBIND; + + if (ap->path[1] == '-') + ap->type = LKP_DIRECT; + else + ap->type = LKP_INDIRECT; + + ap->logopt = logopt; + + ap->parent = NULL; + ap->thid = 0; + ap->submnt_count = 0; + ap->submount = submount; + INIT_LIST_HEAD(&ap->mounts); + INIT_LIST_HEAD(&ap->submounts); + INIT_LIST_HEAD(&ap->amdmounts); + ap->shutdown = 0; + + status = pthread_mutex_init(&ap->mounts_mutex, NULL); + if (status) { + free(ap->path); + free(ap); + return 0; + } + ap->mode = 0; + + entry->ap = ap; + + return 1; +} + +void master_free_autofs_point(struct autofs_point *ap) +{ + struct list_head *p, *head; + int status; + + if (!ap) + return; + + mounts_mutex_lock(ap); + head = &ap->amdmounts; + p = head->next; + while (p != head) { + struct mnt_list *mnt = list_entry(p, struct mnt_list, amdmount); + p = p->next; + ext_mount_remove(mnt->ext_mp); + mnts_remove_amdmount(mnt->mp); + } + mounts_mutex_unlock(ap); + + status = pthread_mutex_destroy(&ap->mounts_mutex); + if (status) + fatal(status); + + if (ap->pref) + free(ap->pref); + free(ap->path); + free(ap); +} + +struct map_source * +master_add_map_source(struct master_mapent *entry, + char *type, char *format, time_t age, + int argc, const char **argv) +{ + struct map_source *source; + char *ntype, *nformat; + const char **tmpargv; + + source = malloc(sizeof(struct map_source)); + if (!source) + return NULL; + memset(source, 0, sizeof(struct map_source)); + source->ref = 1; + + if (type) { + ntype = strdup(type); + if (!ntype) { + master_free_map_source(source, 0); + return NULL; + } + source->type = ntype; + } + + if (format) { + nformat = strdup(format); + if (!nformat) { + master_free_map_source(source, 0); + return NULL; + } + source->format = nformat; + if (!strcmp(nformat, "amd")) + source->flags |= MAP_FLAG_FORMAT_AMD; + } + + source->age = age; + source->stale = 1; + + tmpargv = copy_argv(argc, argv); + if (!tmpargv) { + master_free_map_source(source, 0); + return NULL; + } + source->argc = argc; + source->argv = tmpargv; + if (source->argv[0]) + source->name = strdup(source->argv[0]); + + master_source_writelock(entry); + + if (!entry->maps) { + source->mc = cache_init(entry->ap, source); + if (!source->mc) { + master_free_map_source(source, 0); + master_source_unlock(entry); + return NULL; + } + entry->maps = source; + } else { + struct map_source *this, *last, *next; + + /* Typically there only a few map sources */ + + this = __master_find_map_source(entry, type, format, argc, tmpargv); + if (this) { + debug(entry->ap->logopt, + "map source used without taking reference"); + this->age = age; + master_free_map_source(source, 0); + master_source_unlock(entry); + return this; + } + + source->mc = cache_init(entry->ap, source); + if (!source->mc) { + master_free_map_source(source, 0); + master_source_unlock(entry); + return NULL; + } + + last = NULL; + next = entry->maps; + while (next) { + last = next; + next = next->next; + } + if (last) + last->next = source; + else + entry->maps = source; + } + + master_source_unlock(entry); + + return source; +} + +static int compare_source_type_and_format(struct map_source *map, const char *type, const char *format) +{ + int res = 0; + + if (type) { + if (!map->type) + goto done; + + if (strcmp(map->type, type)) + goto done; + } else if (map->type) + goto done; + + if (format) { + if (!map->format) + goto done; + + if (strcmp(map->format, format)) + goto done; + } else if (map->format) + goto done; + + res = 1; +done: + return res; +} + +static struct map_source * +__master_find_map_source(struct master_mapent *entry, + const char *type, const char *format, + int argc, const char **argv) +{ + struct map_source *map; + struct map_source *source = NULL; + int res; + + map = entry->maps; + while (map) { + res = compare_source_type_and_format(map, type, format); + if (!res) + goto next; + + res = compare_argv(map->argc, map->argv, argc, argv); + if (!res) + goto next; + + source = map; + break; +next: + map = map->next; + } + + return source; +} + +struct map_source *master_find_map_source(struct master_mapent *entry, + const char *type, const char *format, + int argc, const char **argv) +{ + struct map_source *source = NULL; + + master_source_readlock(entry); + source = __master_find_map_source(entry, type, format, argc, argv); + master_source_unlock(entry); + + return source; +} + +struct map_source * +master_get_map_source(struct master_mapent *entry, + const char *type, const char *format, + int argc, const char **argv) +{ + struct map_source *source = NULL; + + master_source_readlock(entry); + source = __master_find_map_source(entry, type, format, argc, argv); + if (source) + source->ref++; + master_source_unlock(entry); + + return source; +} + +static void __master_free_map_source(struct map_source *source, unsigned int free_cache) +{ + /* instance map sources are not ref counted */ + if (source->ref && --source->ref) + return; + if (source->type) + free(source->type); + if (source->format) + free(source->format); + if (source->name) + free(source->name); + if (free_cache && source->mc) + cache_release(source); + if (source->lookup) { + struct map_source *instance; + + instance = source->instance; + while (instance) { + if (instance->lookup) + close_lookup(instance->lookup); + instance = instance->next; + } + close_lookup(source->lookup); + } + if (source->argv) + free_argv(source->argc, source->argv); + if (source->instance) { + struct map_source *instance, *next; + + instance = source->instance; + while (instance) { + next = instance->next; + __master_free_map_source(instance, 0); + instance = next; + } + } + + free(source); + + return; +} + +void master_free_map_source(struct map_source *source, unsigned int free_cache) +{ + int status; + + status = pthread_mutex_lock(&instance_mutex); + if (status) + fatal(status); + + __master_free_map_source(source, free_cache); + + status = pthread_mutex_unlock(&instance_mutex); + if (status) + fatal(status); +} + +struct map_source *master_find_source_instance(struct map_source *source, const char *type, const char *format, int argc, const char **argv) +{ + struct map_source *map; + struct map_source *instance = NULL; + int status, res; + + status = pthread_mutex_lock(&instance_mutex); + if (status) + fatal(status); + + map = source->instance; + while (map) { + res = compare_source_type_and_format(map, type, format); + if (!res) + goto next; + + if (!argv) { + instance = map; + break; + } + + res = compare_argv(map->argc, map->argv, argc, argv); + if (!res) + goto next; + + instance = map; + break; +next: + map = map->next; + } + + status = pthread_mutex_unlock(&instance_mutex); + if (status) + fatal(status); + + return instance; +} + +struct map_source * +master_add_source_instance(struct map_source *source, const char *type, const char *format, time_t age, int argc, const char **argv) +{ + struct map_source *instance; + struct map_source *new; + char *ntype, *nformat; + const char **tmpargv; + int status; + + instance = master_find_source_instance(source, type, format, argc, argv); + if (instance) + return instance; + + new = malloc(sizeof(struct map_source)); + if (!new) + return NULL; + memset(new, 0, sizeof(struct map_source)); + + if (type) { + ntype = strdup(type); + if (!ntype) { + master_free_map_source(new, 0); + return NULL; + } + new->type = ntype; + } + + if (format) { + nformat = strdup(format); + if (!nformat) { + master_free_map_source(new, 0); + return NULL; + } + new->format = nformat; + if (!strcmp(nformat, "amd")) + new->flags |= MAP_FLAG_FORMAT_AMD; + } + + new->age = age; + new->master_line = 0; + new->mc = source->mc; + new->exp_timeout = source->exp_timeout; + new->stale = 1; + + tmpargv = copy_argv(argc, argv); + if (!tmpargv) { + master_free_map_source(new, 0); + return NULL; + } + new->argc = argc; + new->argv = tmpargv; + if (source->name) + new->name = strdup(source->name); + + status = pthread_mutex_lock(&instance_mutex); + if (status) + fatal(status); + + if (!source->instance) + source->instance = new; + else { + /* + * We know there's no other instance of this + * type so just add to head of list + */ + new->next = source->instance; + source->instance = new; + } + + status = pthread_mutex_unlock(&instance_mutex); + if (status) + fatal(status); + + return new; +} + +int check_stale_instances(struct map_source *source) +{ + struct map_source *map; + + if (!source) + return 0; + + map = source->instance; + while (map) { + if (map->stale) + return 1; + if (check_stale_instances(map)) + return 1; + map = map->next; + } + + return 0; +} + +void clear_stale_instances(struct map_source *source) +{ + struct map_source *map; + + if (!source) + return; + + map = source->instance; + while (map) { + clear_stale_instances(map); + if (map->stale) + map->stale = 0; + map = map->next; + } + + return; +} + +void send_map_update_request(struct autofs_point *ap) +{ + struct map_source *map; + int status, need_update = 0; + + status = pthread_mutex_lock(&instance_mutex); + if (status) + fatal(status); + + map = ap->entry->maps; + while (map) { + if (check_stale_instances(map)) + map->stale = 1; + if (map->stale) { + need_update = 1; + break; + } + map = map->next; + } + + status = pthread_mutex_unlock(&instance_mutex); + if (status) + fatal(status); + + if (!need_update) + return; + + st_add_task(ap, ST_READMAP); + + return; +} + +void master_source_writelock(struct master_mapent *entry) +{ + int status; + + status = pthread_rwlock_wrlock(&entry->source_lock); + if (status) { + logmsg("master_mapent source write lock failed"); + fatal(status); + } + return; +} + +void master_source_readlock(struct master_mapent *entry) +{ + int retries = 25; + int status; + + while (retries--) { + status = pthread_rwlock_rdlock(&entry->source_lock); + if (status != EAGAIN && status != EBUSY) + break; + else { + struct timespec t = { 0, 200000000 }; + struct timespec r; + + if (status == EAGAIN) + logmsg("master_mapent source too many readers"); + else + logmsg("master_mapent source write lock held"); + + while (nanosleep(&t, &r) == -1 && errno == EINTR) + memcpy(&t, &r, sizeof(struct timespec)); + } + } + + if (status) { + logmsg("master_mapent source read lock failed"); + fatal(status); + } + + return; +} + +void master_source_unlock(struct master_mapent *entry) +{ + int status; + + status = pthread_rwlock_unlock(&entry->source_lock); + if (status) { + logmsg("master_mapent source unlock failed"); + fatal(status); + } + return; +} + +void master_source_lock_cleanup(void *arg) +{ + struct master_mapent *entry = (struct master_mapent *) arg; + + master_source_unlock(entry); + + return; +} + +void master_source_current_wait(struct master_mapent *entry) +{ + int status; + + status = pthread_mutex_lock(&entry->current_mutex); + if (status) { + logmsg("entry current source lock failed"); + fatal(status); + } + + while (entry->current != NULL) { + status = pthread_cond_wait( + &entry->current_cond, &entry->current_mutex); + if (status) { + logmsg("entry current source condition wait failed"); + fatal(status); + } + } + + return; +} + +void master_source_current_signal(struct master_mapent *entry) +{ + int status; + + status = pthread_cond_signal(&entry->current_cond); + if (status) { + logmsg("entry current source condition signal failed"); + fatal(status); + } + + status = pthread_mutex_unlock(&entry->current_mutex); + if (status) { + logmsg("entry current source unlock failed"); + fatal(status); + } + + return; +} + +struct master_mapent *master_find_mapent(struct master *master, const char *path) +{ + struct list_head *head, *p; + + head = &master->mounts; + list_for_each(p, head) { + struct master_mapent *entry; + + entry = list_entry(p, struct master_mapent, list); + + if (!strcmp(entry->path, path)) + return entry; + } + + return NULL; +} + +unsigned int master_partial_match_mapent(struct master *master, const char *path) +{ + struct list_head *head, *p; + size_t path_len = strlen(path); + int ret = 0; + + head = &master->mounts; + list_for_each(p, head) { + struct master_mapent *entry; + size_t entry_len; + size_t cmp_len; + + entry = list_entry(p, struct master_mapent, list); + + entry_len = strlen(entry->path); + cmp_len = min(entry_len, path_len); + + if (!strncmp(entry->path, path, cmp_len)) { + /* paths are equal, matching master map entry ? */ + if (entry_len == path_len) { + if (entry->maps && + entry->maps->flags & MAP_FLAG_FORMAT_AMD) + ret = 1; + else + ret = -1; + break; + } + + /* amd mount conflicts with entry mount */ + if (entry_len > path_len && + *(entry->path + path_len) == '/') { + ret = -1; + break; + } + + /* entry mount conflicts with amd mount */ + if (entry_len < path_len && + *(path + entry_len) == '/') { + ret = -1; + break; + } + } + } + + return ret; +} + +struct master_mapent *master_new_mapent(struct master *master, const char *path, time_t age) +{ + struct master_mapent *entry; + int status; + char *tmp; + + entry = malloc(sizeof(struct master_mapent)); + if (!entry) + return NULL; + + memset(entry, 0, sizeof(struct master_mapent)); + + tmp = strdup(path); + if (!tmp) { + free(entry); + return NULL; + } + entry->path = tmp; + + entry->thid = 0; + entry->age = age; + entry->master = master; + entry->current = NULL; + entry->maps = NULL; + entry->ap = NULL; + + status = pthread_rwlock_init(&entry->source_lock, NULL); + if (status) + fatal(status); + + status = pthread_mutex_init(&entry->current_mutex, NULL); + if (status) + fatal(status); + + status = pthread_cond_init(&entry->current_cond, NULL); + if (status) + fatal(status); + + INIT_LIST_HEAD(&entry->list); + + return entry; +} + +void master_add_mapent(struct master *master, struct master_mapent *entry) +{ + list_add_tail(&entry->list, &master->mounts); + return; +} + +void master_remove_mapent(struct master_mapent *entry) +{ + struct master *master = entry->master; + + if (entry->ap->submount) + return; + + if (!list_empty(&entry->list)) { + list_del_init(&entry->list); + list_add(&entry->join, &master->completed); + } + + return; +} + +void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_cache) +{ + if (entry->maps) { + struct map_source *m, *n; + + m = entry->maps; + while (m) { + n = m->next; + master_free_map_source(m, free_cache); + m = n; + } + entry->maps = NULL; + } + + return; +} + +void master_free_mapent(struct master_mapent *entry) +{ + int status; + + if (entry->path) + free(entry->path); + + master_free_autofs_point(entry->ap); + + status = pthread_rwlock_destroy(&entry->source_lock); + if (status) + fatal(status); + + status = pthread_mutex_destroy(&entry->current_mutex); + if (status) + fatal(status); + + status = pthread_cond_destroy(&entry->current_cond); + if (status) + fatal(status); + + free(entry); + + return; +} + +struct master *master_new(const char *name, unsigned int timeout, unsigned int flags) +{ + struct master *master; + char *tmp; + + master = malloc(sizeof(struct master)); + if (!master) + return NULL; + + if (!name) + tmp = (char *) defaults_get_master_map(); + else + tmp = strdup(name); + + if (!tmp) { + free(master); + return NULL; + } + + master->name = tmp; + master->nc = NULL; + + master->recurse = 0; + master->depth = 0; + master->reading = 0; + master->read_fail = 0; + master->readall = 0; + master->default_ghost = flags & DAEMON_FLAGS_GHOST; + master->default_timeout = timeout; + master->default_logging = defaults_get_logging(); + master->logopt = master->default_logging; + + INIT_LIST_HEAD(&master->mounts); + INIT_LIST_HEAD(&master->completed); + + return master; +} + +static void master_add_amd_mount_section_mounts(struct master *master, time_t age) +{ + unsigned int m_logopt = master->logopt; + struct master_mapent *entry; + struct map_source *source; + unsigned int loglevel; + unsigned int logopt; + unsigned int flags; + char *argv[2]; + char **paths; + int ret; + int i; + + loglevel = conf_amd_get_log_options(); + + paths = conf_amd_get_mount_paths(); + if (!paths) + return; + + i = 0; + while (paths[i]) { + const char *path = paths[i]; + unsigned int ghost = 0; + time_t timeout; + char *type = NULL; + char *map = NULL; + char *opts; + + ret = master_partial_match_mapent(master, path); + if (ret) { + /* If this amd entry is already present in the + * master map it's not a duplicate, don't issue + * an error message. + */ + if (ret == 1) + goto next; + info(m_logopt, + "amd section mount path conflict, %s ignored", + path); + goto next; + } + + map = conf_amd_get_map_name(path); + if (!map) { + error(m_logopt, + "failed to get map name for amd section mount %s", + path); + goto next; + } + + entry = master_new_mapent(master, path, age); + if (!entry) { + error(m_logopt, + "failed to allocate new amd section mount %s", + path); + goto next; + } + + logopt = m_logopt; + if (loglevel <= LOG_DEBUG && loglevel > LOG_INFO) + logopt = LOGOPT_DEBUG; + else if (loglevel <= LOG_INFO && loglevel > LOG_ERR) + logopt = LOGOPT_VERBOSE; + + /* It isn't possible to provide the fullybrowsable amd + * browsing functionality within the autofs framework. + * This flag will not be set if browsable_dirs = full + * in the configuration or fullybrowsable is present as + * an option. + */ + flags = conf_amd_get_flags(path); + if (flags & CONF_BROWSABLE_DIRS) + ghost = 1; + + ret = master_add_autofs_point(entry, logopt, 0, ghost, 0); + if (!ret) { + error(m_logopt, "failed to add autofs_point"); + master_free_mapent(entry); + goto next; + } + + opts = conf_amd_get_map_options(path); + if (opts) { + /* autofs uses the equivalent of cache:=inc,sync + * (except for file maps which use cache:=all,sync) + * but if the map is large then it may be necessary + * to read the whole map at startup even if browsing + * is is not enabled, so look for cache:=all in the + * map_options configuration entry. + */ + if (strstr(opts, "cache:=all")) + entry->ap->flags |= MOUNT_FLAG_AMD_CACHE_ALL; + free(opts); + } + + type = conf_amd_get_map_type(path); + argv[0] = map; + argv[1] = NULL; + + source = master_add_map_source(entry, type, "amd", + age, 1, (const char **) argv); + if (!source) { + error(m_logopt, + "failed to add source for amd section mount %s", + path); + master_free_mapent(entry); + goto next; + } + + timeout = conf_amd_get_dismount_interval(path); + set_exp_timeout(entry->ap, source, timeout); + source->master_line = 0; + + entry->age = age; + entry->current = NULL; + + master_add_mapent(master, entry); +next: + if (type) + free(type); + if (map) + free(map); + i++; + } + + i = 0; + while (paths[i]) + free(paths[i++]); + free(paths); +} + +static void wait_for_lookups_and_lock(struct master *master) +{ + struct list_head *p, *head; + int status; + +again: + master_mutex_lock(); + + head = &master->mounts; + p = head->next; + while (p != head) { + struct master_mapent *this; + + this = list_entry(p, struct master_mapent, list); + + status = pthread_rwlock_trywrlock(&this->source_lock); + if (status) { + struct timespec t = { 0, 200000000 }; + struct timespec r; + + master_mutex_unlock(); + + while (nanosleep(&t, &r) == -1 && errno == EINTR) + memcpy(&t, &r, sizeof(struct timespec)); + + goto again; + } + master_source_unlock(this); + + p = p->next; + } +} + +int master_read_master(struct master *master, time_t age) +{ + unsigned int logopt = master->logopt; + struct mapent_cache *nc; + + /* + * We need to clear and re-populate the null map entry cache + * before alowing anyone else to use it. + */ + wait_for_lookups_and_lock(master); + if (master->nc) { + cache_writelock(master->nc); + nc = master->nc; + cache_clean_null_cache(nc); + } else { + nc = cache_init_null_cache(master); + if (!nc) { + error(logopt, + "failed to init null map cache for %s", + master->name); + return 0; + } + cache_writelock(nc); + master->nc = nc; + } + master_init_scan(); + lookup_nss_read_master(master, age); + cache_unlock(nc); + master_add_amd_mount_section_mounts(master, age); + + if (!master->read_fail) + master_mount_mounts(master, age); + else { + master->read_fail = 0; + /* HUP signal sets master->readall == 1 only */ + if (!master->readall) { + master_mutex_unlock(); + return 0; + } else + master_mount_mounts(master, age); + } + + if (list_empty(&master->mounts)) + warn(logopt, "no mounts in table"); + + master_mutex_unlock(); + + return 1; +} + +int master_submount_list_empty(struct autofs_point *ap) +{ + int res = 0; + + mounts_mutex_lock(ap); + if (list_empty(&ap->submounts)) + res = 1; + mounts_mutex_unlock(ap); + + return res; +} + +int master_notify_submount(struct autofs_point *ap, const char *path, enum states state) +{ + struct mnt_list *this, *sbmnt; + int ret = 1; + + this = mnts_find_submount(path); + if (this) { + /* We have found a submount to expire */ + st_mutex_lock(); + + if (this->ap->state == ST_SHUTDOWN) { + this = NULL; + st_mutex_unlock(); + goto done; + } + + this->ap->shutdown = ap->shutdown; + + __st_add_task(this->ap, state); + + st_mutex_unlock(); + + st_wait_task(this->ap, state, 0); + + /* + * If our submount gets to state ST_SHUTDOWN, ST_SHUTDOWN_PENDING or + * ST_SHUTDOWN_FORCE we need to wait until it goes away or changes + * to ST_READY. + */ + st_mutex_lock(); + while ((sbmnt = mnts_find_submount(path))) { + struct timespec t = { 0, 300000000 }; + struct timespec r; + + if (sbmnt->ap->state != ST_SHUTDOWN && + sbmnt->ap->state != ST_SHUTDOWN_PENDING && + sbmnt->ap->state != ST_SHUTDOWN_FORCE) { + ret = 0; + mnts_put_mount(sbmnt); + break; + } + mnts_put_mount(sbmnt); + + st_mutex_unlock(); + while (nanosleep(&t, &r) == -1 && errno == EINTR) + memcpy(&t, &r, sizeof(struct timespec)); + st_mutex_lock(); + } + st_mutex_unlock(); +done: + mnts_put_mount(this); + } + + return ret; +} + +void master_notify_state_change(struct master *master, int sig) +{ + struct master_mapent *entry; + struct autofs_point *ap; + struct list_head *p; + int cur_state; + unsigned int logopt; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); + master_mutex_lock(); + + list_for_each(p, &master->mounts) { + enum states next = ST_INVAL; + + entry = list_entry(p, struct master_mapent, list); + + ap = entry->ap; + logopt = ap->logopt; + + st_mutex_lock(); + + if (ap->state == ST_SHUTDOWN) + goto next; + + switch (sig) { + case SIGTERM: + case SIGINT: + if (ap->state != ST_SHUTDOWN_PENDING && + ap->state != ST_SHUTDOWN_FORCE) { + next = ST_SHUTDOWN_PENDING; + ap->shutdown = 1; + __st_add_task(ap, next); + } + break; +#ifdef ENABLE_FORCED_SHUTDOWN + case SIGUSR2: + if (ap->state != ST_SHUTDOWN_FORCE && + ap->state != ST_SHUTDOWN_PENDING) { + next = ST_SHUTDOWN_FORCE; + ap->shutdown = 1; + __st_add_task(ap, next); + } + break; +#endif + case SIGUSR1: + assert(ap->state == ST_READY); + next = ST_PRUNE; + __st_add_task(ap, next); + break; + } +next: + if (next != ST_INVAL) + debug(logopt, + "sig %d switching %s from %d to %d", + sig, ap->path, ap->state, next); + + st_mutex_unlock(); + } + + master_mutex_unlock(); + pthread_setcancelstate(cur_state, NULL); + + return; +} + +static int master_do_mount(struct master_mapent *entry) +{ + struct startup_cond suc; + struct autofs_point *ap; + pthread_t thid; + int status; + + ap = entry->ap; + + if (handle_mounts_startup_cond_init(&suc)) { + crit(ap->logopt, + "failed to init startup cond for mount %s", entry->path); + return 0; + } + + suc.ap = ap; + suc.root = ap->path; + suc.done = 0; + suc.status = 0; + + if (!(do_force_unlink & UNLINK_AND_EXIT)) + debug(ap->logopt, "mounting %s", entry->path); + + status = pthread_create(&thid, &th_attr, handle_mounts, &suc); + if (status) { + crit(ap->logopt, + "failed to create mount handler thread for %s", + entry->path); + handle_mounts_startup_cond_destroy(&suc); + return 0; + } + + while (!suc.done) { + status = pthread_cond_wait(&suc.cond, &suc.mutex); + if (status) + fatal(status); + } + + if (suc.status) { + if (!(do_force_unlink & UNLINK_AND_EXIT)) + error(ap->logopt, "failed to startup mount"); + handle_mounts_startup_cond_destroy(&suc); + return 0; + } + entry->thid = thid; + + handle_mounts_startup_cond_destroy(&suc); + + return 1; +} + +static void check_update_map_sources(struct master_mapent *entry, int readall) +{ + struct map_source *source, *last; + struct autofs_point *ap; + int map_stale = 0; + + if (readall) + map_stale = 1; + + ap = entry->ap; + + master_source_writelock(entry); + + last = NULL; + source = entry->maps; + while (source) { + if (readall) + source->stale = 1; + + /* + * If a map source is no longer valid and all it's + * entries have expired away we can get rid of it. + */ + if (entry->age > source->age) { + struct mapent *me; + cache_readlock(source->mc); + me = cache_lookup_first(source->mc); + if (!me) { + struct map_source *next = source->next; + + cache_unlock(source->mc); + + if (!last) + entry->maps = next; + else + last->next = next; + + if (entry->maps == source) + entry->maps = next; + + master_free_map_source(source, 1); + + source = next; + continue; + } else { + source->stale = 1; + map_stale = 1; + } + cache_unlock(source->mc); + } + last = source; + source = source->next; + } + + master_source_unlock(entry); + + /* The map sources have changed */ + if (map_stale) + st_add_task(ap, ST_READMAP); + + return; +} + +int master_mount_mounts(struct master *master, time_t age) +{ + struct mapent_cache *nc = master->nc; + struct list_head *p, *head; + int cur_state; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); + + head = &master->mounts; + p = head->next; + while (p != head) { + struct master_mapent *this; + struct autofs_point *ap; + struct mapent *ne, *nested; + struct stat st; + int state_pipe, save_errno; + int ret; + + this = list_entry(p, struct master_mapent, list); + p = p->next; + + ap = this->ap; + + /* A master map entry has gone away */ + if (this->age < age) { + st_add_task(ap, ST_SHUTDOWN_PENDING); + continue; + } + + cache_readlock(nc); + ne = cache_lookup_distinct(nc, this->path); + /* + * If this path matched a nulled entry the master map entry + * must be an indirect mount so the master map entry line + * number may be obtained from this->maps. + */ + if (ne) { + int lineno = ne->age; + cache_unlock(nc); + + /* null entry appears after map entry */ + if (this->maps->master_line < lineno) { + warn(ap->logopt, + "ignoring null entry that appears after " + "existing entry for %s", this->path); + goto cont; + } + if (ap->state != ST_INIT) { + st_add_task(ap, ST_SHUTDOWN_PENDING); + continue; + } + /* + * The map entry hasn't been started yet and we've + * seen a preceeding null map entry for it so just + * delete it from the master map entry list so it + * doesn't get in the road. + */ + list_del_init(&this->list); + master_free_mapent_sources(ap->entry, 1); + master_free_mapent(ap->entry); + continue; + } + nested = cache_partial_match(nc, this->path); + if (nested) { + error(ap->logopt, + "removing invalid nested null entry %s", + nested->key); + nested = cache_partial_match(nc, this->path); + if (nested) + cache_delete(nc, nested->key); + } + cache_unlock(nc); +cont: + st_mutex_lock(); + + state_pipe = this->ap->state_pipe[1]; + + /* No pipe so mount is needed */ + ret = fstat(state_pipe, &st); + save_errno = errno; + + st_mutex_unlock(); + + if (!ret) + check_update_map_sources(this, master->readall); + else if (ret == -1 && save_errno == EBADF) { + if (!master_do_mount(this)) { + list_del_init(&this->list); + master_free_mapent_sources(ap->entry, 1); + master_free_mapent(ap->entry); + } + } + } + + pthread_setcancelstate(cur_state, NULL); + + return 1; +} + +/* The nss source instances end up in reverse order. */ +static void list_source_instances(struct map_source *source, struct map_source *instance) +{ + if (!source || !instance) { + printf("none"); + return; + } + + if (instance->next) + list_source_instances(source, instance->next); + + /* + * For convienience we map nss instance type "files" to "file". + * Check for that and report corrected instance type. + */ + if (strcmp(instance->type, "file")) + printf("%s ", instance->type); + else { + if (source->argv && *(source->argv[0]) != '/') + printf("files "); + else + printf("%s ", instance->type); + } + + return; +} + +static void print_map_info(struct map_source *source) +{ + int argc = source->argc; + int i, multi, map_num; + + multi = (source->type && !strcmp(source->type, "multi")); + map_num = 1; + for (i = 0; i < argc; i++) { + if (source->argv[i] && *source->argv[i] != '-') { + if (!multi) + printf(" map: %s\n", source->argv[i]); + else + printf(" map[%i]: %s\n", map_num, source->argv[i]); + i++; + } + + if (i >= argc) + return; + + if (!strcmp(source->argv[i], "--")) + continue; + + if (source->argv[i]) { + int need_newline = 0; + int j; + + if (!multi) + printf(" arguments:"); + else + printf(" arguments[%i]:", map_num); + + for (j = i; j < source->argc; j++) { + if (!strcmp(source->argv[j], "--")) + break; + printf(" %s", source->argv[j]); + i++; + need_newline = 1; + } + if (need_newline) + printf("\n"); + } + if (multi) + map_num++; + } + + return; +} + +static int match_type(const char *source, const char *type) +{ + if (!strcmp(source, type)) + return 1; + /* Sources file and files are synonymous */ + if (!strncmp(source, type, 4) && (strlen(source) <= 5)) + return 1; + return 0; +} + +static char *get_map_name(const char *string) +{ + char *name, *tmp; + char *start, *end, *base; + + tmp = strdup(string); + if (!tmp) { + printf("error: allocation failure: %s\n", strerror(errno)); + return NULL; + } + + base = basename(tmp); + end = strchr(base, ','); + if (end) + *end = '\0'; + start = strchr(tmp, '='); + if (start) + start++; + else { + char *colon = strrchr(base, ':'); + if (colon) + start = ++colon; + else + start = base; + } + + name = strdup(start); + if (!name) + printf("error: allocation failure: %s\n", strerror(errno)); + free(tmp); + + return name; +} + +static int match_name(struct map_source *source, const char *name) +{ + int argc = source->argc; + int ret = 0; + int i; + + /* + * This can't work for old style "multi" type sources since + * there's no way to know from which map the cache entry came + * from and duplicate entries are ignored at map read time. + * All we can really do is list all the entries for the given + * multi map if one of its map names matches. + */ + for (i = 0; i < argc; i++) { + if (i == 0 || !strcmp(source->argv[i], "--")) { + if (i != 0) { + i++; + if (i >= argc) + break; + } + + if (source->argv[i] && *source->argv[i] != '-') { + char *map = get_map_name(source->argv[i]); + if (!map) + break; + if (!strcmp(map, name)) { + ret = 1; + free(map); + break; + } + free(map); + } + } + } + + return ret; +} + +int dump_map(struct master *master, const char *type, const char *name) +{ + struct list_head *p, *head; + + if (list_empty(&master->mounts)) { + printf("no master map entries found\n"); + return 1; + } + + head = &master->mounts; + p = head->next; + while (p != head) { + struct map_source *source; + struct master_mapent *this; + struct autofs_point *ap; + time_t now = monotonic_time(NULL); + + this = list_entry(p, struct master_mapent, list); + p = p->next; + + ap = this->ap; + + /* + * Ensure we actually read indirect map entries so we can + * list them. The map reads won't read any indirect map + * entries (other than those in a file map) unless the + * browse option is set. + */ + if (ap->type == LKP_INDIRECT) + ap->flags |= MOUNT_FLAG_GHOST; + + /* Read the map content into the cache */ + if (lookup_nss_read_map(ap, NULL, now)) + lookup_prune_cache(ap, now); + else { + printf("failed to read map\n"); + lookup_close_lookup(ap); + continue; + } + + if (!this->maps) { + printf("no map sources found for %s\n", ap->path); + lookup_close_lookup(ap); + continue; + } + + source = this->maps; + while (source) { + struct map_source *instance; + struct mapent *me; + + instance = NULL; + if (source->type) { + if (!match_type(source->type, type)) { + source = source->next; + continue; + } + if (!match_name(source, name)) { + source = source->next; + continue; + } + instance = source; + } else { + struct map_source *map; + + map = source->instance; + while (map) { + if (!match_type(map->type, type)) { + map = map->next; + continue; + } + if (!match_name(map, name)) { + map = map->next; + continue; + } + instance = map; + break; + } + } + + if (!instance) { + source = source->next; + lookup_close_lookup(ap); + continue; + } + + me = cache_lookup_first(source->mc); + if (!me) + printf("no keys found in map\n"); + else { + do { + if (me->source == instance) + printf("%s\t%s\n", me->key, me->mapent); + } while ((me = cache_lookup_next(source->mc, me))); + } + + lookup_close_lookup(ap); + return 1; + } + lookup_close_lookup(ap); + } + + return 0; +} + +int master_show_mounts(struct master *master) +{ + struct list_head *p, *head; + + printf("\nautofs dump map information\n" + "===========================\n\n"); + + printf("global options: "); + if (!global_options) + printf("none configured\n"); + else { + printf("%s\n", global_options); + unsigned int append_options = defaults_get_append_options(); + const char *append = append_options ? "will" : "will not"; + printf("global options %s be appended to map entries\n", append); + } + + if (list_empty(&master->mounts)) { + printf("no master map entries found\n\n"); + return 1; + } + + head = &master->mounts; + p = head->next; + while (p != head) { + struct map_source *source; + struct master_mapent *this; + struct autofs_point *ap; + time_t now = monotonic_time(NULL); + unsigned int count = 0; + + this = list_entry(p, struct master_mapent, list); + p = p->next; + + ap = this->ap; + + printf("\nMount point: %s\n", ap->path); + + printf("\nsource(s):\n"); + + /* + * Ensure we actually read indirect map entries so we can + * list them. The map reads won't read any indirect map + * entries (other than those in a file map) unless the + * browse option is set. + */ + if (ap->type == LKP_INDIRECT) + ap->flags |= MOUNT_FLAG_GHOST; + + /* Read the map content into the cache */ + if (lookup_nss_read_map(ap, NULL, now)) + lookup_prune_cache(ap, now); + else { + printf(" failed to read map\n\n"); + continue; + } + + if (!this->maps) { + printf(" no map sources found\n\n"); + continue; + } + + source = this->maps; + while (source) { + struct mapent *me; + + if (source->type) + printf("\n type: %s\n", source->type); + else { + printf("\n instance type(s): "); + list_source_instances(source, source->instance); + printf("\n"); + } + + if (source->argc >= 1) { + print_map_info(source); + if (count && ap->type == LKP_INDIRECT) + printf(" duplicate indirect map entry" + " will be ignored at run time\n"); + } + + printf("\n"); + + me = cache_lookup_first(source->mc); + if (!me) + printf(" no keys found in map\n"); + else { + do { + printf(" %s | %s\n", me->key, me->mapent); + } while ((me = cache_lookup_next(source->mc, me))); + } + + count++; + + source = source->next; + } + + lookup_close_lookup(ap); + + printf("\n"); + } + + return 1; +} + +int master_list_empty(struct master *master) +{ + int res = 0; + + master_mutex_lock(); + if (list_empty(&master->mounts)) + res = 1; + master_mutex_unlock(); + + return res; +} + +int master_done(struct master *master) +{ + struct list_head *head, *p; + struct master_mapent *entry; + int res = 0; + + head = &master->completed; + p = head->next; + while (p != head) { + entry = list_entry(p, struct master_mapent, join); + p = p->next; + list_del(&entry->join); + pthread_join(entry->thid, NULL); + master_free_mapent_sources(entry, 1); + master_free_mapent(entry); + } + if (list_empty(&master->mounts)) + res = 1; + + return res; +} + +unsigned int master_get_logopt(void) +{ + return master_list ? master_list->logopt : LOGOPT_NONE; +} + +int master_kill(struct master *master) +{ + if (!list_empty(&master->mounts)) + return 0; + + if (master->name) + free(master->name); + + cache_release_null_cache(master); + free(master); + + return 1; +} diff --git a/daemon/master_parse.y b/daemon/master_parse.y new file mode 100644 index 00000000..08e44b57 --- /dev/null +++ b/daemon/master_parse.y @@ -0,0 +1,983 @@ +%{ +/* ----------------------------------------------------------------------- * + * + * master_parser.y - master map buffer parser. + * + * Copyright 2006 Ian Kent + * + * 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 +#include +#include +#include +#include +#include + +#include "automount.h" +#include "master.h" + +#define MAX_ERR_LEN 512 + +extern struct master *master_list; + +char **add_argv(int, char **, char *); +const char **copy_argv(int, const char **); +int free_argv(int, const char **); + +extern FILE *master_in; +extern char *master_text; +extern int master_lex(void); +extern int master_lineno; +extern void master_set_scan_buffer(const char *); + +static char *master_strdup(char *); +static void local_init_vars(void); +static void local_free_vars(void); +static void trim_maptype(char *); +static int add_multi_mapstr(void); + +static int master_error(const char *s); +static int master_notify(const char *s); +static int master_msg(const char *s); + +static char *path; +static char *type; +static char *format; +static long timeout; +static long negative_timeout; +static unsigned symlnk; +static unsigned strictexpire; +static unsigned nobind; +static unsigned ghost; +extern unsigned global_selection_options; +static unsigned random_selection; +static unsigned use_weight; +static unsigned long mode; +static char **tmp_argv; +static int tmp_argc; +static char **local_argv; +static int local_argc; + +#define PROPAGATION_SHARED MOUNT_FLAG_SHARED +#define PROPAGATION_SLAVE MOUNT_FLAG_SLAVE +#define PROPAGATION_PRIVATE MOUNT_FLAG_PRIVATE +#define PROPAGATION_MASK (MOUNT_FLAG_SHARED | \ + MOUNT_FLAG_SLAVE | \ + MOUNT_FLAG_PRIVATE) +static unsigned int propagation; + +static char errstr[MAX_ERR_LEN]; + +static unsigned int verbose; +static unsigned int debug; + +static int lineno; + +#define YYDEBUG 0 + +#ifndef YYENABLE_NLS +#define YYENABLE_NLS 0 +#endif +#ifndef YYLTYPE_IS_TRIVIAL +#define YYLTYPE_IS_TRIVIAL 0 +#endif + +#if YYDEBUG +static int master_fprintf(FILE *, char *, ...); +#undef YYFPRINTF +#define YYFPRINTF master_fprintf +#endif + +%} + +%union { + char strtype[2048]; + int inttype; + long longtype; +} + +%token COMMENT +%token MAP +%token OPT_TIMEOUT OPT_NTIMEOUT OPT_NOBIND OPT_NOGHOST OPT_GHOST OPT_VERBOSE +%token OPT_DEBUG OPT_RANDOM OPT_USE_WEIGHT OPT_SYMLINK OPT_MODE +%token OPT_STRICTEXPIRE OPT_SHARED OPT_SLAVE OPT_PRIVATE +%token COLON COMMA NL DDASH +%type map +%type options +%type dn +%type dnattrs +%type dnattr +%type option +%type daemon_option +%type mount_option +%token PATH +%token QUOTE +%token NILL +%token SPACE +%token EQUAL +%token MULTITYPE +%token MAPTYPE +%token DNSERVER +%token DNATTR +%token DNNAME +%token MAPHOSTS +%token MAPNULL +%token MAPXFN +%token MAPNAME +%token NUMBER +%token OCTALNUMBER +%token OPTION + +%start file + +%% + +file: { + master_lineno = 0; +#if YYDEBUG != 0 + master_debug = YYDEBUG; +#endif + } line + ; + +line: + | PATH mapspec + { + path = master_strdup($1); + if (!path) { + local_free_vars(); + YYABORT; + } + } + | PATH MULTITYPE maplist + { + char *tmp = NULL; + + trim_maptype($2); + + if (path) + free(path); + path = master_strdup($1); + if (!path) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + + if ((tmp = strchr($2, ','))) + *tmp++ = '\0'; +#ifndef WITH_HESIOD + /* Map type or map type parser is hesiod */ + if (!strcmp($2, "hesiod") || (tmp && !strcmp(tmp, "hesiod"))) { + master_error("hesiod support not built in"); + local_free_vars(); + YYABORT; + } +#endif + if (type) + free(type); + type = master_strdup($2); + if (!type) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + if (tmp) { + if (format) + free(format); + format = master_strdup(tmp); + if (!format) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + } + | PATH COLON { master_notify($1); YYABORT; } + | PATH OPTION { master_notify($2); YYABORT; } + | PATH NILL { master_notify($2); YYABORT; } + | PATH OPT_RANDOM { master_notify($1); YYABORT; } + | PATH OPT_USE_WEIGHT { master_notify($1); YYABORT; } + | PATH OPT_DEBUG { master_notify($1); YYABORT; } + | PATH OPT_TIMEOUT { master_notify($1); YYABORT; } + | PATH OPT_SYMLINK { master_notify($1); YYABORT; } + | PATH OPT_STRICTEXPIRE { master_notify($1); YYABORT; } + | PATH OPT_SHARED { master_notify($1); YYABORT; } + | PATH OPT_SLAVE { master_notify($1); YYABORT; } + | PATH OPT_PRIVATE { master_notify($1); YYABORT; } + | PATH OPT_NOBIND { master_notify($1); YYABORT; } + | PATH OPT_GHOST { master_notify($1); YYABORT; } + | PATH OPT_NOGHOST { master_notify($1); YYABORT; } + | PATH OPT_VERBOSE { master_notify($1); YYABORT; } + | PATH OPT_MODE { master_notify($1); YYABORT; } + | PATH { master_notify($1); YYABORT; } + | QUOTE { master_notify($1); YYABORT; } + | OPTION { master_notify($1); YYABORT; } + | NILL { master_notify($1); YYABORT; } + | COMMENT { YYABORT; } + ; + +mapspec: map + { + if (local_argv) + free_argv(local_argc, (const char **) local_argv); + local_argc = tmp_argc; + local_argv = tmp_argv; + tmp_argc = 0; + tmp_argv = NULL; + } + | map options + { + if (local_argv) + free_argv(local_argc, (const char **) local_argv); + local_argc = tmp_argc; + local_argv = tmp_argv; + tmp_argc = 0; + tmp_argv = NULL; + } + ; + +maplist: map + { + if (!add_multi_mapstr()) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + | map options + { + if (!add_multi_mapstr()) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + | maplist DDASH map + { + local_argc++; + local_argv = add_argv(local_argc, local_argv, "--"); + if (!local_argv) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + if (!add_multi_mapstr()) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + | maplist DDASH map options + { + local_argc++; + local_argv = add_argv(local_argc, local_argv, "--"); + if (!local_argv) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + if (!add_multi_mapstr()) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + ; + +map: PATH + { + tmp_argc++; + tmp_argv = add_argv(tmp_argc, tmp_argv, $1); + if (!tmp_argv) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + | MAPNAME + { + tmp_argc++; + tmp_argv = add_argv(tmp_argc, tmp_argv, $1); + if (!tmp_argv) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + | MAPHOSTS + { + if (type) + free(type); + type = master_strdup($1 + 1); + if (!type) { + local_free_vars(); + YYABORT; + } + } + | MAPXFN + { + master_notify($1); + master_msg("X/Open Federated Naming service not supported"); + YYABORT; + } + | MAPNULL + { + if (type) + free(type); + type = master_strdup($1 + 1); + if (!type) { + local_free_vars(); + YYABORT; + } + } + | dnattrs + { + if (type) + free(type); + type = master_strdup("ldap"); + if (!type) { + local_free_vars(); + YYABORT; + } + tmp_argc++; + tmp_argv = add_argv(tmp_argc, tmp_argv, $1); + if (!tmp_argv) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + | MAPTYPE PATH + { + char *tmp = NULL; + + trim_maptype($1); + + if ((tmp = strchr($1, ','))) + *tmp++ = '\0'; +#ifndef WITH_HESIOD + /* Map type or map type parser is hesiod */ + if (!strcmp($1, "hesiod") || (tmp && !strcmp(tmp, "hesiod"))) { + master_error("hesiod support not built in"); + local_free_vars(); + YYABORT; + } +#endif + if (type) + free(type); + if (strcmp($1, "exec")) + type = master_strdup($1); + else + type = master_strdup("program"); + if (!type) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + if (tmp) { + if (format) + free(format); + format = master_strdup(tmp); + if (!format) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + tmp_argc++; + tmp_argv = add_argv(tmp_argc, tmp_argv, $2); + if (!tmp_argv) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + | MAPTYPE MAPNAME + { + char *tmp = NULL; + + trim_maptype($1); + + if ((tmp = strchr($1, ','))) + *tmp++ = '\0'; + + if (type) + free(type); + if (strcmp($1, "exec")) + type = master_strdup($1); + else + type = master_strdup("program"); + if (!type) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + if (tmp) { + if (format) + free(format); + format = master_strdup(tmp); + if (!format) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + tmp_argc++; + tmp_argv = add_argv(tmp_argc, tmp_argv, $2); + if (!tmp_argv) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + | MAPTYPE dn + { + char *tmp = NULL; + + trim_maptype($1); + + if ((tmp = strchr($1, ','))) + *tmp++ = '\0'; + + if (type) + free(type); + if (strcmp($1, "exec")) + type = master_strdup($1); + else + type = master_strdup("program"); + if (!type) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + if (tmp) { + if (format) + free(format); + format = master_strdup(tmp); + if (!format) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + tmp_argc++; + tmp_argv = add_argv(tmp_argc, tmp_argv, $2); + if (!tmp_argv) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + /* Add back the type for lookup_ldap.c to handle ldaps */ + if (*tmp_argv[0]) { + tmp = malloc(strlen(type) + strlen(tmp_argv[0]) + 2); + if (!tmp) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + strcpy(tmp, type); + strcat(tmp, ":"); + strcat(tmp, tmp_argv[0]); + free(tmp_argv[0]); + tmp_argv[0] = tmp; + } + } + ; + +dn: DNSERVER dnattrs + { + strcpy($$, $1); + strcat($$, $2); + } + | dnattrs + { + strcpy($$, $1); + } + | + { + master_notify("syntax error in dn"); + YYABORT; + } + ; + +dnattrs: DNATTR EQUAL DNNAME + { + if (strcasecmp($1, "cn") && + strcasecmp($1, "ou") && + strcasecmp($1, "automountMapName") && + strcasecmp($1, "nisMapName")) { + strcpy(errstr, $1); + strcat(errstr, "="); + strcat(errstr, $3); + master_notify(errstr); + YYABORT; + } + strcpy($$, $1); + strcat($$, "="); + strcat($$, $3); + } + | DNATTR EQUAL DNNAME COMMA dnattr + { + if (strcasecmp($1, "cn") && + strcasecmp($1, "ou") && + strcasecmp($1, "automountMapName") && + strcasecmp($1, "nisMapName")) { + strcpy(errstr, $1); + strcat(errstr, "="); + strcat(errstr, $3); + master_notify(errstr); + YYABORT; + } + strcpy($$, $1); + strcat($$, "="); + strcat($$, $3); + strcat($$, ","); + strcat($$, $5); + } + | DNNAME + { + /* Matches map in old style syntax ldap:server:map */ + strcpy($$, $1); + } + | DNATTR + { + master_notify($1); + YYABORT; + } + ; + +dnattr: DNATTR EQUAL DNNAME + { + if (!strcasecmp($1, "automountMapName") || + !strcasecmp($1, "nisMapName")) { + strcpy(errstr, $1); + strcat(errstr, "="); + strcat(errstr, $3); + master_notify(errstr); + YYABORT; + } + strcpy($$, $1); + strcat($$, "="); + strcat($$, $3); + } + | DNATTR EQUAL DNNAME COMMA dnattr + { + if (!strcasecmp($1, "automountMapName") || + !strcasecmp($1, "nisMapName")) { + strcpy(errstr, $1); + strcat(errstr, "="); + strcat(errstr, $3); + master_notify(errstr); + YYABORT; + } + strcpy($$, $1); + strcat($$, "="); + strcat($$, $3); + strcat($$, ","); + strcat($$, $5); + } + | DNATTR + { + master_notify($1); + YYABORT; + } + | DNNAME + { + master_notify($1); + YYABORT; + } + ; + +options: option {} + | options COMMA option {} + | options option {} + | options COMMA COMMA option + { + master_notify($1); + YYABORT; + } + | options EQUAL + { + master_notify($1); + YYABORT; + } + ; + +option: daemon_option + | mount_option {} + | error + { + master_notify("bogus option"); + YYABORT; + } + ; + +daemon_option: OPT_TIMEOUT NUMBER { timeout = $2; } + | OPT_NTIMEOUT NUMBER { negative_timeout = $2; } + | OPT_SYMLINK { symlnk = 1; } + | OPT_STRICTEXPIRE { strictexpire = 1; } + | OPT_SHARED { propagation = PROPAGATION_SHARED; } + | OPT_SLAVE { propagation = PROPAGATION_SLAVE; } + | OPT_PRIVATE { propagation = PROPAGATION_PRIVATE; } + | OPT_NOBIND { nobind = 1; } + | OPT_NOGHOST { ghost = 0; } + | OPT_GHOST { ghost = 1; } + | OPT_VERBOSE { verbose = 1; } + | OPT_DEBUG { debug = 1; } + | OPT_RANDOM { random_selection = 1; } + | OPT_USE_WEIGHT { use_weight = 1; } + | OPT_MODE OCTALNUMBER { mode = $2; } + ; + +mount_option: OPTION + { + tmp_argc++; + tmp_argv = add_argv(tmp_argc, tmp_argv, $1); + if (!tmp_argv) { + master_error("memory allocation error"); + local_free_vars(); + YYABORT; + } + } + ; +%% + +#if YYDEBUG +static int master_fprintf(FILE *f, char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + vsyslog(LOG_DEBUG, msg, ap); + va_end(ap); + return 1; +} +#endif + +static char *master_strdup(char *str) +{ + char *tmp; + + tmp = strdup(str); + if (!tmp) + master_error("memory allocation error"); + return tmp; +} + +static int master_error(const char *s) +{ + logmsg("%s while parsing map.", s); + return 0; +} + +static int master_notify(const char *s) +{ + logmsg("syntax error in map near [ %s ]", s); + return(0); +} + +static int master_msg(const char *s) +{ + logmsg("%s", s); + return 0; +} + +static void local_init_vars(void) +{ + path = NULL; + type = NULL; + format = NULL; + verbose = 0; + debug = 0; + timeout = -1; + negative_timeout = 0; + symlnk = 0; + strictexpire = 0; + propagation = PROPAGATION_SLAVE; + nobind = 0; + ghost = defaults_get_browse_mode(); + random_selection = global_selection_options & MOUNT_FLAG_RANDOM_SELECT; + use_weight = 0; + mode = 0; + tmp_argv = NULL; + tmp_argc = 0; + local_argv = NULL; + local_argc = 0; +} + +static void local_free_vars(void) +{ + if (path) + free(path); + + if (type) + free(type); + + if (format) + free(format); + + if (local_argv) { + free_argv(local_argc, (const char **) local_argv); + local_argv = NULL; + local_argc = 0; + } + + if (tmp_argv) { + free_argv(tmp_argc, (const char **) tmp_argv); + tmp_argv = NULL; + tmp_argc = 0; + } +} + +static void trim_maptype(char *type) +{ + char *tmp; + + tmp = strchr(type, ':'); + if (tmp) + *tmp = '\0'; + else { + int len = strlen(type); + while (len-- && isblank(type[len])) + type[len] = '\0'; + } + return; +} + +static int add_multi_mapstr(void) +{ + if (type) { + /* If type given and format is non-null add it back */ + if (format) { + int len = strlen(type) + strlen(format) + 2; + char *tmp = realloc(type, len); + if (!tmp) + return 0; + type = tmp; + strcat(type, ","); + strcat(type, format); + free(format); + format = NULL; + } + + local_argc++; + local_argv = add_argv(local_argc, local_argv, type); + if (!local_argv) { + free(type); + type = NULL; + return 0; + } + + free(type); + type = NULL; + } + + local_argv = append_argv(local_argc, local_argv, tmp_argc, tmp_argv); + if (!local_argv) { + free(type); + type = NULL; + return 0; + } + local_argc += tmp_argc; + + tmp_argc = 0; + tmp_argv = NULL; + + return 1; +} + +void master_init_scan(void) +{ + lineno = 0; +} + +int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigned int logging, time_t age) +{ + struct master *master = master_list; + struct mapent_cache *nc; + struct master_mapent *entry, *new; + struct map_source *source; + unsigned int logopt = logging; + unsigned int m_logopt = master->logopt; + size_t mp_len; + int ret; + + local_init_vars(); + + lineno++; + + master_set_scan_buffer(buffer); + + ret = master_parse(); + if (ret != 0) { + local_free_vars(); + return 0; + } + + mp_len = strlen(path); + while (mp_len && path[--mp_len] == '/') + path[mp_len] = 0; + + nc = master->nc; + + /* Add null map entries to the null map cache */ + if (type && !strcmp(type, "null")) { + cache_update(nc, NULL, path, NULL, lineno); + local_free_vars(); + return 1; + } + + /* Ignore all subsequent matching nulled entries */ + if (cache_lookup_distinct(nc, path)) { + local_free_vars(); + return 1; + } + + if (debug || verbose) { + logopt = (debug ? LOGOPT_DEBUG : 0); + logopt |= (verbose ? LOGOPT_VERBOSE : 0); + } + + new = NULL; + entry = master_find_mapent(master, path); + if (!entry) { + new = master_new_mapent(master, path, age); + if (!new) { + local_free_vars(); + return 0; + } + entry = new; + } else { + if (entry->age && entry->age == age) { + if (strcmp(path, "/-")) { + info(m_logopt, + "ignoring duplicate indirect mount %s", + path); + local_free_vars(); + return 0; + } + } + } + + if (!format) { + if (conf_amd_mount_section_exists(path)) + format = strdup("amd"); + } + + if (format && !strcmp(format, "amd")) { + unsigned int loglevel = conf_amd_get_log_options(); + unsigned int flags = conf_amd_get_flags(path); + + if (loglevel <= LOG_DEBUG && loglevel > LOG_INFO) + logopt = LOGOPT_DEBUG; + else if (loglevel <= LOG_INFO && loglevel > LOG_ERR) + logopt = LOGOPT_VERBOSE; + + /* It isn't possible to provide the fullybrowsable amd + * browsing functionality within the autofs framework. + * This flag will not be set if browsable_dirs = full + * in the configuration or fullybrowsable is present as + * an option. + */ + if (flags & CONF_BROWSABLE_DIRS) + ghost = 1; + } + + if (!entry->ap) { + ret = master_add_autofs_point(entry, logopt, nobind, ghost, 0); + if (!ret) { + error(m_logopt, "failed to add autofs_point"); + if (new) + master_free_mapent(new); + local_free_vars(); + return 0; + } + } + entry->ap->flags &= ~(PROPAGATION_MASK); + entry->ap->flags |= propagation; + + if (random_selection) + entry->ap->flags |= MOUNT_FLAG_RANDOM_SELECT; + if (use_weight) + entry->ap->flags |= MOUNT_FLAG_USE_WEIGHT_ONLY; + if (symlnk) + entry->ap->flags |= MOUNT_FLAG_SYMLINK; + if (strictexpire) + entry->ap->flags |= MOUNT_FLAG_STRICTEXPIRE; + if (negative_timeout) + entry->ap->negative_timeout = negative_timeout; + if (mode && mode < LONG_MAX) + entry->ap->mode = mode; + + if (timeout < 0) { + /* + * If no timeout is given get the timout from the + * autofs point, or the first map, or the config + * for amd maps. + */ + if (format && !strcmp(format, "amd")) + timeout = conf_amd_get_dismount_interval(path); + else + timeout = get_exp_timeout(entry->ap, entry->maps); + } + + if (format && !strcmp(format, "amd")) { + char *opts = conf_amd_get_map_options(path); + if (opts) { + /* autofs uses the equivalent of cache:=inc,sync + * (except for file maps which use cache:=all,sync) + * but if the map is large then it may be necessary + * to read the whole map at startup even if browsing + * is is not enabled, so look for cache:=all in the + * map_options configuration entry. + */ + if (strstr(opts, "cache:=all")) + entry->ap->flags |= MOUNT_FLAG_AMD_CACHE_ALL; + free(opts); + } + } + +/* + source = master_find_map_source(entry, type, format, + local_argc, (const char **) local_argv); + if (!source) + source = master_add_map_source(entry, type, format, age, + local_argc, (const char **) local_argv); + else + source->age = age; +*/ + source = master_add_map_source(entry, type, format, age, + local_argc, (const char **) local_argv); + if (!source) { + error(m_logopt, "failed to add source"); + if (new) + master_free_mapent(new); + local_free_vars(); + return 0; + } + set_exp_timeout(entry->ap, source, timeout); + source->master_line = lineno; + + entry->age = age; + entry->current = NULL; + + if (new) + master_add_mapent(master, entry); + + local_free_vars(); + + return 1; +} + diff --git a/daemon/master_tok.l b/daemon/master_tok.l new file mode 100644 index 00000000..87a6b958 --- /dev/null +++ b/daemon/master_tok.l @@ -0,0 +1,504 @@ +%{ +/* ----------------------------------------------------------------------- * + * + * master_tok.l - master map tokenizer. + * + * Copyright 2006 Ian Kent + * + * 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. + * + * ----------------------------------------------------------------------- */ + +#ifdef ECHO +# undef ECHO +#endif /* ECHO */ +static void master_echo(void); /* forward definition */ +#define ECHO master_echo() + +#include +#include +#include +#include +#include "master_parse.tab.h" + +/* + * There are some things that need to be defined only if useing GNU flex. + * These must not be defined if using standard lex + */ +#ifdef FLEX_SCANNER +int master_lineno; +#endif + +int master_lex(void); +int master_wrap(void); + +/* no need for yywrap() */ +#define YY_SKIP_YYWRAP + +#ifndef YY_STACK_USED +#define YY_STACK_USED 0 +#endif +#ifndef YY_ALWAYS_INTERACTIVE +#define YY_ALWAYS_INTERACTIVE 0 +#endif +#ifndef YY_NEVER_INTERACTIVE +#define YY_NEVER_INTERACTIVE 0 +#endif +#ifndef YY_MAIN +#define YY_MAIN 0 +#endif + +void master_set_scan_buffer(const char *); +const char *line = NULL; + +#ifdef FLEX_SCANNER +const char *line_pos = NULL; +const char *line_lim = NULL; +int my_yyinput(char *, int); + +#undef YY_INPUT +#define YY_INPUT(b, r, ms) (r = my_yyinput(b, ms)) +#else +#undef input +#undef unput +#define input() (*(char *) line++) +#define unput(c) (*(char *) --line = c) +#endif + +#define BUFF_LEN 1024 +char buff[BUFF_LEN]; +char *bptr; +char *optr = buff; +unsigned int tlen; + +%} + +%option nounput + +%x PATHSTR MAPSTR DNSTR OPTSTR OCTAL + +WS [[:blank:]]+ +OPTWS [[:blank:]]* +NL \r?\n +CONT \\\n{OPTWS} + +OPTIONSTR ([\-]?([[:alpha:]_]([[:alnum:]_\-])*(=(\"?([[:alnum:]_\-\:\.])+\"?))?)+) +MACROSTR (-D{OPTWS}([[:alpha:]_]([[:alnum:]_\-\.])*)=([[:alnum:]_\-\.])+) +SLASHIFYSTR (--(no-)?slashify-colons) +NUMBER [0-9]+ +OCTALNUMBER [0-7]+ + +DNSERVSTR1 ([[:alpha:]][[:alnum:]\-.]*(:[0-9]+)?:) +DNSERVSTR2 (\[([[:xdigit:]]:.)+\](:[0-9]+)?:) +DNSERVSTR3 (\/\/[[:alpha:]][[:alnum:]\-.]*(:[0-9]+)?\/) +DNSERVSTR4 (\/\/\[([[:xdigit:]]:.)+\](:[0-9]+)?\/) +DNSERVSTR5 (([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(:[0-9]+)?:) +DNSERVSTR6 (\/\/([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(:[0-9]+)?\/) +DNSERVERSTR ({DNSERVSTR1}|{DNSERVSTR2}|{DNSERVSTR3}|{DNSERVSTR4}|{DNSERVSTR5}|{DNSERVSTR6}) + +AT_CN ([cC][[nN]) +AT_NMN ([nN][iI][sS][Mm][aA][pP][Nn][aA][mM][eE]) +AT_AMN ([aA][uU][tT][oO][mM][oO][uU][nN][tT][Mm][aA][pP][Nn][aA][mM][eE]) +AT_OU ([oO][[uU]) +AT_DC ([dD][[cC]) +AT_O ([oO]) +AT_C ([cC]) +AT_L ([lL]) +DNATTRSTR ({AT_CN}|{AT_NMN}|{AT_AMN}|{AT_OU}|{AT_DC}|{AT_O}|{AT_C}|{AT_L}) +DNNAMESTR1 ([[:alnum:]_.\- ]+) +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})) + + +OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS}) +OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|--negative-timeout{OPTWS}|--negative-timeout{OPTWS}={OPTWS}) + +MODE (--mode{OPTWS}|--mode{OPTWS}={OPTWS}) + +%% + +{ + {NL} | + \x00 { + if (optr != buff) { + *optr = '\0'; + strcpy(master_lval.strtype, buff); + return NILL; + } + } + + #.* { return COMMENT; } + + "/" { + if (optr != buff) { + *optr = '\0'; + strcpy(master_lval.strtype, buff); + return NILL; + } + BEGIN(PATHSTR); + bptr = buff; + yyless(0); + } + + . { *optr++ = *master_text; } +} + +{ + \x00 { + BEGIN(INITIAL); + *bptr++ = *master_text; + strcpy(master_lval.strtype, buff); + return NILL; + } + + \\. { *bptr++ = *(master_text + 1); } + \" { + BEGIN(INITIAL); + *bptr++ = *master_text; + *bptr = '\0'; + strcpy(master_lval.strtype, buff); + return QUOTE; + } + + {WS} { + BEGIN(MAPSTR); + *bptr = '\0'; + strcpy(master_lval.strtype, buff); + bptr = buff; + memset(buff, 0, BUFF_LEN); + return(PATH); + } + + <> { + BEGIN(INITIAL); + *bptr = '\0'; + strcpy(master_lval.strtype, buff); + return(PATH); + } + + {NL} { + BEGIN(INITIAL); + *bptr = '\0'; + strcpy(master_lval.strtype, buff); + return PATH; + } + + . { *bptr++ = *master_text; } +} + +{ + {OPTWS}\\\n{OPTWS} {} + + {MULTI} { + tlen = master_leng - 1; + if (bptr != buff && isblank(master_text[tlen])) { + /* + * We can't handle unescaped white space in map names + * so just eat the white space. We always have the + * "multi" at the beginning of the string so the while + * will not fall off the end. + */ + while (isblank(master_text[tlen - 1])) + tlen--; + strncat(buff, master_text, tlen); + bptr += tlen; + yyless(tlen); + } else { + strcpy(master_lval.strtype, master_text); + return(MULTITYPE); + } + } + + {MTYPE} | + {MTYPE}/{DNSERVERSTR}{DNATTRSTR}= | + {MTYPE}/{DNATTRSTR}= { + tlen = master_leng - 1; + if (bptr != buff && isblank(master_text[tlen])) { + /* + * We can't handle unescaped white space in map names + * so just eat the white space. We always have the + * maptype keyword at the beginning of the string so + * the while will not fall off the end. + */ + while (isblank(master_text[tlen - 1])) + tlen--; + strncat(buff, master_text, tlen); + bptr += tlen; + yyless(tlen); + } else { + strcpy(master_lval.strtype, master_text); + return(MAPTYPE); + } + } + + {MULTISEP} { return(DDASH); } + + ":" { return(COLON); } + + "-hosts" { + BEGIN(OPTSTR); + strcpy(master_lval.strtype, master_text); + return MAPHOSTS; + } + + "-null" { + BEGIN(OPTSTR); + strcpy(master_lval.strtype, master_text); + return MAPNULL; + } + + "-xfn" { + /* + * The X/Open Federated Naming service isn't supported + * and the parser will call YYABORT() when it sees the + * MAPXFN token so we must set the start state to the + * INITIAL state here for the next yylex() call. + */ + BEGIN(INITIAL); + strcpy(master_lval.strtype, master_text); + return MAPXFN; + } + + "//" { + BEGIN(DNSTR); + yyless(0); + } + + {DNSERVERSTR}{DNATTRSTR}= { + BEGIN(DNSTR); + yyless(0); + } + + {DNATTRSTR}= { + BEGIN(DNSTR); + yyless(0); + } + + {OPTWS}/{NL} { + BEGIN(INITIAL); + *bptr = '\0'; + strcpy(master_lval.strtype, buff); + bptr = buff; + return(MAPNAME); + } + + \\. { *bptr++ = *(master_text + 1); } + + {WS} { + BEGIN(OPTSTR); + *bptr = '\0'; + strcpy(master_lval.strtype, buff); + bptr = buff; + return(MAPNAME); + } + + {NL} | + \x00 { + BEGIN(INITIAL); + *bptr = '\0'; + strcpy(master_lval.strtype, buff); + return(MAPNAME); + } + + <> { + BEGIN(INITIAL); + *bptr = '\0'; + strcpy(master_lval.strtype, buff); + return(MAPNAME); + } + + . { *bptr++ = *master_text; } +} + +{ + {OPTWS}\\\n{OPTWS} {} + + {DNSERVERSTR} { + strcpy(master_lval.strtype, master_text); + return DNSERVER; + } + + {DNATTRSTR}/"=" { + strcpy(master_lval.strtype, master_text); + return DNATTR; + } + + "=" { + return EQUAL; + } + + {DNNAMESTR1}/","{DNATTRSTR}"=" { + strcpy(master_lval.strtype, master_text); + return DNNAME; + } + + {DNNAMESTR2} { + strcpy(master_lval.strtype, master_text); + return DNNAME; + } + + {OPTWS}","{OPTWS} { + return COMMA; + } + + {WS}"=" | + "="{WS} { + BEGIN(INITIAL); + strcpy(master_lval.strtype, master_text); + return SPACE; + } + + {WS} { BEGIN(OPTSTR); } + + {NL} | + \x00 { BEGIN(INITIAL); } + + <> { BEGIN(INITIAL); } +} + +{ + {OPTWS}\\\n{OPTWS} {} + + {MULTISEP} { + BEGIN(MAPSTR); + return(DDASH); + } + + {OPTTOUT}/{NUMBER} { return(OPT_TIMEOUT); } + + {OPTNTOUT}/{NUMBER} { return(OPT_NTIMEOUT); } + + {NUMBER} { + master_lval.longtype = atol(master_text); + return(NUMBER); + } + + -?symlink { return(OPT_SYMLINK); } + -?nobind { return(OPT_NOBIND); } + -?nobrowse { return(OPT_NOGHOST); } + -?shared { return(OPT_SHARED); } + -?slave { return(OPT_SLAVE); } + -?private { return(OPT_PRIVATE); } + -?strictexpire { return(OPT_STRICTEXPIRE); } + -g|--ghost|-?browse { return(OPT_GHOST); } + -v|--verbose { return(OPT_VERBOSE); } + -d|--debug { return(OPT_DEBUG); } + -w|--use-weight-only { return(OPT_USE_WEIGHT); } + -r|--random-multimount-selection { return(OPT_RANDOM); } + + {MODE}/{OCTALNUMBER} { + BEGIN(OCTAL); + return(OPT_MODE); + } + + {OPTWS}","{OPTWS} { return(COMMA); } + + {OPTWS} {} + + {SLASHIFYSTR} { + strcpy(master_lval.strtype, master_text); + return(OPTION); + } + + {MACROSTR} { + strcpy(master_lval.strtype, master_text); + return(OPTION); + } + + {OPTIONSTR} { + strcpy(master_lval.strtype, master_text); + return(OPTION); + } + + "=" { + strcpy(master_lval.strtype, master_text); + return(EQUAL); + } + + {WS} {} + {NL} | + \x00 { BEGIN(INITIAL); } + + <> { BEGIN(INITIAL); } +} + +{ + {OCTALNUMBER} { + master_lval.longtype = strtoul(master_text, NULL, 8); + return(OCTALNUMBER); + } + + . { BEGIN(OPTSTR); yyless(0); } +} + +%% + +#include "automount.h" + +int master_wrap(void) +{ + return 1; +} + +static void master_echo(void) +{ + logmsg("%s", master_text); + return; +} + +#ifdef FLEX_SCANNER + +void master_set_scan_buffer(const char *buffer) +{ + memset(buff, 0, sizeof(buff)); + optr = buff; + + YY_FLUSH_BUFFER; + + line = buffer; + line_pos = &line[0]; + /* + * Ensure buffer is 1 greater than string and is zeroed before + * the parse so we can fit the extra NULL which allows us to + * explicitly match an end of line within the buffer (ie. the + * need for 2 NULLS when parsing in memeory buffers). + */ + line_lim = line + strlen(buffer) + 1; +} + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +int my_yyinput(char *buffer, int max_size) +{ + int n = min(max_size, line_lim - line_pos); + + if (n > 0) { + memcpy(buffer, line_pos, n); + line_pos += n; + } + return n; +} + +#else + +void master_set_scan_buffer(const char *buffer) +{ + line = buffer; +} + +#endif diff --git a/lib/Makefile b/lib/Makefile index b20b95b4..b6f3669f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -6,17 +6,14 @@ include ../Makefile.rules SRCS = cache.c cat_path.c rpc_subs.c mounts.c log.c nsswitch.c \ - master_tok.l master_parse.y nss_tok.c nss_parse.tab.c \ - args.c alarm.c macros.c master.c defaults.c parse_subs.c \ - dev-ioctl-lib.c + nss_tok.c nss_parse.tab.c args.c alarm.c macros.c defaults.c \ + parse_subs.c dev-ioctl-lib.c RPCS = mount.h mount_clnt.c mount_xdr.c OBJS = cache.o mount_clnt.o mount_xdr.o cat_path.o rpc_subs.o \ - mounts.o log.o nsswitch.o master_tok.o master_parse.tab.o \ - nss_tok.o nss_parse.tab.o args.o alarm.o macros.o master.o \ - defaults.o parse_subs.o dev-ioctl-lib.o + mounts.o log.o nsswitch.o nss_tok.o nss_parse.tab.o args.o \ + alarm.o macros.o defaults.o parse_subs.o dev-ioctl-lib.o -YACCSRC = nss_tok.c nss_parse.tab.c nss_parse.tab.h \ - master_tok.c master_parse.tab.c master_parse.tab.h +YACCSRC = nss_tok.c nss_parse.tab.c nss_parse.tab.h LIB = autofs.a @@ -54,16 +51,6 @@ mount_xdr.o: mount_xdr.c $(CC) $(CFLAGS) -Wno-unused-variable -o mount_xdr.o -c mount_xdr.c $(STRIP) mount_xdr.o -master_tok.c: master_tok.l - $(LEX) -o$@ -Pmaster_ $? - -master_parse.tab.c master_parse.tab.h: master_parse.y - $(YACC) -v -d -p master_ -b master_parse $? - -master_tok.o: master_tok.c master_parse.tab.h - -master_parse.tab.o: master_parse.tab.c master_parse.tab.h - nss_tok.c: nss_tok.l $(LEX) -o$@ -Pnss_ $? diff --git a/lib/master.c b/lib/master.c deleted file mode 100644 index 5ce7aed6..00000000 --- a/lib/master.c +++ /dev/null @@ -1,1885 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * master.c - master map utility routines. - * - * Copyright 2006 Ian Kent - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include "automount.h" - -/* The root of the map entry tree */ -struct master *master_list = NULL; - -extern const char *global_options; -extern long global_negative_timeout; - -/* Attribute to create a joinable thread */ -extern pthread_attr_t th_attr; - -extern struct startup_cond suc; - -static struct map_source * -__master_find_map_source(struct master_mapent *, - const char *, const char *, int, const char **); - -static pthread_mutex_t master_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER; - -void master_mutex_lock(void) -{ - int status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); -} - -void master_mutex_unlock(void) -{ - int status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); -} - -void master_mutex_lock_cleanup(void *arg) -{ - master_mutex_unlock(); - return; -} - -int master_add_autofs_point(struct master_mapent *entry, unsigned logopt, - unsigned nobind, unsigned ghost, int submount) -{ - struct autofs_point *ap; - int status; - - ap = malloc(sizeof(struct autofs_point)); - if (!ap) - return 0; - - ap->state = ST_INIT; - - ap->state_pipe[0] = -1; - ap->state_pipe[1] = -1; - ap->logpri_fifo = -1; - - ap->path = strdup(entry->path); - if (!ap->path) { - free(ap); - return 0; - } - ap->pref = NULL; - - ap->entry = entry; - ap->exp_thread = 0; - ap->readmap_thread = 0; - /* - * Program command line option overrides config. - * We can't use 0 negative timeout so use default. - */ - if (global_negative_timeout <= 0) - ap->negative_timeout = defaults_get_negative_timeout(); - else - ap->negative_timeout = global_negative_timeout; - ap->exp_timeout = defaults_get_timeout(); - ap->exp_runfreq = 0; - ap->flags = 0; - - if (defaults_get_use_ignore_mount_option()) - ap->flags = MOUNT_FLAG_IGNORE; - if (ghost) - ap->flags |= MOUNT_FLAG_GHOST; - - if (nobind) - ap->flags |= MOUNT_FLAG_NOBIND; - - if (ap->path[1] == '-') - ap->type = LKP_DIRECT; - else - ap->type = LKP_INDIRECT; - - ap->logopt = logopt; - - ap->parent = NULL; - ap->thid = 0; - ap->submnt_count = 0; - ap->submount = submount; - INIT_LIST_HEAD(&ap->mounts); - INIT_LIST_HEAD(&ap->submounts); - INIT_LIST_HEAD(&ap->amdmounts); - ap->shutdown = 0; - - status = pthread_mutex_init(&ap->mounts_mutex, NULL); - if (status) { - free(ap->path); - free(ap); - return 0; - } - ap->mode = 0; - - entry->ap = ap; - - return 1; -} - -void master_free_autofs_point(struct autofs_point *ap) -{ - struct list_head *p, *head; - int status; - - if (!ap) - return; - - mounts_mutex_lock(ap); - head = &ap->amdmounts; - p = head->next; - while (p != head) { - struct mnt_list *mnt = list_entry(p, struct mnt_list, amdmount); - p = p->next; - ext_mount_remove(mnt->ext_mp); - mnts_remove_amdmount(mnt->mp); - } - mounts_mutex_unlock(ap); - - status = pthread_mutex_destroy(&ap->mounts_mutex); - if (status) - fatal(status); - - if (ap->pref) - free(ap->pref); - free(ap->path); - free(ap); -} - -struct map_source * -master_add_map_source(struct master_mapent *entry, - char *type, char *format, time_t age, - int argc, const char **argv) -{ - struct map_source *source; - char *ntype, *nformat; - const char **tmpargv; - - source = malloc(sizeof(struct map_source)); - if (!source) - return NULL; - memset(source, 0, sizeof(struct map_source)); - source->ref = 1; - - if (type) { - ntype = strdup(type); - if (!ntype) { - master_free_map_source(source, 0); - return NULL; - } - source->type = ntype; - } - - if (format) { - nformat = strdup(format); - if (!nformat) { - master_free_map_source(source, 0); - return NULL; - } - source->format = nformat; - if (!strcmp(nformat, "amd")) - source->flags |= MAP_FLAG_FORMAT_AMD; - } - - source->age = age; - source->stale = 1; - - tmpargv = copy_argv(argc, argv); - if (!tmpargv) { - master_free_map_source(source, 0); - return NULL; - } - source->argc = argc; - source->argv = tmpargv; - if (source->argv[0]) - source->name = strdup(source->argv[0]); - - master_source_writelock(entry); - - if (!entry->maps) { - source->mc = cache_init(entry->ap, source); - if (!source->mc) { - master_free_map_source(source, 0); - master_source_unlock(entry); - return NULL; - } - entry->maps = source; - } else { - struct map_source *this, *last, *next; - - /* Typically there only a few map sources */ - - this = __master_find_map_source(entry, type, format, argc, tmpargv); - if (this) { - debug(entry->ap->logopt, - "map source used without taking reference"); - this->age = age; - master_free_map_source(source, 0); - master_source_unlock(entry); - return this; - } - - source->mc = cache_init(entry->ap, source); - if (!source->mc) { - master_free_map_source(source, 0); - master_source_unlock(entry); - return NULL; - } - - last = NULL; - next = entry->maps; - while (next) { - last = next; - next = next->next; - } - if (last) - last->next = source; - else - entry->maps = source; - } - - master_source_unlock(entry); - - return source; -} - -static int compare_source_type_and_format(struct map_source *map, const char *type, const char *format) -{ - int res = 0; - - if (type) { - if (!map->type) - goto done; - - if (strcmp(map->type, type)) - goto done; - } else if (map->type) - goto done; - - if (format) { - if (!map->format) - goto done; - - if (strcmp(map->format, format)) - goto done; - } else if (map->format) - goto done; - - res = 1; -done: - return res; -} - -static struct map_source * -__master_find_map_source(struct master_mapent *entry, - const char *type, const char *format, - int argc, const char **argv) -{ - struct map_source *map; - struct map_source *source = NULL; - int res; - - map = entry->maps; - while (map) { - res = compare_source_type_and_format(map, type, format); - if (!res) - goto next; - - res = compare_argv(map->argc, map->argv, argc, argv); - if (!res) - goto next; - - source = map; - break; -next: - map = map->next; - } - - return source; -} - -struct map_source *master_find_map_source(struct master_mapent *entry, - const char *type, const char *format, - int argc, const char **argv) -{ - struct map_source *source = NULL; - - master_source_readlock(entry); - source = __master_find_map_source(entry, type, format, argc, argv); - master_source_unlock(entry); - - return source; -} - -struct map_source * -master_get_map_source(struct master_mapent *entry, - const char *type, const char *format, - int argc, const char **argv) -{ - struct map_source *source = NULL; - - master_source_readlock(entry); - source = __master_find_map_source(entry, type, format, argc, argv); - if (source) - source->ref++; - master_source_unlock(entry); - - return source; -} - -static void __master_free_map_source(struct map_source *source, unsigned int free_cache) -{ - /* instance map sources are not ref counted */ - if (source->ref && --source->ref) - return; - if (source->type) - free(source->type); - if (source->format) - free(source->format); - if (source->name) - free(source->name); - if (free_cache && source->mc) - cache_release(source); - if (source->lookup) { - struct map_source *instance; - - instance = source->instance; - while (instance) { - if (instance->lookup) - close_lookup(instance->lookup); - instance = instance->next; - } - close_lookup(source->lookup); - } - if (source->argv) - free_argv(source->argc, source->argv); - if (source->instance) { - struct map_source *instance, *next; - - instance = source->instance; - while (instance) { - next = instance->next; - __master_free_map_source(instance, 0); - instance = next; - } - } - - free(source); - - return; -} - -void master_free_map_source(struct map_source *source, unsigned int free_cache) -{ - int status; - - status = pthread_mutex_lock(&instance_mutex); - if (status) - fatal(status); - - __master_free_map_source(source, free_cache); - - status = pthread_mutex_unlock(&instance_mutex); - if (status) - fatal(status); -} - -struct map_source *master_find_source_instance(struct map_source *source, const char *type, const char *format, int argc, const char **argv) -{ - struct map_source *map; - struct map_source *instance = NULL; - int status, res; - - status = pthread_mutex_lock(&instance_mutex); - if (status) - fatal(status); - - map = source->instance; - while (map) { - res = compare_source_type_and_format(map, type, format); - if (!res) - goto next; - - if (!argv) { - instance = map; - break; - } - - res = compare_argv(map->argc, map->argv, argc, argv); - if (!res) - goto next; - - instance = map; - break; -next: - map = map->next; - } - - status = pthread_mutex_unlock(&instance_mutex); - if (status) - fatal(status); - - return instance; -} - -struct map_source * -master_add_source_instance(struct map_source *source, const char *type, const char *format, time_t age, int argc, const char **argv) -{ - struct map_source *instance; - struct map_source *new; - char *ntype, *nformat; - const char **tmpargv; - int status; - - instance = master_find_source_instance(source, type, format, argc, argv); - if (instance) - return instance; - - new = malloc(sizeof(struct map_source)); - if (!new) - return NULL; - memset(new, 0, sizeof(struct map_source)); - - if (type) { - ntype = strdup(type); - if (!ntype) { - master_free_map_source(new, 0); - return NULL; - } - new->type = ntype; - } - - if (format) { - nformat = strdup(format); - if (!nformat) { - master_free_map_source(new, 0); - return NULL; - } - new->format = nformat; - if (!strcmp(nformat, "amd")) - new->flags |= MAP_FLAG_FORMAT_AMD; - } - - new->age = age; - new->master_line = 0; - new->mc = source->mc; - new->exp_timeout = source->exp_timeout; - new->stale = 1; - - tmpargv = copy_argv(argc, argv); - if (!tmpargv) { - master_free_map_source(new, 0); - return NULL; - } - new->argc = argc; - new->argv = tmpargv; - if (source->name) - new->name = strdup(source->name); - - status = pthread_mutex_lock(&instance_mutex); - if (status) - fatal(status); - - if (!source->instance) - source->instance = new; - else { - /* - * We know there's no other instance of this - * type so just add to head of list - */ - new->next = source->instance; - source->instance = new; - } - - status = pthread_mutex_unlock(&instance_mutex); - if (status) - fatal(status); - - return new; -} - -int check_stale_instances(struct map_source *source) -{ - struct map_source *map; - - if (!source) - return 0; - - map = source->instance; - while (map) { - if (map->stale) - return 1; - if (check_stale_instances(map)) - return 1; - map = map->next; - } - - return 0; -} - -void clear_stale_instances(struct map_source *source) -{ - struct map_source *map; - - if (!source) - return; - - map = source->instance; - while (map) { - clear_stale_instances(map); - if (map->stale) - map->stale = 0; - map = map->next; - } - - return; -} - -void send_map_update_request(struct autofs_point *ap) -{ - struct map_source *map; - int status, need_update = 0; - - status = pthread_mutex_lock(&instance_mutex); - if (status) - fatal(status); - - map = ap->entry->maps; - while (map) { - if (check_stale_instances(map)) - map->stale = 1; - if (map->stale) { - need_update = 1; - break; - } - map = map->next; - } - - status = pthread_mutex_unlock(&instance_mutex); - if (status) - fatal(status); - - if (!need_update) - return; - - st_add_task(ap, ST_READMAP); - - return; -} - -void master_source_writelock(struct master_mapent *entry) -{ - int status; - - status = pthread_rwlock_wrlock(&entry->source_lock); - if (status) { - logmsg("master_mapent source write lock failed"); - fatal(status); - } - return; -} - -void master_source_readlock(struct master_mapent *entry) -{ - int retries = 25; - int status; - - while (retries--) { - status = pthread_rwlock_rdlock(&entry->source_lock); - if (status != EAGAIN && status != EBUSY) - break; - else { - struct timespec t = { 0, 200000000 }; - struct timespec r; - - if (status == EAGAIN) - logmsg("master_mapent source too many readers"); - else - logmsg("master_mapent source write lock held"); - - while (nanosleep(&t, &r) == -1 && errno == EINTR) - memcpy(&t, &r, sizeof(struct timespec)); - } - } - - if (status) { - logmsg("master_mapent source read lock failed"); - fatal(status); - } - - return; -} - -void master_source_unlock(struct master_mapent *entry) -{ - int status; - - status = pthread_rwlock_unlock(&entry->source_lock); - if (status) { - logmsg("master_mapent source unlock failed"); - fatal(status); - } - return; -} - -void master_source_lock_cleanup(void *arg) -{ - struct master_mapent *entry = (struct master_mapent *) arg; - - master_source_unlock(entry); - - return; -} - -void master_source_current_wait(struct master_mapent *entry) -{ - int status; - - status = pthread_mutex_lock(&entry->current_mutex); - if (status) { - logmsg("entry current source lock failed"); - fatal(status); - } - - while (entry->current != NULL) { - status = pthread_cond_wait( - &entry->current_cond, &entry->current_mutex); - if (status) { - logmsg("entry current source condition wait failed"); - fatal(status); - } - } - - return; -} - -void master_source_current_signal(struct master_mapent *entry) -{ - int status; - - status = pthread_cond_signal(&entry->current_cond); - if (status) { - logmsg("entry current source condition signal failed"); - fatal(status); - } - - status = pthread_mutex_unlock(&entry->current_mutex); - if (status) { - logmsg("entry current source unlock failed"); - fatal(status); - } - - return; -} - -struct master_mapent *master_find_mapent(struct master *master, const char *path) -{ - struct list_head *head, *p; - - head = &master->mounts; - list_for_each(p, head) { - struct master_mapent *entry; - - entry = list_entry(p, struct master_mapent, list); - - if (!strcmp(entry->path, path)) - return entry; - } - - return NULL; -} - -unsigned int master_partial_match_mapent(struct master *master, const char *path) -{ - struct list_head *head, *p; - size_t path_len = strlen(path); - int ret = 0; - - head = &master->mounts; - list_for_each(p, head) { - struct master_mapent *entry; - size_t entry_len; - size_t cmp_len; - - entry = list_entry(p, struct master_mapent, list); - - entry_len = strlen(entry->path); - cmp_len = min(entry_len, path_len); - - if (!strncmp(entry->path, path, cmp_len)) { - /* paths are equal, matching master map entry ? */ - if (entry_len == path_len) { - if (entry->maps && - entry->maps->flags & MAP_FLAG_FORMAT_AMD) - ret = 1; - else - ret = -1; - break; - } - - /* amd mount conflicts with entry mount */ - if (entry_len > path_len && - *(entry->path + path_len) == '/') { - ret = -1; - break; - } - - /* entry mount conflicts with amd mount */ - if (entry_len < path_len && - *(path + entry_len) == '/') { - ret = -1; - break; - } - } - } - - return ret; -} - -struct master_mapent *master_new_mapent(struct master *master, const char *path, time_t age) -{ - struct master_mapent *entry; - int status; - char *tmp; - - entry = malloc(sizeof(struct master_mapent)); - if (!entry) - return NULL; - - memset(entry, 0, sizeof(struct master_mapent)); - - tmp = strdup(path); - if (!tmp) { - free(entry); - return NULL; - } - entry->path = tmp; - - entry->thid = 0; - entry->age = age; - entry->master = master; - entry->current = NULL; - entry->maps = NULL; - entry->ap = NULL; - - status = pthread_rwlock_init(&entry->source_lock, NULL); - if (status) - fatal(status); - - status = pthread_mutex_init(&entry->current_mutex, NULL); - if (status) - fatal(status); - - status = pthread_cond_init(&entry->current_cond, NULL); - if (status) - fatal(status); - - INIT_LIST_HEAD(&entry->list); - - return entry; -} - -void master_add_mapent(struct master *master, struct master_mapent *entry) -{ - list_add_tail(&entry->list, &master->mounts); - return; -} - -void master_remove_mapent(struct master_mapent *entry) -{ - struct master *master = entry->master; - - if (entry->ap->submount) - return; - - if (!list_empty(&entry->list)) { - list_del_init(&entry->list); - list_add(&entry->join, &master->completed); - } - - return; -} - -void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_cache) -{ - if (entry->maps) { - struct map_source *m, *n; - - m = entry->maps; - while (m) { - n = m->next; - master_free_map_source(m, free_cache); - m = n; - } - entry->maps = NULL; - } - - return; -} - -void master_free_mapent(struct master_mapent *entry) -{ - int status; - - if (entry->path) - free(entry->path); - - master_free_autofs_point(entry->ap); - - status = pthread_rwlock_destroy(&entry->source_lock); - if (status) - fatal(status); - - status = pthread_mutex_destroy(&entry->current_mutex); - if (status) - fatal(status); - - status = pthread_cond_destroy(&entry->current_cond); - if (status) - fatal(status); - - free(entry); - - return; -} - -struct master *master_new(const char *name, unsigned int timeout, unsigned int flags) -{ - struct master *master; - char *tmp; - - master = malloc(sizeof(struct master)); - if (!master) - return NULL; - - if (!name) - tmp = (char *) defaults_get_master_map(); - else - tmp = strdup(name); - - if (!tmp) { - free(master); - return NULL; - } - - master->name = tmp; - master->nc = NULL; - - master->recurse = 0; - master->depth = 0; - master->reading = 0; - master->read_fail = 0; - master->readall = 0; - master->default_ghost = flags & DAEMON_FLAGS_GHOST; - master->default_timeout = timeout; - master->default_logging = defaults_get_logging(); - master->logopt = master->default_logging; - - INIT_LIST_HEAD(&master->mounts); - INIT_LIST_HEAD(&master->completed); - - return master; -} - -static void master_add_amd_mount_section_mounts(struct master *master, time_t age) -{ - unsigned int m_logopt = master->logopt; - struct master_mapent *entry; - struct map_source *source; - unsigned int loglevel; - unsigned int logopt; - unsigned int flags; - char *argv[2]; - char **paths; - int ret; - int i; - - loglevel = conf_amd_get_log_options(); - - paths = conf_amd_get_mount_paths(); - if (!paths) - return; - - i = 0; - while (paths[i]) { - const char *path = paths[i]; - unsigned int ghost = 0; - time_t timeout; - char *type = NULL; - char *map = NULL; - char *opts; - - ret = master_partial_match_mapent(master, path); - if (ret) { - /* If this amd entry is already present in the - * master map it's not a duplicate, don't issue - * an error message. - */ - if (ret == 1) - goto next; - info(m_logopt, - "amd section mount path conflict, %s ignored", - path); - goto next; - } - - map = conf_amd_get_map_name(path); - if (!map) { - error(m_logopt, - "failed to get map name for amd section mount %s", - path); - goto next; - } - - entry = master_new_mapent(master, path, age); - if (!entry) { - error(m_logopt, - "failed to allocate new amd section mount %s", - path); - goto next; - } - - logopt = m_logopt; - if (loglevel <= LOG_DEBUG && loglevel > LOG_INFO) - logopt = LOGOPT_DEBUG; - else if (loglevel <= LOG_INFO && loglevel > LOG_ERR) - logopt = LOGOPT_VERBOSE; - - /* It isn't possible to provide the fullybrowsable amd - * browsing functionality within the autofs framework. - * This flag will not be set if browsable_dirs = full - * in the configuration or fullybrowsable is present as - * an option. - */ - flags = conf_amd_get_flags(path); - if (flags & CONF_BROWSABLE_DIRS) - ghost = 1; - - ret = master_add_autofs_point(entry, logopt, 0, ghost, 0); - if (!ret) { - error(m_logopt, "failed to add autofs_point"); - master_free_mapent(entry); - goto next; - } - - opts = conf_amd_get_map_options(path); - if (opts) { - /* autofs uses the equivalent of cache:=inc,sync - * (except for file maps which use cache:=all,sync) - * but if the map is large then it may be necessary - * to read the whole map at startup even if browsing - * is is not enabled, so look for cache:=all in the - * map_options configuration entry. - */ - if (strstr(opts, "cache:=all")) - entry->ap->flags |= MOUNT_FLAG_AMD_CACHE_ALL; - free(opts); - } - - type = conf_amd_get_map_type(path); - argv[0] = map; - argv[1] = NULL; - - source = master_add_map_source(entry, type, "amd", - age, 1, (const char **) argv); - if (!source) { - error(m_logopt, - "failed to add source for amd section mount %s", - path); - master_free_mapent(entry); - goto next; - } - - timeout = conf_amd_get_dismount_interval(path); - set_exp_timeout(entry->ap, source, timeout); - source->master_line = 0; - - entry->age = age; - entry->current = NULL; - - master_add_mapent(master, entry); -next: - if (type) - free(type); - if (map) - free(map); - i++; - } - - i = 0; - while (paths[i]) - free(paths[i++]); - free(paths); -} - -static void wait_for_lookups_and_lock(struct master *master) -{ - struct list_head *p, *head; - int status; - -again: - master_mutex_lock(); - - head = &master->mounts; - p = head->next; - while (p != head) { - struct master_mapent *this; - - this = list_entry(p, struct master_mapent, list); - - status = pthread_rwlock_trywrlock(&this->source_lock); - if (status) { - struct timespec t = { 0, 200000000 }; - struct timespec r; - - master_mutex_unlock(); - - while (nanosleep(&t, &r) == -1 && errno == EINTR) - memcpy(&t, &r, sizeof(struct timespec)); - - goto again; - } - master_source_unlock(this); - - p = p->next; - } -} - -int master_read_master(struct master *master, time_t age) -{ - unsigned int logopt = master->logopt; - struct mapent_cache *nc; - - /* - * We need to clear and re-populate the null map entry cache - * before alowing anyone else to use it. - */ - wait_for_lookups_and_lock(master); - if (master->nc) { - cache_writelock(master->nc); - nc = master->nc; - cache_clean_null_cache(nc); - } else { - nc = cache_init_null_cache(master); - if (!nc) { - error(logopt, - "failed to init null map cache for %s", - master->name); - return 0; - } - cache_writelock(nc); - master->nc = nc; - } - master_init_scan(); - lookup_nss_read_master(master, age); - cache_unlock(nc); - master_add_amd_mount_section_mounts(master, age); - - if (!master->read_fail) - master_mount_mounts(master, age); - else { - master->read_fail = 0; - /* HUP signal sets master->readall == 1 only */ - if (!master->readall) { - master_mutex_unlock(); - return 0; - } else - master_mount_mounts(master, age); - } - - if (list_empty(&master->mounts)) - warn(logopt, "no mounts in table"); - - master_mutex_unlock(); - - return 1; -} - -int master_submount_list_empty(struct autofs_point *ap) -{ - int res = 0; - - mounts_mutex_lock(ap); - if (list_empty(&ap->submounts)) - res = 1; - mounts_mutex_unlock(ap); - - return res; -} - -int master_notify_submount(struct autofs_point *ap, const char *path, enum states state) -{ - struct mnt_list *this, *sbmnt; - int ret = 1; - - this = mnts_find_submount(path); - if (this) { - /* We have found a submount to expire */ - st_mutex_lock(); - - if (this->ap->state == ST_SHUTDOWN) { - this = NULL; - st_mutex_unlock(); - goto done; - } - - this->ap->shutdown = ap->shutdown; - - __st_add_task(this->ap, state); - - st_mutex_unlock(); - - st_wait_task(this->ap, state, 0); - - /* - * If our submount gets to state ST_SHUTDOWN, ST_SHUTDOWN_PENDING or - * ST_SHUTDOWN_FORCE we need to wait until it goes away or changes - * to ST_READY. - */ - st_mutex_lock(); - while ((sbmnt = mnts_find_submount(path))) { - struct timespec t = { 0, 300000000 }; - struct timespec r; - - if (sbmnt->ap->state != ST_SHUTDOWN && - sbmnt->ap->state != ST_SHUTDOWN_PENDING && - sbmnt->ap->state != ST_SHUTDOWN_FORCE) { - ret = 0; - mnts_put_mount(sbmnt); - break; - } - mnts_put_mount(sbmnt); - - st_mutex_unlock(); - while (nanosleep(&t, &r) == -1 && errno == EINTR) - memcpy(&t, &r, sizeof(struct timespec)); - st_mutex_lock(); - } - st_mutex_unlock(); -done: - mnts_put_mount(this); - } - - return ret; -} - -void master_notify_state_change(struct master *master, int sig) -{ - struct master_mapent *entry; - struct autofs_point *ap; - struct list_head *p; - int cur_state; - unsigned int logopt; - - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); - master_mutex_lock(); - - list_for_each(p, &master->mounts) { - enum states next = ST_INVAL; - - entry = list_entry(p, struct master_mapent, list); - - ap = entry->ap; - logopt = ap->logopt; - - st_mutex_lock(); - - if (ap->state == ST_SHUTDOWN) - goto next; - - switch (sig) { - case SIGTERM: - case SIGINT: - if (ap->state != ST_SHUTDOWN_PENDING && - ap->state != ST_SHUTDOWN_FORCE) { - next = ST_SHUTDOWN_PENDING; - ap->shutdown = 1; - __st_add_task(ap, next); - } - break; -#ifdef ENABLE_FORCED_SHUTDOWN - case SIGUSR2: - if (ap->state != ST_SHUTDOWN_FORCE && - ap->state != ST_SHUTDOWN_PENDING) { - next = ST_SHUTDOWN_FORCE; - ap->shutdown = 1; - __st_add_task(ap, next); - } - break; -#endif - case SIGUSR1: - assert(ap->state == ST_READY); - next = ST_PRUNE; - __st_add_task(ap, next); - break; - } -next: - if (next != ST_INVAL) - debug(logopt, - "sig %d switching %s from %d to %d", - sig, ap->path, ap->state, next); - - st_mutex_unlock(); - } - - master_mutex_unlock(); - pthread_setcancelstate(cur_state, NULL); - - return; -} - -static int master_do_mount(struct master_mapent *entry) -{ - struct startup_cond suc; - struct autofs_point *ap; - pthread_t thid; - int status; - - ap = entry->ap; - - if (handle_mounts_startup_cond_init(&suc)) { - crit(ap->logopt, - "failed to init startup cond for mount %s", entry->path); - return 0; - } - - suc.ap = ap; - suc.root = ap->path; - suc.done = 0; - suc.status = 0; - - if (!(do_force_unlink & UNLINK_AND_EXIT)) - debug(ap->logopt, "mounting %s", entry->path); - - status = pthread_create(&thid, &th_attr, handle_mounts, &suc); - if (status) { - crit(ap->logopt, - "failed to create mount handler thread for %s", - entry->path); - handle_mounts_startup_cond_destroy(&suc); - return 0; - } - - while (!suc.done) { - status = pthread_cond_wait(&suc.cond, &suc.mutex); - if (status) - fatal(status); - } - - if (suc.status) { - if (!(do_force_unlink & UNLINK_AND_EXIT)) - error(ap->logopt, "failed to startup mount"); - handle_mounts_startup_cond_destroy(&suc); - return 0; - } - entry->thid = thid; - - handle_mounts_startup_cond_destroy(&suc); - - return 1; -} - -static void check_update_map_sources(struct master_mapent *entry, int readall) -{ - struct map_source *source, *last; - struct autofs_point *ap; - int map_stale = 0; - - if (readall) - map_stale = 1; - - ap = entry->ap; - - master_source_writelock(entry); - - last = NULL; - source = entry->maps; - while (source) { - if (readall) - source->stale = 1; - - /* - * If a map source is no longer valid and all it's - * entries have expired away we can get rid of it. - */ - if (entry->age > source->age) { - struct mapent *me; - cache_readlock(source->mc); - me = cache_lookup_first(source->mc); - if (!me) { - struct map_source *next = source->next; - - cache_unlock(source->mc); - - if (!last) - entry->maps = next; - else - last->next = next; - - if (entry->maps == source) - entry->maps = next; - - master_free_map_source(source, 1); - - source = next; - continue; - } else { - source->stale = 1; - map_stale = 1; - } - cache_unlock(source->mc); - } - last = source; - source = source->next; - } - - master_source_unlock(entry); - - /* The map sources have changed */ - if (map_stale) - st_add_task(ap, ST_READMAP); - - return; -} - -int master_mount_mounts(struct master *master, time_t age) -{ - struct mapent_cache *nc = master->nc; - struct list_head *p, *head; - int cur_state; - - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); - - head = &master->mounts; - p = head->next; - while (p != head) { - struct master_mapent *this; - struct autofs_point *ap; - struct mapent *ne, *nested; - struct stat st; - int state_pipe, save_errno; - int ret; - - this = list_entry(p, struct master_mapent, list); - p = p->next; - - ap = this->ap; - - /* A master map entry has gone away */ - if (this->age < age) { - st_add_task(ap, ST_SHUTDOWN_PENDING); - continue; - } - - cache_readlock(nc); - ne = cache_lookup_distinct(nc, this->path); - /* - * If this path matched a nulled entry the master map entry - * must be an indirect mount so the master map entry line - * number may be obtained from this->maps. - */ - if (ne) { - int lineno = ne->age; - cache_unlock(nc); - - /* null entry appears after map entry */ - if (this->maps->master_line < lineno) { - warn(ap->logopt, - "ignoring null entry that appears after " - "existing entry for %s", this->path); - goto cont; - } - if (ap->state != ST_INIT) { - st_add_task(ap, ST_SHUTDOWN_PENDING); - continue; - } - /* - * The map entry hasn't been started yet and we've - * seen a preceeding null map entry for it so just - * delete it from the master map entry list so it - * doesn't get in the road. - */ - list_del_init(&this->list); - master_free_mapent_sources(ap->entry, 1); - master_free_mapent(ap->entry); - continue; - } - nested = cache_partial_match(nc, this->path); - if (nested) { - error(ap->logopt, - "removing invalid nested null entry %s", - nested->key); - nested = cache_partial_match(nc, this->path); - if (nested) - cache_delete(nc, nested->key); - } - cache_unlock(nc); -cont: - st_mutex_lock(); - - state_pipe = this->ap->state_pipe[1]; - - /* No pipe so mount is needed */ - ret = fstat(state_pipe, &st); - save_errno = errno; - - st_mutex_unlock(); - - if (!ret) - check_update_map_sources(this, master->readall); - else if (ret == -1 && save_errno == EBADF) { - if (!master_do_mount(this)) { - list_del_init(&this->list); - master_free_mapent_sources(ap->entry, 1); - master_free_mapent(ap->entry); - } - } - } - - pthread_setcancelstate(cur_state, NULL); - - return 1; -} - -/* The nss source instances end up in reverse order. */ -static void list_source_instances(struct map_source *source, struct map_source *instance) -{ - if (!source || !instance) { - printf("none"); - return; - } - - if (instance->next) - list_source_instances(source, instance->next); - - /* - * For convienience we map nss instance type "files" to "file". - * Check for that and report corrected instance type. - */ - if (strcmp(instance->type, "file")) - printf("%s ", instance->type); - else { - if (source->argv && *(source->argv[0]) != '/') - printf("files "); - else - printf("%s ", instance->type); - } - - return; -} - -static void print_map_info(struct map_source *source) -{ - int argc = source->argc; - int i, multi, map_num; - - multi = (source->type && !strcmp(source->type, "multi")); - map_num = 1; - for (i = 0; i < argc; i++) { - if (source->argv[i] && *source->argv[i] != '-') { - if (!multi) - printf(" map: %s\n", source->argv[i]); - else - printf(" map[%i]: %s\n", map_num, source->argv[i]); - i++; - } - - if (i >= argc) - return; - - if (!strcmp(source->argv[i], "--")) - continue; - - if (source->argv[i]) { - int need_newline = 0; - int j; - - if (!multi) - printf(" arguments:"); - else - printf(" arguments[%i]:", map_num); - - for (j = i; j < source->argc; j++) { - if (!strcmp(source->argv[j], "--")) - break; - printf(" %s", source->argv[j]); - i++; - need_newline = 1; - } - if (need_newline) - printf("\n"); - } - if (multi) - map_num++; - } - - return; -} - -static int match_type(const char *source, const char *type) -{ - if (!strcmp(source, type)) - return 1; - /* Sources file and files are synonymous */ - if (!strncmp(source, type, 4) && (strlen(source) <= 5)) - return 1; - return 0; -} - -static char *get_map_name(const char *string) -{ - char *name, *tmp; - char *start, *end, *base; - - tmp = strdup(string); - if (!tmp) { - printf("error: allocation failure: %s\n", strerror(errno)); - return NULL; - } - - base = basename(tmp); - end = strchr(base, ','); - if (end) - *end = '\0'; - start = strchr(tmp, '='); - if (start) - start++; - else { - char *colon = strrchr(base, ':'); - if (colon) - start = ++colon; - else - start = base; - } - - name = strdup(start); - if (!name) - printf("error: allocation failure: %s\n", strerror(errno)); - free(tmp); - - return name; -} - -static int match_name(struct map_source *source, const char *name) -{ - int argc = source->argc; - int ret = 0; - int i; - - /* - * This can't work for old style "multi" type sources since - * there's no way to know from which map the cache entry came - * from and duplicate entries are ignored at map read time. - * All we can really do is list all the entries for the given - * multi map if one of its map names matches. - */ - for (i = 0; i < argc; i++) { - if (i == 0 || !strcmp(source->argv[i], "--")) { - if (i != 0) { - i++; - if (i >= argc) - break; - } - - if (source->argv[i] && *source->argv[i] != '-') { - char *map = get_map_name(source->argv[i]); - if (!map) - break; - if (!strcmp(map, name)) { - ret = 1; - free(map); - break; - } - free(map); - } - } - } - - return ret; -} - -int dump_map(struct master *master, const char *type, const char *name) -{ - struct list_head *p, *head; - - if (list_empty(&master->mounts)) { - printf("no master map entries found\n"); - return 1; - } - - head = &master->mounts; - p = head->next; - while (p != head) { - struct map_source *source; - struct master_mapent *this; - struct autofs_point *ap; - time_t now = monotonic_time(NULL); - - this = list_entry(p, struct master_mapent, list); - p = p->next; - - ap = this->ap; - - /* - * Ensure we actually read indirect map entries so we can - * list them. The map reads won't read any indirect map - * entries (other than those in a file map) unless the - * browse option is set. - */ - if (ap->type == LKP_INDIRECT) - ap->flags |= MOUNT_FLAG_GHOST; - - /* Read the map content into the cache */ - if (lookup_nss_read_map(ap, NULL, now)) - lookup_prune_cache(ap, now); - else { - printf("failed to read map\n"); - lookup_close_lookup(ap); - continue; - } - - if (!this->maps) { - printf("no map sources found for %s\n", ap->path); - lookup_close_lookup(ap); - continue; - } - - source = this->maps; - while (source) { - struct map_source *instance; - struct mapent *me; - - instance = NULL; - if (source->type) { - if (!match_type(source->type, type)) { - source = source->next; - continue; - } - if (!match_name(source, name)) { - source = source->next; - continue; - } - instance = source; - } else { - struct map_source *map; - - map = source->instance; - while (map) { - if (!match_type(map->type, type)) { - map = map->next; - continue; - } - if (!match_name(map, name)) { - map = map->next; - continue; - } - instance = map; - break; - } - } - - if (!instance) { - source = source->next; - lookup_close_lookup(ap); - continue; - } - - me = cache_lookup_first(source->mc); - if (!me) - printf("no keys found in map\n"); - else { - do { - if (me->source == instance) - printf("%s\t%s\n", me->key, me->mapent); - } while ((me = cache_lookup_next(source->mc, me))); - } - - lookup_close_lookup(ap); - return 1; - } - lookup_close_lookup(ap); - } - - return 0; -} - -int master_show_mounts(struct master *master) -{ - struct list_head *p, *head; - - printf("\nautofs dump map information\n" - "===========================\n\n"); - - printf("global options: "); - if (!global_options) - printf("none configured\n"); - else { - printf("%s\n", global_options); - unsigned int append_options = defaults_get_append_options(); - const char *append = append_options ? "will" : "will not"; - printf("global options %s be appended to map entries\n", append); - } - - if (list_empty(&master->mounts)) { - printf("no master map entries found\n\n"); - return 1; - } - - head = &master->mounts; - p = head->next; - while (p != head) { - struct map_source *source; - struct master_mapent *this; - struct autofs_point *ap; - time_t now = monotonic_time(NULL); - unsigned int count = 0; - - this = list_entry(p, struct master_mapent, list); - p = p->next; - - ap = this->ap; - - printf("\nMount point: %s\n", ap->path); - - printf("\nsource(s):\n"); - - /* - * Ensure we actually read indirect map entries so we can - * list them. The map reads won't read any indirect map - * entries (other than those in a file map) unless the - * browse option is set. - */ - if (ap->type == LKP_INDIRECT) - ap->flags |= MOUNT_FLAG_GHOST; - - /* Read the map content into the cache */ - if (lookup_nss_read_map(ap, NULL, now)) - lookup_prune_cache(ap, now); - else { - printf(" failed to read map\n\n"); - continue; - } - - if (!this->maps) { - printf(" no map sources found\n\n"); - continue; - } - - source = this->maps; - while (source) { - struct mapent *me; - - if (source->type) - printf("\n type: %s\n", source->type); - else { - printf("\n instance type(s): "); - list_source_instances(source, source->instance); - printf("\n"); - } - - if (source->argc >= 1) { - print_map_info(source); - if (count && ap->type == LKP_INDIRECT) - printf(" duplicate indirect map entry" - " will be ignored at run time\n"); - } - - printf("\n"); - - me = cache_lookup_first(source->mc); - if (!me) - printf(" no keys found in map\n"); - else { - do { - printf(" %s | %s\n", me->key, me->mapent); - } while ((me = cache_lookup_next(source->mc, me))); - } - - count++; - - source = source->next; - } - - lookup_close_lookup(ap); - - printf("\n"); - } - - return 1; -} - -int master_list_empty(struct master *master) -{ - int res = 0; - - master_mutex_lock(); - if (list_empty(&master->mounts)) - res = 1; - master_mutex_unlock(); - - return res; -} - -int master_done(struct master *master) -{ - struct list_head *head, *p; - struct master_mapent *entry; - int res = 0; - - head = &master->completed; - p = head->next; - while (p != head) { - entry = list_entry(p, struct master_mapent, join); - p = p->next; - list_del(&entry->join); - pthread_join(entry->thid, NULL); - master_free_mapent_sources(entry, 1); - master_free_mapent(entry); - } - if (list_empty(&master->mounts)) - res = 1; - - return res; -} - -unsigned int master_get_logopt(void) -{ - return master_list ? master_list->logopt : LOGOPT_NONE; -} - -int master_kill(struct master *master) -{ - if (!list_empty(&master->mounts)) - return 0; - - if (master->name) - free(master->name); - - cache_release_null_cache(master); - free(master); - - return 1; -} diff --git a/lib/master_parse.y b/lib/master_parse.y deleted file mode 100644 index 08e44b57..00000000 --- a/lib/master_parse.y +++ /dev/null @@ -1,983 +0,0 @@ -%{ -/* ----------------------------------------------------------------------- * - * - * master_parser.y - master map buffer parser. - * - * Copyright 2006 Ian Kent - * - * 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 -#include -#include -#include -#include -#include - -#include "automount.h" -#include "master.h" - -#define MAX_ERR_LEN 512 - -extern struct master *master_list; - -char **add_argv(int, char **, char *); -const char **copy_argv(int, const char **); -int free_argv(int, const char **); - -extern FILE *master_in; -extern char *master_text; -extern int master_lex(void); -extern int master_lineno; -extern void master_set_scan_buffer(const char *); - -static char *master_strdup(char *); -static void local_init_vars(void); -static void local_free_vars(void); -static void trim_maptype(char *); -static int add_multi_mapstr(void); - -static int master_error(const char *s); -static int master_notify(const char *s); -static int master_msg(const char *s); - -static char *path; -static char *type; -static char *format; -static long timeout; -static long negative_timeout; -static unsigned symlnk; -static unsigned strictexpire; -static unsigned nobind; -static unsigned ghost; -extern unsigned global_selection_options; -static unsigned random_selection; -static unsigned use_weight; -static unsigned long mode; -static char **tmp_argv; -static int tmp_argc; -static char **local_argv; -static int local_argc; - -#define PROPAGATION_SHARED MOUNT_FLAG_SHARED -#define PROPAGATION_SLAVE MOUNT_FLAG_SLAVE -#define PROPAGATION_PRIVATE MOUNT_FLAG_PRIVATE -#define PROPAGATION_MASK (MOUNT_FLAG_SHARED | \ - MOUNT_FLAG_SLAVE | \ - MOUNT_FLAG_PRIVATE) -static unsigned int propagation; - -static char errstr[MAX_ERR_LEN]; - -static unsigned int verbose; -static unsigned int debug; - -static int lineno; - -#define YYDEBUG 0 - -#ifndef YYENABLE_NLS -#define YYENABLE_NLS 0 -#endif -#ifndef YYLTYPE_IS_TRIVIAL -#define YYLTYPE_IS_TRIVIAL 0 -#endif - -#if YYDEBUG -static int master_fprintf(FILE *, char *, ...); -#undef YYFPRINTF -#define YYFPRINTF master_fprintf -#endif - -%} - -%union { - char strtype[2048]; - int inttype; - long longtype; -} - -%token COMMENT -%token MAP -%token OPT_TIMEOUT OPT_NTIMEOUT OPT_NOBIND OPT_NOGHOST OPT_GHOST OPT_VERBOSE -%token OPT_DEBUG OPT_RANDOM OPT_USE_WEIGHT OPT_SYMLINK OPT_MODE -%token OPT_STRICTEXPIRE OPT_SHARED OPT_SLAVE OPT_PRIVATE -%token COLON COMMA NL DDASH -%type map -%type options -%type dn -%type dnattrs -%type dnattr -%type option -%type daemon_option -%type mount_option -%token PATH -%token QUOTE -%token NILL -%token SPACE -%token EQUAL -%token MULTITYPE -%token MAPTYPE -%token DNSERVER -%token DNATTR -%token DNNAME -%token MAPHOSTS -%token MAPNULL -%token MAPXFN -%token MAPNAME -%token NUMBER -%token OCTALNUMBER -%token OPTION - -%start file - -%% - -file: { - master_lineno = 0; -#if YYDEBUG != 0 - master_debug = YYDEBUG; -#endif - } line - ; - -line: - | PATH mapspec - { - path = master_strdup($1); - if (!path) { - local_free_vars(); - YYABORT; - } - } - | PATH MULTITYPE maplist - { - char *tmp = NULL; - - trim_maptype($2); - - if (path) - free(path); - path = master_strdup($1); - if (!path) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - - if ((tmp = strchr($2, ','))) - *tmp++ = '\0'; -#ifndef WITH_HESIOD - /* Map type or map type parser is hesiod */ - if (!strcmp($2, "hesiod") || (tmp && !strcmp(tmp, "hesiod"))) { - master_error("hesiod support not built in"); - local_free_vars(); - YYABORT; - } -#endif - if (type) - free(type); - type = master_strdup($2); - if (!type) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - if (tmp) { - if (format) - free(format); - format = master_strdup(tmp); - if (!format) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - } - | PATH COLON { master_notify($1); YYABORT; } - | PATH OPTION { master_notify($2); YYABORT; } - | PATH NILL { master_notify($2); YYABORT; } - | PATH OPT_RANDOM { master_notify($1); YYABORT; } - | PATH OPT_USE_WEIGHT { master_notify($1); YYABORT; } - | PATH OPT_DEBUG { master_notify($1); YYABORT; } - | PATH OPT_TIMEOUT { master_notify($1); YYABORT; } - | PATH OPT_SYMLINK { master_notify($1); YYABORT; } - | PATH OPT_STRICTEXPIRE { master_notify($1); YYABORT; } - | PATH OPT_SHARED { master_notify($1); YYABORT; } - | PATH OPT_SLAVE { master_notify($1); YYABORT; } - | PATH OPT_PRIVATE { master_notify($1); YYABORT; } - | PATH OPT_NOBIND { master_notify($1); YYABORT; } - | PATH OPT_GHOST { master_notify($1); YYABORT; } - | PATH OPT_NOGHOST { master_notify($1); YYABORT; } - | PATH OPT_VERBOSE { master_notify($1); YYABORT; } - | PATH OPT_MODE { master_notify($1); YYABORT; } - | PATH { master_notify($1); YYABORT; } - | QUOTE { master_notify($1); YYABORT; } - | OPTION { master_notify($1); YYABORT; } - | NILL { master_notify($1); YYABORT; } - | COMMENT { YYABORT; } - ; - -mapspec: map - { - if (local_argv) - free_argv(local_argc, (const char **) local_argv); - local_argc = tmp_argc; - local_argv = tmp_argv; - tmp_argc = 0; - tmp_argv = NULL; - } - | map options - { - if (local_argv) - free_argv(local_argc, (const char **) local_argv); - local_argc = tmp_argc; - local_argv = tmp_argv; - tmp_argc = 0; - tmp_argv = NULL; - } - ; - -maplist: map - { - if (!add_multi_mapstr()) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - | map options - { - if (!add_multi_mapstr()) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - | maplist DDASH map - { - local_argc++; - local_argv = add_argv(local_argc, local_argv, "--"); - if (!local_argv) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - if (!add_multi_mapstr()) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - | maplist DDASH map options - { - local_argc++; - local_argv = add_argv(local_argc, local_argv, "--"); - if (!local_argv) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - if (!add_multi_mapstr()) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - ; - -map: PATH - { - tmp_argc++; - tmp_argv = add_argv(tmp_argc, tmp_argv, $1); - if (!tmp_argv) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - | MAPNAME - { - tmp_argc++; - tmp_argv = add_argv(tmp_argc, tmp_argv, $1); - if (!tmp_argv) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - | MAPHOSTS - { - if (type) - free(type); - type = master_strdup($1 + 1); - if (!type) { - local_free_vars(); - YYABORT; - } - } - | MAPXFN - { - master_notify($1); - master_msg("X/Open Federated Naming service not supported"); - YYABORT; - } - | MAPNULL - { - if (type) - free(type); - type = master_strdup($1 + 1); - if (!type) { - local_free_vars(); - YYABORT; - } - } - | dnattrs - { - if (type) - free(type); - type = master_strdup("ldap"); - if (!type) { - local_free_vars(); - YYABORT; - } - tmp_argc++; - tmp_argv = add_argv(tmp_argc, tmp_argv, $1); - if (!tmp_argv) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - | MAPTYPE PATH - { - char *tmp = NULL; - - trim_maptype($1); - - if ((tmp = strchr($1, ','))) - *tmp++ = '\0'; -#ifndef WITH_HESIOD - /* Map type or map type parser is hesiod */ - if (!strcmp($1, "hesiod") || (tmp && !strcmp(tmp, "hesiod"))) { - master_error("hesiod support not built in"); - local_free_vars(); - YYABORT; - } -#endif - if (type) - free(type); - if (strcmp($1, "exec")) - type = master_strdup($1); - else - type = master_strdup("program"); - if (!type) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - if (tmp) { - if (format) - free(format); - format = master_strdup(tmp); - if (!format) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - tmp_argc++; - tmp_argv = add_argv(tmp_argc, tmp_argv, $2); - if (!tmp_argv) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - | MAPTYPE MAPNAME - { - char *tmp = NULL; - - trim_maptype($1); - - if ((tmp = strchr($1, ','))) - *tmp++ = '\0'; - - if (type) - free(type); - if (strcmp($1, "exec")) - type = master_strdup($1); - else - type = master_strdup("program"); - if (!type) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - if (tmp) { - if (format) - free(format); - format = master_strdup(tmp); - if (!format) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - tmp_argc++; - tmp_argv = add_argv(tmp_argc, tmp_argv, $2); - if (!tmp_argv) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - | MAPTYPE dn - { - char *tmp = NULL; - - trim_maptype($1); - - if ((tmp = strchr($1, ','))) - *tmp++ = '\0'; - - if (type) - free(type); - if (strcmp($1, "exec")) - type = master_strdup($1); - else - type = master_strdup("program"); - if (!type) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - if (tmp) { - if (format) - free(format); - format = master_strdup(tmp); - if (!format) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - tmp_argc++; - tmp_argv = add_argv(tmp_argc, tmp_argv, $2); - if (!tmp_argv) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - /* Add back the type for lookup_ldap.c to handle ldaps */ - if (*tmp_argv[0]) { - tmp = malloc(strlen(type) + strlen(tmp_argv[0]) + 2); - if (!tmp) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - strcpy(tmp, type); - strcat(tmp, ":"); - strcat(tmp, tmp_argv[0]); - free(tmp_argv[0]); - tmp_argv[0] = tmp; - } - } - ; - -dn: DNSERVER dnattrs - { - strcpy($$, $1); - strcat($$, $2); - } - | dnattrs - { - strcpy($$, $1); - } - | - { - master_notify("syntax error in dn"); - YYABORT; - } - ; - -dnattrs: DNATTR EQUAL DNNAME - { - if (strcasecmp($1, "cn") && - strcasecmp($1, "ou") && - strcasecmp($1, "automountMapName") && - strcasecmp($1, "nisMapName")) { - strcpy(errstr, $1); - strcat(errstr, "="); - strcat(errstr, $3); - master_notify(errstr); - YYABORT; - } - strcpy($$, $1); - strcat($$, "="); - strcat($$, $3); - } - | DNATTR EQUAL DNNAME COMMA dnattr - { - if (strcasecmp($1, "cn") && - strcasecmp($1, "ou") && - strcasecmp($1, "automountMapName") && - strcasecmp($1, "nisMapName")) { - strcpy(errstr, $1); - strcat(errstr, "="); - strcat(errstr, $3); - master_notify(errstr); - YYABORT; - } - strcpy($$, $1); - strcat($$, "="); - strcat($$, $3); - strcat($$, ","); - strcat($$, $5); - } - | DNNAME - { - /* Matches map in old style syntax ldap:server:map */ - strcpy($$, $1); - } - | DNATTR - { - master_notify($1); - YYABORT; - } - ; - -dnattr: DNATTR EQUAL DNNAME - { - if (!strcasecmp($1, "automountMapName") || - !strcasecmp($1, "nisMapName")) { - strcpy(errstr, $1); - strcat(errstr, "="); - strcat(errstr, $3); - master_notify(errstr); - YYABORT; - } - strcpy($$, $1); - strcat($$, "="); - strcat($$, $3); - } - | DNATTR EQUAL DNNAME COMMA dnattr - { - if (!strcasecmp($1, "automountMapName") || - !strcasecmp($1, "nisMapName")) { - strcpy(errstr, $1); - strcat(errstr, "="); - strcat(errstr, $3); - master_notify(errstr); - YYABORT; - } - strcpy($$, $1); - strcat($$, "="); - strcat($$, $3); - strcat($$, ","); - strcat($$, $5); - } - | DNATTR - { - master_notify($1); - YYABORT; - } - | DNNAME - { - master_notify($1); - YYABORT; - } - ; - -options: option {} - | options COMMA option {} - | options option {} - | options COMMA COMMA option - { - master_notify($1); - YYABORT; - } - | options EQUAL - { - master_notify($1); - YYABORT; - } - ; - -option: daemon_option - | mount_option {} - | error - { - master_notify("bogus option"); - YYABORT; - } - ; - -daemon_option: OPT_TIMEOUT NUMBER { timeout = $2; } - | OPT_NTIMEOUT NUMBER { negative_timeout = $2; } - | OPT_SYMLINK { symlnk = 1; } - | OPT_STRICTEXPIRE { strictexpire = 1; } - | OPT_SHARED { propagation = PROPAGATION_SHARED; } - | OPT_SLAVE { propagation = PROPAGATION_SLAVE; } - | OPT_PRIVATE { propagation = PROPAGATION_PRIVATE; } - | OPT_NOBIND { nobind = 1; } - | OPT_NOGHOST { ghost = 0; } - | OPT_GHOST { ghost = 1; } - | OPT_VERBOSE { verbose = 1; } - | OPT_DEBUG { debug = 1; } - | OPT_RANDOM { random_selection = 1; } - | OPT_USE_WEIGHT { use_weight = 1; } - | OPT_MODE OCTALNUMBER { mode = $2; } - ; - -mount_option: OPTION - { - tmp_argc++; - tmp_argv = add_argv(tmp_argc, tmp_argv, $1); - if (!tmp_argv) { - master_error("memory allocation error"); - local_free_vars(); - YYABORT; - } - } - ; -%% - -#if YYDEBUG -static int master_fprintf(FILE *f, char *msg, ...) -{ - va_list ap; - va_start(ap, msg); - vsyslog(LOG_DEBUG, msg, ap); - va_end(ap); - return 1; -} -#endif - -static char *master_strdup(char *str) -{ - char *tmp; - - tmp = strdup(str); - if (!tmp) - master_error("memory allocation error"); - return tmp; -} - -static int master_error(const char *s) -{ - logmsg("%s while parsing map.", s); - return 0; -} - -static int master_notify(const char *s) -{ - logmsg("syntax error in map near [ %s ]", s); - return(0); -} - -static int master_msg(const char *s) -{ - logmsg("%s", s); - return 0; -} - -static void local_init_vars(void) -{ - path = NULL; - type = NULL; - format = NULL; - verbose = 0; - debug = 0; - timeout = -1; - negative_timeout = 0; - symlnk = 0; - strictexpire = 0; - propagation = PROPAGATION_SLAVE; - nobind = 0; - ghost = defaults_get_browse_mode(); - random_selection = global_selection_options & MOUNT_FLAG_RANDOM_SELECT; - use_weight = 0; - mode = 0; - tmp_argv = NULL; - tmp_argc = 0; - local_argv = NULL; - local_argc = 0; -} - -static void local_free_vars(void) -{ - if (path) - free(path); - - if (type) - free(type); - - if (format) - free(format); - - if (local_argv) { - free_argv(local_argc, (const char **) local_argv); - local_argv = NULL; - local_argc = 0; - } - - if (tmp_argv) { - free_argv(tmp_argc, (const char **) tmp_argv); - tmp_argv = NULL; - tmp_argc = 0; - } -} - -static void trim_maptype(char *type) -{ - char *tmp; - - tmp = strchr(type, ':'); - if (tmp) - *tmp = '\0'; - else { - int len = strlen(type); - while (len-- && isblank(type[len])) - type[len] = '\0'; - } - return; -} - -static int add_multi_mapstr(void) -{ - if (type) { - /* If type given and format is non-null add it back */ - if (format) { - int len = strlen(type) + strlen(format) + 2; - char *tmp = realloc(type, len); - if (!tmp) - return 0; - type = tmp; - strcat(type, ","); - strcat(type, format); - free(format); - format = NULL; - } - - local_argc++; - local_argv = add_argv(local_argc, local_argv, type); - if (!local_argv) { - free(type); - type = NULL; - return 0; - } - - free(type); - type = NULL; - } - - local_argv = append_argv(local_argc, local_argv, tmp_argc, tmp_argv); - if (!local_argv) { - free(type); - type = NULL; - return 0; - } - local_argc += tmp_argc; - - tmp_argc = 0; - tmp_argv = NULL; - - return 1; -} - -void master_init_scan(void) -{ - lineno = 0; -} - -int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigned int logging, time_t age) -{ - struct master *master = master_list; - struct mapent_cache *nc; - struct master_mapent *entry, *new; - struct map_source *source; - unsigned int logopt = logging; - unsigned int m_logopt = master->logopt; - size_t mp_len; - int ret; - - local_init_vars(); - - lineno++; - - master_set_scan_buffer(buffer); - - ret = master_parse(); - if (ret != 0) { - local_free_vars(); - return 0; - } - - mp_len = strlen(path); - while (mp_len && path[--mp_len] == '/') - path[mp_len] = 0; - - nc = master->nc; - - /* Add null map entries to the null map cache */ - if (type && !strcmp(type, "null")) { - cache_update(nc, NULL, path, NULL, lineno); - local_free_vars(); - return 1; - } - - /* Ignore all subsequent matching nulled entries */ - if (cache_lookup_distinct(nc, path)) { - local_free_vars(); - return 1; - } - - if (debug || verbose) { - logopt = (debug ? LOGOPT_DEBUG : 0); - logopt |= (verbose ? LOGOPT_VERBOSE : 0); - } - - new = NULL; - entry = master_find_mapent(master, path); - if (!entry) { - new = master_new_mapent(master, path, age); - if (!new) { - local_free_vars(); - return 0; - } - entry = new; - } else { - if (entry->age && entry->age == age) { - if (strcmp(path, "/-")) { - info(m_logopt, - "ignoring duplicate indirect mount %s", - path); - local_free_vars(); - return 0; - } - } - } - - if (!format) { - if (conf_amd_mount_section_exists(path)) - format = strdup("amd"); - } - - if (format && !strcmp(format, "amd")) { - unsigned int loglevel = conf_amd_get_log_options(); - unsigned int flags = conf_amd_get_flags(path); - - if (loglevel <= LOG_DEBUG && loglevel > LOG_INFO) - logopt = LOGOPT_DEBUG; - else if (loglevel <= LOG_INFO && loglevel > LOG_ERR) - logopt = LOGOPT_VERBOSE; - - /* It isn't possible to provide the fullybrowsable amd - * browsing functionality within the autofs framework. - * This flag will not be set if browsable_dirs = full - * in the configuration or fullybrowsable is present as - * an option. - */ - if (flags & CONF_BROWSABLE_DIRS) - ghost = 1; - } - - if (!entry->ap) { - ret = master_add_autofs_point(entry, logopt, nobind, ghost, 0); - if (!ret) { - error(m_logopt, "failed to add autofs_point"); - if (new) - master_free_mapent(new); - local_free_vars(); - return 0; - } - } - entry->ap->flags &= ~(PROPAGATION_MASK); - entry->ap->flags |= propagation; - - if (random_selection) - entry->ap->flags |= MOUNT_FLAG_RANDOM_SELECT; - if (use_weight) - entry->ap->flags |= MOUNT_FLAG_USE_WEIGHT_ONLY; - if (symlnk) - entry->ap->flags |= MOUNT_FLAG_SYMLINK; - if (strictexpire) - entry->ap->flags |= MOUNT_FLAG_STRICTEXPIRE; - if (negative_timeout) - entry->ap->negative_timeout = negative_timeout; - if (mode && mode < LONG_MAX) - entry->ap->mode = mode; - - if (timeout < 0) { - /* - * If no timeout is given get the timout from the - * autofs point, or the first map, or the config - * for amd maps. - */ - if (format && !strcmp(format, "amd")) - timeout = conf_amd_get_dismount_interval(path); - else - timeout = get_exp_timeout(entry->ap, entry->maps); - } - - if (format && !strcmp(format, "amd")) { - char *opts = conf_amd_get_map_options(path); - if (opts) { - /* autofs uses the equivalent of cache:=inc,sync - * (except for file maps which use cache:=all,sync) - * but if the map is large then it may be necessary - * to read the whole map at startup even if browsing - * is is not enabled, so look for cache:=all in the - * map_options configuration entry. - */ - if (strstr(opts, "cache:=all")) - entry->ap->flags |= MOUNT_FLAG_AMD_CACHE_ALL; - free(opts); - } - } - -/* - source = master_find_map_source(entry, type, format, - local_argc, (const char **) local_argv); - if (!source) - source = master_add_map_source(entry, type, format, age, - local_argc, (const char **) local_argv); - else - source->age = age; -*/ - source = master_add_map_source(entry, type, format, age, - local_argc, (const char **) local_argv); - if (!source) { - error(m_logopt, "failed to add source"); - if (new) - master_free_mapent(new); - local_free_vars(); - return 0; - } - set_exp_timeout(entry->ap, source, timeout); - source->master_line = lineno; - - entry->age = age; - entry->current = NULL; - - if (new) - master_add_mapent(master, entry); - - local_free_vars(); - - return 1; -} - diff --git a/lib/master_tok.l b/lib/master_tok.l deleted file mode 100644 index 87a6b958..00000000 --- a/lib/master_tok.l +++ /dev/null @@ -1,504 +0,0 @@ -%{ -/* ----------------------------------------------------------------------- * - * - * master_tok.l - master map tokenizer. - * - * Copyright 2006 Ian Kent - * - * 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. - * - * ----------------------------------------------------------------------- */ - -#ifdef ECHO -# undef ECHO -#endif /* ECHO */ -static void master_echo(void); /* forward definition */ -#define ECHO master_echo() - -#include -#include -#include -#include -#include "master_parse.tab.h" - -/* - * There are some things that need to be defined only if useing GNU flex. - * These must not be defined if using standard lex - */ -#ifdef FLEX_SCANNER -int master_lineno; -#endif - -int master_lex(void); -int master_wrap(void); - -/* no need for yywrap() */ -#define YY_SKIP_YYWRAP - -#ifndef YY_STACK_USED -#define YY_STACK_USED 0 -#endif -#ifndef YY_ALWAYS_INTERACTIVE -#define YY_ALWAYS_INTERACTIVE 0 -#endif -#ifndef YY_NEVER_INTERACTIVE -#define YY_NEVER_INTERACTIVE 0 -#endif -#ifndef YY_MAIN -#define YY_MAIN 0 -#endif - -void master_set_scan_buffer(const char *); -const char *line = NULL; - -#ifdef FLEX_SCANNER -const char *line_pos = NULL; -const char *line_lim = NULL; -int my_yyinput(char *, int); - -#undef YY_INPUT -#define YY_INPUT(b, r, ms) (r = my_yyinput(b, ms)) -#else -#undef input -#undef unput -#define input() (*(char *) line++) -#define unput(c) (*(char *) --line = c) -#endif - -#define BUFF_LEN 1024 -char buff[BUFF_LEN]; -char *bptr; -char *optr = buff; -unsigned int tlen; - -%} - -%option nounput - -%x PATHSTR MAPSTR DNSTR OPTSTR OCTAL - -WS [[:blank:]]+ -OPTWS [[:blank:]]* -NL \r?\n -CONT \\\n{OPTWS} - -OPTIONSTR ([\-]?([[:alpha:]_]([[:alnum:]_\-])*(=(\"?([[:alnum:]_\-\:\.])+\"?))?)+) -MACROSTR (-D{OPTWS}([[:alpha:]_]([[:alnum:]_\-\.])*)=([[:alnum:]_\-\.])+) -SLASHIFYSTR (--(no-)?slashify-colons) -NUMBER [0-9]+ -OCTALNUMBER [0-7]+ - -DNSERVSTR1 ([[:alpha:]][[:alnum:]\-.]*(:[0-9]+)?:) -DNSERVSTR2 (\[([[:xdigit:]]:.)+\](:[0-9]+)?:) -DNSERVSTR3 (\/\/[[:alpha:]][[:alnum:]\-.]*(:[0-9]+)?\/) -DNSERVSTR4 (\/\/\[([[:xdigit:]]:.)+\](:[0-9]+)?\/) -DNSERVSTR5 (([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(:[0-9]+)?:) -DNSERVSTR6 (\/\/([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(:[0-9]+)?\/) -DNSERVERSTR ({DNSERVSTR1}|{DNSERVSTR2}|{DNSERVSTR3}|{DNSERVSTR4}|{DNSERVSTR5}|{DNSERVSTR6}) - -AT_CN ([cC][[nN]) -AT_NMN ([nN][iI][sS][Mm][aA][pP][Nn][aA][mM][eE]) -AT_AMN ([aA][uU][tT][oO][mM][oO][uU][nN][tT][Mm][aA][pP][Nn][aA][mM][eE]) -AT_OU ([oO][[uU]) -AT_DC ([dD][[cC]) -AT_O ([oO]) -AT_C ([cC]) -AT_L ([lL]) -DNATTRSTR ({AT_CN}|{AT_NMN}|{AT_AMN}|{AT_OU}|{AT_DC}|{AT_O}|{AT_C}|{AT_L}) -DNNAMESTR1 ([[:alnum:]_.\- ]+) -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})) - - -OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS}) -OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|--negative-timeout{OPTWS}|--negative-timeout{OPTWS}={OPTWS}) - -MODE (--mode{OPTWS}|--mode{OPTWS}={OPTWS}) - -%% - -{ - {NL} | - \x00 { - if (optr != buff) { - *optr = '\0'; - strcpy(master_lval.strtype, buff); - return NILL; - } - } - - #.* { return COMMENT; } - - "/" { - if (optr != buff) { - *optr = '\0'; - strcpy(master_lval.strtype, buff); - return NILL; - } - BEGIN(PATHSTR); - bptr = buff; - yyless(0); - } - - . { *optr++ = *master_text; } -} - -{ - \x00 { - BEGIN(INITIAL); - *bptr++ = *master_text; - strcpy(master_lval.strtype, buff); - return NILL; - } - - \\. { *bptr++ = *(master_text + 1); } - \" { - BEGIN(INITIAL); - *bptr++ = *master_text; - *bptr = '\0'; - strcpy(master_lval.strtype, buff); - return QUOTE; - } - - {WS} { - BEGIN(MAPSTR); - *bptr = '\0'; - strcpy(master_lval.strtype, buff); - bptr = buff; - memset(buff, 0, BUFF_LEN); - return(PATH); - } - - <> { - BEGIN(INITIAL); - *bptr = '\0'; - strcpy(master_lval.strtype, buff); - return(PATH); - } - - {NL} { - BEGIN(INITIAL); - *bptr = '\0'; - strcpy(master_lval.strtype, buff); - return PATH; - } - - . { *bptr++ = *master_text; } -} - -{ - {OPTWS}\\\n{OPTWS} {} - - {MULTI} { - tlen = master_leng - 1; - if (bptr != buff && isblank(master_text[tlen])) { - /* - * We can't handle unescaped white space in map names - * so just eat the white space. We always have the - * "multi" at the beginning of the string so the while - * will not fall off the end. - */ - while (isblank(master_text[tlen - 1])) - tlen--; - strncat(buff, master_text, tlen); - bptr += tlen; - yyless(tlen); - } else { - strcpy(master_lval.strtype, master_text); - return(MULTITYPE); - } - } - - {MTYPE} | - {MTYPE}/{DNSERVERSTR}{DNATTRSTR}= | - {MTYPE}/{DNATTRSTR}= { - tlen = master_leng - 1; - if (bptr != buff && isblank(master_text[tlen])) { - /* - * We can't handle unescaped white space in map names - * so just eat the white space. We always have the - * maptype keyword at the beginning of the string so - * the while will not fall off the end. - */ - while (isblank(master_text[tlen - 1])) - tlen--; - strncat(buff, master_text, tlen); - bptr += tlen; - yyless(tlen); - } else { - strcpy(master_lval.strtype, master_text); - return(MAPTYPE); - } - } - - {MULTISEP} { return(DDASH); } - - ":" { return(COLON); } - - "-hosts" { - BEGIN(OPTSTR); - strcpy(master_lval.strtype, master_text); - return MAPHOSTS; - } - - "-null" { - BEGIN(OPTSTR); - strcpy(master_lval.strtype, master_text); - return MAPNULL; - } - - "-xfn" { - /* - * The X/Open Federated Naming service isn't supported - * and the parser will call YYABORT() when it sees the - * MAPXFN token so we must set the start state to the - * INITIAL state here for the next yylex() call. - */ - BEGIN(INITIAL); - strcpy(master_lval.strtype, master_text); - return MAPXFN; - } - - "//" { - BEGIN(DNSTR); - yyless(0); - } - - {DNSERVERSTR}{DNATTRSTR}= { - BEGIN(DNSTR); - yyless(0); - } - - {DNATTRSTR}= { - BEGIN(DNSTR); - yyless(0); - } - - {OPTWS}/{NL} { - BEGIN(INITIAL); - *bptr = '\0'; - strcpy(master_lval.strtype, buff); - bptr = buff; - return(MAPNAME); - } - - \\. { *bptr++ = *(master_text + 1); } - - {WS} { - BEGIN(OPTSTR); - *bptr = '\0'; - strcpy(master_lval.strtype, buff); - bptr = buff; - return(MAPNAME); - } - - {NL} | - \x00 { - BEGIN(INITIAL); - *bptr = '\0'; - strcpy(master_lval.strtype, buff); - return(MAPNAME); - } - - <> { - BEGIN(INITIAL); - *bptr = '\0'; - strcpy(master_lval.strtype, buff); - return(MAPNAME); - } - - . { *bptr++ = *master_text; } -} - -{ - {OPTWS}\\\n{OPTWS} {} - - {DNSERVERSTR} { - strcpy(master_lval.strtype, master_text); - return DNSERVER; - } - - {DNATTRSTR}/"=" { - strcpy(master_lval.strtype, master_text); - return DNATTR; - } - - "=" { - return EQUAL; - } - - {DNNAMESTR1}/","{DNATTRSTR}"=" { - strcpy(master_lval.strtype, master_text); - return DNNAME; - } - - {DNNAMESTR2} { - strcpy(master_lval.strtype, master_text); - return DNNAME; - } - - {OPTWS}","{OPTWS} { - return COMMA; - } - - {WS}"=" | - "="{WS} { - BEGIN(INITIAL); - strcpy(master_lval.strtype, master_text); - return SPACE; - } - - {WS} { BEGIN(OPTSTR); } - - {NL} | - \x00 { BEGIN(INITIAL); } - - <> { BEGIN(INITIAL); } -} - -{ - {OPTWS}\\\n{OPTWS} {} - - {MULTISEP} { - BEGIN(MAPSTR); - return(DDASH); - } - - {OPTTOUT}/{NUMBER} { return(OPT_TIMEOUT); } - - {OPTNTOUT}/{NUMBER} { return(OPT_NTIMEOUT); } - - {NUMBER} { - master_lval.longtype = atol(master_text); - return(NUMBER); - } - - -?symlink { return(OPT_SYMLINK); } - -?nobind { return(OPT_NOBIND); } - -?nobrowse { return(OPT_NOGHOST); } - -?shared { return(OPT_SHARED); } - -?slave { return(OPT_SLAVE); } - -?private { return(OPT_PRIVATE); } - -?strictexpire { return(OPT_STRICTEXPIRE); } - -g|--ghost|-?browse { return(OPT_GHOST); } - -v|--verbose { return(OPT_VERBOSE); } - -d|--debug { return(OPT_DEBUG); } - -w|--use-weight-only { return(OPT_USE_WEIGHT); } - -r|--random-multimount-selection { return(OPT_RANDOM); } - - {MODE}/{OCTALNUMBER} { - BEGIN(OCTAL); - return(OPT_MODE); - } - - {OPTWS}","{OPTWS} { return(COMMA); } - - {OPTWS} {} - - {SLASHIFYSTR} { - strcpy(master_lval.strtype, master_text); - return(OPTION); - } - - {MACROSTR} { - strcpy(master_lval.strtype, master_text); - return(OPTION); - } - - {OPTIONSTR} { - strcpy(master_lval.strtype, master_text); - return(OPTION); - } - - "=" { - strcpy(master_lval.strtype, master_text); - return(EQUAL); - } - - {WS} {} - {NL} | - \x00 { BEGIN(INITIAL); } - - <> { BEGIN(INITIAL); } -} - -{ - {OCTALNUMBER} { - master_lval.longtype = strtoul(master_text, NULL, 8); - return(OCTALNUMBER); - } - - . { BEGIN(OPTSTR); yyless(0); } -} - -%% - -#include "automount.h" - -int master_wrap(void) -{ - return 1; -} - -static void master_echo(void) -{ - logmsg("%s", master_text); - return; -} - -#ifdef FLEX_SCANNER - -void master_set_scan_buffer(const char *buffer) -{ - memset(buff, 0, sizeof(buff)); - optr = buff; - - YY_FLUSH_BUFFER; - - line = buffer; - line_pos = &line[0]; - /* - * Ensure buffer is 1 greater than string and is zeroed before - * the parse so we can fit the extra NULL which allows us to - * explicitly match an end of line within the buffer (ie. the - * need for 2 NULLS when parsing in memeory buffers). - */ - line_lim = line + strlen(buffer) + 1; -} - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -int my_yyinput(char *buffer, int max_size) -{ - int n = min(max_size, line_lim - line_pos); - - if (n > 0) { - memcpy(buffer, line_pos, n); - line_pos += n; - } - return n; -} - -#else - -void master_set_scan_buffer(const char *buffer) -{ - line = buffer; -} - -#endif