~ubuntu-branches/ubuntu/natty/autofs5/natty-proposed

« back to all changes in this revision

Viewing changes to modules/lookup_hesiod.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Christoph Nordholz
  • Date: 2008-04-28 15:55:37 UTC
  • Revision ID: james.westby@ubuntu.com-20080428155537-h6h457h1fwwzhvby
Tags: upstream-5.0.3
ImportĀ upstreamĀ versionĀ 5.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * lookup_hesiod.c
 
3
 *
 
4
 * Module for Linux automountd to access automount maps in hesiod filsys
 
5
 * entries.
 
6
 *
 
7
 */
 
8
 
 
9
#include <sys/types.h>
 
10
#include <ctype.h>
 
11
#include <limits.h>
 
12
#include <string.h>
 
13
#include <unistd.h>
 
14
#include <stdlib.h>
 
15
#include <netinet/in.h>
 
16
#include <arpa/nameser.h>
 
17
#include <resolv.h>
 
18
#include <hesiod.h>
 
19
 
 
20
#define MODULE_LOOKUP
 
21
#include "automount.h"
 
22
#include "nsswitch.h"
 
23
 
 
24
#define MAPFMT_DEFAULT "hesiod"
 
25
 
 
26
#define MODPREFIX "lookup(hesiod): "
 
27
#define HESIOD_LEN 512
 
28
 
 
29
struct lookup_context {
 
30
        struct parse_mod *parser;
 
31
        void *hesiod_context;
 
32
};
 
33
 
 
34
static pthread_mutex_t hesiod_mutex = PTHREAD_MUTEX_INITIALIZER;
 
35
 
 
36
int lookup_version = AUTOFS_LOOKUP_VERSION;     /* Required by protocol */
 
37
 
 
38
/* This initializes a context (persistent non-global data) for queries to
 
39
   this module. */
 
40
int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **context)
 
41
{
 
42
        struct lookup_context *ctxt = NULL;
 
43
        char buf[MAX_ERR_BUF];
 
44
 
 
45
        *context = NULL;
 
46
 
 
47
        /* If we can't build a context, bail. */
 
48
        ctxt = malloc(sizeof(struct lookup_context));
 
49
        if (!ctxt) {
 
50
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 
51
                logerr(MODPREFIX "malloc: %s", estr);
 
52
                return 1;
 
53
        }
 
54
 
 
55
        /* Initialize the resolver. */
 
56
        res_init();
 
57
 
 
58
        /* Initialize the hesiod context. */
 
59
        if (hesiod_init(&(ctxt->hesiod_context)) != 0) {
 
60
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 
61
                logerr(MODPREFIX "hesiod_init(): %s", estr);
 
62
                free(ctxt);
 
63
                return 1;
 
64
        }
 
65
 
 
66
        /* If a map type isn't explicitly given, parse it as hesiod entries. */
 
67
        if (!mapfmt)
 
68
                mapfmt = MAPFMT_DEFAULT;
 
69
 
 
70
        /* Open the parser, if we can. */
 
71
        ctxt->parser = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
 
72
        if (!ctxt->parser) {
 
73
                logerr(MODPREFIX "failed to open parse context");
 
74
                free(ctxt);
 
75
                return 1;
 
76
        }
 
77
        *context = ctxt;
 
78
 
 
79
        return 0;
 
80
}
 
81
 
 
82
int lookup_read_master(struct master *master, time_t age, void *context)
 
83
{
 
84
        return NSS_STATUS_UNKNOWN;
 
85
}
 
86
 
 
87
int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
 
88
{
 
89
        ap->entry->current = NULL;
 
90
        master_source_current_signal(ap->entry);
 
91
 
 
92
        return NSS_STATUS_UNKNOWN;
 
93
}
 
94
 
 
95
/*
 
96
 * Lookup and act on a filesystem name.  In this case, lookup the "filsys"
 
97
 * record in hesiod.  If it's an AFS or NFS filesystem, parse it out.  If
 
98
 * it's an ERR filesystem, it's an error message we should log.  Otherwise,
 
99
 * assume it's something we know how to deal with already (generic).
 
100
 */
 
