|
Packit |
8480eb |
/* ----------------------------------------------------------------------- *
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* lookup_hosts.c - module for Linux automount to mount the exports
|
|
Packit |
8480eb |
* from a given host
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* Copyright 2005 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; incorporated herein by reference.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* ----------------------------------------------------------------------- */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include <stdio.h>
|
|
Packit |
8480eb |
#include <malloc.h>
|
|
Packit |
8480eb |
#include <sys/param.h>
|
|
Packit |
8480eb |
#include <sys/types.h>
|
|
Packit |
8480eb |
#include <sys/stat.h>
|
|
Packit |
8480eb |
#include <netdb.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 |
#define MODPREFIX "lookup(hosts): "
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_mutex_t hostent_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
struct lookup_context {
|
|
Packit |
8480eb |
struct parse_mod *parse;
|
|
Packit |
8480eb |
};
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
|
|
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 |
|
|
Packit |
8480eb |
mapfmt = MAPFMT_DEFAULT;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ctxt->parse = open_parse(mapfmt, MODPREFIX, argc, argv);
|
|
Packit |
8480eb |
if (!ctxt->parse) {
|
|
Packit |
8480eb |
logerr(MODPREFIX "failed to open parse context");
|
|
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 |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mapfmt = MAPFMT_DEFAULT;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = reinit_parse(ctxt->parse, mapfmt, MODPREFIX, argc, argv);
|
|
Packit |
8480eb |
if (ret)
|
|
Packit |
8480eb |
return 1;
|
|
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 |
static char *get_exports(struct autofs_point *ap, const char *host)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
char buf[MAX_ERR_BUF];
|
|
Packit |
8480eb |
char *mapent;
|
|
Packit Service |
27309f |
struct exportinfo *exp, *this;
|
|
Packit Service |
d5db16 |
size_t hostlen = strlen(host);
|
|
Packit Service |
d5db16 |
size_t mapent_len;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(ap->logopt, MODPREFIX "fetchng export list for %s", host);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
exp = rpc_get_exports(host, 10, 0, RPC_CLOSE_NOLINGER);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = exp;
|
|
Packit Service |
d5db16 |
mapent_len = 0;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit Service |
d5db16 |
mapent_len += hostlen + 2*(strlen(this->dir) + 2) + 3;
|
|
Packit Service |
d5db16 |
this = this->next;
|
|
Packit Service |
d5db16 |
}
|
|
Packit Service |
d5db16 |
|
|
Packit Service |
d5db16 |
mapent = malloc(mapent_len + 1);
|
|
Packit Service |
d5db16 |
if (!mapent) {
|
|
Packit Service |
d5db16 |
char *estr;
|
|
Packit Service |
d5db16 |
estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
Packit Service |
d5db16 |
error(ap->logopt, MODPREFIX "malloc: %s", estr);
|
|
Packit Service |
d5db16 |
error(ap->logopt, MODPREFIX "exports lookup failed for %s", host);
|
|
Packit Service |
d5db16 |
rpc_exports_free(exp);
|
|
Packit Service |
d5db16 |
return NULL;
|
|
Packit Service |
d5db16 |
}
|
|
Packit Service |
d5db16 |
*mapent = 0;
|
|
Packit Service |
d5db16 |
|
|
Packit Service |
d5db16 |
this = exp;
|
|
Packit Service |
d5db16 |
while (this) {
|
|
Packit Service |
d5db16 |
if (!*mapent)
|
|
Packit |
8480eb |
strcpy(mapent, "\"");
|
|
Packit Service |
d5db16 |
else
|
|
Packit Service |
d5db16 |
strcat(mapent, " \"");
|
|
Packit Service |
d5db16 |
strcat(mapent, this->dir);
|
|
Packit Service |
d5db16 |
strcat(mapent, "\"");
|
|
Packit Service |
d5db16 |
|
|
Packit |
8480eb |
strcat(mapent, " \"");
|
|
Packit |
8480eb |
strcat(mapent, host);
|
|
Packit |
8480eb |
strcat(mapent, ":");
|
|
Packit Service |
27309f |
strcat(mapent, this->dir);
|
|
Packit |
8480eb |
strcat(mapent, "\"");
|
|
Packit |
8480eb |
|
|
Packit Service |
27309f |
this = this->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
rpc_exports_free(exp);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return mapent;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int do_parse_mount(struct autofs_point *ap, struct map_source *source,
|
|
Packit |
8480eb |
const char *name, int name_len, char *mapent,
|
|
Packit |
8480eb |
struct lookup_context *ctxt)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int ret;
|
|
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 |
if (ret) {
|
|
Packit |
8480eb |
struct mapent_cache *mc = source->mc;
|
|
Packit |
8480eb |
|
|
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 |
return NSS_STATUS_SUCCESS;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void update_hosts_mounts(struct autofs_point *ap,
|
|
Packit |
8480eb |
struct map_source *source, time_t age,
|
|
Packit |
8480eb |
struct lookup_context *ctxt)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct mapent_cache *mc;
|
|
Packit |
8480eb |
struct mapent *me;
|
|
Packit |
8480eb |
char *mapent;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mc = source->mc;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(cache_lock_cleanup, mc);
|
|
Packit |
8480eb |
cache_writelock(mc);
|
|
Packit |
8480eb |
me = cache_lookup_first(mc);
|
|
Packit |
8480eb |
while (me) {
|
|
Packit |
8480eb |
/* Hosts map entry not yet expanded or already expired */
|
|
Packit |
8480eb |
if (!me->multi)
|
|
Packit |
8480eb |
goto next;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(ap->logopt, MODPREFIX "get list of exports for %s", me->key);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mapent = get_exports(ap, me->key);
|
|
Packit |
8480eb |
if (mapent) {
|
|
Packit |
8480eb |
cache_update(mc, source, me->key, mapent, age);
|
|
Packit |
8480eb |
free(mapent);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
next:
|
|
Packit |
8480eb |
me = cache_lookup_next(mc, me);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(cache_lock_cleanup, mc);
|
|
Packit |
8480eb |
cache_readlock(mc);
|
|
Packit |
8480eb |
me = cache_lookup_first(mc);
|
|
Packit |
8480eb |
while (me) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Hosts map entry not yet expanded, already expired
|
|
Packit |
8480eb |
* or not the base of the tree
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!me->multi || me->multi != me)
|
|
Packit |
8480eb |
goto cont;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(ap->logopt, MODPREFIX
|
|
Packit |
8480eb |
"attempt to update exports for %s", me->key);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
master_source_current_wait(ap->entry);
|
|
Packit |
8480eb |
ap->entry->current = source;
|
|
Packit |
8480eb |
ap->flags |= MOUNT_FLAG_REMOUNT;
|
|
Packit |
8480eb |
ret = ctxt->parse->parse_mount(ap, me->key, strlen(me->key),
|
|
Packit |
8480eb |
me->mapent, ctxt->parse->context);
|
|
Packit |
8480eb |
if (ret)
|
|
Packit |
8480eb |
warn(ap->logopt, MODPREFIX
|
|
Packit |
8480eb |
"failed to parse mount %s", me->mapent);
|
|
Packit |
8480eb |
ap->flags &= ~MOUNT_FLAG_REMOUNT;
|
|
Packit |
8480eb |
cont:
|
|
Packit |
8480eb |
me = cache_lookup_next(mc, me);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int lookup_read_map(struct autofs_point *ap, time_t age, 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 |
struct hostent *host;
|
|
Packit |
8480eb |
int status;
|
|
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 |
debug(ap->logopt, MODPREFIX "read hosts map");
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If we don't need to create directories then there's no use
|
|
Packit |
8480eb |
* reading the map. We always need to read the whole map for
|
|
Packit |
8480eb |
* direct mounts in order to mount the triggers.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT) {
|
|
Packit |
8480eb |
debug(ap->logopt, MODPREFIX
|
|
Packit |
8480eb |
"map not browsable, update existing host entries only");
|
|
Packit |
8480eb |
update_hosts_mounts(ap, source, age, ctxt);
|
|
Packit |
8480eb |
source->age = age;
|
|
Packit |
8480eb |
return NSS_STATUS_SUCCESS;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = pthread_mutex_lock(&hostent_mutex);
|
|
Packit |
8480eb |
if (status) {
|
|
Packit |
8480eb |
error(ap->logopt, MODPREFIX "failed to lock hostent mutex");
|
|
Packit |
8480eb |
return NSS_STATUS_UNAVAIL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sethostent(0);
|
|
Packit |
8480eb |
while ((host = gethostent()) != NULL) {
|
|
Packit |
8480eb |
pthread_cleanup_push(cache_lock_cleanup, mc);
|
|
Packit |
8480eb |
cache_writelock(mc);
|
|
Packit |
8480eb |
cache_update(mc, source, host->h_name, NULL, age);
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
pthread_cleanup_pop(0);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
endhostent();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = pthread_mutex_unlock(&hostent_mutex);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
error(ap->logopt, MODPREFIX "failed to unlock hostent mutex");
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
update_hosts_mounts(ap, source, age, ctxt);
|
|
Packit |
8480eb |
source->age = age;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return NSS_STATUS_SUCCESS;
|
|
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 |
struct mapent *me;
|
|
Packit |
8480eb |
char *mapent = NULL;
|
|
Packit |
8480eb |
int mapent_len;
|
|
Packit |
8480eb |
time_t now = monotonic_time(NULL);
|
|
Packit |
8480eb |
int ret;
|
|
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 |
cache_readlock(mc);
|
|
Packit |
8480eb |
me = cache_lookup_distinct(mc, name);
|
|
Packit |
8480eb |
if (!me) {
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* We haven't read the list of hosts into the
|
|
Packit |
8480eb |
* cache so go straight to the lookup.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!(ap->flags & MOUNT_FLAG_GHOST)) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If name contains a '/' we're searching for an
|
|
Packit |
8480eb |
* offset that doesn't exist in the export list
|
|
Packit |
8480eb |
* so it's NOTFOUND otherwise this could be a
|
|
Packit |
8480eb |
* lookup for a new host.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (*name != '/' && strchr(name, '/'))
|
|
Packit |
8480eb |
return NSS_STATUS_NOTFOUND;
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (*name == '/')
|
|
Packit |
8480eb |
info(ap->logopt, MODPREFIX
|
|
Packit |
8480eb |
"can't find path in hosts map %s", name);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
info(ap->logopt, MODPREFIX
|
|
Packit |
8480eb |
"can't find path in hosts map %s/%s",
|
|
Packit |
8480eb |
ap->path, name);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(ap->logopt,
|
|
Packit |
8480eb |
MODPREFIX "lookup failed - update exports list");
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Host map export entries are added to the cache as
|
|
Packit |
8480eb |
* direct mounts. If the name we seek starts with a slash
|
|
Packit |
8480eb |
* it must be a mount request for one of the exports.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (*name == '/') {
|
|
Packit |
8480eb |
pthread_cleanup_push(cache_lock_cleanup, mc);
|
|
Packit |
8480eb |
mapent_len = strlen(me->mapent);
|
|
Packit |
8480eb |
mapent = malloc(mapent_len + 1);
|
|
Packit |
8480eb |
if (mapent)
|
|
Packit |
8480eb |
strcpy(mapent, me->mapent);
|
|
Packit |
8480eb |
pthread_cleanup_pop(0);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
done:
|
|
Packit |
8480eb |
debug(ap->logopt, MODPREFIX "%s -> %s", name, mapent);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!mapent) {
|
|
Packit |
8480eb |
/* We need to get the exports list and update the cache. */
|
|
Packit |
8480eb |
mapent = get_exports(ap, name);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Exports lookup failed so we're outa here */
|
|
Packit |
8480eb |
if (!mapent)
|
|
Packit |
8480eb |
return NSS_STATUS_UNAVAIL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
cache_writelock(mc);
|
|
Packit |
8480eb |
cache_update(mc, source, name, mapent, now);
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = do_parse_mount(ap, source, name, name_len, mapent, ctxt);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
free(mapent);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return ret;
|
|
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 |
free(ctxt);
|
|
Packit |
8480eb |
return rv;
|
|
Packit |
8480eb |
}
|