diff --git a/CHANGELOG b/CHANGELOG index 2ffaba6..111c6af 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,8 @@ - cthon more cleanup and corrections. - cthon correction to host validation. - cthon fix submount operation broken by above. +- cthon more parser corrections and attempt to fix multi-mounts + with various combinations of submounts (still broken). 13/7/2006 autofs-5.0.1 rc1 -------------------------- diff --git a/daemon/automount.c b/daemon/automount.c index 21f0378..8fcf19a 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -243,8 +243,6 @@ static int umount_offsets(struct autofs_ sched_yield(); - debug(ap->logopt, "umount offset %s", offset); - strcpy(key, base); strcat(key, offset); oe = cache_lookup_distinct(mc, key); @@ -254,6 +252,8 @@ static int umount_offsets(struct autofs_ continue; } + warn(ap->logopt, "umount offset %s", key); + /* * We're in trouble if umounting the triggers fails. * It should always succeed due to the expire design. @@ -306,26 +306,16 @@ static int umount_ent(struct autofs_poin rv = spawnll(log_debug, PATH_UMOUNT, PATH_UMOUNT, path, NULL); } - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); - /* We are doing a forced shutcwdown down so unlink busy mounts */ if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) { ret = stat(path, &st); if (ret == -1 && errno == ENOENT) { warn(ap->logopt, "mount point does not exist"); - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); return 0; } if (ret == 0 && !S_ISDIR(st.st_mode)) { warn(ap->logopt, "mount point is not a directory"); - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); return 0; } @@ -353,10 +343,6 @@ static int umount_ent(struct autofs_poin } } - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); - return rv; } @@ -559,7 +545,7 @@ int umount_multi(struct autofs_point *ap if (!tree_get_mnt_list(mnts, &list, path, incl)) { debug(ap->logopt, "no mounts found under %s", path); check_rm_dirs(ap, path, incl); - return 1; + return 0; } left = 0; @@ -581,6 +567,8 @@ int umount_multi(struct autofs_point *ap debug(ap->logopt, "unmounting dir = %s", mptr->path); if (umount_ent(ap, mptr->path, mptr->fs_type)) { + warn(ap->logopt, "could not umount dir %s", + mptr->path); left++; } } @@ -612,13 +600,11 @@ int umount_multi(struct autofs_point *ap break; } - if (!tree_is_mounted(mnts, buf)) { - if (umount_offsets(ap, mnts, buf)) { - warn(ap->logopt, - "could not umount some offsets under %s", - buf); - left++; - } + if (umount_offsets(ap, mnts, buf)) { + warn(ap->logopt, + "could not umount some offsets under %s", + buf); + left++; } free(de[n]); } @@ -670,35 +656,16 @@ int umount_autofs(struct autofs_point *a /* * Since lookup.c is lazy about closing lookup modules * to prevent unneeded opens, we need to clean them up - * before umount or the fs will be busy. + * before umount. */ lookup_close_lookup(ap); if (ap->type == LKP_INDIRECT) { if (umount_all(ap, force) && !force) return -1; - ret = umount_autofs_indirect(ap); - } else { + } else ret = umount_autofs_direct(ap); - } - - if (ap->submount) { - int status; - - status = pthread_mutex_lock(&ap->parent->mounts_mutex); - if (status) - fatal(status); - ap->parent->submnt_count--; - list_del_init(&ap->mounts); - status = pthread_cond_signal(&ap->parent->mounts_cond); - if (status) - error(ap->logopt, - "failed to signal submount umount notify condition"); - status = pthread_mutex_unlock(&ap->parent->mounts_mutex); - if (status) - fatal(status); - } return ret; } @@ -778,28 +745,35 @@ static int get_pkt(struct autofs_point * } if (fds[1].revents & POLLIN) { - enum states next_state; + enum states next_state, post_state; + size_t read_size = sizeof(next_state); + int state_pipe; int status; - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); + next_state = post_state = ST_INVAL; + + state_mutex_lock(ap); - if (fullread(ap->state_pipe[0], &next_state, sizeof(next_state))) + state_pipe = ap->state_pipe[0]; + + if (fullread(state_pipe, &next_state, read_size)) { + state_mutex_unlock(ap); continue; + } - if (next_state != ap->state) { + if (next_state != ST_INVAL && next_state != ap->state) { if (next_state != ST_SHUTDOWN) - st_add_task(ap, next_state); + post_state = next_state; else ap->state = ST_SHUTDOWN; } - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); - if (ap->state == ST_SHUTDOWN) + if (post_state != ST_INVAL) + st_add_task(ap, post_state); + + if (next_state == ST_SHUTDOWN) return -1; } @@ -837,7 +811,7 @@ int do_expire(struct autofs_point *ap, c if (ret == 0) msg("expired %s", buf); else - error(ap->logopt, "error while expiring %s", buf); + warn(ap->logopt, "couldn't complet expire of %s", buf); tree_free_mnt_tree(mnts); @@ -1238,23 +1212,26 @@ static void handle_mounts_cleanup(void * struct autofs_point *ap; char path[PATH_MAX + 1]; char buf[MAX_ERR_BUF]; - unsigned int clean = 0; + unsigned int clean = 0, submount; ap = (struct autofs_point *) arg; + submount = ap->submount; + strcpy(path, ap->path); - if (!ap->submount && strcmp(ap->path, "/-") && ap->dir_created) + if (!submount && strcmp(ap->path, "/-") && ap->dir_created) clean = 1; - /* Make sure alarms are cleared */ - alarm_delete(ap); - - umount_autofs(ap, 1); - /* If we have been canceled then we may hold the state mutex. */ mutex_operation_wait(&ap->state_mutex); - master_remove_mapent(ap->entry); + st_remove_tasks(ap); + umount_autofs(ap, 1); + + if (submount) + master_signal_submount(ap); + else + master_remove_mapent(ap->entry); master_free_mapent_sources(ap->entry, 1); master_free_mapent(ap->entry); @@ -1271,7 +1248,7 @@ static void handle_mounts_cleanup(void * msg("shut down path %s", path); /* If we are the last tell the state machine to shutdown */ - if (master_list_empty(master_list)) + if (!submount && master_list_empty(master_list)) kill(getpid(), SIGTERM); return; @@ -1287,9 +1264,7 @@ void *handle_mounts(void *arg) pthread_cleanup_push(return_start_status, &suc); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_lock(ap); status = pthread_mutex_lock(&suc.mutex); if (status) { @@ -1300,9 +1275,7 @@ void *handle_mounts(void *arg) if (mount_autofs(ap) < 0) { crit(ap->logopt, "mount of %s failed!", ap->path); suc.status = 1; - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); umount_autofs(ap, 1); pthread_exit(NULL); } @@ -1315,33 +1288,26 @@ void *handle_mounts(void *arg) /* We often start several automounters at the same time. Add some randomness so we don't all expire at the same time. */ - if (ap->exp_timeout) + if (!ap->submount && ap->exp_timeout) alarm_add(ap, ap->exp_runfreq + rand() % ap->exp_runfreq); - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); - pthread_cleanup_push(handle_mounts_cleanup, ap); pthread_setcancelstate(cancel_state, &cancel_state); + state_mutex_unlock(ap); + while (ap->state != ST_SHUTDOWN) { if (handle_packet(ap)) { int ret, result; - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); - + state_mutex_lock(ap); /* * For a direct mount map all mounts have already gone * by the time we get here. */ if (ap->type == LKP_DIRECT) { status = 1; - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); break; } @@ -1351,24 +1317,13 @@ void *handle_mounts(void *arg) */ ret = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &result); if (ret == -1) { - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); break; } /* OK to exit */ - if (result) { - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); - break; - } - - if (ap->state == ST_SHUTDOWN) { - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + if (ap->state == ST_SHUTDOWN || result) { + state_mutex_unlock(ap); break; } @@ -1376,29 +1331,14 @@ void *handle_mounts(void *arg) warn(ap->logopt, "can't shutdown: filesystem %s still busy", ap->path); - alarm_add(ap, ap->exp_runfreq); + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); nextstate(ap->state_pipe[1], ST_READY); - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); } } - status = pthread_mutex_lock(&ap->mounts_mutex); - if (status) - fatal(status); - - while (ap->submnt_count) { - status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex); - if (status) - fatal(status); - } - - status = pthread_mutex_unlock(&ap->mounts_mutex); - if (status) - fatal(status); - pthread_cleanup_pop(1); /* diff --git a/daemon/direct.c b/daemon/direct.c index 3905ed0..89c8db2 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -493,16 +493,20 @@ int umount_autofs_offset(struct autofs_p rv = umount(me->key); if (rv == -1) { - if (errno == ENOENT) { + switch (errno) { + case ENOENT: warn(ap->logopt, "mount point does not exist"); return 0; - } else if (errno == EBUSY) { + break; + case EBUSY: warn(ap->logopt, "mount point %s is in use", me->key); if (ap->state != ST_SHUTDOWN_FORCE) - return 0; - } else if (errno == ENOTDIR) { + return 1; + break; + case ENOTDIR: error(ap->logopt, "mount point is not a directory"); return 0; + break; } goto force_umount; } @@ -684,11 +688,13 @@ void *expire_proc_direct(void *arg) pthread_exit(NULL); } + pthread_cleanup_push(expire_cleanup, ea); + status = pthread_mutex_unlock(&ea->mutex); if (status) fatal(status); - pthread_cleanup_push(expire_cleanup, ea); + master_notify_submounts(ap, ap->state); /* Get a list of real mounts and expire them if possible */ mnts = get_mnt_list(_PROC_MOUNTS, "/", 0); diff --git a/daemon/indirect.c b/daemon/indirect.c index 0c47cfd..7bde7ec 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -280,7 +280,8 @@ int mount_autofs_indirect(struct autofs_ int umount_autofs_indirect(struct autofs_point *ap) { - int rv; + char buf[MAX_ERR_BUF]; + int ret, rv; /* * Since submounts look after themselves the parent never knows @@ -290,10 +291,13 @@ int umount_autofs_indirect(struct autofs */ if (ap->submount) { struct master_mapent *entry = ap->parent->entry; - struct map_source *map = entry->first; + struct map_source *map; struct mapent_cache *mc; struct mapent *me; + pthread_cleanup_push(master_source_lock_cleanup, entry); + master_source_readlock(entry); + map = entry->first; while (map) { mc = map->mc; cache_readlock(mc); @@ -307,6 +311,13 @@ int umount_autofs_indirect(struct autofs cache_unlock(mc); map = map->next; } + pthread_cleanup_pop(1); + } + + /* If we are trying to shutdown make sure we can umount */ + if (!ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) { + if (!ret) + warn(ap->logopt, "mount still busy %s", ap->path); } if (ap->ioctlfd >= 0) { @@ -373,7 +384,7 @@ void *expire_proc_indirect(void *arg) unsigned int now; int offsets, submnts, count; int ioctlfd; - int status; + int status, ret; ea = (struct expire_args *) arg; @@ -395,11 +406,13 @@ void *expire_proc_indirect(void *arg) pthread_exit(NULL); } + pthread_cleanup_push(expire_cleanup, ea); + status = pthread_mutex_unlock(&ea->mutex); if (status) fatal(status); - pthread_cleanup_push(expire_cleanup, ea); + master_notify_submounts(ap, ap->state); /* Get a list of real mounts and expire them if possible */ mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0); @@ -518,28 +531,13 @@ void *expire_proc_indirect(void *arg) } /* If we are trying to shutdown make sure we can umount */ - status = pthread_mutex_lock(&ap->mounts_mutex); - if (status) - fatal(status); - - if (!list_empty(&ap->submounts)) { - ea->status = 1; - } else { - int ret; - - if (!ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) { - if (!ret) { - warn(ap->logopt, - "mount still busy %s", ap->path); - ea->status = 1; - } + if (!ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) { + if (!ret) { + warn(ap->logopt, "mount still busy %s", ap->path); + ea->status = 1; } } - status = pthread_mutex_unlock(&ap->mounts_mutex); - if (status) - fatal(status); - pthread_cleanup_pop(1); return NULL; diff --git a/daemon/state.c b/daemon/state.c index 212b2c2..e74674a 100644 --- a/daemon/state.c +++ b/daemon/state.c @@ -33,6 +33,10 @@ static LIST_HEAD(state_queue); static unsigned int signaled = 0; static void st_set_thid(struct autofs_point *, pthread_t); +static pthread_mutex_t task_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t task_cond = PTHREAD_COND_INITIALIZER; +static unsigned int task_signaled; + int do_mount_autofs_direct(struct autofs_point *, struct mnt_list *, struct mapent *); void dump_state_queue(void) @@ -83,18 +87,12 @@ void expire_cleanup(void *arg) int statefd; enum states next = ST_INVAL; int success; - int status; ea = (struct expire_args *) arg; ap = ea->ap; success = ea->status; - status = pthread_mutex_lock(&ap->state_mutex); - if (status) { - error(ap->logopt, "state mutex lock failed"); - free(ea); - return; - } + state_mutex_lock(ap); debug(ap->logopt, "got thid %lu path %s stat %d", @@ -105,6 +103,7 @@ void expire_cleanup(void *arg) /* Check to see if expire process finished */ if (thid == ap->exp_thread) { ap->exp_thread = 0; + st_set_thid(ap, 0); switch (ap->state) { case ST_EXPIRE: @@ -113,11 +112,13 @@ void expire_cleanup(void *arg) /* If we're a submount and we've just pruned or expired everything away, try to shut down */ - if (ap->submount && !success && ap->state != ST_SHUTDOWN) { + if (ap->submount && !success) { next = ST_SHUTDOWN_PENDING; break; } - alarm_add(ap, ap->exp_runfreq); + + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); /* FALLTHROUGH */ case ST_READY: @@ -134,7 +135,8 @@ #else /* Failed shutdown returns to ready */ warn(ap->logopt, "filesystem %s still busy", ap->path); - alarm_add(ap, ap->exp_runfreq); + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); next = ST_READY; break; #endif @@ -157,9 +159,7 @@ #endif if (next != ST_INVAL) nextstate(statefd, next); - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - error(ap->logopt, "state mutex unlock failed"); + state_mutex_unlock(ap); free(ea); @@ -173,22 +173,8 @@ static unsigned int st_ready(struct auto ap->state = ST_READY; - if (ap->submount) { - int status; - - status = pthread_mutex_lock(&ap->parent->mounts_mutex); - if (status) - fatal(status); - - status = pthread_cond_signal(&ap->parent->mounts_cond); - if (status) - error(ap->logopt, - "failed to signal submount notify condition"); - - status = pthread_mutex_unlock(&ap->parent->mounts_mutex); - if (status) - fatal(status); - } + if (ap->submount) + master_signal_submount(ap); return 1; } @@ -298,22 +284,17 @@ static void do_readmap_cleanup(void *arg { struct readmap_args *ra; struct autofs_point *ap; - int status; ra = (struct readmap_args *) arg; ap = ra->ap; ap->readmap_thread = 0; - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_lock(ap); nextstate(ap->state_pipe[1], ST_READY); - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); free(ra); @@ -485,7 +466,8 @@ static unsigned int st_prepare_shutdown( debug(ap->logopt, "state %d path %s", ap->state, ap->path); /* Turn off timeouts for this mountpoint */ - alarm_delete(ap); + if (!ap->submount) + alarm_delete(ap); assert(ap->state == ST_READY || ap->state == ST_EXPIRE); ap->state = ST_SHUTDOWN_PENDING; @@ -496,7 +478,8 @@ static unsigned int st_prepare_shutdown( case EXP_ERROR: case EXP_PARTIAL: /* It didn't work: return to ready */ - alarm_add(ap, ap->exp_runfreq); + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); nextstate(ap->state_pipe[1], ST_READY); return 0; @@ -513,7 +496,8 @@ static unsigned int st_force_shutdown(st debug(ap->logopt, "state %d path %s", ap->state, ap->path); /* Turn off timeouts for this mountpoint */ - alarm_delete(ap); + if (!ap->submount) + alarm_delete(ap); assert(ap->state == ST_READY || ap->state == ST_EXPIRE); ap->state = ST_SHUTDOWN_FORCE; @@ -524,7 +508,8 @@ static unsigned int st_force_shutdown(st case EXP_ERROR: case EXP_PARTIAL: /* It didn't work: return to ready */ - alarm_add(ap, ap->exp_runfreq); + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); nextstate(ap->state_pipe[1], ST_READY); return 0; @@ -542,12 +527,14 @@ static unsigned int st_prune(struct auto ap->state = ST_PRUNE; /* Turn off timeouts while we prune */ - alarm_delete(ap); + if (!ap->submount) + alarm_delete(ap); switch (expire_proc(ap, 1)) { case EXP_ERROR: case EXP_PARTIAL: - alarm_add(ap, ap->exp_runfreq); + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); nextstate(ap->state_pipe[1], ST_READY); return 0; @@ -565,12 +552,14 @@ static unsigned int st_expire(struct aut ap->state = ST_EXPIRE; /* Turn off timeouts while we expire */ - alarm_delete(ap); + if (!ap->submount) + alarm_delete(ap); switch (expire_proc(ap, 0)) { case EXP_ERROR: case EXP_PARTIAL: - alarm_add(ap, ap->exp_runfreq); + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); nextstate(ap->state_pipe[1], ST_READY); return 0; @@ -583,20 +572,24 @@ static unsigned int st_expire(struct aut /* Insert alarm entry on ordered list. */ int st_add_task(struct autofs_point *ap, enum states state) { - struct list_head *head = &state_queue; + struct list_head *head; struct list_head *p; struct state_queue *new; unsigned int empty = 1; int status; + state_mutex_lock(ap); + /* Task termination marker, poke state machine */ if (state == ST_READY) { + st_ready(ap); + + state_mutex_unlock(ap); + status = pthread_mutex_lock(&mutex); if (status) fatal(status); - st_ready(ap); - signaled = 1; status = pthread_cond_signal(&cond); if (status) @@ -609,6 +602,13 @@ int st_add_task(struct autofs_point *ap, return 1; } + if (ap->state == ST_SHUTDOWN) { + state_mutex_unlock(ap); + return 1; + } + + state_mutex_unlock(ap); + new = malloc(sizeof(struct state_queue)); if (!new) return 0; @@ -620,15 +620,12 @@ int st_add_task(struct autofs_point *ap, INIT_LIST_HEAD(&new->list); INIT_LIST_HEAD(&new->pending); - /* If we are shutting down get rid on all tasks */ -/* if (ap->state == ST_SHUTDOWN_PENDING || - ap->state == ST_SHUTDOWN_FORCE) - st_remove_tasks(ap); -*/ status = pthread_mutex_lock(&mutex); if (status) fatal(status); + head = &state_queue; + /* Add to task queue for autofs_point ? */ list_for_each(p, head) { struct state_queue *task; @@ -660,7 +657,7 @@ int st_add_task(struct autofs_point *ap, void st_remove_tasks(struct autofs_point *ap) { - struct list_head *head = &state_queue; + struct list_head *head; struct list_head *p, *q; struct state_queue *task, *waiting; int status; @@ -669,6 +666,8 @@ void st_remove_tasks(struct autofs_point if (status) fatal(status); + head = &state_queue; + if (list_empty(head)) { status = pthread_mutex_unlock(&mutex); if (status) @@ -707,22 +706,33 @@ void st_remove_tasks(struct autofs_point fatal(status); } -static int run_state_task(struct state_queue *task) +static void *do_run_task(void *arg) { + struct state_queue *task; struct autofs_point *ap; - enum states state; - enum states next_state; - int status, ret = 1; + enum states next_state, state; + int status, ret; + + status = pthread_mutex_lock(&task_mutex); + if (status) + fatal(status); + task = (struct state_queue *) arg; ap = task->ap; - status = pthread_mutex_lock(&ap->state_mutex); + next_state = task->state; + + task_signaled = 1; + status = pthread_cond_signal(&task_cond); if (status) fatal(status); - state = ap->state; - next_state = task->state; + status = pthread_mutex_unlock(&task_mutex); + if (status) + fatal(status); -/* debug("task %p state %d next %d", task, state, task->state); */ + state_mutex_lock(ap); + + state = ap->state; if (next_state != state) { switch (next_state) { @@ -752,11 +762,41 @@ static int run_state_task(struct state_q } } - status = pthread_mutex_unlock(&ap->state_mutex); + state_mutex_unlock(ap); + + return; +} + +static int run_state_task(struct state_queue *task) +{ + pthread_t thid; + int status; + + status = pthread_mutex_lock(&task_mutex); + if (status) + fatal(status); + + status = pthread_create(&thid, &thread_attr, do_run_task, task); + if (status) { + error(task->ap->logopt, "error running task"); + status = pthread_mutex_unlock(&task_mutex); + if (status) + fatal(status); + return 0; + } + + task_signaled = 0; + while (!task_signaled) { + status = pthread_cond_wait(&task_cond, &task_mutex); + if (status) + fatal(status); + } + + status = pthread_mutex_unlock(&task_mutex); if (status) fatal(status); - return ret; + return 1; } static void st_set_thid(struct autofs_point *ap, pthread_t thid) @@ -776,7 +816,7 @@ static void st_set_thid(struct autofs_po static void *st_queue_handler(void *arg) { - struct list_head *head = &state_queue; + struct list_head *head; struct list_head *p; int status; @@ -784,6 +824,8 @@ static void *st_queue_handler(void *arg) if (status) fatal(status); + head = &state_queue; + while (1) { /* * If the state queue list is empty, wait until an @@ -853,10 +895,10 @@ static void *st_queue_handler(void *arg) run_state_task(task); continue; } - - if (task->cancel) +/* + if (task->thid && task->cancel) pthread_cancel(task->thid); - +*/ /* Still busy */ if (task->thid) { status = pthread_kill(task->thid, 0); diff --git a/include/automount.h b/include/automount.h index a71606e..a689046 100644 --- a/include/automount.h +++ b/include/automount.h @@ -84,18 +84,19 @@ #define LKP_FAIL 0x0001 #define LKP_INDIRECT 0x0002 #define LKP_DIRECT 0x0004 -#define LKP_NOMATCH 0x0008 -#define LKP_MATCH 0x0010 -#define LKP_NEXT 0x0020 -#define LKP_MOUNT 0x0040 -#define LKP_WILD 0x0080 -#define LKP_LOOKUP 0x0100 -#define LKP_GHOST 0x0200 -#define LKP_REREAD 0x0400 -#define LKP_EMPTY 0x0800 -#define LKP_ERR_FORMAT 0x1000 -#define LKP_ERR_MOUNT 0x2000 -#define LKP_NOTSUP 0x4000 +#define LKP_MULTI 0x0008 +#define LKP_NOMATCH 0x0010 +#define LKP_MATCH 0x0020 +#define LKP_NEXT 0x0040 +#define LKP_MOUNT 0x0080 +#define LKP_WILD 0x0100 +#define LKP_LOOKUP 0x0200 +#define LKP_GHOST 0x0400 +#define LKP_REREAD 0x0800 +#define LKP_EMPTY 0x1000 +#define LKP_ERR_FORMAT 0x2000 +#define LKP_ERR_MOUNT 0x4000 +#define LKP_NOTSUP 0x8000 #define MAX_ERR_BUF 128 @@ -185,7 +186,7 @@ const char **copy_argv(int argc, const c int compare_argv(int argc1, const char **argv1, int argc2, const char **argv2); int free_argv(int argc, const char **argv); -void dump_core(void); +inline void dump_core(void); int sigchld_start_handler(void); int sigchld_block(void); int sigchld_unblock(void); @@ -435,6 +436,7 @@ struct autofs_point { struct autofs_point *parent; /* Owner of mounts list for submount */ pthread_mutex_t mounts_mutex; /* Protect mount lists */ pthread_cond_t mounts_cond; /* Submounts condition variable */ + unsigned int mounts_signaled; /* Submount signals task complete */ struct list_head mounts; /* List of autofs mounts at current level */ unsigned int submount; /* Is this a submount */ unsigned int submnt_count; /* Number of submounts */ @@ -454,6 +456,7 @@ int expire_offsets_direct(struct autofs_ int mount_autofs_indirect(struct autofs_point *ap); int mount_autofs_direct(struct autofs_point *ap); int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, int is_autofs_fs); +void submount_signal_parent(struct autofs_point *ap, unsigned int success); int umount_autofs(struct autofs_point *ap, int force); int umount_autofs_indirect(struct autofs_point *ap); int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me); @@ -466,6 +469,34 @@ int handle_packet_missing_direct(struct void rm_unwanted(const char *path, int incl, dev_t dev); int count_mounts(struct autofs_point *ap, const char *path); +#define state_mutex_lock(ap) \ +do { \ + int status = pthread_mutex_lock(&ap->state_mutex); \ + if (status) \ + fatal(status); \ +} while(0) + +#define state_mutex_unlock(ap) \ +do{ \ + int status = pthread_mutex_unlock(&ap->state_mutex); \ + if (status) \ + fatal(status); \ +} while (0) + +#define mounts_mutex_lock(ap) \ +do { \ + int status = pthread_mutex_lock(&ap->mounts_mutex); \ + if (status) \ + fatal(status); \ +} while (0) + +#define mounts_mutex_unlock(ap) \ +do { \ + int status = pthread_mutex_unlock(&ap->mounts_mutex); \ + if (status) \ + fatal(status); \ +} while(0) + /* Expire alarm handling routines */ int alarm_start_handler(void); int alarm_add(struct autofs_point *ap, time_t seconds); diff --git a/include/master.h b/include/master.h index dcd77eb..57760a6 100644 --- a/include/master.h +++ b/include/master.h @@ -93,9 +93,25 @@ void master_free_mapent_sources(struct m void master_free_mapent(struct master_mapent *); struct master *master_new(const char *, unsigned int, unsigned int); int master_read_master(struct master *, time_t, int); +void master_notify_submounts(struct autofs_point *, enum states); +void master_signal_submount(struct autofs_point *); void master_notify_state_change(struct master *, int); int master_mount_mounts(struct master *, time_t, int); int master_list_empty(struct master *); int master_kill(struct master *); +#define master_mutex_lock() \ +do { \ + int status = pthread_mutex_lock(&master_mutex); \ + if (status) \ + fatal(status); \ +} while (0) + +#define master_mutex_unlock() \ +do { \ + int status = pthread_mutex_unlock(&master_mutex); \ + if (status) \ + fatal(status); \ +} while (0) + #endif diff --git a/include/parse_subs.h b/include/parse_subs.h index 7c23429..e87cea5 100644 --- a/include/parse_subs.h +++ b/include/parse_subs.h @@ -23,6 +23,7 @@ int check_colon(const char *); int chunklen(const char *, int); int strmcmp(const char *, const char *, int); char *dequote(const char *, int, unsigned int); -char *sanitize_path(const char *, int); +int span_space(const char *, unsigned int); +char *sanitize_path(const char *, int, unsigned int, unsigned int); #endif diff --git a/lib/alarm.c b/lib/alarm.c index dc90b59..8124796 100755 --- a/lib/alarm.c +++ b/lib/alarm.c @@ -26,12 +26,27 @@ static pthread_mutex_t mutex = PTHREAD_M static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; static LIST_HEAD(alarms); +#define alarm_lock() \ +do { \ + int status = pthread_mutex_lock(&mutex); \ + if (status) \ + fatal(status); \ +} while (0) + +#define alarm_unlock() \ +do { \ + int status = pthread_mutex_unlock(&mutex); \ + if (status) \ + fatal(status); \ +} while (0) + void dump_alarms(void) { - struct list_head *head = &alarms; + struct list_head *head; struct list_head *p; pthread_mutex_lock(&mutex); + head = &alarms; list_for_each(p, head) { struct alarm *this; @@ -44,7 +59,7 @@ void dump_alarms(void) /* Insert alarm entry on ordered list. */ int alarm_add(struct autofs_point *ap, time_t seconds) { - struct list_head *head = &alarms; + struct list_head *head; struct list_head *p; struct alarm *new; time_t now = time(NULL); @@ -60,9 +75,9 @@ int alarm_add(struct autofs_point *ap, t new->cancel = 0; new->time = now + seconds; - status = pthread_mutex_lock(&mutex); - if (status) - fatal(status); + alarm_lock(); + + head = &alarms; /* Check if we have a pending alarm */ if (!list_empty(head)) { @@ -95,29 +110,25 @@ int alarm_add(struct autofs_point *ap, t fatal(status); } - status = pthread_mutex_unlock(&mutex); - if (status) - fatal(status); + alarm_unlock(); return 1; } void alarm_delete(struct autofs_point *ap) { - struct list_head *head = &alarms; + struct list_head *head; struct list_head *p; struct alarm *current; unsigned int signal_cancel = 0; int status; - status = pthread_mutex_lock(&mutex); - if (status) - fatal(status); + alarm_lock(); + + head = &alarms; if (list_empty(head)) { - status = pthread_mutex_unlock(&mutex); - if (status) - fatal(status); + alarm_unlock(); return; } @@ -149,22 +160,22 @@ void alarm_delete(struct autofs_point *a fatal(status); } - status = pthread_mutex_unlock(&mutex); - if (status) - fatal(status); + alarm_unlock(); + + return; } static void *alarm_handler(void *arg) { - struct list_head *head = &alarms; + struct list_head *head; struct autofs_point *ap; struct timespec expire; time_t now; int status; - status = pthread_mutex_lock(&mutex); - if (status) - fatal(status); + alarm_lock(); + + head = &alarms; while (1) { struct alarm *current; @@ -192,15 +203,11 @@ static void *alarm_handler(void *arg) continue; } - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_lock(ap); nextstate(ap->state_pipe[1], ST_EXPIRE); - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); free(current); continue; @@ -227,18 +234,12 @@ static void *alarm_handler(void *arg) break; list_del(¤t->list); + free(current); - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); - - nextstate(ap->state_pipe[1], ST_EXPIRE); - - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + alarm_unlock(); + st_add_task(ap, ST_EXPIRE); + alarm_lock(); - free(current); break; } } diff --git a/lib/master.c b/lib/master.c index 1fe17bb..6bf21ad 100644 --- a/lib/master.c +++ b/lib/master.c @@ -131,6 +131,13 @@ void master_free_autofs_point(struct aut if (!ap) return; + if (ap->submount) { + mounts_mutex_lock(ap); + ap->parent->submnt_count--; + list_del(&ap->mounts); + mounts_mutex_unlock(ap); + } + status = pthread_mutex_destroy(&ap->state_mutex); if (status) fatal(status); @@ -291,15 +298,11 @@ struct map_source *master_find_map_sourc struct map_source *source = NULL; int status; - status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); + master_mutex_lock(); source = __master_find_map_source(entry, type, format, argc, argv); - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); return source; } @@ -558,9 +561,7 @@ struct master_mapent *master_find_mapent struct list_head *head, *p; int status; - status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); + master_mutex_lock(); head = &master->mounts; list_for_each(p, head) { @@ -569,16 +570,12 @@ struct master_mapent *master_find_mapent entry = list_entry(p, struct master_mapent, list); if (!strcmp(entry->path, path)) { - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); return entry; } } - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); return NULL; } @@ -630,33 +627,26 @@ void master_add_mapent(struct master *ma { int status; - status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); - + master_mutex_lock(); list_add_tail(&entry->list, &master->mounts); - - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); return; } void master_remove_mapent(struct master_mapent *entry) { + struct autofs_point *ap; int status; - status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); + master_mutex_lock(); if (!list_empty(&entry->list)) list_del_init(&entry->list); - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); + + return; } void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_cache) @@ -749,73 +739,84 @@ int master_read_master(struct master *ma master_mount_mounts(master, age, readall); - status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); + master_mutex_lock(); if (list_empty(&master->mounts)) { error(LOGOPT_ANY, "no mounts in table"); - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); return 0; } - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); return 1; } static void notify_submounts(struct autofs_point *ap, enum states state) { - struct list_head *head; struct list_head *p; struct autofs_point *this; int status; - status = pthread_mutex_lock(&ap->mounts_mutex); - if (status) - fatal(status); - - head = &ap->submounts; - p = head->next; - while (p != head) { - unsigned int empty; + mounts_mutex_lock(ap); + list_for_each(p, &ap->submounts) { this = list_entry(p, struct autofs_point, mounts); - p = p->next; - empty = list_empty(&this->submounts); + if (!list_empty(&this->submounts)) + notify_submounts(this, state); - status = pthread_mutex_lock(&this->state_mutex); - if (status) - fatal(status); + state_mutex_lock(this); - if (!empty) { - pthread_mutex_unlock(&ap->mounts_mutex); - notify_submounts(this, state); - pthread_mutex_lock(&ap->mounts_mutex); + if (this->state == ST_SHUTDOWN) { + state_mutex_unlock(this); + continue; } nextstate(this->state_pipe[1], state); - status = pthread_mutex_unlock(&this->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(this); - status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex); - if (status) { - error(LOGOPT_ANY, "wait for submount failed"); - fatal(status); + ap->mounts_signaled = 0; + while (!ap->mounts_signaled) { + status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex); + if (status) + fatal(status); } } - status = pthread_mutex_unlock(&ap->mounts_mutex); + mounts_mutex_unlock(ap); + + return; +} + +void master_notify_submounts(struct autofs_point *ap, enum states state) +{ + /* Initiate from master entries only */ + if (ap->submount || list_empty(&ap->submounts)) + return; + master_mutex_lock(); + notify_submounts(ap, state); + master_mutex_unlock(); + return; +} + +void master_signal_submount(struct autofs_point *ap) +{ + int status; + + if (!ap->parent) + return; + + mounts_mutex_lock(ap->parent); + + ap->parent->mounts_signaled = 1; + status = pthread_cond_signal(&ap->parent->mounts_cond); if (status) fatal(status); + mounts_mutex_unlock(ap->parent); + return; } @@ -824,41 +825,40 @@ void master_notify_state_change(struct m struct master_mapent *entry; struct autofs_point *ap; struct list_head *p; - enum states next = ST_INVAL; int state_pipe; int status; - status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); + 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; - if (ap->state == ST_INVAL) - return; + state_mutex_lock(ap); - status = pthread_mutex_lock(&ap->state_mutex); + if (ap->state == ST_SHUTDOWN) + goto next; state_pipe = ap->state_pipe[1]; switch (sig) { case SIGTERM: if (ap->state != ST_SHUTDOWN && - ap->state != ST_SHUTDOWN_PENDING) { + ap->state != ST_SHUTDOWN_PENDING && + ap->state != ST_SHUTDOWN_FORCE) { next = ST_SHUTDOWN_PENDING; - notify_submounts(ap, next); nextstate(state_pipe, next); } break; #ifdef ENABLE_FORCED_SHUTDOWN case SIGUSR2: if (ap->state != ST_SHUTDOWN && - ap->state != ST_SHUTDOWN_FORCE) { + ap->state != ST_SHUTDOWN_FORCE && + ap->state != ST_SHUTDOWN_PENDING) { next = ST_SHUTDOWN_FORCE; - notify_submounts(ap, next); nextstate(state_pipe, next); } break; @@ -866,14 +866,11 @@ #endif case SIGUSR1: assert(ap->state == ST_READY); next = ST_PRUNE; - notify_submounts(ap, next); nextstate(state_pipe, next); break; } - - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); +next: + state_mutex_unlock(ap); if (next != ST_INVAL) debug(ap->logopt, @@ -881,9 +878,7 @@ #endif sig, ap->path, ap->state, next); } - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); return; } @@ -946,11 +941,9 @@ static void shutdown_entry(struct master ap = entry->ap; - debug(ap->logopt, "shutting down %s", entry->path); + debug(ap->logopt, "%s", entry->path); - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_lock(ap); state_pipe = ap->state_pipe[1]; @@ -958,12 +951,9 @@ static void shutdown_entry(struct master if (ret == -1) goto next; - notify_submounts(ap, ST_SHUTDOWN_PENDING); nextstate(state_pipe, ST_SHUTDOWN_PENDING); next: - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); return; } @@ -1030,9 +1020,7 @@ static void check_update_map_sources(str /* The map sources have changed */ if (map_stale) { - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_lock(ap); state_pipe = entry->ap->state_pipe[1]; @@ -1040,9 +1028,7 @@ static void check_update_map_sources(str if (ret != -1) nextstate(state_pipe, ST_READMAP); - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); } return; @@ -1053,9 +1039,7 @@ int master_mount_mounts(struct master *m struct list_head *p, *head; int status; - status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); + master_mutex_lock(); head = &master->mounts; p = head->next; @@ -1079,9 +1063,7 @@ int master_mount_mounts(struct master *m check_update_map_sources(this, readall); - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_lock(ap); state_pipe = this->ap->state_pipe[1]; @@ -1089,9 +1071,7 @@ int master_mount_mounts(struct master *m ret = fstat(state_pipe, &st); save_errno = errno; - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + state_mutex_unlock(ap); if (ret == -1 && save_errno == EBADF) if (!master_do_mount(this)) { @@ -1101,9 +1081,7 @@ int master_mount_mounts(struct master *m } } - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); return 1; } @@ -1113,16 +1091,12 @@ int master_list_empty(struct master *mas int status; int res = 0; - status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); + master_mutex_lock(); if (list_empty(&master->mounts)) res = 1; - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + master_mutex_unlock(); return res; } diff --git a/lib/parse_subs.c b/lib/parse_subs.c index ab5de39..5847eb0 100644 --- a/lib/parse_subs.c +++ b/lib/parse_subs.c @@ -16,7 +16,7 @@ * ----------------------------------------------------------------------- */ #include -#include "log.h" +#include "automount.h" /* * Skip whitespace in a string; if we hit a #, consider the rest of the @@ -153,9 +153,11 @@ char *dequote(const char *str, int origl continue; } - if (*scp == '\\') { - quote = 1; - continue; + if (!dquote) { + if (*scp == '\\') { + quote = 1; + continue; + } } } quote = 0; @@ -172,28 +174,76 @@ char *dequote(const char *str, int origl return ret; } -char *sanitize_path(const char *path, int origlen) +int span_space(const char *str, unsigned int maxlen) { - char *ret = malloc(origlen + 1); - char *cp = ret; + const char *p = str; + unsigned int len = 0; + + while (!isblank(*(p++)) && len++ < maxlen) { + if (*p == '\\') { + p += 2; + len += 2; + } + } + return len; +} + +char *sanitize_path(const char *path, int origlen, unsigned int type, unsigned int logopt) +{ + char *slash, *cp, *s_path; const char *scp; int len = origlen; - unsigned int seen_slash = 0, quote = 0; + unsigned int seen_slash = 0, quote = 0, dquote = 0; - if (ret == NULL) + if (type & (LKP_INDIRECT | LKP_DIRECT)) { + slash = strchr(path, '/'); + if (slash) { + if (type == LKP_INDIRECT) + return NULL; + if (*path != '/') + return NULL; + } else { + if (type == LKP_DIRECT) + return NULL; + } + } + + s_path = malloc(origlen + 1); + if (!s_path) return NULL; - for (scp = path; len > 0 && *scp; scp++, len--) { + for (cp = s_path, scp = path; len > 0; scp++, len--) { if (!quote) { - if (*scp == '\\') { - quote = 1; + if (*scp == '"') { + if (dquote) + dquote = 0; + else + dquote = 1; continue; } + if (!dquote) { + /* Badness in string - go away */ + if (*scp < 32) { + free(s_path); + return NULL; + } + + if (*scp == '\\') { + quote = 1; + continue; + } + } + + /* + * Not really proper but we get problems with + * paths with multiple slashes. The kernel + * compresses them so when we get a query there + * should be only single slashes. + */ if (*scp == '/') { if (seen_slash) continue; - seen_slash = 1; } else seen_slash = 0; @@ -203,9 +253,15 @@ char *sanitize_path(const char *path, in } *cp = '\0'; + if (dquote) { + debug(logopt, "unmatched quote in %.*s", origlen, path); + free(s_path); + return NULL; + } + if (origlen > 1 && *(cp - 1) == '/') *(cp - 1) = '\0'; - return ret; + return s_path; } diff --git a/modules/lookup_file.c b/modules/lookup_file.c index 81ade74..1a3ee13 100644 --- a/modules/lookup_file.c +++ b/modules/lookup_file.c @@ -113,7 +113,7 @@ int lookup_init(const char *mapfmt, int return 0; } -static int read_one(FILE *f, char *key, char *mapent) +static int read_one(FILE *f, char *key, unsigned *k_len, char *mapent, unsigned *m_len) { char *kptr, *p; int mapent_len, key_len; @@ -228,11 +228,25 @@ static int read_one(FILE *f, char *key, if (ch == '\n') state = st_begin; else if (!isspace(ch) || escape) { + if (escape) { + if (escape == esc_char) + break; + if (ch <= 32) { + getting = got_nothing; + state = st_badent; + break; + } + p = mapent; + *(p++) = '\\'; + *(p++) = ch; + mapent_len = 2; + } else { + p = mapent; + *(p++) = ch; + mapent_len = 1; + } state = st_getent; - p = mapent; gotten = getting; - *(p++) = ch; - mapent_len = 1; } break; @@ -240,8 +254,8 @@ static int read_one(FILE *f, char *key, if (ch == '\n') { nch = getc(f); if (nch != EOF && isblank(nch)) { - state = st_badent; ungetc(nch, f); + state = st_badent; gotten = got_nothing; warn(LOGOPT_ANY, MODPREFIX "bad map entry \"%s...\" for key " @@ -276,6 +290,9 @@ static int read_one(FILE *f, char *key, if (gotten == got_nothing) goto next; + *k_len = key_len; + *m_len = mapent_len; + return 1; next: @@ -329,7 +346,7 @@ int lookup_read_master(struct master *ma char *ent; struct stat st; FILE *f; - int entry; + int entry, path_len, ent_len; if (master->recurse) return NSS_STATUS_UNAVAIL; @@ -368,7 +385,7 @@ int lookup_read_master(struct master *ma master_init_scan(); while(1) { - entry = read_one(f, path, ent); + entry = read_one(f, path, &path_len, ent, &ent_len); if (!entry) { if (feof(f)) break; @@ -404,7 +421,7 @@ int lookup_read_master(struct master *ma master->name = save_name; } else { - blen = strlen(path) + 1 + strlen(ent) + 1; + blen = path_len + 1 + ent_len + 1; buffer = malloc(blen); if (!buffer) { error(LOGOPT_ANY, @@ -576,7 +593,7 @@ int lookup_read_map(struct autofs_point char *mapent; struct stat st; FILE *f; - int entry; + int entry, k_len, m_len; source = ap->entry->current; ap->entry->current = NULL; @@ -618,7 +635,7 @@ int lookup_read_map(struct autofs_point } while(1) { - entry = read_one(f, key, mapent); + entry = read_one(f, key, &k_len, mapent, &m_len); if (!entry) { if (feof(f)) break; @@ -657,36 +674,17 @@ int lookup_read_map(struct autofs_point master_free_mapent_sources(iap->entry, 0); master_free_mapent(iap->entry); } else { - char *dq_key, *dq_mapent; - - dq_key = dequote(key, strlen(key), ap->logopt); - if (!dq_key) - continue; + char *s_key; - if (*dq_key == '/') { - if (ap->type == LKP_INDIRECT) { - free(dq_key); - continue; - } - } else { - if (ap->type == LKP_DIRECT) { - free(dq_key); - continue; - } - } - - dq_mapent = dequote(mapent, strlen(mapent), ap->logopt); - if (!dq_mapent) { - free(dq_key); + s_key = sanitize_path(key, k_len, ap->type, ap->logopt); + if (!s_key) continue; - } cache_writelock(mc); - cache_update(mc, source, dq_key, dq_mapent, age); + cache_update(mc, source, s_key, mapent, age); cache_unlock(mc); - free(dq_key); - free(dq_mapent); + free(s_key); } if (feof(f)) @@ -702,6 +700,7 @@ int lookup_read_map(struct autofs_point return NSS_STATUS_UNAVAIL; } ctxt->mtime = st.st_mtime; + source->age = age; fclose(f); @@ -721,7 +720,7 @@ static int lookup_one(struct autofs_poin char mapent[MAPENT_MAX_LEN + 1]; time_t age = time(NULL); FILE *f; - int entry, ret; + int entry, ret, k_len, m_len; source = ap->entry->current; ap->entry->current = NULL; @@ -737,7 +736,7 @@ static int lookup_one(struct autofs_poin } while(1) { - entry = read_one(f, mkey, mapent); + entry = read_one(f, mkey, &k_len, mapent, &m_len); if (entry) { /* * If key starts with '+' it has to be an @@ -773,11 +772,30 @@ static int lookup_one(struct autofs_poin if (status) return CHE_COMPLETED; - } else if (strncmp(mkey, key, key_len) == 0) { + } else { + char *s_key; + int eq; + + s_key = sanitize_path(mkey, k_len, ap->type, ap->logopt); + if (!s_key) + continue; + + if (key_len != strlen(s_key)) { + free(s_key); + continue; + } + + eq = strncmp(s_key, key, key_len); + if (eq != 0) + continue; + + free(s_key); + fclose(f); cache_writelock(mc); ret = cache_update(mc, source, key, mapent, age); cache_unlock(mc); + return ret; } } @@ -799,7 +817,7 @@ static int lookup_wild(struct autofs_poi char mapent[MAPENT_MAX_LEN + 1]; time_t age = time(NULL); FILE *f; - int entry, ret; + int entry, ret, k_len, m_len; source = ap->entry->current; ap->entry->current = NULL; @@ -815,7 +833,7 @@ static int lookup_wild(struct autofs_poi } while(1) { - entry = read_one(f, mkey, mapent); + entry = read_one(f, mkey, &k_len, mapent, &m_len); if (entry) { /* * If key starts with '+' it has to be an @@ -848,7 +866,13 @@ static int lookup_wild(struct autofs_poi if (status) return CHE_COMPLETED; - } else if (strncmp(mkey, "*", 1) == 0) { + } else { + int eq; + + eq = (*mkey == '*' && k_len == 1); + if (eq == 0) + continue; + fclose(f); cache_writelock(mc); ret = cache_update(mc, source, "*", mapent, age); @@ -1029,7 +1053,7 @@ int lookup_mount(struct autofs_point *ap cache_readlock(mc); me = cache_lookup(mc, key); - if (me) { + if (me && me->mapent) { pthread_cleanup_push(cache_lock_cleanup, mc); mapent_len = strlen(me->mapent); mapent = alloca(mapent_len + 1); diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c index 16fd1bd..7255794 100644 --- a/modules/lookup_hosts.c +++ b/modules/lookup_hosts.c @@ -107,6 +107,8 @@ int lookup_read_map(struct autofs_point if (status) error(LOGOPT_ANY, MODPREFIX "failed to unlock hostent mutex"); + source->age = age; + return NSS_STATUS_SUCCESS; } diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c index 0bcd249..8c627b4 100644 --- a/modules/lookup_ldap.c +++ b/modules/lookup_ldap.c @@ -1078,8 +1078,8 @@ static int read_one_map(struct autofs_po char *query; LDAPMessage *result, *e; char *class, *info, *entry; - char **keyValue = NULL; - char **values = NULL; + struct berval **bvKey; + struct berval **bvValues; char *attrs[3]; int scope = LDAP_SCOPE_SUBTREE; LDAP *ldap; @@ -1146,11 +1146,14 @@ static int read_one_map(struct autofs_po while (e) { char *mapent = NULL; - char *dq_key, *dq_mapent; + char *k_val; + ber_len_t k_len; + size_t mapent_len; + char *s_key; - keyValue = ldap_get_values(ldap, e, entry); + bvKey = ldap_get_values_len(ldap, e, entry); - if (!keyValue || !*keyValue) { + if (!bvKey || !*bvKey) { e = ldap_next_entry(ldap, e); continue; } @@ -1159,27 +1162,30 @@ static int read_one_map(struct autofs_po * By definition keys must be unique within * each map entry */ - if (ldap_count_values(keyValue) > 1) { + if (ldap_count_values_len(bvKey) > 1) { error(ap->logopt, MODPREFIX - "key %s has duplicate entries - ignoring", - *keyValue); + "key %.*s has duplicate entries - ignoring", + bvKey[0]->bv_len, bvKey[0]->bv_val); goto next; } + k_val = bvKey[0]->bv_val; + k_len = bvKey[0]->bv_len; + /* * Ignore keys beginning with '+' as plus map * inclusion is only valid in file maps. */ - if (**keyValue == '+') { + if (*k_val == '+') { warn(ap->logopt, MODPREFIX "ignoreing '+' map entry - not in file map"); goto next; } - values = ldap_get_values(ldap, e, info); - if (!values || !*values) { + bvValues = ldap_get_values_len(ldap, e, info); + if (!bvValues || !*bvValues) { debug(ap->logopt, MODPREFIX "no %s defined for %s", info, query); goto next; @@ -1196,9 +1202,10 @@ static int read_one_map(struct autofs_po * how to force an ordering. * */ - count = ldap_count_values(values); + count = ldap_count_values_len(bvValues); for (i = 0; i < count; i++) { - int v_len = strlen(values[i]); + char *v_val = bvValues[i]->bv_val; + ber_len_t v_len = bvValues[i]->bv_len; if (!mapent) { mapent = malloc(v_len + 1); @@ -1207,17 +1214,22 @@ static int read_one_map(struct autofs_po estr = strerror_r(errno, buf, MAX_ERR_BUF); error(ap->logopt, MODPREFIX "malloc: %s", estr); + ldap_value_free_len(bvValues); goto next; } - strcpy(mapent, values[i]); + strncpy(mapent, v_val, v_len); + mapent[v_len] = '\0'; + mapent_len = v_len; } else { - int new_size = strlen(mapent) + v_len + 2; + int new_size = mapent_len + v_len + 2; char *new_me; new_me = realloc(mapent, new_size); if (new_me) { mapent = new_me; strcat(mapent, " "); - strcat(mapent, values[i]); + strncat(mapent, v_val, v_len); + mapent[new_size] = '\0'; + mapent_len = new_size; } else { char *estr; estr = strerror_r(errno, buf, MAX_ERR_BUF); @@ -1226,46 +1238,30 @@ static int read_one_map(struct autofs_po } } } - ldap_value_free(values); + ldap_value_free_len(bvValues); - dq_key = dequote(*keyValue, strlen(*keyValue), ap->logopt); - if (!dq_key) - goto next; - - if (*dq_key == '/' && strlen(dq_key) == 1) - *dq_key = '*'; - - if (*dq_key == '/') { - if (ap->type == LKP_INDIRECT) { - free(dq_key); - goto next; - } - } else { - if (ap->type == LKP_DIRECT) { - free(dq_key); + if (*k_val == '/' && k_len == 1) { + if (ap->type == LKP_DIRECT) goto next; - } + *k_val = '*'; } - dq_mapent = dequote(mapent, strlen(mapent), ap->logopt); - if (!mapent) { - free(dq_key); + s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt); + if (!s_key) goto next; - } cache_writelock(mc); - cache_update(mc, source, dq_key, dq_mapent, age); + cache_update(mc, source, s_key, mapent, age); cache_unlock(mc); - free(dq_key); - free(dq_mapent); + free(s_key); next: if (mapent) { free(mapent); mapent = NULL; } - ldap_value_free(keyValue); + ldap_value_free_len(bvKey); e = ldap_next_entry(ldap, e); } @@ -1275,6 +1271,8 @@ next: ldap_msgfree(result); unbind_ldap_connection(ldap, ctxt); + source->age = age; + return NSS_STATUS_SUCCESS; } @@ -1307,12 +1305,11 @@ static int lookup_one(struct autofs_poin char *query; LDAPMessage *result, *e; char *class, *info, *entry; - char **keyValue; - char **values = NULL; + struct berval **bvKey; + struct berval **bvValues; char *attrs[3]; int scope = LDAP_SCOPE_SUBTREE; LDAP *ldap; - char *mapent = NULL; unsigned int wild = 0; int ret = CHE_MISSING; @@ -1390,34 +1387,43 @@ static int lookup_one(struct autofs_poin } while (e) { - keyValue = ldap_get_values(ldap, e, entry); + char *mapent = NULL; + char *k_val; + ber_len_t k_len; + char *s_key; + size_t mapent_len; - if (!keyValue || !*keyValue) { + bvKey = ldap_get_values_len(ldap, e, entry); + if (!bvKey || !*bvKey) { e = ldap_next_entry(ldap, e); continue; } /* By definition keys must be unique within each map entry */ - if (ldap_count_values(keyValue) > 1) { + if (ldap_count_values_len(bvKey) > 1) { error(ap->logopt, - MODPREFIX "key %s has duplicate entries", - *keyValue); + MODPREFIX "key %.*s has duplicate entries", + bvKey[0]->bv_len, bvKey[0]->bv_val); ret = CHE_FAIL; goto next; } debug(ap->logopt, MODPREFIX "examining first entry"); - values = ldap_get_values(ldap, e, info); - if (!values || !*values) { + k_val = bvKey[0]->bv_val; + k_len = bvKey[0]->bv_len; + + bvValues = ldap_get_values_len(ldap, e, info); + if (!bvValues || !*bvValues) { debug(ap->logopt, MODPREFIX "no %s defined for %s", info, query); goto next; } - count = ldap_count_values(values); + count = ldap_count_values_len(bvValues); for (i = 0; i < count; i++) { - int v_len = strlen(values[i]); + char *v_val = bvValues[i]->bv_val; + ber_len_t v_len = bvValues[i]->bv_len; if (!mapent) { mapent = malloc(v_len + 1); @@ -1426,17 +1432,22 @@ static int lookup_one(struct autofs_poin estr = strerror_r(errno, buf, MAX_ERR_BUF); error(ap->logopt, MODPREFIX "malloc: %s", estr); - continue; + ldap_value_free_len(bvValues); + goto next; } - strcpy(mapent, values[i]); + strncpy(mapent, v_val, v_len); + mapent[v_len] = '\0'; + mapent_len = v_len; } else { - int new_size = strlen(mapent) + v_len + 2; + int new_size = mapent_len + v_len + 2; char *new_me; new_me = realloc(mapent, new_size); if (new_me) { mapent = new_me; strcat(mapent, " "); - strcat(mapent, values[i]); + strncat(mapent, v_val, v_len); + mapent[new_size] = '\0'; + mapent_len = new_size; } else { char *estr; estr = strerror_r(errno, buf, MAX_ERR_BUF); @@ -1445,35 +1456,34 @@ static int lookup_one(struct autofs_poin } } } - ldap_value_free(values); - - if (**keyValue == '/') { - if (ap->type == LKP_INDIRECT) { - if (strlen(*keyValue) == 1) { - wild = 1; - **keyValue = '*'; - cache_writelock(mc); - cache_update(mc, - source, *keyValue, mapent, age); - cache_unlock(mc); - } - goto next; - } - } else { + ldap_value_free_len(bvValues); + + if (*k_val == '/' && k_len == 1) { if (ap->type == LKP_DIRECT) goto next; + wild = 1; + cache_writelock(mc); + cache_update(mc, source, "*", mapent, age); + cache_unlock(mc); + goto next; } + s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt); + if (!s_key) + goto next; + cache_writelock(mc); - ret = cache_update(mc, source, *keyValue, mapent, age); + ret = cache_update(mc, source, s_key, mapent, age); cache_unlock(mc); + + free(s_key); next: if (mapent) { free(mapent); mapent = NULL; } - ldap_value_free(keyValue); + ldap_value_free_len(bvKey); e = ldap_next_entry(ldap, e); } diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c index 4bc8820..4ea7609 100644 --- a/modules/lookup_nisplus.c +++ b/modules/lookup_nisplus.c @@ -202,10 +202,13 @@ int lookup_read_map(struct autofs_point result_count = NIS_RES_NUMOBJ(result); while (result_count--) { - char *dq_key, *dq_mapent; + char *s_key; + size_t len; this = &result->objects.objects_val[current++]; key = ENTRY_VAL(this, 0); + len = ENTRY_LEN(this, 0); + /* * Ignore keys beginning with '+' as plus map * inclusion is only valid in file maps. @@ -213,39 +216,23 @@ int lookup_read_map(struct autofs_point if (*key == '+') continue; - dq_key = dequote(key, ENTRY_LEN(this, 0), ap->logopt); - if (!dq_key) + s_key = sanitize_path(key, len, ap->type, ap->logopt); + if (!s_key) continue; - if (*dq_key == '/') { - if (ap->type == LKP_INDIRECT) { - free(dq_key); - continue; - } - } else { - if (ap->type == LKP_DIRECT) { - free(dq_key); - continue; - } - } - mapent = ENTRY_VAL(this, 1); - dq_mapent = dequote(mapent, ENTRY_LEN(this, 1), ap->logopt); - if (!dq_mapent) { - free(dq_key); - continue; - } cache_writelock(mc); - cache_update(mc, source, dq_key, dq_mapent, age); + cache_update(mc, source, s_key, mapent, age); cache_unlock(mc); - free(dq_key); - free(dq_mapent); + free(s_key); } nis_freeresult(result); + source->age = age; + return NSS_STATUS_SUCCESS; } diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c index fcee26b..dec4a21 100644 --- a/modules/lookup_yp.c +++ b/modules/lookup_yp.c @@ -248,7 +248,7 @@ int yp_all_callback(int status, char *yp struct map_source *source = cbdata->source; struct mapent_cache *mc = source->mc; time_t age = cbdata->age; - char *key, *mapent; + char *tmp, *key, *mapent; int ret; if (status != YP_TRUE) @@ -261,34 +261,19 @@ int yp_all_callback(int status, char *yp if (*ypkey == '+') return 0; - key = dequote(ypkey, ypkeylen, ap->logopt); + key = sanitize_path(ypkey, ypkeylen, ap->type, ap->logopt); if (!key) return 0; - if (*key == '/') { - if (ap->type == LKP_INDIRECT) { - free(key); - return 0; - } - } else { - if (ap->type == LKP_DIRECT) { - free(key); - return 0; - } - } - - mapent = dequote(val, vallen, ap->logopt); - if (!mapent) { - free(key); - return 0; - } + mapent = alloca(vallen + 1); + strncpy(mapent, val, vallen); + *(mapent + vallen) = '\0'; cache_writelock(mc); ret = cache_update(mc, source, key, mapent, age); cache_unlock(mc); free(key); - free(mapent); if (ret == CHE_FAIL) return -1; @@ -301,16 +286,18 @@ int lookup_read_map(struct autofs_point struct lookup_context *ctxt = (struct lookup_context *) context; struct ypall_callback ypcb; struct callback_data ypcb_data; + struct map_source *source; char *mapname; int err; - ypcb_data.ap = ap; - ypcb_data.source = ap->entry->current; - ypcb_data.age = age; - + source = ap->entry->current; ap->entry->current = NULL; master_source_current_signal(ap->entry); + ypcb_data.ap = ap; + ypcb_data.source = source; + ypcb_data.age = age; + ypcb.foreach = yp_all_callback; ypcb.data = (char *) &ypcb_data; @@ -342,6 +329,8 @@ int lookup_read_map(struct autofs_point return NSS_STATUS_NOTFOUND; } + source->age = age; + return NSS_STATUS_SUCCESS; } diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c index 768bcbf..95fe00d 100644 --- a/modules/mount_autofs.c +++ b/modules/mount_autofs.c @@ -58,28 +58,26 @@ int mount_mount(struct autofs_point *ap, struct autofs_point *nap; char buf[MAX_ERR_BUF]; char *options, *p; - int ret, rlen; + int ret; + struct list_head *l; - /* Root offset of multi-mount */ - if (*name == '/' && name_len == 1) { - rlen = strlen(root); - name_len = 0; - } else if (*name == '/') - rlen = 0; - else - rlen = strlen(root); - - fullpath = alloca(rlen + name_len + 2); + fullpath = alloca(strlen(root) + name_len + 2); if (!fullpath) { char *estr = strerror_r(errno, buf, MAX_ERR_BUF); error(ap->logopt, MODPREFIX "alloca: %s", estr); return 1; } - if (rlen) - sprintf(fullpath, "%s/%s", root, name); - else - sprintf(fullpath, "%s", name); + /* Root offset of multi-mount */ + if (*name == '/' && name_len == 1) + strcpy(fullpath, root); + else if (*name == '/') + strcpy(fullpath, name); + else { + strcpy(fullpath, root); + strcat(fullpath, "/"); + strcat(fullpath, name); + } if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { error(ap->logopt, @@ -201,14 +199,14 @@ int mount_mount(struct autofs_point *ap, suc.done = 0; suc.status = 0; - pthread_mutex_lock(&ap->mounts_mutex); + mounts_mutex_lock(ap); if (pthread_create(&thid, &thread_attr, handle_mounts, nap)) { crit(ap->logopt, MODPREFIX "failed to create mount handler thread for %s", fullpath); - pthread_mutex_unlock(&ap->mounts_mutex); + mounts_mutex_unlock(ap); status = pthread_mutex_unlock(&suc.mutex); if (status) fatal(status); @@ -221,7 +219,7 @@ int mount_mount(struct autofs_point *ap, while (!suc.done) { status = pthread_cond_wait(&suc.cond, &suc.mutex); if (status) { - pthread_mutex_unlock(&ap->mounts_mutex); + mounts_mutex_unlock(ap); pthread_mutex_unlock(&suc.mutex); fatal(status); } @@ -230,17 +228,18 @@ int mount_mount(struct autofs_point *ap, if (suc.status) { crit(ap->logopt, MODPREFIX "failed to create submount for %s", fullpath); - pthread_mutex_unlock(&ap->mounts_mutex); + mounts_mutex_unlock(ap); status = pthread_mutex_unlock(&suc.mutex); if (status) fatal(status); + master_free_mapent(entry); return 1; } ap->submnt_count++; list_add(&nap->mounts, &ap->submounts); - pthread_mutex_unlock(&ap->mounts_mutex); + mounts_mutex_unlock(ap); status = pthread_mutex_unlock(&suc.mutex); if (status) diff --git a/modules/parse_sun.c b/modules/parse_sun.c index 50f086d..c6dffef 100644 --- a/modules/parse_sun.c +++ b/modules/parse_sun.c @@ -807,7 +807,7 @@ static int parse_mapent(const char *ent, l = chunklen(p, check_colon(p)); loc = dequote(p, l, logopt); if (!loc) { - error(logopt, MODPREFIX "out of memory"); + warn(logopt, MODPREFIX "possible missing location"); free(myoptions); return 0; } @@ -1039,45 +1039,32 @@ int parse_mount(struct autofs_point *ap, /* It's a multi-mount; deal with it */ do { - char *tmp, *path, *myoptions, *loc; + char *path, *myoptions, *loc; + unsigned int s_len = 0; int status; if (*p != '/') { l = 0; - tmp = dequote("/", 1, ap->logopt); + path = dequote("/", 1, ap->logopt); debug(ap->logopt, - MODPREFIX "dequote(\"/\") -> %s", tmp); + MODPREFIX "dequote(\"/\") -> %s", path); } else { - l = chunklen(p, 0); - tmp = dequote(p, l, ap->logopt); + l = span_space(p, mapent_len - (p - pmapent)); + path = sanitize_path(p, l, LKP_MULTI, ap->logopt); debug(ap->logopt, MODPREFIX - "dequote(\"%.*s\") -> %s", l, p, tmp); + "dequote(\"%.*s\") -> %s", l, p, path); } - if (!tmp) { - error(ap->logopt, MODPREFIX "out of memory"); - cache_readlock(mc); - cache_multi_lock(mc); - cache_delete_offset_list(mc, name); - cache_multi_unlock(mc); - cache_unlock(mc); - free(options); - return 1; - } - - path = sanitize_path(tmp, strlen(tmp)); if (!path) { - warn(ap->logopt, MODPREFIX "invalid path"); + error(ap->logopt, MODPREFIX "out of memory"); cache_readlock(mc); cache_multi_lock(mc); cache_delete_offset_list(mc, name); cache_multi_unlock(mc); cache_unlock(mc); - free(tmp); free(options); return 1; } - free(tmp); p += l; p = skipspace(p);