101
int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context)
 
102
{
 
103
        struct map_source *source;
 
104
        struct mapent_cache *mc;
 
105
        char **hes_result;
 
106
        struct lookup_context *ctxt = (struct lookup_context *) context;
 
107
        int status, rv;
 
108
        char **record, *best_record = NULL, *p;
 
109
        int priority, lowest_priority = INT_MAX;        
 
110
 
 
111
        source = ap->entry->current;
 
112
        ap->entry->current = NULL;
 
113
        master_source_current_signal(ap->entry);
 
114
 
 
115
        mc = source->mc;
 
116
 
 
117
        debug(ap->logopt,
 
118
              MODPREFIX "looking up root=\"%s\", name=\"%s\"",
 
119
              ap->path, name);
 
120
 
 
121
        chdir("/");             /* If this is not here the filesystem stays
 
122
                                   busy, for some reason... */
 
123
 
 
124
        status = pthread_mutex_lock(&hesiod_mutex);
 
125
        if (status)
 
126
                fatal(status);
 
127
 
 
128
        hes_result = hesiod_resolve(ctxt->hesiod_context, name, "filsys");
 
129
        if (!hes_result || !hes_result[0]) {
 
130
                /* Note: it is not clear to me how to distinguish between
 
131
                 * the "no search results" case and other failures.  --JM */
 
132
                error(ap->logopt,
 
133
                      MODPREFIX "key \"%s\" not found in map", name);
 
134
                status = pthread_mutex_unlock(&hesiod_mutex);
 
135
                if (status)
 
136
                        fatal(status);
 
137
                return NSS_STATUS_NOTFOUND;
 
138
        }
 
139
 
 
140
        /* autofs doesn't support falling back to alternate records, so just
 
141
           find the record with the lowest priority and hope it works.
 
142
           -- Aaron Ucko <amu@alum.mit.edu> 2002-03-11 */
 
143
        for (record = hes_result; *record; ++record) {
 
144
            p = strrchr(*record, ' ');
 
145
            if ( p && isdigit(p[1]) ) {
 
146
                priority = atoi(p+1);
 
147
            } else {
 
148
                priority = INT_MAX - 1;
 
149
            }
 
150
            if (priority < lowest_priority) {
 
151
                lowest_priority = priority;
 
152
                best_record = *record;
 
153
            }
 
154
        }
 
155
 
 
156
        cache_writelock(mc);
 
157
        rv = cache_update(mc, source, name, best_record, time(NULL));
 
158
        cache_unlock(mc);
 
159
        if (rv == CHE_FAIL)
 
160
                return NSS_STATUS_UNAVAIL;
 
161
 
 
162
        debug(ap->logopt,
 
163
              MODPREFIX "lookup for \"%s\" gave \"%s\"",
 
164
              name, best_record);
 
165
 
 
166
        rv = ctxt->parser->parse_mount(ap, name, name_len, best_record,
 
167
                                       ctxt->parser->context);
 
168
 
 
169
        hesiod_free_list(ctxt->hesiod_context, hes_result);
 
170
 
 
171
        status = pthread_mutex_unlock(&hesiod_mutex);
 
172
        if (status)
 
173
                fatal(status);
 
174
 
 
175
        /*
 
176
         * Unavailable due to error such as module load fail 
 
177
         * or out of memory, etc.
 
178
         */
 
179
        if (rv == 1 || rv == -1)
 
180
                return NSS_STATUS_UNAVAIL;
 
181
 
 
182
        return NSS_STATUS_SUCCESS;
 
183
}
 
184
 
 
185
/* This destroys a context for queries to this module.  It releases the parser
 
186
   structure (unloading the module) and frees the memory used by the context. */
 
187
int lookup_done(void *context)
 
188
{
 
189
        struct lookup_context *ctxt = (struct lookup_context *) context;
 
190
        int rv = close_parse(ctxt->parser);
 
191
 
 
192
        hesiod_end(ctxt->hesiod_context);
 
193
        free(ctxt);
 
194
        return rv;
 
195
}