|
Packit |
8480eb |
/* ----------------------------------------------------------------------- *
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* lookup.c - API layer to implement nsswitch semantics for map reading
|
|
Packit |
8480eb |
* and mount lookups.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* Copyright 2006 Ian Kent <raven@themaw.net>
|
|
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.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8480eb |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8480eb |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8480eb |
* GNU General Public License for more details.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* ----------------------------------------------------------------------- */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include <stdlib.h>
|
|
Packit |
8480eb |
#include <stdio.h>
|
|
Packit |
8480eb |
#include <string.h>
|
|
Packit |
8480eb |
#include <sys/stat.h>
|
|
Packit |
8480eb |
#include "automount.h"
|
|
Packit |
8480eb |
#include "nsswitch.h"
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void nsslist_cleanup(void *arg)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct list_head *nsslist = (struct list_head *) arg;
|
|
Packit |
8480eb |
if (!list_empty(nsslist))
|
|
Packit |
8480eb |
free_sources(nsslist);
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int do_read_master(struct master *master, char *type, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct lookup_mod *lookup;
|
|
Packit |
8480eb |
const char *argv[2];
|
|
Packit |
8480eb |
int argc;
|
|
Packit |
8480eb |
int status;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
argc = 1;
|
|
Packit |
8480eb |
argv[0] = master->name;
|
|
Packit |
8480eb |
argv[1] = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = open_lookup(type, "", NULL, argc, argv, &lookup);
|
|
Packit |
8480eb |
if (status != NSS_STATUS_SUCCESS)
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = lookup->lookup_read_master(master, age, lookup->context);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
close_lookup(lookup);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static char *find_map_path(struct autofs_point *ap, struct map_source *map)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
const char *mname = map->argv[0];
|
|
Packit |
8480eb |
unsigned int mlen = strlen(mname);
|
|
Packit |
8480eb |
char *tok, *ptr = NULL;
|
|
Packit |
8480eb |
char *path = NULL;
|
|
Packit |
8480eb |
char *search_path;
|
|
Packit |
8480eb |
struct stat st;
|
|
Packit |
8480eb |
|
|
Packit Bot |
44a4b2 |
/* Absolute path, just return a copy */
|
|
Packit Bot |
44a4b2 |
if (mname[0] == '/')
|
|
Packit Bot |
44a4b2 |
return strdup(mname);
|
|
Packit Bot |
44a4b2 |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* This is different to the way it is in amd.
|
|
Packit |
8480eb |
* autofs will always try to locate maps in AUTOFS_MAP_DIR
|
|
Packit |
8480eb |
* but amd has no default and will not find a file map that
|
|
Packit |
8480eb |
* isn't a full path when no search_path is configured, either
|
|
Packit |
8480eb |
* in the mount point or global configuration.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
search_path = strdup(AUTOFS_MAP_DIR);
|
|
Packit |
8480eb |
if (map->flags & MAP_FLAG_FORMAT_AMD) {
|
|
Packit |
8480eb |
struct autofs_point *pap = ap;
|
|
Packit |
8480eb |
char *tmp;
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Make sure we get search_path from the root of the
|
|
Packit |
8480eb |
* mount tree, if one is present in the configuration.
|
|
Packit |
8480eb |
* Again different from amd, which ignores the submount
|
|
Packit |
8480eb |
* case.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
while (pap->parent)
|
|
Packit |
8480eb |
pap = pap->parent;
|
|
Packit |
8480eb |
tmp = conf_amd_get_search_path(pap->path);
|
|
Packit |
8480eb |
if (tmp) {
|
|
Packit |
8480eb |
if (search_path)
|
|
Packit |
8480eb |
free(search_path);
|
|
Packit |
8480eb |
search_path = tmp;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (!search_path)
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
tok = strtok_r(search_path, ":", &ptr);
|
|
Packit |
8480eb |
while (tok) {
|
|
Packit |
8480eb |
char *this = malloc(strlen(tok) + mlen + 2);
|
|
Packit |
8480eb |
if (!this) {
|
|
Packit |
8480eb |
free(search_path);
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
strcpy(this, tok);
|
|
Packit |
8480eb |
strcat(this, "/");
|
|
Packit |
8480eb |
strcat(this, mname);
|
|
Packit |
8480eb |
if (!stat(this, &st)) {
|
|
Packit |
8480eb |
path = this;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
free(this);
|
|
Packit |
8480eb |
tok = strtok_r(NULL, ":", &ptr);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
free(search_path);
|
|
Packit |
8480eb |
return path;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int read_master_map(struct master *master, char *type, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
unsigned int logopt = master->logopt;
|
|
Packit |
8480eb |
char *path, *save_name;
|
|
Packit |
8480eb |
int result;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (strcasecmp(type, "files")) {
|
|
Packit |
8480eb |
return do_read_master(master, type, age);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* This is a special case as we need to append the
|
|
Packit |
8480eb |
* normal location to the map name.
|
|
Packit |
8480eb |
* note: It's invalid to specify a relative path.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (strchr(master->name, '/')) {
|
|
Packit |
8480eb |
error(logopt, "relative path invalid in files map name");
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
path = malloc(strlen(AUTOFS_MAP_DIR) + strlen(master->name) + 2);
|
|
Packit |
8480eb |
if (!path)
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
strcpy(path, AUTOFS_MAP_DIR);
|
|
Packit |
8480eb |
strcat(path, "/");
|
|
Packit |
8480eb |
strcat(path, master->name);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
save_name = master->name;
|
|
Packit |
8480eb |
master->name = path;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
result = do_read_master(master, type, age);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
master->name = save_name;
|
|
Packit |
8480eb |
free(path);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return result;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int lookup_nss_read_master(struct master *master, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
unsigned int logopt = master->logopt;
|
|
Packit |
8480eb |
struct list_head nsslist;
|
|
Packit |
8480eb |
struct list_head *head, *p;
|
|
Packit |
8480eb |
int result = NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* If it starts with a '/' it has to be a file or LDAP map */
|
|
Packit |
8480eb |
if (*master->name == '/') {
|
|
Packit |
8480eb |
if (*(master->name + 1) == '/') {
|
|
Packit |
8480eb |
debug(logopt, "reading master ldap %s", master->name);
|
|
Packit |
8480eb |
result = do_read_master(master, "ldap", age);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
debug(logopt, "reading master file %s", master->name);
|
|
Packit |
8480eb |
result = do_read_master(master, "file", age);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (result == NSS_STATUS_UNAVAIL)
|
|
Packit |
8480eb |
master->read_fail = 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return result;
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
char *name = master->name;
|
|
Packit |
8480eb |
char *tmp;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Old style name specification will remain I think. */
|
|
Packit |
8480eb |
tmp = strchr(name, ':');
|
|
Packit |
8480eb |
if (tmp) {
|
|
Packit |
8480eb |
char source[10];
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(source, 0, 10);
|
|
Packit |
8480eb |
if ((!strncmp(name, "file", 4) &&
|
|
Packit |
8480eb |
(name[4] == ',' || name[4] == ':')) ||
|
|
Packit |
8480eb |
(!strncmp(name, "yp", 2) &&
|
|
Packit |
8480eb |
(name[2] == ',' || name[2] == ':')) ||
|
|
Packit |
8480eb |
(!strncmp(name, "nis", 3) &&
|
|
Packit |
8480eb |
(name[3] == ',' || name[3] == ':')) ||
|
|
Packit |
8480eb |
(!strncmp(name, "nisplus", 7) &&
|
|
Packit |
8480eb |
(name[7] == ',' || name[7] == ':')) ||
|
|
Packit |
8480eb |
(!strncmp(name, "ldap", 4) &&
|
|
Packit |
8480eb |
(name[4] == ',' || name[4] == ':')) ||
|
|
Packit |
8480eb |
(!strncmp(name, "ldaps", 5) &&
|
|
Packit |
8480eb |
(name[5] == ',' || name[5] == ':')) ||
|
|
Packit |
8480eb |
(!strncmp(name, "sss", 3) ||
|
|
Packit |
8480eb |
(name[3] == ',' || name[3] == ':')) ||
|
|
Packit |
8480eb |
(!strncmp(name, "dir", 3) &&
|
|
Packit |
8480eb |
(name[3] == ',' || name[3] == ':'))) {
|
|
Packit |
8480eb |
strncpy(source, name, tmp - name);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If it's an ldap map leave the source in the
|
|
Packit |
8480eb |
* name so the lookup module can work out if
|
|
Packit |
8480eb |
* ldaps has been requested.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (strncmp(name, "ldap", 4)) {
|
|
Packit |
8480eb |
master->name = tmp + 1;
|
|
Packit |
8480eb |
debug(logopt, "reading master %s %s",
|
|
Packit |
8480eb |
source, master->name);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
master->name = name;
|
|
Packit |
8480eb |
debug(logopt, "reading master %s %s",
|
|
Packit |
8480eb |
source, tmp + 1);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
result = do_read_master(master, source, age);
|
|
Packit |
8480eb |
master->name = name;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (result == NSS_STATUS_UNAVAIL)
|
|
Packit |
8480eb |
master->read_fail = 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return result;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
INIT_LIST_HEAD(&nsslist);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
result = nsswitch_parse(&nsslist);
|
|
Packit |
8480eb |
if (result) {
|
|
Packit |
8480eb |
if (!list_empty(&nsslist))
|
|
Packit |
8480eb |
free_sources(&nsslist);
|
|
Packit |
8480eb |
error(logopt, "can't to read name service switch config.");
|
|
Packit |
8480eb |
return NSS_STATUS_UNAVAIL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* First one gets it */
|
|
Packit |
8480eb |
result = NSS_STATUS_SUCCESS;
|
|
Packit |
8480eb |
head = &nsslist;
|
|
Packit |
8480eb |
list_for_each(p, head) {
|
|
Packit |
8480eb |
struct nss_source *this;
|
|
Packit |
8480eb |
int status;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = list_entry(p, struct nss_source, list);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (strncmp(this->source, "files", 5) &&
|
|
Packit |
8480eb |
strncmp(this->source, "nis", 3) &&
|
|
Packit |
8480eb |
strncmp(this->source, "nisplus", 7) &&
|
|
Packit |
8480eb |
strncmp(this->source, "ldap", 4) &&
|
|
Packit |
8480eb |
strncmp(this->source, "sss", 3))
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"reading master %s %s", this->source, master->name);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
result = read_master_map(master, this->source, age);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If the name of the master map hasn't been explicitly
|
|
Packit |
8480eb |
* configured and we're not reading an included master map
|
|
Packit |
8480eb |
* then we're using auto.master as the default. Many setups
|
|
Packit |
8480eb |
* also use auto_master as the default master map so we
|
|
Packit |
8480eb |
* check for this map when auto.master isn't found.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (result != NSS_STATUS_SUCCESS &&
|
|
Packit |
8480eb |
!master->depth && !defaults_master_set()) {
|
|
Packit |
8480eb |
char *tmp = strchr(master->name, '.');
|
|
Packit |
8480eb |
if (tmp) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"%s not found, replacing '.' with '_'",
|
|
Packit |
8480eb |
master->name);
|
|
Packit |
8480eb |
*tmp = '_';
|
|
Packit |
8480eb |
result = read_master_map(master, this->source, age);
|
|
Packit |
8480eb |
if (result != NSS_STATUS_SUCCESS)
|
|
Packit |
8480eb |
*tmp = '.';
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* We've been instructed to move onto the next source */
|
|
Packit |
8480eb |
if (result == NSS_STATUS_TRYAGAIN) {
|
|
Packit |
8480eb |
result = NSS_STATUS_SUCCESS;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (result == NSS_STATUS_UNKNOWN ||
|
|
Packit |
8480eb |
result == NSS_STATUS_NOTFOUND) {
|
|
Packit |
8480eb |
debug(logopt, "no map - continuing to next source");
|
|
Packit |
8480eb |
result = NSS_STATUS_SUCCESS;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (result == NSS_STATUS_UNAVAIL)
|
|
Packit |
8480eb |
master->read_fail = 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = check_nss_result(this, result);
|
|
Packit Bot |
c2600d |
if (status >= 0)
|
|
Packit Bot |
c2600d |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!list_empty(&nsslist))
|
|
Packit |
8480eb |
free_sources(&nsslist);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return result;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct lookup_mod *lookup;
|
|
Packit |
8480eb |
int status;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
lookup = NULL;
|
|
Packit |
8480eb |
master_source_writelock(ap->entry);
|
|
Packit |
8480eb |
if (!map->lookup) {
|
|
Packit |
8480eb |
status = open_lookup(map->type, "", map->format,
|
|
Packit |
8480eb |
map->argc, map->argv, &lookup);
|
|
Packit |
8480eb |
if (status != NSS_STATUS_SUCCESS) {
|
|
Packit |
8480eb |
master_source_unlock(ap->entry);
|
|
Packit |
8480eb |
debug(ap->logopt,
|
|
Packit |
8480eb |
"lookup module %s open failed", map->type);
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
map->lookup = lookup;
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
lookup = map->lookup;
|
|
Packit |
8480eb |
status = lookup->lookup_reinit(map->format,
|
|
Packit |
8480eb |
map->argc, map->argv,
|
|
Packit |
8480eb |
&lookup->context);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
warn(ap->logopt,
|
|
Packit |
8480eb |
"lookup module %s reinit failed", map->type);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
master_source_unlock(ap->entry);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!map->stale)
|
|
Packit |
8480eb |
return NSS_STATUS_SUCCESS;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
master_source_current_wait(ap->entry);
|
|
Packit |
8480eb |
ap->entry->current = map;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = lookup->lookup_read_map(ap, age, lookup->context);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (status != NSS_STATUS_SUCCESS)
|
|
Packit |
8480eb |
map->stale = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* For maps that don't support enumeration return success
|
|
Packit |
8480eb |
* and do whatever we must to have autofs function with an
|
|
Packit |
8480eb |
* empty map entry cache.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* For indirect maps that use the browse option, when the
|
|
Packit |
8480eb |
* server is unavailable continue as best we can with
|
|
Packit |
8480eb |
* whatever we have in the cache, if anything.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (status == NSS_STATUS_UNKNOWN ||
|
|
Packit |
8480eb |
(ap->type == LKP_INDIRECT && status == NSS_STATUS_UNAVAIL))
|
|
Packit |
8480eb |
return NSS_STATUS_SUCCESS;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int read_file_source_instance(struct autofs_point *ap, struct map_source *map, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct map_source *instance;
|
|
Packit |
8480eb |
char src_file[] = "file";
|
|
Packit |
8480eb |
char src_prog[] = "program";
|
|
Packit |
8480eb |
struct stat st;
|
|
Packit |
8480eb |
char *type, *format;
|
|
Packit Bot |
44a4b2 |
char *path;
|
|
Packit Bot |
44a4b2 |
|
|
Packit Bot |
44a4b2 |
if (map->argc < 1) {
|
|
Packit Bot |
44a4b2 |
error(ap->logopt, "invalid arguments for autofs_point");
|
|
Packit Bot |
44a4b2 |
return NSS_STATUS_UNKNOWN;
|
|
Packit Bot |
44a4b2 |
}
|
|
Packit Service |
b713d9 |
|
|
Packit Bot |
44a4b2 |
path = find_map_path(ap, map);
|
|
Packit Bot |
44a4b2 |
if (!path)
|
|
Packit Bot |
44a4b2 |
return NSS_STATUS_UNKNOWN;
|
|
Packit Bot |
44a4b2 |
|
|
Packit Bot |
44a4b2 |
if (stat(path, &st) == -1) {
|
|
Packit Bot |
44a4b2 |
warn(ap->logopt, "file map %s not found", path);
|
|
Packit Bot |
44a4b2 |
free(path);
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
44a4b2 |
if (!S_ISREG(st.st_mode)) {
|
|
Packit Bot |
44a4b2 |
free(path);
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit Bot |
44a4b2 |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (st.st_mode & __S_IEXEC)
|
|
Packit |
8480eb |
type = src_prog;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
type = src_file;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
format = map->format;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
instance = master_find_source_instance(map, type, format, 0, NULL);
|
|
Packit |
8480eb |
if (!instance) {
|
|
Packit Bot |
44a4b2 |
const char **argv;
|
|
Packit Bot |
44a4b2 |
int argc;
|
|
Packit Bot |
44a4b2 |
|
|
Packit Bot |
44a4b2 |
argc = map->argc;
|
|
Packit Bot |
44a4b2 |
argv = copy_argv(map->argc, map->argv);
|
|
Packit Bot |
44a4b2 |
if (!argv) {
|
|
Packit Bot |
44a4b2 |
error(ap->logopt, "failed to copy args");
|
|
Packit Bot |
44a4b2 |
free(path);
|
|
Packit Bot |
44a4b2 |
return NSS_STATUS_UNKNOWN;
|
|
Packit Bot |
44a4b2 |
}
|
|
Packit Bot |
44a4b2 |
if (argv[0])
|
|
Packit Bot |
44a4b2 |
free((char *) argv[0]);
|
|
Packit Bot |
44a4b2 |
argv[0] = path;
|
|
Packit Bot |
44a4b2 |
path = NULL;
|
|
Packit Bot |
44a4b2 |
|
|
Packit |
8480eb |
instance = master_add_source_instance(map, type, format, age, argc, argv);
|
|
Packit Bot |
44a4b2 |
free_argv(argc, argv);
|
|
Packit |
8480eb |
if (!instance)
|
|
Packit |
8480eb |
return NSS_STATUS_UNAVAIL;
|
|
Packit |
8480eb |
instance->recurse = map->recurse;
|
|
Packit |
8480eb |
instance->depth = map->depth;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
instance->stale = map->stale;
|
|
Packit |
8480eb |
|
|
Packit Bot |
44a4b2 |
if (path)
|
|
Packit Bot |
44a4b2 |
free(path);
|
|
Packit Bot |
44a4b2 |
|
|
Packit |
8480eb |
return do_read_map(ap, instance, age);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int read_source_instance(struct autofs_point *ap, struct map_source *map, const char *type, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct map_source *instance;
|
|
Packit |
8480eb |
const char *format;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
format = map->format;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
instance = master_find_source_instance(map, type, format, 0, NULL);
|
|
Packit |
8480eb |
if (!instance) {
|
|
Packit |
8480eb |
int argc = map->argc;
|
|
Packit |
8480eb |
const char **argv = map->argv;
|
|
Packit |
8480eb |
instance = master_add_source_instance(map, type, format, age, argc, argv);
|
|
Packit |
8480eb |
if (!instance)
|
|
Packit |
8480eb |
return NSS_STATUS_UNAVAIL;
|
|
Packit |
8480eb |
instance->recurse = map->recurse;
|
|
Packit |
8480eb |
instance->depth = map->depth;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
instance->stale = map->stale;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return do_read_map(ap, instance, age);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void argv_cleanup(void *arg)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct map_source *tmap = (struct map_source *) arg;
|
|
Packit |
8480eb |
/* path is freed in free_argv */
|
|
Packit |
8480eb |
free_argv(tmap->argc, tmap->argv);
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int lookup_map_read_map(struct autofs_point *ap,
|
|
Packit |
8480eb |
struct map_source *map, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
char *path;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!map->argv[0]) {
|
|
Packit |
8480eb |
if (!strcmp(map->type, "hosts"))
|
|
Packit |
8480eb |
return do_read_map(ap, map, age);
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* This is only called when map->type != NULL.
|
|
Packit |
8480eb |
* We only need to look for a map if source type is
|
|
Packit |
8480eb |
* file and the map name doesn't begin with a "/".
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (strncmp(map->type, "file", 4))
|
|
Packit |
8480eb |
return do_read_map(ap, map, age);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map->argv[0][0] == '/')
|
|
Packit |
8480eb |
return do_read_map(ap, map, age);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
path = find_map_path(ap, map);
|
|
Packit |
8480eb |
if (!path)
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map->argc >= 1) {
|
|
Packit |
8480eb |
if (map->argv[0])
|
|
Packit |
8480eb |
free((char *) map->argv[0]);
|
|
Packit |
8480eb |
map->argv[0] = path;
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
error(ap->logopt, "invalid arguments for autofs_point");
|
|
Packit |
8480eb |
free(path);
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return do_read_map(ap, map, age);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static enum nsswitch_status read_map_source(struct nss_source *this,
|
|
Packit |
8480eb |
struct autofs_point *ap, struct map_source *map, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
if (strcasecmp(this->source, "files")) {
|
|
Packit |
8480eb |
return read_source_instance(ap, map, this->source, age);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* This is a special case as we need to append the
|
|
Packit |
8480eb |
* normal location to the map name.
|
|
Packit |
8480eb |
* note: It's invalid to specify a relative path.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (strchr(map->argv[0], '/')) {
|
|
Packit |
8480eb |
error(ap->logopt, "relative path invalid in files map name");
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
44a4b2 |
return read_file_source_instance(ap, map, age);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct master_mapent *entry = ap->entry;
|
|
Packit |
8480eb |
struct list_head nsslist;
|
|
Packit |
8480eb |
struct list_head *head, *p;
|
|
Packit |
8480eb |
struct nss_source *this;
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
enum nsswitch_status status;
|
|
Packit |
8480eb |
unsigned int at_least_one = 0;
|
|
Packit |
8480eb |
int result = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* For each map source (ie. each entry for the mount
|
|
Packit |
8480eb |
* point in the master map) do the nss lookup to
|
|
Packit |
8480eb |
* locate the map and read it.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (source)
|
|
Packit |
8480eb |
map = source;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
map = entry->maps;
|
|
Packit |
8480eb |
while (map) {
|
|
Packit |
8480eb |
/* Is map source up to date or no longer valid */
|
|
Packit |
8480eb |
if (!map->stale || entry->age > map->age) {
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map->type) {
|
|
Packit |
8480eb |
if (!strncmp(map->type, "multi", 5))
|
|
Packit |
8480eb |
debug(ap->logopt, "reading multi map");
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
debug(ap->logopt,
|
|
Packit |
8480eb |
"reading map %s %s",
|
|
Packit |
8480eb |
map->type, map->argv[0]);
|
|
Packit |
8480eb |
result = lookup_map_read_map(ap, map, age);
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* If it starts with a '/' it has to be a file or LDAP map */
|
|
Packit |
8480eb |
if (map->argv && *map->argv[0] == '/') {
|
|
Packit |
8480eb |
if (*(map->argv[0] + 1) == '/') {
|
|
Packit |
8480eb |
char *tmp = strdup("ldap");
|
|
Packit |
8480eb |
if (!tmp) {
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
map->type = tmp;
|
|
Packit |
8480eb |
debug(ap->logopt,
|
|
Packit |
8480eb |
"reading map %s %s", tmp, map->argv[0]);
|
|
Packit |
8480eb |
result = do_read_map(ap, map, age);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
debug(ap->logopt,
|
|
Packit |
8480eb |
"reading map file %s", map->argv[0]);
|
|
Packit |
8480eb |
result = read_file_source_instance(ap, map, age);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
INIT_LIST_HEAD(&nsslist);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(nsslist_cleanup, &nsslist);
|
|
Packit |
8480eb |
status = nsswitch_parse(&nsslist);
|
|
Packit |
8480eb |
pthread_cleanup_pop(0);
|
|
Packit |
8480eb |
if (status) {
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
"can't to read name service switch config.");
|
|
Packit |
8480eb |
result = 1;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(nsslist_cleanup, &nsslist);
|
|
Packit |
8480eb |
head = &nsslist;
|
|
Packit |
8480eb |
list_for_each(p, head) {
|
|
Packit |
8480eb |
this = list_entry(p, struct nss_source, list);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map->flags & MAP_FLAG_FORMAT_AMD &&
|
|
Packit |
8480eb |
!strcmp(this->source, "sss")) {
|
|
Packit |
8480eb |
warn(ap->logopt,
|
|
Packit |
8480eb |
"source sss is not available for amd maps.");
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(ap->logopt,
|
|
Packit |
8480eb |
"reading map %s %s", this->source, map->argv[0]);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
result = read_map_source(this, ap, map, age);
|
|
Packit |
8480eb |
if (result == NSS_STATUS_UNKNOWN)
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Try to avoid updating the map cache if an instance
|
|
Packit |
8480eb |
* is unavailable */
|
|
Packit |
8480eb |
if (result == NSS_STATUS_UNAVAIL)
|
|
Packit |
8480eb |
map->stale = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (result == NSS_STATUS_SUCCESS) {
|
|
Packit |
8480eb |
at_least_one = 1;
|
|
Packit |
8480eb |
result = NSS_STATUS_TRYAGAIN;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = check_nss_result(this, result);
|
|
Packit |
8480eb |
if (status >= 0) {
|
|
Packit |
8480eb |
map = NULL;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
result = NSS_STATUS_SUCCESS;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!map)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!result || at_least_one)
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static char *make_browse_path(unsigned int logopt,
|
|
Packit |
8480eb |
const char *root, const char *key,
|
|
Packit |
8480eb |
const char *prefix)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
unsigned int l_prefix;
|
|
Packit |
8480eb |
unsigned int k_len, r_len;
|
|
Packit |
8480eb |
char *k_start;
|
|
Packit |
8480eb |
char *path;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
k_start = (char *) key;
|
|
Packit |
8480eb |
k_len = strlen(key);
|
|
Packit |
8480eb |
l_prefix = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (prefix) {
|
|
Packit |
8480eb |
l_prefix = strlen(prefix);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (l_prefix > k_len)
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* If the prefix doesn't match the beginning
|
|
Packit |
8480eb |
* of the key this entry isn't a sub directory
|
|
Packit |
8480eb |
* at this level.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (strncmp(key, prefix, l_prefix))
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Directory entry starts following the prefix */
|
|
Packit |
8480eb |
k_start += l_prefix;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* No remaining "/" allowed here */
|
|
Packit |
8480eb |
if (strchr(k_start, '/'))
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
r_len = strlen(root);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if ((r_len + strlen(k_start)) > KEY_MAX_LEN)
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
path = malloc(r_len + k_len + 2);
|
|
Packit |
8480eb |
if (!path) {
|
|
Packit |
8480eb |
warn(logopt, "failed to allocate full path");
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sprintf(path, "%s/%s", root, k_start);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return path;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int lookup_ghost(struct autofs_point *ap, const char *root)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct master_mapent *entry = ap->entry;
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
struct mapent_cache *mc;
|
|
Packit |
8480eb |
struct mapent *me;
|
|
Packit |
8480eb |
char buf[MAX_ERR_BUF];
|
|
Packit |
8480eb |
struct stat st;
|
|
Packit |
8480eb |
char *fullpath;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!strcmp(ap->path, "/-"))
|
|
Packit |
8480eb |
return LKP_FAIL | LKP_DIRECT;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!(ap->flags & MOUNT_FLAG_GHOST))
|
|
Packit |
8480eb |
return LKP_INDIRECT;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(master_source_lock_cleanup, entry);
|
|
Packit |
8480eb |
master_source_readlock(entry);
|
|
Packit |
8480eb |
map = entry->maps;
|
|
Packit |
8480eb |
while (map) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Only consider map sources that have been read since
|
|
Packit |
8480eb |
* the map entry was last updated.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (entry->age > map->age) {
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mc = map->mc;
|
|
Packit |
8480eb |
pthread_cleanup_push(cache_lock_cleanup, mc);
|
|
Packit |
8480eb |
cache_readlock(mc);
|
|
Packit |
8480eb |
me = cache_enumerate(mc, NULL);
|
|
Packit |
8480eb |
while (me) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Map entries that have been created in the cache
|
|
Packit |
8480eb |
* due to a negative lookup shouldn't have directories
|
|
Packit |
8480eb |
* created if they haven't already been created.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!me->mapent)
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Wildcard cannot be a browse directory and amd map
|
|
Packit |
8480eb |
* keys may end with the wildcard.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (strchr(me->key, '*'))
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* This will also take care of amd "/defaults" entry as
|
|
Packit |
8480eb |
* amd map keys are not allowd to start with "/"
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (*me->key == '/') {
|
|
Packit |
8480eb |
if (map->flags & MAP_FLAG_FORMAT_AMD)
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* It's a busy multi-mount - leave till next time */
|
|
Packit Bot |
7bc25c |
if (IS_MM(me))
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
"invalid key %s", me->key);
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
fullpath = make_browse_path(ap->logopt,
|
|
Packit |
8480eb |
root, me->key, ap->pref);
|
|
Packit |
8480eb |
if (!fullpath)
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = stat(fullpath, &st);
|
|
Packit |
8480eb |
if (ret == -1 && errno != ENOENT) {
|
|
Packit |
8480eb |
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
Packit |
8480eb |
warn(ap->logopt, "stat error %s", estr);
|
|
Packit |
8480eb |
free(fullpath);
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Directory already exists? */
|
|
Packit |
8480eb |
if (!ret) {
|
|
Packit |
8480eb |
free(fullpath);
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
bc4df2 |
ret = mkdir_path(fullpath, mp_mode);
|
|
Packit |
8480eb |
if (ret < 0 && errno != EEXIST) {
|
|
Packit |
8480eb |
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
Packit |
8480eb |
warn(ap->logopt,
|
|
Packit |
8480eb |
"mkdir_path %s failed: %s", fullpath, estr);
|
|
Packit |
8480eb |
free(fullpath);
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (stat(fullpath, &st) != -1) {
|
|
Packit |
8480eb |
me->dev = st.st_dev;
|
|
Packit |
8480eb |
me->ino = st.st_ino;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
free(fullpath);
|
|
Packit |
8480eb |
next:
|
|
Packit |
8480eb |
me = cache_enumerate(mc, me);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return LKP_INDIRECT;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int do_lookup_mount(struct autofs_point *ap, struct map_source *map, const char *name, int name_len)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct lookup_mod *lookup;
|
|
Packit |
8480eb |
int status;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!map->lookup) {
|
|
Packit |
8480eb |
status = open_lookup(map->type, "",
|
|
Packit |
8480eb |
map->format, map->argc, map->argv, &lookup);
|
|
Packit |
8480eb |
if (status != NSS_STATUS_SUCCESS) {
|
|
Packit |
8480eb |
debug(ap->logopt,
|
|
Packit |
8480eb |
"lookup module %s open failed", map->type);
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
map->lookup = lookup;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
lookup = map->lookup;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
master_source_current_wait(ap->entry);
|
|
Packit |
8480eb |
ap->entry->current = map;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = lookup->lookup_mount(ap, name, name_len, lookup->context);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int lookup_amd_instance(struct autofs_point *ap,
|
|
Packit |
8480eb |
struct map_source *map,
|
|
Packit |
8480eb |
const char *name, int name_len)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct map_source *instance;
|
|
Packit Bot |
5cfc5d |
struct mnt_list *mnt;
|
|
Packit |
8480eb |
const char *argv[2];
|
|
Packit |
8480eb |
const char **pargv = NULL;
|
|
Packit |
8480eb |
int argc = 0;
|
|
Packit |
8480eb |
struct mapent *me;
|
|
Packit |
8480eb |
char *m_key;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
me = cache_lookup_distinct(map->mc, name);
|
|
Packit Bot |
7bc25c |
if (!me || !IS_MM(me)) {
|
|
Packit |
8480eb |
error(ap->logopt, "expected multi mount entry not found");
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
c177e8 |
m_key = malloc(ap->len + MM_ROOT(me)->len + 2);
|
|
Packit |
8480eb |
if (!m_key) {
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
"failed to allocate storage for search key");
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
strcpy(m_key, ap->path);
|
|
Packit |
8480eb |
strcat(m_key, "/");
|
|
Packit Bot |
7bc25c |
strcat(m_key, MM_ROOT(me)->key);
|
|
Packit Bot |
5cfc5d |
|
|
Packit Bot |
5cfc5d |
mnt = mnts_find_amdmount(m_key);
|
|
Packit |
8480eb |
free(m_key);
|
|
Packit |
8480eb |
|
|
Packit Bot |
5cfc5d |
if (!mnt) {
|
|
Packit |
8480eb |
error(ap->logopt, "expected amd mount entry not found");
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
5cfc5d |
if (strcmp(mnt->amd_type, "host")) {
|
|
Packit Bot |
5cfc5d |
error(ap->logopt, "unexpected map type %s", mnt->amd_type);
|
|
Packit Bot |
5cfc5d |
mnts_put_mount(mnt);
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
5cfc5d |
if (mnt->amd_opts && *mnt->amd_opts) {
|
|
Packit Bot |
5cfc5d |
argv[0] = mnt->amd_opts;
|
|
Packit |
8480eb |
argv[1] = NULL;
|
|
Packit |
8480eb |
pargv = argv;
|
|
Packit |
8480eb |
argc = 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
instance = master_find_source_instance(map, "hosts", "sun", argc, pargv);
|
|
Packit |
8480eb |
/* If this is an nss map instance it may have an amd host map sub instance */
|
|
Packit |
8480eb |
if (!instance && map->instance) {
|
|
Packit |
8480eb |
struct map_source *next = map->instance;
|
|
Packit |
8480eb |
while (next) {
|
|
Packit |
8480eb |
instance = master_find_source_instance(next,
|
|
Packit |
8480eb |
"hosts", "sun", argc, pargv);
|
|
Packit |
8480eb |
if (instance)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
next = next->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (!instance) {
|
|
Packit Bot |
5cfc5d |
mnts_put_mount(mnt);
|
|
Packit |
8480eb |
error(ap->logopt, "expected hosts map instance not found");
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
}
|
|
Packit Bot |
5cfc5d |
mnts_put_mount(mnt);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return do_lookup_mount(ap, instance, name, name_len);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int lookup_name_file_source_instance(struct autofs_point *ap, struct map_source *map, const char *name, int name_len)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct map_source *instance;
|
|
Packit |
8480eb |
char src_file[] = "file";
|
|
Packit |
8480eb |
char src_prog[] = "program";
|
|
Packit |
8480eb |
time_t age = monotonic_time(NULL);
|
|
Packit |
8480eb |
struct stat st;
|
|
Packit |
8480eb |
char *type, *format;
|
|
Packit Bot |
44a4b2 |
char *path;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (*name == '/' && map->flags & MAP_FLAG_FORMAT_AMD)
|
|
Packit |
8480eb |
return lookup_amd_instance(ap, map, name, name_len);
|
|
Packit |
8480eb |
|
|
Packit Bot |
44a4b2 |
if (map->argc < 1) {
|
|
Packit Bot |
44a4b2 |
error(ap->logopt, "invalid arguments for autofs_point");
|
|
Packit Bot |
44a4b2 |
return NSS_STATUS_UNKNOWN;
|
|
Packit Bot |
44a4b2 |
}
|
|
Packit Bot |
44a4b2 |
|
|
Packit Bot |
44a4b2 |
path = find_map_path(ap, map);
|
|
Packit Bot |
44a4b2 |
if (!path)
|
|
Packit Bot |
44a4b2 |
return NSS_STATUS_UNKNOWN;
|
|
Packit Bot |
44a4b2 |
|
|
Packit Bot |
44a4b2 |
if (stat(path, &st) == -1) {
|
|
Packit |
8480eb |
debug(ap->logopt, "file map not found");
|
|
Packit Bot |
44a4b2 |
free(path);
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
44a4b2 |
if (!S_ISREG(st.st_mode)) {
|
|
Packit Bot |
44a4b2 |
free(path);
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit Bot |
44a4b2 |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (st.st_mode & __S_IEXEC)
|
|
Packit |
8480eb |
type = src_prog;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
type = src_file;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
format = map->format;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
instance = master_find_source_instance(map, type, format, 0, NULL);
|
|
Packit |
8480eb |
if (!instance) {
|
|
Packit Bot |
44a4b2 |
const char **argv;
|
|
Packit Bot |
44a4b2 |
int argc;
|
|
Packit Bot |
44a4b2 |
|
|
Packit Bot |
44a4b2 |
argc = map->argc;
|
|
Packit Bot |
44a4b2 |
argv = copy_argv(map->argc, map->argv);
|
|
Packit Bot |
44a4b2 |
if (!argv) {
|
|
Packit Bot |
44a4b2 |
error(ap->logopt, "failed to copy args");
|
|
Packit Bot |
44a4b2 |
free(path);
|
|
Packit Bot |
44a4b2 |
return NSS_STATUS_UNKNOWN;
|
|
Packit Bot |
44a4b2 |
}
|
|
Packit Bot |
44a4b2 |
if (argv[0])
|
|
Packit Bot |
44a4b2 |
free((char *) argv[0]);
|
|
Packit Bot |
44a4b2 |
argv[0] = path;
|
|
Packit Bot |
44a4b2 |
path = NULL;
|
|
Packit Bot |
44a4b2 |
|
|
Packit |
8480eb |
instance = master_add_source_instance(map, type, format, age, argc, argv);
|
|
Packit Bot |
44a4b2 |
free_argv(argc, argv);
|
|
Packit |
8480eb |
if (!instance)
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit |
8480eb |
instance->recurse = map->recurse;
|
|
Packit |
8480eb |
instance->depth = map->depth;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
44a4b2 |
if (path)
|
|
Packit Bot |
44a4b2 |
free(path);
|
|
Packit Bot |
44a4b2 |
|
|
Packit |
8480eb |
return do_lookup_mount(ap, instance, name, name_len);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int lookup_name_source_instance(struct autofs_point *ap, struct map_source *map, const char *type, const char *name, int name_len)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct map_source *instance;
|
|
Packit |
8480eb |
const char *format;
|
|
Packit |
8480eb |
time_t age = monotonic_time(NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (*name == '/' && map->flags & MAP_FLAG_FORMAT_AMD)
|
|
Packit |
8480eb |
return lookup_amd_instance(ap, map, name, name_len);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
format = map->format;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
instance = master_find_source_instance(map, type, format, 0, NULL);
|
|
Packit |
8480eb |
if (!instance) {
|
|
Packit |
8480eb |
int argc = map->argc;
|
|
Packit |
8480eb |
const char **argv = map->argv;
|
|
Packit |
8480eb |
instance = master_add_source_instance(map, type, format, age, argc, argv);
|
|
Packit |
8480eb |
if (!instance)
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit |
8480eb |
instance->recurse = map->recurse;
|
|
Packit |
8480eb |
instance->depth = map->depth;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return do_lookup_mount(ap, instance, name, name_len);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int do_name_lookup_mount(struct autofs_point *ap,
|
|
Packit |
8480eb |
struct map_source *map,
|
|
Packit |
8480eb |
const char *name, int name_len)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
char *path;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!map->argv[0]) {
|
|
Packit |
8480eb |
if (!strcmp(map->type, "hosts"))
|
|
Packit |
8480eb |
return do_lookup_mount(ap, map, name, name_len);
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (*name == '/' && map->flags & MAP_FLAG_FORMAT_AMD)
|
|
Packit |
8480eb |
return lookup_amd_instance(ap, map, name, name_len);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* This is only called when map->type != NULL.
|
|
Packit |
8480eb |
* We only need to look for a map if source type is
|
|
Packit |
8480eb |
* file and the map name doesn't begin with a "/".
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (strncmp(map->type, "file", 4))
|
|
Packit |
8480eb |
return do_lookup_mount(ap, map, name, name_len);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map->argv[0][0] == '/')
|
|
Packit |
8480eb |
return do_lookup_mount(ap, map, name, name_len);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
path = find_map_path(ap, map);
|
|
Packit |
8480eb |
if (!path)
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map->argc >= 1) {
|
|
Packit |
8480eb |
if (map->argv[0])
|
|
Packit |
8480eb |
free((char *) map->argv[0]);
|
|
Packit |
8480eb |
map->argv[0] = path;
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
error(ap->logopt, "invalid arguments for autofs_point");
|
|
Packit |
8480eb |
free(path);
|
|
Packit |
8480eb |
return NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return do_lookup_mount(ap, map, name, name_len);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static enum nsswitch_status lookup_map_name(struct nss_source *this,
|
|
Packit |
8480eb |
struct autofs_point *ap, struct map_source *map,
|
|
Packit |
8480eb |
const char *name, int name_len)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
if (strcasecmp(this->source, "files"))
|
|
Packit |
8480eb |
return lookup_name_source_instance(ap, map,
|
|
Packit |
8480eb |
this->source, name, name_len);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* autofs build-in map for nsswitch "files" is "file".
|
|
Packit |
8480eb |
* This is a special case as we need to append the
|
|
Packit |
8480eb |
* normal location to the map name.
|
|
Packit |
8480eb |
* note: we consider it invalid to specify a relative
|
|
Packit |
8480eb |
* path.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (strchr(map->argv[0], '/')) {
|
|
Packit |
8480eb |
error(ap->logopt, "relative path invalid in files map name");
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
44a4b2 |
return lookup_name_file_source_instance(ap, map, name, name_len);
|
|
Packit Service |
5a0782 |
}
|
|
Packit Service |
5a0782 |
|
|
Packit Bot |
7679ed |
static struct map_source *lookup_get_map_source(struct master_mapent *entry)
|
|
Packit Bot |
7679ed |
{
|
|
Packit Bot |
7679ed |
struct map_source *map = entry->maps;
|
|
Packit Bot |
7679ed |
struct stat st;
|
|
Packit Bot |
7679ed |
char *type;
|
|
Packit Bot |
7679ed |
|
|
Packit Bot |
7679ed |
if (map->type || *map->argv[0] != '/')
|
|
Packit Bot |
7679ed |
return map;
|
|
Packit Bot |
7679ed |
|
|
Packit Bot |
7679ed |
if (*(map->argv[0] + 1) == '/')
|
|
Packit Bot |
7679ed |
return map;
|
|
Packit Bot |
7679ed |
|
|
Packit Bot |
7679ed |
if (stat(map->argv[0], &st) == -1)
|
|
Packit Bot |
7679ed |
return NULL;
|
|
Packit Bot |
7679ed |
|
|
Packit Bot |
7679ed |
if (!S_ISREG(st.st_mode))
|
|
Packit Bot |
7679ed |
return NULL;
|
|
Packit Bot |
7679ed |
|
|
Packit Bot |
7679ed |
if (st.st_mode & __S_IEXEC)
|
|
Packit Bot |
7679ed |
type = "program";
|
|
Packit Bot |
7679ed |
else
|
|
Packit Bot |
7679ed |
type = "file";
|
|
Packit Bot |
7679ed |
|
|
Packit Bot |
7679ed |
/* This is a file source with a path starting with "/".
|
|
Packit Bot |
7679ed |
* But file maps can be either plain text or executable
|
|
Packit Bot |
7679ed |
* so they use a map instance and the actual map source
|
|
Packit Bot |
7679ed |
* remains untouched.
|
|
Packit Bot |
7679ed |
*/
|
|
Packit Bot |
7679ed |
return master_find_source_instance(map, type, map->format, 0, NULL);
|
|
Packit Bot |
7679ed |
}
|
|
Packit Bot |
7679ed |
|
|
Packit |
8480eb |
static void update_negative_cache(struct autofs_point *ap, struct map_source *source, const char *name)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct master_mapent *entry = ap->entry;
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
struct mapent *me;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Don't update negative cache for included maps */
|
|
Packit |
8480eb |
if (source && source->depth)
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Don't update the wildcard */
|
|
Packit |
8480eb |
if (strlen(name) == 1 && *name == '*')
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Have we recorded the lookup fail for negative caching? */
|
|
Packit |
8480eb |
me = lookup_source_mapent(ap, name, LKP_DISTINCT);
|
|
Packit |
8480eb |
if (me)
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Already exists in the cache, the mount fail updates
|
|
Packit |
8480eb |
* will update negative timeout status.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
cache_unlock(me->mc);
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
if (!defaults_disable_not_found_message()) {
|
|
Packit |
8480eb |
/* This really should be a warning but the original
|
|
Packit |
8480eb |
* request for this needed it to be unconditional.
|
|
Packit |
8480eb |
* That produces, IMHO, unnecessary noise in the log
|
|
Packit |
8480eb |
* so a configuration option has been added to provide
|
|
Packit |
8480eb |
* the ability to turn it off.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
logmsg("key \"%s\" not found in map source(s).", name);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
7679ed |
/* Doesn't exist in any source, just add it somewhere.
|
|
Packit Bot |
7679ed |
* Also take care to use the same map source used by
|
|
Packit Bot |
7679ed |
* map reads and key lookups for the update.
|
|
Packit Bot |
7679ed |
*/
|
|
Packit |
8480eb |
if (source)
|
|
Packit |
8480eb |
map = source;
|
|
Packit |
8480eb |
else
|
|
Packit Bot |
7679ed |
map = lookup_get_map_source(entry);
|
|
Packit |
8480eb |
if (map) {
|
|
Packit |
8480eb |
time_t now = monotonic_time(NULL);
|
|
Packit |
8480eb |
int rv = CHE_FAIL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
cache_writelock(map->mc);
|
|
Packit |
8480eb |
me = cache_lookup_distinct(map->mc, name);
|
|
Packit |
8480eb |
if (me)
|
|
Packit |
8480eb |
rv = cache_push_mapent(me, NULL);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
rv = cache_update(map->mc, map, name, NULL, now);
|
|
Packit |
8480eb |
if (rv != CHE_FAIL) {
|
|
Packit |
8480eb |
me = cache_lookup_distinct(map->mc, name);
|
|
Packit |
8480eb |
if (me)
|
|
Packit |
8480eb |
me->status = now + ap->negative_timeout;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
cache_unlock(map->mc);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct master_mapent *entry = ap->entry;
|
|
Packit |
8480eb |
struct list_head nsslist;
|
|
Packit |
8480eb |
struct list_head *head, *p;
|
|
Packit |
8480eb |
struct nss_source *this;
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
enum nsswitch_status status;
|
|
Packit |
8480eb |
int result = NSS_STATUS_UNKNOWN;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* For each map source (ie. each entry for the mount
|
|
Packit |
8480eb |
* point in the master map) do the nss lookup to
|
|
Packit |
8480eb |
* locate the map and lookup the name.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
pthread_cleanup_push(master_source_lock_cleanup, entry);
|
|
Packit |
8480eb |
master_source_readlock(entry);
|
|
Packit |
8480eb |
if (source)
|
|
Packit |
8480eb |
map = source;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
map = entry->maps;
|
|
Packit |
8480eb |
while (map) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Only consider map sources that have been read since
|
|
Packit |
8480eb |
* the map entry was last updated.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (entry->age > map->age) {
|
|
Packit |
8480eb |
status = NSS_STATUS_UNAVAIL;
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sched_yield();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map->type) {
|
|
Packit |
8480eb |
result = do_name_lookup_mount(ap, map, name, name_len);
|
|
Packit |
8480eb |
if (result == NSS_STATUS_SUCCESS)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* If it starts with a '/' it has to be a file or LDAP map */
|
|
Packit |
8480eb |
if (*map->argv[0] == '/') {
|
|
Packit |
8480eb |
if (*(map->argv[0] + 1) == '/') {
|
|
Packit |
8480eb |
char *tmp = strdup("ldap");
|
|
Packit |
8480eb |
if (!tmp) {
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
status = NSS_STATUS_TRYAGAIN;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
map->type = tmp;
|
|
Packit |
8480eb |
result = do_lookup_mount(ap, map, name, name_len);
|
|
Packit |
8480eb |
} else
|
|
Packit |
8480eb |
result = lookup_name_file_source_instance(ap, map, name, name_len);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (result == NSS_STATUS_SUCCESS)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
INIT_LIST_HEAD(&nsslist);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = nsswitch_parse(&nsslist);
|
|
Packit |
8480eb |
if (status) {
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
"can't to read name service switch config.");
|
|
Packit |
8480eb |
result = 1;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
head = &nsslist;
|
|
Packit |
8480eb |
list_for_each(p, head) {
|
|
Packit |
8480eb |
this = list_entry(p, struct nss_source, list);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map->flags & MAP_FLAG_FORMAT_AMD &&
|
|
Packit |
8480eb |
!strcmp(this->source, "sss")) {
|
|
Packit |
8480eb |
warn(ap->logopt,
|
|
Packit |
8480eb |
"source sss is not available for amd maps.");
|
|
Packit |
8480eb |
result = NSS_STATUS_UNAVAIL;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
result = lookup_map_name(this, ap, map, name, name_len);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (result == NSS_STATUS_UNKNOWN)
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = check_nss_result(this, result);
|
|
Packit |
8480eb |
if (status >= 0) {
|
|
Packit |
8480eb |
map = NULL;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!list_empty(&nsslist))
|
|
Packit |
8480eb |
free_sources(&nsslist);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!map)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (ap->state != ST_INIT)
|
|
Packit |
8480eb |
send_map_update_request(ap);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* The last source lookup will return NSS_STATUS_NOTFOUND if the
|
|
Packit |
8480eb |
* map exits and the key has not been found but the map may also
|
|
Packit |
8480eb |
* not exist in which case the key is also not found.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (result == NSS_STATUS_NOTFOUND || result == NSS_STATUS_UNAVAIL)
|
|
Packit |
8480eb |
update_negative_cache(ap, source, name);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return !result;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void lookup_close_lookup_instances(struct map_source *map)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct map_source *instance;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
instance = map->instance;
|
|
Packit |
8480eb |
while (instance) {
|
|
Packit |
8480eb |
lookup_close_lookup_instances(instance);
|
|
Packit |
8480eb |
instance = instance->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map->lookup) {
|
|
Packit |
8480eb |
close_lookup(map->lookup);
|
|
Packit |
8480eb |
map->lookup = NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void lookup_close_lookup(struct autofs_point *ap)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = ap->entry->maps;
|
|
Packit |
8480eb |
if (!map)
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (map) {
|
|
Packit |
8480eb |
lookup_close_lookup_instances(map);
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static char *make_fullpath(struct autofs_point *ap, const char *key)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
char *path = NULL;
|
|
Packit |
8480eb |
int l;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (*key != '/')
|
|
Packit |
8480eb |
path = make_browse_path(ap->logopt, ap->path, key, ap->pref);
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
l = strlen(key) + 1;
|
|
Packit |
8480eb |
if (l > KEY_MAX_LEN)
|
|
Packit |
8480eb |
goto out;
|
|
Packit |
8480eb |
path = malloc(l);
|
|
Packit |
8480eb |
if (!path)
|
|
Packit |
8480eb |
goto out;
|
|
Packit |
8480eb |
strcpy(path, key);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
out:
|
|
Packit |
8480eb |
return path;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct mapent *me, *this;
|
|
Packit |
8480eb |
char *path;
|
|
Packit |
8480eb |
int status = CHE_FAIL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
me = cache_enumerate(mc, NULL);
|
|
Packit |
8480eb |
while (me) {
|
|
Packit |
8480eb |
struct mapent *valid;
|
|
Packit |
8480eb |
char *key = NULL, *next_key = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (me->age >= age) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Reset time of last fail for valid map entries to
|
|
Packit |
8480eb |
* force entry update and subsequent mount retry.
|
|
Packit |
8480eb |
* A map entry that's still invalid after a read
|
|
Packit |
8480eb |
* may have been created by a failed wildcard lookup
|
|
Packit |
8480eb |
* so reset the status on those too.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (me->mapent || cache_lookup(mc, "*"))
|
|
Packit |
8480eb |
me->status = 0;
|
|
Packit |
8480eb |
me = cache_enumerate(mc, me);
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Bot |
ed9139 |
if (ap->type == LKP_INDIRECT) {
|
|
Packit Bot |
36a717 |
/* Don't prune offset map entries since they are
|
|
Packit Bot |
36a717 |
* created on demand and managed by expire and don't
|
|
Packit Bot |
36a717 |
* prune the multi-map owner map entry.
|
|
Packit Bot |
36a717 |
*/
|
|
Packit Bot |
7bc25c |
if (*me->key == '/' || IS_MM_ROOT(me)) {
|
|
Packit Bot |
36a717 |
me = cache_enumerate(mc, me);
|
|
Packit Bot |
36a717 |
continue;
|
|
Packit Bot |
36a717 |
}
|
|
Packit Bot |
36a717 |
|
|
Packit Bot |
ed9139 |
/* If the map hasn't been read (nobrowse
|
|
Packit Bot |
ed9139 |
* indirect mounts) then keep cached entries
|
|
Packit Bot |
ed9139 |
* for POSITIVE_TIMEOUT.
|
|
Packit Bot |
ed9139 |
*/
|
|
Packit Bot |
ed9139 |
if (!(ap->flags & (MOUNT_FLAG_GHOST |
|
|
Packit Bot |
ed9139 |
MOUNT_FLAG_AMD_CACHE_ALL))) {
|
|
Packit Bot |
ed9139 |
time_t until = me->age + POSITIVE_TIMEOUT;
|
|
Packit Bot |
ed9139 |
if ((long) age - (long) until < 0) {
|
|
Packit Bot |
ed9139 |
me = cache_enumerate(mc, me);
|
|
Packit Bot |
ed9139 |
continue;
|
|
Packit Bot |
ed9139 |
}
|
|
Packit Bot |
ed9139 |
}
|
|
Packit Bot |
ed9139 |
}
|
|
Packit Bot |
ed9139 |
|
|
Packit |
8480eb |
key = strdup(me->key);
|
|
Packit |
8480eb |
/* Don't consider any entries with a wildcard */
|
|
Packit |
8480eb |
if (!key || strchr(key, '*')) {
|
|
Packit |
8480eb |
if (key)
|
|
Packit |
8480eb |
free(key);
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
path = make_fullpath(ap, key);
|
|
Packit |
8480eb |
if (!path) {
|
|
Packit |
8480eb |
warn(ap->logopt, "can't malloc storage for path");
|
|
Packit |
8480eb |
free(key);
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If this key has another valid entry we want to prune it,
|
|
Packit |
8480eb |
* even if it's a mount, as the valid entry will take the
|
|
Packit |
8480eb |
* mount if it is a direct mount or it's just a stale indirect
|
|
Packit |
8480eb |
* cache entry.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
valid = lookup_source_valid_mapent(ap, key, LKP_DISTINCT);
|
|
Packit |
8480eb |
if (valid && valid->mc == mc) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* We've found a map entry that has been removed from
|
|
Packit Bot |
e11954 |
* the current cache so it isn't really valid. Set the
|
|
Packit Bot |
e11954 |
* mapent negative to prevent further mount requests
|
|
Packit Bot |
e11954 |
* using the cache entry.
|
|
Packit |
8480eb |
*/
|
|
Packit Bot |
e11954 |
debug(ap->logopt, "removed map entry detected, mark negative");
|
|
Packit Bot |
e11954 |
if (valid->mapent) {
|
|
Packit Bot |
e11954 |
free(valid->mapent);
|
|
Packit Bot |
e11954 |
valid->mapent = NULL;
|
|
Packit Bot |
e11954 |
}
|
|
Packit |
8480eb |
cache_unlock(valid->mc);
|
|
Packit |
8480eb |
valid = NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (!valid &&
|
|
Packit Bot |
28887b |
is_mounted(path, MNTS_REAL)) {
|
|
Packit Bot |
e11954 |
debug(ap->logopt, "prune posponed, %s mounted", path);
|
|
Packit |
8480eb |
free(key);
|
|
Packit |
8480eb |
free(path);
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (valid)
|
|
Packit |
8480eb |
cache_unlock(valid->mc);
|
|
Packit |
8480eb |
|
|
Packit Bot |
350828 |
me = cache_enumerate(mc, me);
|
|
Packit |
8480eb |
if (me)
|
|
Packit |
8480eb |
next_key = strdup(me->key);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
cache_writelock(mc);
|
|
Packit |
8480eb |
this = cache_lookup_distinct(mc, key);
|
|
Packit |
8480eb |
if (!this) {
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (valid)
|
|
Packit |
8480eb |
cache_delete(mc, key);
|
|
Packit Bot |
28887b |
else if (!is_mounted(path, MNTS_AUTOFS)) {
|
|
Packit |
8480eb |
dev_t devid = ap->dev;
|
|
Packit |
8480eb |
status = CHE_FAIL;
|
|
Packit |
8480eb |
if (ap->type == LKP_DIRECT)
|
|
Packit |
8480eb |
devid = this->dev;
|
|
Packit |
8480eb |
if (this->ioctlfd == -1)
|
|
Packit |
8480eb |
status = cache_delete(mc, key);
|
|
Packit |
8480eb |
if (status != CHE_FAIL) {
|
|
Packit |
8480eb |
if (ap->type == LKP_INDIRECT) {
|
|
Packit |
8480eb |
if (ap->flags & MOUNT_FLAG_GHOST)
|
|
Packit |
8480eb |
rmdir_path(ap, path, devid);
|
|
Packit |
8480eb |
} else
|
|
Packit |
8480eb |
rmdir_path(ap, path, devid);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
next:
|
|
Packit |
8480eb |
cache_readlock(mc);
|
|
Packit |
8480eb |
if (next_key) {
|
|
Packit Bot |
350828 |
/* The lock release and reaquire above can mean
|
|
Packit Bot |
350828 |
* a number of things could happen.
|
|
Packit Bot |
350828 |
*
|
|
Packit Bot |
350828 |
* First, mapents could be added between the
|
|
Packit Bot |
350828 |
* current mapent and the mapent of next_key.
|
|
Packit Bot |
350828 |
* Don't care about that because there's no
|
|
Packit Bot |
350828 |
* need to prune newly added entries.
|
|
Packit Bot |
350828 |
*
|
|
Packit Bot |
350828 |
* Second, the next mapent data could have
|
|
Packit Bot |
350828 |
* changed. Don't care about that either since
|
|
Packit Bot |
350828 |
* we are looking to prune stale map entries
|
|
Packit Bot |
350828 |
* and don't care when they become stale.
|
|
Packit Bot |
350828 |
*
|
|
Packit Bot |
350828 |
* Finally, the mapent of next_key could have
|
|
Packit Bot |
350828 |
* gone away. Again don't care about this either,
|
|
Packit Bot |
350828 |
* the loop will exit prematurely so just wait
|
|
Packit Bot |
350828 |
* until the next prune and try again.
|
|
Packit Bot |
350828 |
*/
|
|
Packit |
8480eb |
me = cache_lookup_distinct(mc, next_key);
|
|
Packit |
8480eb |
free(next_key);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
free(key);
|
|
Packit |
8480eb |
free(path);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int lookup_prune_cache(struct autofs_point *ap, time_t age)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct master_mapent *entry = ap->entry;
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(master_source_lock_cleanup, entry);
|
|
Packit |
8480eb |
master_source_readlock(entry);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = entry->maps;
|
|
Packit |
8480eb |
while (map) {
|
|
Packit |
8480eb |
/* Is the map stale */
|
|
Packit |
8480eb |
if (!map->stale && !check_stale_instances(map)) {
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_cleanup_push(cache_lock_cleanup, map->mc);
|
|
Packit |
8480eb |
cache_readlock(map->mc);
|
|
Packit |
8480eb |
lookup_prune_one_cache(ap, map->mc, age);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
clear_stale_instances(map);
|
|
Packit |
8480eb |
map->stale = 0;
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Return with cache readlock held */
|
|
Packit |
8480eb |
struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *key, unsigned int type)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct master_mapent *entry = ap->entry;
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
struct mapent_cache *mc;
|
|
Packit |
8480eb |
struct mapent *me = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = entry->maps;
|
|
Packit |
8480eb |
while (map) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Only consider map sources that have been read since
|
|
Packit |
8480eb |
* the map entry was last updated.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (ap->entry->age > map->age) {
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mc = map->mc;
|
|
Packit |
8480eb |
cache_readlock(mc);
|
|
Packit |
8480eb |
if (type == LKP_DISTINCT)
|
|
Packit |
8480eb |
me = cache_lookup_distinct(mc, key);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
me = cache_lookup(mc, key);
|
|
Packit |
8480eb |
if (me)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return me;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Return with cache readlock held */
|
|
Packit |
8480eb |
struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, unsigned int type)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct master_mapent *entry = ap->entry;
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
struct mapent_cache *mc;
|
|
Packit |
8480eb |
struct mapent *me = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = entry->maps;
|
|
Packit |
8480eb |
while (map) {
|
|
Packit |
8480eb |
mc = map->mc;
|
|
Packit |
8480eb |
cache_readlock(mc);
|
|
Packit |
8480eb |
if (type == LKP_DISTINCT)
|
|
Packit |
8480eb |
me = cache_lookup_distinct(mc, key);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
me = cache_lookup(mc, key);
|
|
Packit |
8480eb |
if (me)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (me && me->mc != mc)
|
|
Packit |
8480eb |
error(LOGOPT_ANY, "mismatching mc in cache", me->key);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return me;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int lookup_source_close_ioctlfd(struct autofs_point *ap, const char *key)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct master_mapent *entry = ap->entry;
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
struct mapent_cache *mc;
|
|
Packit |
8480eb |
struct mapent *me;
|
|
Packit |
8480eb |
int ret = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = entry->maps;
|
|
Packit |
8480eb |
while (map) {
|
|
Packit |
8480eb |
mc = map->mc;
|
|
Packit |
8480eb |
cache_readlock(mc);
|
|
Packit |
8480eb |
me = cache_lookup_distinct(mc, key);
|
|
Packit |
8480eb |
if (me) {
|
|
Packit |
8480eb |
if (me->ioctlfd != -1) {
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
ops->close(ap->logopt, me->ioctlfd);
|
|
Packit |
8480eb |
me->ioctlfd = -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
ret = 1;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|