|
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 |
}
|