Blame modules/lookup_program.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *   
Packit 8480eb
 *  lookup_program.c - module for Linux automount to access an
Packit 8480eb
 *                     automount map via a query program 
Packit 8480eb
 *
Packit 8480eb
 *   Copyright 1997 Transmeta Corporation - All Rights Reserved
Packit 8480eb
 *   Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
Packit 8480eb
 *
Packit 8480eb
 *   This program is free software; you can redistribute it and/or modify
Packit 8480eb
 *   it under the terms of the GNU General Public License as published by
Packit 8480eb
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
Packit 8480eb
 *   USA; either version 2 of the License, or (at your option) any later
Packit 8480eb
 *   version; incorporated herein by reference.
Packit 8480eb
 *
Packit 8480eb
 * ----------------------------------------------------------------------- */
Packit 8480eb
Packit 8480eb
#include <ctype.h>
Packit 8480eb
#include <malloc.h>
Packit 8480eb
#include <stdio.h>
Packit 8480eb
#include <string.h>
Packit 8480eb
#include <signal.h>
Packit 8480eb
#include <sys/param.h>
Packit 8480eb
#include <sys/stat.h>
Packit 8480eb
#include <sys/times.h>
Packit 8480eb
#include <sys/types.h>
Packit 8480eb
#include <sys/wait.h>
Packit 8480eb
#include <poll.h>
Packit 8480eb
Packit 8480eb
#define MODULE_LOOKUP
Packit 8480eb
#include "automount.h"
Packit 8480eb
#include "nsswitch.h"
Packit 8480eb
Packit 8480eb
#define MAPFMT_DEFAULT "sun"
Packit 8480eb
Packit 8480eb
#define MODPREFIX "lookup(program): "
Packit 8480eb
Packit 8480eb
struct lookup_context {
Packit 8480eb
	const char *mapname;
Packit 8480eb
	char *mapfmt;
Packit 8480eb
	struct parse_mod *parse;
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
struct parse_context {
Packit 8480eb
	char *optstr;		/* Mount options */
Packit 8480eb
	char *macros;		/* Map wide macro defines */
Packit 8480eb
	struct substvar *subst;	/* $-substitutions */
Packit 8480eb
	int slashify_colons;	/* Change colons to slashes? */
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
int lookup_version = AUTOFS_LOOKUP_VERSION;	/* Required by protocol */
Packit 8480eb
Packit 8480eb
static int do_init(const char *mapfmt,
Packit 8480eb
		   int argc, const char *const *argv,
Packit 8480eb
		   struct lookup_context *ctxt, unsigned int reinit)
Packit 8480eb
{
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	if (argc < 1) {
Packit 8480eb
		logmsg(MODPREFIX "No map name");
Packit 8480eb
		ret = 1;
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
	ctxt->mapname = argv[0];
Packit 8480eb
Packit 8480eb
	if (ctxt->mapname[0] != '/') {
Packit 8480eb
		logmsg(MODPREFIX "program map %s is not an absolute pathname",
Packit 8480eb
		     ctxt->mapname);
Packit 8480eb
		ret = 1;
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (access(ctxt->mapname, X_OK)) {
Packit 8480eb
		logmsg(MODPREFIX "program map %s missing or not executable",
Packit 8480eb
		     ctxt->mapname);
Packit 8480eb
		ret = 1;
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!mapfmt)
Packit 8480eb
		mapfmt = MAPFMT_DEFAULT;
Packit 8480eb
Packit 8480eb
	ctxt->mapfmt = strdup(mapfmt);
Packit 8480eb
	if (!ctxt->mapfmt) {
Packit 8480eb
		logmsg(MODPREFIX "failed to allocate storage for map format");
Packit 8480eb
		ret = 1;
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (reinit) {
Packit 8480eb
		ret = reinit_parse(ctxt->parse, mapfmt, MODPREFIX, argc - 1, argv + 1);
Packit 8480eb
		if (ret)
Packit 8480eb
			logmsg(MODPREFIX "failed to reinit parse context");
Packit 8480eb
	} else {
Packit 8480eb
		ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
Packit 8480eb
		if (!ctxt->parse) {
Packit 8480eb
			logmsg(MODPREFIX "failed to open parse context");
Packit 8480eb
			ret = 1;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
out:
Packit 8480eb
	if (ret && ctxt->mapfmt)
Packit 8480eb
		free(ctxt->mapfmt);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_init(const char *mapfmt,
Packit 8480eb
		int argc, const char *const *argv, void **context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
Packit 8480eb
	*context = NULL;
Packit 8480eb
Packit 8480eb
	ctxt = malloc(sizeof(struct lookup_context));
Packit 8480eb
	if (!ctxt) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	memset(ctxt, 0, sizeof(struct lookup_context));
Packit 8480eb
Packit 8480eb
	if (do_init(mapfmt, argc, argv, ctxt, 0)) {
Packit 8480eb
		free(ctxt);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*context = ctxt;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_reinit(const char *mapfmt,
Packit 8480eb
		  int argc, const char *const *argv, void **context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt = (struct lookup_context *) *context;
Packit 8480eb
	struct lookup_context *new;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	new = malloc(sizeof(struct lookup_context));
Packit 8480eb
	if (!new) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	memset(new, 0, sizeof(struct lookup_context));
Packit 8480eb
Packit 8480eb
	new->parse = ctxt->parse;
Packit 8480eb
	ret = do_init(mapfmt, argc, argv, new, 1);
Packit 8480eb
	if (ret) {
Packit 8480eb
		free(new);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*context = new;
Packit 8480eb
Packit 8480eb
	free(ctxt->mapfmt);
Packit 8480eb
	free(ctxt);
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_read_master(struct master *master, time_t age, void *context)
Packit 8480eb
{
Packit 8480eb
        return NSS_STATUS_UNKNOWN;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
Packit 8480eb
{
Packit 8480eb
	ap->entry->current = NULL;
Packit 8480eb
	master_source_current_signal(ap->entry);
Packit 8480eb
Packit 8480eb
	return NSS_STATUS_UNKNOWN;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static char *lookup_one(struct autofs_point *ap,
Packit 8480eb
			const char *name, int name_len,
Packit 8480eb
			struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	char *mapent = NULL, *mapp, *tmp;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	char errbuf[1024], *errp;
Packit 8480eb
	char ch;
Packit 8480eb
	int pipefd[2], epipefd[2];
Packit 8480eb
	struct pollfd pfd[2];
Packit 8480eb
	pid_t f;
Packit 8480eb
	enum state { st_space, st_map, st_done } state;
Packit 8480eb
	int quoted = 0;
Packit 8480eb
	int distance;
Packit 8480eb
	int alloci = 1;
Packit 8480eb
	int status;
Packit 8480eb
	char *prefix;
Packit 8480eb
Packit 8480eb
	mapent = (char *) malloc(MAPENT_MAX_LEN + 1);
Packit 8480eb
	if (!mapent) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * By default use a prefix with standard environment
Packit 8480eb
	 * variables to prevent system subversion by interpreted
Packit 8480eb
	 * languages.
Packit 8480eb
	 */
Packit 8480eb
	if (defaults_force_std_prog_map_env())
Packit 8480eb
		prefix = NULL;
Packit 8480eb
	else
Packit 8480eb
		prefix = "AUTOFS_";
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * We don't use popen because we don't want to run /bin/sh plus we
Packit 8480eb
	 * want to send stderr to the syslog, and we don't use spawnl()
Packit 8480eb
	 * because we need the pipe hooks
Packit 8480eb
	 */
Packit 8480eb
	if (open_pipe(pipefd)) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "pipe: %s", estr);
Packit 8480eb
		goto out_error;
Packit 8480eb
	}
Packit 8480eb
	if (open_pipe(epipefd)) {
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		close(pipefd[1]);
Packit 8480eb
		goto out_error;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	open_mutex_lock();
Packit 8480eb
	f = fork();
Packit 8480eb
	if (f < 0) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "fork: %s", estr);
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		close(pipefd[1]);
Packit 8480eb
		close(epipefd[0]);
Packit 8480eb
		close(epipefd[1]);
Packit 8480eb
		open_mutex_unlock();
Packit 8480eb
		goto out_error;
Packit 8480eb
	} else if (f == 0) {
Packit 8480eb
		reset_signals();
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		close(epipefd[0]);
Packit 8480eb
		dup2(pipefd[1], STDOUT_FILENO);
Packit 8480eb
		dup2(epipefd[1], STDERR_FILENO);
Packit 8480eb
		close(pipefd[1]);
Packit 8480eb
		close(epipefd[1]);
Packit 8480eb
		if (chdir(ap->path))
Packit 8480eb
			warn(ap->logopt,
Packit 8480eb
			     MODPREFIX "failed to set PWD to %s for map %s",
Packit 8480eb
			     ap->path, ctxt->mapname);
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * MAPFMT_DEFAULT must be "sun" for ->parse_init() to have setup
Packit 8480eb
		 * the macro table.
Packit 8480eb
		 */
Packit 8480eb
		if (ctxt->mapfmt && !strcmp(ctxt->mapfmt, MAPFMT_DEFAULT)) {
Packit 8480eb
			struct parse_context *pctxt = (struct parse_context *) ctxt->parse->context;
Packit 8480eb
			/* Add standard environment as seen by sun map parser */
Packit 8480eb
			pctxt->subst = addstdenv(pctxt->subst, prefix);
Packit 8480eb
			macro_setenv(pctxt->subst);
Packit 8480eb
		}
Packit 8480eb
		execl(ctxt->mapname, ctxt->mapname, name, NULL);
Packit 8480eb
		_exit(255);	/* execl() failed */
Packit 8480eb
	}
Packit 8480eb
	close(pipefd[1]);
Packit 8480eb
	close(epipefd[1]);
Packit 8480eb
	open_mutex_unlock();
Packit 8480eb
Packit 8480eb
	mapp = mapent;
Packit 8480eb
	errp = errbuf;
Packit 8480eb
	state = st_space;
Packit 8480eb
Packit 8480eb
	pfd[0].fd = pipefd[0];
Packit 8480eb
	pfd[0].events = POLLIN;
Packit 8480eb
	pfd[1].fd = epipefd[0];
Packit 8480eb
	pfd[1].events = POLLIN;
Packit 8480eb
Packit 8480eb
	while (1) {
Packit 8480eb
		int bytes;
Packit 8480eb
Packit 8480eb
		if (poll(pfd, 2, -1) < 0 && errno != EINTR)
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		if (pfd[0].fd == -1 && pfd[1].fd == -1)
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		if ((pfd[0].revents & (POLLIN|POLLHUP)) == POLLHUP &&
Packit 8480eb
		    (pfd[1].revents & (POLLIN|POLLHUP)) == POLLHUP)
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		/* Parse maps from stdout */
Packit 8480eb
		if (pfd[0].revents) {
Packit 8480eb
cont:
Packit 8480eb
			bytes = read(pipefd[0], &ch, 1);
Packit 8480eb
			if (bytes == 0)
Packit 8480eb
				goto next;
Packit 8480eb
			else if (bytes < 0) {
Packit 8480eb
				pfd[0].fd = -1;
Packit 8480eb
				state = st_done;
Packit 8480eb
				goto next;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (!quoted && ch == '\\') {
Packit 8480eb
				quoted = 1;
Packit 8480eb
				goto cont;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			switch (state) {
Packit 8480eb
			case st_space:
Packit 8480eb
				if (quoted || !isspace(ch)) {
Packit 8480eb
					*mapp++ = ch;
Packit 8480eb
					state = st_map;
Packit 8480eb
				}
Packit 8480eb
				break;
Packit 8480eb
			case st_map:
Packit 8480eb
				if (!quoted && ch == '\n') {
Packit 8480eb
					*mapp = '\0';
Packit 8480eb
					state = st_done;
Packit 8480eb
					break;
Packit 8480eb
				}
Packit 8480eb
Packit 8480eb
				/* We overwrite up to 3 characters, so we
Packit 8480eb
				 * need to make sure we have enough room
Packit 8480eb
				 * in the buffer for this. */
Packit 8480eb
				/* else */
Packit 8480eb
				if (mapp - mapent > 
Packit 8480eb
				    ((MAPENT_MAX_LEN+1) * alloci) - 3) {
Packit 8480eb
					/*
Packit 8480eb
					 * Alloc another page for map entries.
Packit 8480eb
					 */
Packit 8480eb
					distance = mapp - mapent;
Packit 8480eb
					tmp = realloc(mapent,
Packit 8480eb
						      ((MAPENT_MAX_LEN + 1) * 
Packit 8480eb
						       ++alloci));
Packit 8480eb
					if (!tmp) {
Packit 8480eb
						alloci--;
Packit 8480eb
						logerr(MODPREFIX "realloc: %s",
Packit 8480eb
						      strerror(errno));
Packit 8480eb
						break;
Packit 8480eb
					}
Packit 8480eb
					mapent = tmp;
Packit 8480eb
					mapp = tmp + distance;
Packit 8480eb
				}
Packit 8480eb
				/* 
Packit 8480eb
				 * Eat \ quoting \n, otherwise pass it
Packit 8480eb
				 * through for the parser
Packit 8480eb
				 */
Packit 8480eb
				if (quoted) {
Packit 8480eb
					if (ch == '\n')
Packit 8480eb
						*mapp++ = ' ';
Packit 8480eb
					else {
Packit 8480eb
						*mapp++ = '\\';
Packit 8480eb
						*mapp++ = ch;
Packit 8480eb
					}
Packit 8480eb
				} else
Packit 8480eb
					*mapp++ = ch;
Packit 8480eb
				break;
Packit 8480eb
			case st_done:
Packit 8480eb
				/* Eat characters till there's no more output */
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
			quoted = 0;
Packit 8480eb
			goto cont;
Packit 8480eb
		}
Packit 8480eb
		quoted = 0;
Packit 8480eb
next:
Packit 8480eb
		/* Deal with stderr */
Packit 8480eb
		if (pfd[1].revents) {
Packit 8480eb
			while (1) {
Packit 8480eb
				bytes = read(epipefd[0], &ch, 1);
Packit 8480eb
				if (bytes == 0)
Packit 8480eb
					break;
Packit 8480eb
				else if (bytes < 0) {
Packit 8480eb
					pfd[1].fd = -1;
Packit 8480eb
					break;
Packit 8480eb
				} else if (ch == '\n') {
Packit 8480eb
					*errp = '\0';
Packit 8480eb
					if (errbuf[0])
Packit 8480eb
						logmsg(">> %s", errbuf);
Packit 8480eb
					errp = errbuf;
Packit 8480eb
				} else {
Packit 8480eb
					if (errp >= &errbuf[1023]) {
Packit 8480eb
						*errp = '\0';
Packit 8480eb
						logmsg(">> %s", errbuf);
Packit 8480eb
						errp = errbuf;
Packit 8480eb
					}
Packit 8480eb
					*(errp++) = ch;
Packit 8480eb
				}
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (mapp)
Packit 8480eb
		*mapp = '\0';
Packit 8480eb
	if (errp > errbuf) {
Packit 8480eb
		*errp = '\0';
Packit 8480eb
		logmsg(">> %s", errbuf);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	close(pipefd[0]);
Packit 8480eb
	close(epipefd[0]);
Packit 8480eb
Packit 8480eb
	if (waitpid(f, &status, 0) != f) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "waitpid: %s", estr);
Packit 8480eb
		goto out_error;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (mapp == mapent || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
Packit 8480eb
		info(ap->logopt, MODPREFIX "lookup for %s failed", name);
Packit 8480eb
		goto out_error;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return mapent;
Packit 8480eb
Packit 8480eb
out_error:
Packit 8480eb
	if (mapent)
Packit 8480eb
		free(mapent);
Packit 8480eb
Packit 8480eb
	return NULL;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int lookup_amd_defaults(struct autofs_point *ap,
Packit 8480eb
			       struct map_source *source,
Packit 8480eb
			       struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	struct mapent_cache *mc = source->mc;
Packit 8480eb
	char *ment = lookup_one(ap, "/defaults", 9, ctxt);
Packit 8480eb
	if (ment) {
Packit 8480eb
		char *start = ment + 9;
Packit 8480eb
		int ret;
Packit 8480eb
Packit 8480eb
		while (isblank(*start))
Packit 8480eb
			start++;
Packit 8480eb
		cache_writelock(mc);
Packit 8480eb
		ret = cache_update(mc, source, "/defaults", start, monotonic_time(NULL));
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
		if (ret == CHE_FAIL) {
Packit 8480eb
			free(ment);
Packit 8480eb
			return NSS_STATUS_UNAVAIL;
Packit 8480eb
		}
Packit 8480eb
		free(ment);
Packit 8480eb
	}
Packit 8480eb
	return NSS_STATUS_SUCCESS;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int match_key(struct autofs_point *ap,
Packit 8480eb
		     struct map_source *source,
Packit 8480eb
		     const char *name, int name_len,
Packit 8480eb
		     char **mapent, struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	unsigned int is_amd_format = source->flags & MAP_FLAG_FORMAT_AMD;
Packit 8480eb
	struct mapent_cache *mc = source->mc;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	char *ment;
Packit 8480eb
	char *lkp_key;
Packit 8480eb
	size_t lkp_len;
Packit 8480eb
	char *prefix;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	if (is_amd_format) {
Packit 8480eb
		ret = lookup_amd_defaults(ap, source, ctxt);
Packit 8480eb
		if (ret != NSS_STATUS_SUCCESS) {
Packit 8480eb
			warn(ap->logopt,
Packit 8480eb
			     MODPREFIX "failed to save /defaults entry");
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!is_amd_format) {
Packit 8480eb
		lkp_key = strdup(name);
Packit 8480eb
		lkp_len = name_len;
Packit 8480eb
	} else {
Packit 8480eb
		size_t len;
Packit 8480eb
Packit 8480eb
		if (ap->pref)
Packit 8480eb
			len = strlen(ap->pref) + strlen(name);
Packit 8480eb
		else
Packit 8480eb
			len = strlen(name);
Packit 8480eb
Packit 8480eb
		lkp_key = malloc(len + 1);
Packit 8480eb
		if (!lkp_key) {
Packit 8480eb
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(ap->logopt, MODPREFIX "malloc: %s", estr);
Packit 8480eb
			return NSS_STATUS_UNAVAIL;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (ap->pref) {
Packit 8480eb
			strcpy(lkp_key, ap->pref);
Packit 8480eb
			strcat(lkp_key, name);
Packit 8480eb
		} else
Packit 8480eb
			strcpy(lkp_key, name);
Packit 8480eb
Packit 8480eb
		lkp_len = len;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ment = lookup_one(ap, lkp_key, lkp_len, ctxt);
Packit 8480eb
	if (ment) {
Packit 8480eb
		char *start = ment;
Packit 8480eb
		if (is_amd_format) {
Packit 8480eb
			start = ment + lkp_len;
Packit 8480eb
			while (isblank(*start))
Packit 8480eb
				start++;
Packit 8480eb
		}
Packit 8480eb
		cache_writelock(mc);
Packit 8480eb
		ret = cache_update(mc, source, lkp_key, start, monotonic_time(NULL));
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
		if (ret == CHE_FAIL) {
Packit 8480eb
			free(ment);
Packit 8480eb
			free(lkp_key);
Packit 8480eb
			return NSS_STATUS_UNAVAIL;
Packit 8480eb
		}
Packit 8480eb
		*mapent = strdup(start);
Packit 8480eb
		if (!*mapent) {
Packit 8480eb
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(ap->logopt, MODPREFIX "malloc: %s", estr);
Packit 8480eb
			free(lkp_key);
Packit 8480eb
			free(ment);
Packit 8480eb
			return NSS_STATUS_UNAVAIL;
Packit 8480eb
		}
Packit 8480eb
		free(lkp_key);
Packit 8480eb
		free(ment);
Packit 8480eb
		return NSS_STATUS_SUCCESS;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!is_amd_format) {
Packit 8480eb
		free(lkp_key);
Packit 8480eb
		return NSS_STATUS_NOTFOUND;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ret = NSS_STATUS_NOTFOUND;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * Now strip successive directory components and try a
Packit 8480eb
	 * match against map entries ending with a wildcard and
Packit 8480eb
	 * finally try the wilcard entry itself.
Packit 8480eb
	 */
Packit 8480eb
	while ((prefix = strrchr(lkp_key, '/'))) {
Packit 8480eb
		char *match;
Packit 8480eb
		size_t len;
Packit 8480eb
		*prefix = '\0';
Packit 8480eb
		len = strlen(lkp_key) + 3;
Packit 8480eb
		match = malloc(len);
Packit 8480eb
		if (!match) {
Packit 8480eb
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(ap->logopt, MODPREFIX "malloc: %s", estr);
Packit 8480eb
			free(lkp_key);
Packit 8480eb
			return NSS_STATUS_UNAVAIL;
Packit 8480eb
		}
Packit 8480eb
		len--;
Packit 8480eb
		strcpy(match, lkp_key);
Packit 8480eb
		strcat(match, "/*");
Packit 8480eb
		ment = lookup_one(ap, match, len, ctxt);
Packit 8480eb
		if (ment) {
Packit 8480eb
			char *start = ment + len;
Packit 8480eb
			while (isblank(*start))
Packit 8480eb
				start++;
Packit 8480eb
			cache_writelock(mc);
Packit 8480eb
			ret = cache_update(mc, source, match, start, monotonic_time(NULL));
Packit 8480eb
			cache_unlock(mc);
Packit 8480eb
			if (ret == CHE_FAIL) {
Packit 8480eb
				free(match);
Packit 8480eb
				free(ment);
Packit 8480eb
				free(lkp_key);
Packit 8480eb
				return NSS_STATUS_UNAVAIL;
Packit 8480eb
			}
Packit 8480eb
			free(match);
Packit 8480eb
			*mapent = strdup(start);
Packit 8480eb
			if (!*mapent) {
Packit 8480eb
				char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
				error(ap->logopt, MODPREFIX "malloc: %s", estr);
Packit 8480eb
				free(ment);
Packit 8480eb
				free(lkp_key);
Packit 8480eb
				return NSS_STATUS_UNAVAIL;
Packit 8480eb
			}
Packit 8480eb
			free(ment);
Packit 8480eb
			free(lkp_key);
Packit 8480eb
			return NSS_STATUS_SUCCESS;
Packit 8480eb
		}
Packit 8480eb
		free(match);
Packit 8480eb
	}
Packit 8480eb
	free(lkp_key);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt = (struct lookup_context *) context;
Packit 8480eb
	struct map_source *source;
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	char *mapent = NULL;
Packit 8480eb
	struct mapent *me;
Packit 8480eb
	int ret = 1;
Packit 8480eb
Packit 8480eb
	source = ap->entry->current;
Packit 8480eb
	ap->entry->current = NULL;
Packit 8480eb
	master_source_current_signal(ap->entry);
Packit 8480eb
Packit 8480eb
	mc = source->mc;
Packit 8480eb
Packit 8480eb
	/* Check if we recorded a mount fail for this key anywhere */
Packit 8480eb
	me = lookup_source_mapent(ap, name, LKP_DISTINCT);
Packit 8480eb
	if (me) {
Packit 8480eb
		if (me->status >= monotonic_time(NULL)) {
Packit 8480eb
			cache_unlock(me->mc);
Packit 8480eb
			return NSS_STATUS_NOTFOUND;
Packit 8480eb
		} else {
Packit 8480eb
			struct mapent_cache *smc = me->mc;
Packit 8480eb
			struct mapent *sme;
Packit 8480eb
Packit 8480eb
			if (me->mapent)
Packit 8480eb
				cache_unlock(smc);
Packit 8480eb
			else {
Packit 8480eb
				cache_unlock(smc);
Packit 8480eb
				cache_writelock(smc);
Packit 8480eb
				sme = cache_lookup_distinct(smc, name);
Packit 8480eb
				/* Negative timeout expired for non-existent entry. */
Packit 8480eb
				if (sme && !sme->mapent) {
Packit 8480eb
					if (cache_pop_mapent(sme) == CHE_FAIL)
Packit 8480eb
						cache_delete(smc, name);
Packit 8480eb
				}
Packit 8480eb
				cache_unlock(smc);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Catch installed direct offset triggers */
Packit 8480eb
	cache_readlock(mc);
Packit 8480eb
	me = cache_lookup_distinct(mc, name);
Packit 8480eb
	if (!me) {
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
		/*
Packit 8480eb
		 * If there's a '/' in the name and the offset is not in
Packit 8480eb
		 * the cache then it's not a valid path in the mount tree.
Packit 8480eb
		 */
Packit 8480eb
		if (strchr(name, '/')) {
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      MODPREFIX "offset %s not found", name);
Packit 8480eb
			return NSS_STATUS_NOTFOUND;
Packit 8480eb
		}
Packit 8480eb
	} else {
Packit 8480eb
		/* Otherwise we found a valid offset so try mount it */
Packit 8480eb
		debug(ap->logopt, MODPREFIX "%s -> %s", name, me->mapent);
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * If this is a request for an offset mount (whose entry
Packit 8480eb
		 * must be present in the cache to be valid) or the entry
Packit 8480eb
		 * is newer than the negative timeout value then just
Packit 8480eb
		 * try and mount it. Otherwise try and remove it and
Packit 8480eb
		 * proceed with the program map lookup.
Packit 8480eb
		 */
Packit 8480eb
		if (strchr(name, '/') ||
Packit 8480eb
		    me->age + ap->negative_timeout > monotonic_time(NULL)) {
Packit 8480eb
			char *ent = NULL;
Packit 8480eb
Packit 8480eb
			if (me->mapent) {
Packit 8480eb
				ent = alloca(strlen(me->mapent) + 1);
Packit 8480eb
				strcpy(ent, me->mapent);
Packit 8480eb
			}
Packit 8480eb
			cache_unlock(mc);
Packit 8480eb
			master_source_current_wait(ap->entry);
Packit 8480eb
			ap->entry->current = source;
Packit 8480eb
			ret = ctxt->parse->parse_mount(ap, name,
Packit 8480eb
				 name_len, ent, ctxt->parse->context);
Packit 8480eb
			goto out_free;
Packit 8480eb
		} else {
Packit Bot 7bc25c
			if (IS_MM(me) && !IS_MM_ROOT(me)) {
Packit 8480eb
				cache_unlock(mc);
Packit 8480eb
				warn(ap->logopt, MODPREFIX
Packit 8480eb
				     "unexpected lookup for active multi-mount"
Packit 8480eb
				     " key %s, returning fail", name);
Packit 8480eb
				return NSS_STATUS_UNAVAIL;
Packit 8480eb
			}
Packit 8480eb
			cache_unlock(mc);
Packit 8480eb
			cache_writelock(mc);
Packit 8480eb
			me = cache_lookup_distinct(mc, name);
Packit Bot 0d1189
			if (me) {
Packit Bot 7bc25c
				if (IS_MM(me))
Packit Bot c177e8
					tree_mapent_delete_offsets(mc, name);
Packit 8480eb
				cache_delete(mc, name);
Packit Bot 0d1189
			}
Packit 8480eb
			cache_unlock(mc);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, MODPREFIX "looking up %s", name);
Packit 8480eb
Packit 8480eb
	ret = match_key(ap, source, name, name_len, &mapent, ctxt);
Packit 8480eb
	if (ret != NSS_STATUS_SUCCESS)
Packit 8480eb
		goto out_free;
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, MODPREFIX "%s -> %s", name, mapent);
Packit 8480eb
Packit 8480eb
	master_source_current_wait(ap->entry);
Packit 8480eb
	ap->entry->current = source;
Packit 8480eb
Packit 8480eb
	ret = ctxt->parse->parse_mount(ap, name, name_len,
Packit 8480eb
				       mapent, ctxt->parse->context);
Packit 8480eb
out_free:
Packit 8480eb
	if (mapent)
Packit 8480eb
		free(mapent);
Packit 8480eb
Packit 8480eb
	if (ret) {
Packit 8480eb
		/* Don't update negative cache when re-connecting */
Packit 8480eb
		if (ap->flags & MOUNT_FLAG_REMOUNT)
Packit 8480eb
			return NSS_STATUS_TRYAGAIN;
Packit 8480eb
		cache_writelock(mc);
Packit 8480eb
		cache_update_negative(mc, source, name, ap->negative_timeout);
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
		return NSS_STATUS_TRYAGAIN;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return NSS_STATUS_SUCCESS;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_done(void *context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt = (struct lookup_context *) context;
Packit 8480eb
	int rv = close_parse(ctxt->parse);
Packit 8480eb
	if (ctxt->mapfmt)
Packit 8480eb
		free(ctxt->mapfmt);
Packit 8480eb
	free(ctxt);
Packit 8480eb
	return rv;
Packit 8480eb
}