~ubuntu-branches/ubuntu/precise/autofs5/precise

« back to all changes in this revision

Viewing changes to .pc/autofs-5.0.5-fix-prune-cache-valid-check.patch/daemon/lookup.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2011-07-03 14:35:46 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110703143546-nej26krjij0rf792
Tags: 5.0.6-0ubuntu1
* New upstream release:
  - Dropped upstream patches 
  - Refreshed debian/patches/17ld.patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* ----------------------------------------------------------------------- *
2
 
 *   
3
 
 *  lookup.c - API layer to implement nsswitch semantics for map reading
4
 
 *              and mount lookups.
5
 
 *
6
 
 *   Copyright 2006 Ian Kent <raven@themaw.net>
7
 
 *
8
 
 *   This program is free software; you can redistribute it and/or modify
9
 
 *   it under the terms of the GNU General Public License as published by
10
 
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
11
 
 *   USA; either version 2 of the License, or (at your option) any later
12
 
 *   version.
13
 
 *   
14
 
 *   This program is distributed in the hope that it will be useful,
15
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
 *   GNU General Public License for more details.
18
 
 *
19
 
 * ----------------------------------------------------------------------- */
20
 
 
21
 
#include <stdlib.h>
22
 
#include <stdio.h>
23
 
#include <string.h>
24
 
#include <sys/stat.h>
25
 
#include "automount.h"
26
 
#include "nsswitch.h"
27
 
 
28
 
static int check_nss_result(struct nss_source *this, enum nsswitch_status result)
29
 
{
30
 
        enum nsswitch_status status;
31
 
        struct nss_action a;
32
 
 
33
 
        /* Check if we have negated actions */
34
 
        for (status = 0; status < NSS_STATUS_MAX; status++) {
35
 
                a = this->action[status];
36
 
                if (a.action == NSS_ACTION_UNKNOWN)
37
 
                        continue;
38
 
 
39
 
                if (a.negated && result != status) {
40
 
                        if (a.action == NSS_ACTION_RETURN) {
41
 
                                if (result == NSS_STATUS_SUCCESS)
42
 
                                        return 1;
43
 
                                else
44
 
                                        return 0;
45
 
                        }
46
 
                }
47
 
        }
48
 
 
49
 
        a = this->action[result];
50
 
 
51
 
        /* Check if we have other actions for this status */
52
 
        switch (result) {
53
 
        case NSS_STATUS_SUCCESS:
54
 
                if (a.action == NSS_ACTION_CONTINUE)
55
 
                        break;
56
 
                return 1;
57
 
 
58
 
        case NSS_STATUS_NOTFOUND:
59
 
        case NSS_STATUS_UNAVAIL:
60
 
        case NSS_STATUS_TRYAGAIN:
61
 
                if (a.action == NSS_ACTION_RETURN) {
62
 
                        return 0;
63
 
                }
64
 
                break;
65
 
 
66
 
        default:
67
 
                break;
68
 
        }
69
 
 
70
 
        return -1;
71
 
}
72
 
 
73
 
static void nsslist_cleanup(void *arg)
74
 
{
75
 
        struct list_head *nsslist = (struct list_head *) arg;
76
 
        if (!list_empty(nsslist))
77
 
                free_sources(nsslist);
78
 
        return;
79
 
}
80
 
 
81
 
static int do_read_master(struct master *master, char *type, time_t age)
82
 
{
83
 
        struct lookup_mod *lookup;
84
 
        const char *argv[2];
85
 
        int argc;
86
 
        int status;
87
 
 
88
 
        argc = 1;
89
 
        argv[0] = master->name;
90
 
        argv[1] = NULL;
91
 
 
92
 
        lookup = open_lookup(type, "", NULL, argc, argv);
93
 
        if (!lookup)
94
 
                return NSS_STATUS_UNAVAIL;
95
 
 
96
 
        status = lookup->lookup_read_master(master, age, lookup->context);
97
 
 
98
 
        close_lookup(lookup);
99
 
 
100
 
        return status;
101
 
}
102
 
 
103
 
static int read_master_map(struct master *master, char *type, time_t age)
104
 
{
105
 
        unsigned int logopt = master->logopt;
106
 
        char *path, *save_name;
107
 
        int result;
108
 
 
109
 
        if (strcasecmp(type, "files")) {
110
 
                return do_read_master(master, type, age);
111
 
        }
112
 
 
113
 
        /* 
114
 
         * This is a special case as we need to append the
115
 
         * normal location to the map name.
116
 
         * note: It's invalid to specify a relative path.
117
 
         */
118
 
 
119
 
        if (strchr(master->name, '/')) {
120
 
                error(logopt, "relative path invalid in files map name");
121
 
                return NSS_STATUS_NOTFOUND;
122
 
        }
123
 
 
124
 
        path = malloc(strlen(AUTOFS_MAP_DIR) + strlen(master->name) + 2);
125
 
        if (!path)
126
 
                return NSS_STATUS_UNKNOWN;
127
 
 
128
 
        strcpy(path, AUTOFS_MAP_DIR);
129
 
        strcat(path, "/");
130
 
        strcat(path, master->name);
131
 
 
132
 
        save_name = master->name;
133
 
        master->name = path;
134
 
 
135
 
        result = do_read_master(master, type, age);
136
 
 
137
 
        master->name = save_name;
138
 
        free(path);
139
 
 
140
 
        return result;
141
 
}
142
 
 
143
 
int lookup_nss_read_master(struct master *master, time_t age)
144
 
{
145
 
        unsigned int logopt = master->logopt;
146
 
        struct list_head nsslist;
147
 
        struct list_head *head, *p;
148
 
        int result = NSS_STATUS_UNKNOWN;
149
 
 
150
 
        /* If it starts with a '/' it has to be a file or LDAP map */
151
 
        if (*master->name == '/') {
152
 
                if (*(master->name + 1) == '/') {
153
 
                        debug(logopt, "reading master ldap %s", master->name);
154
 
                        result = do_read_master(master, "ldap", age);
155
 
                } else {
156
 
                        debug(logopt, "reading master file %s", master->name);
157
 
                        result = do_read_master(master, "file", age);
158
 
                }
159
 
 
160
 
                if (result == NSS_STATUS_UNAVAIL)
161
 
                        master->read_fail = 1;
162
 
 
163
 
                return !result;
164
 
        } else {
165
 
                char *name = master->name;
166
 
                char *tmp;
167
 
 
168
 
                /* Old style name specification will remain I think. */
169
 
                tmp = strchr(name, ':');
170
 
                if (tmp) {
171
 
                        char source[10];
172
 
 
173
 
                        memset(source, 0, 10);
174
 
                        if (!strncmp(name, "file:", 5) ||
175
 
                            !strncmp(name, "yp:", 3) ||
176
 
                            !strncmp(name, "nis:", 4) ||
177
 
                            !strncmp(name, "nisplus:", 8) ||
178
 
                            !strncmp(name, "ldap:", 5) ||
179
 
                            !strncmp(name, "ldaps:", 6)) {
180
 
                                strncpy(source, name, tmp - name);
181
 
 
182
 
                                /*
183
 
                                 * If it's an ldap map leave the source in the
184
 
                                 * name so the lookup module can work out if
185
 
                                 * ldaps has been requested.
186
 
                                 */
187
 
                                if (strncmp(name, "ldap", 4)) {
188
 
                                        master->name = tmp + 1;
189
 
                                        debug(logopt, "reading master %s %s",
190
 
                                              source, master->name);
191
 
                                } else {
192
 
                                        master->name = name;
193
 
                                        debug(logopt, "reading master %s %s",
194
 
                                              source, tmp + 1);
195
 
                                }
196
 
 
197
 
                                result = do_read_master(master, source, age);
198
 
                                master->name = name;
199
 
 
200
 
                                if (result == NSS_STATUS_UNAVAIL)
201
 
                                        master->read_fail = 1;
202
 
 
203
 
                                return !result;
204
 
                        }
205
 
                }
206
 
        }
207
 
 
208
 
        INIT_LIST_HEAD(&nsslist);
209
 
 
210
 
        result = nsswitch_parse(&nsslist);
211
 
        if (result) {
212
 
                if (!list_empty(&nsslist))
213
 
                        free_sources(&nsslist);
214
 
                error(logopt, "can't to read name service switch config.");
215
 
                return 0;
216
 
        }
217
 
 
218
 
        /* First one gets it */
219
 
        head = &nsslist;
220
 
        list_for_each(p, head) {
221
 
                struct nss_source *this;
222
 
                int status;
223
 
 
224
 
                this = list_entry(p, struct nss_source, list);
225
 
 
226
 
                debug(logopt,
227
 
                      "reading master %s %s", this->source, master->name);
228
 
 
229
 
                result = read_master_map(master, this->source, age);
230
 
 
231
 
                /*
232
 
                 * If the name of the master map hasn't been explicitly
233
 
                 * configured and we're not reading an included master map
234
 
                 * then we're using auto.master as the default. Many setups
235
 
                 * also use auto_master as the default master map so we
236
 
                 * check for this map when auto.master isn't found.
237
 
                 */
238
 
                if (result != NSS_STATUS_SUCCESS &&
239
 
                    !master->depth && !defaults_master_set()) {
240
 
                        char *tmp = strchr(master->name, '.');
241
 
                        if (tmp) {
242
 
                                debug(logopt,
243
 
                                      "%s not found, replacing '.' with '_'",
244
 
                                       master->name);
245
 
                                *tmp = '_';
246
 
                                result = read_master_map(master, this->source, age);
247
 
                                if (result != NSS_STATUS_SUCCESS)
248
 
                                        *tmp = '.';
249
 
                        }
250
 
                }
251
 
 
252
 
                if (result == NSS_STATUS_UNKNOWN) {
253
 
                        debug(logopt, "no map - continuing to next source");
254
 
                        continue;
255
 
                }
256
 
 
257
 
                if (result == NSS_STATUS_UNAVAIL)
258
 
                        master->read_fail = 1;
259
 
 
260
 
                status = check_nss_result(this, result);
261
 
                if (status >= 0) {
262
 
                        free_sources(&nsslist);
263
 
                        return status;
264
 
                }
265
 
        }
266
 
 
267
 
        if (!list_empty(&nsslist))
268
 
                free_sources(&nsslist);
269
 
 
270
 
        return !result;
271
 
}
272
 
 
273
 
static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t age)
274
 
{
275
 
        struct lookup_mod *lookup;
276
 
        int status;
277
 
 
278
 
        lookup = open_lookup(map->type, "", map->format, map->argc, map->argv);
279
 
        if (!lookup) {
280
 
                debug(ap->logopt, "lookup module %s failed", map->type);
281
 
                return NSS_STATUS_UNAVAIL;
282
 
        }
283
 
 
284
 
        master_source_writelock(ap->entry);
285
 
        if (map->lookup)
286
 
                close_lookup(map->lookup);
287
 
        map->lookup = lookup;
288
 
        master_source_unlock(ap->entry);
289
 
 
290
 
        if (!map->stale)
291
 
                return NSS_STATUS_SUCCESS;
292
 
 
293
 
        master_source_current_wait(ap->entry);
294
 
        ap->entry->current = map;
295
 
 
296
 
        status = lookup->lookup_read_map(ap, age, lookup->context);
297
 
 
298
 
        if (status != NSS_STATUS_SUCCESS)
299
 
                map->stale = 0;
300
 
 
301
 
        /*
302
 
         * For maps that don't support enumeration return success
303
 
         * and do whatever we must to have autofs function with an
304
 
         * empty map entry cache.
305
 
         *
306
 
         * For indirect maps that use the browse option, when the
307
 
         * server is unavailable continue as best we can with
308
 
         * whatever we have in the cache, if anything.
309
 
         */
310
 
        if (status == NSS_STATUS_UNKNOWN ||
311
 
           (ap->type == LKP_INDIRECT && status == NSS_STATUS_UNAVAIL))
312
 
                return NSS_STATUS_SUCCESS;
313
 
 
314
 
        return status;
315
 
}
316
 
 
317
 
static int read_file_source_instance(struct autofs_point *ap, struct map_source *map, time_t age)
318
 
{
319
 
        struct map_source *instance;
320
 
        char src_file[] = "file";
321
 
        char src_prog[] = "program";
322
 
        struct stat st;
323
 
        char *type, *format;
324
 
 
325
 
        if (stat(map->argv[0], &st) == -1) {
326
 
                warn(ap->logopt, "file map %s not found", map->argv[0]);
327
 
                return NSS_STATUS_NOTFOUND;
328
 
        }
329
 
 
330
 
        if (!S_ISREG(st.st_mode))
331
 
                return NSS_STATUS_NOTFOUND;
332
 
 
333
 
        if (st.st_mode & __S_IEXEC)
334
 
                type = src_prog;
335
 
        else
336
 
                type = src_file;
337
 
 
338
 
        format = map->format;
339
 
 
340
 
        instance = master_find_source_instance(map, type, format, 0, NULL);
341
 
        if (!instance) {
342
 
                int argc = map->argc;
343
 
                const char **argv = map->argv;
344
 
                instance = master_add_source_instance(map, type, format, age, argc, argv);
345
 
                if (!instance)
346
 
                        return NSS_STATUS_UNAVAIL;
347
 
                instance->recurse = map->recurse;
348
 
                instance->depth = map->depth;
349
 
        }
350
 
        instance->stale = map->stale;
351
 
 
352
 
        return do_read_map(ap, instance, age);
353
 
}
354
 
 
355
 
static int read_source_instance(struct autofs_point *ap, struct map_source *map, const char *type, time_t age)
356
 
{
357
 
        struct map_source *instance;
358
 
        const char *format;
359
 
 
360
 
        format = map->format;
361
 
 
362
 
        instance = master_find_source_instance(map, type, format, 0, NULL);
363
 
        if (!instance) {
364
 
                int argc = map->argc;
365
 
                const char **argv = map->argv;
366
 
                instance = master_add_source_instance(map, type, format, age, argc, argv);
367
 
                if (!instance)
368
 
                        return NSS_STATUS_UNAVAIL;
369
 
                instance->recurse = map->recurse;
370
 
                instance->depth = map->depth;
371
 
        }
372
 
        instance->stale = map->stale;
373
 
 
374
 
        return do_read_map(ap, instance, age);
375
 
}
376
 
 
377
 
static void argv_cleanup(void *arg)
378
 
{
379
 
        struct map_source *tmap = (struct map_source *) arg;
380
 
        /* path is freed in free_argv */
381
 
        free_argv(tmap->argc, tmap->argv);
382
 
        return;
383
 
}
384
 
 
385
 
static enum nsswitch_status read_map_source(struct nss_source *this,
386
 
                struct autofs_point *ap, struct map_source *map, time_t age)
387
 
{
388
 
        enum nsswitch_status result;
389
 
        struct map_source tmap;
390
 
        char *path;
391
 
 
392
 
        if (strcasecmp(this->source, "files")) {
393
 
                return read_source_instance(ap, map, this->source, age);
394
 
        }
395
 
 
396
 
        /* 
397
 
         * autofs built-in map for nsswitch "files" is "file".
398
 
         * This is a special case as we need to append the
399
 
         * normal location to the map name.
400
 
         * note: It's invalid to specify a relative path.
401
 
         */
402
 
 
403
 
        if (strchr(map->argv[0], '/')) {
404
 
                error(ap->logopt, "relative path invalid in files map name");
405
 
                return NSS_STATUS_NOTFOUND;
406
 
        }
407
 
 
408
 
        this->source[4] = '\0';
409
 
        tmap.type = this->source;
410
 
        tmap.format = map->format;
411
 
        tmap.lookup = map->lookup;
412
 
        tmap.mc = map->mc;
413
 
        tmap.instance = map->instance;
414
 
        tmap.recurse = map->recurse;
415
 
        tmap.depth = map->depth;
416
 
        tmap.stale = map->stale;
417
 
        tmap.argc = 0;
418
 
        tmap.argv = NULL;
419
 
 
420
 
        path = malloc(strlen(AUTOFS_MAP_DIR) + strlen(map->argv[0]) + 2);
421
 
        if (!path)
422
 
                return NSS_STATUS_UNKNOWN;
423
 
 
424
 
        strcpy(path, AUTOFS_MAP_DIR);
425
 
        strcat(path, "/");
426
 
        strcat(path, map->argv[0]);
427
 
 
428
 
        if (map->argc >= 1) {
429
 
                tmap.argc = map->argc;
430
 
                tmap.argv = copy_argv(map->argc, map->argv);
431
 
                if (!tmap.argv) {
432
 
                        error(ap->logopt, "failed to copy args");
433
 
                        free(path);
434
 
                        return NSS_STATUS_UNKNOWN;
435
 
                }
436
 
                if (tmap.argv[0])
437
 
                        free((char *) tmap.argv[0]);
438
 
                tmap.argv[0] = path;
439
 
        } else {
440
 
                error(ap->logopt, "invalid arguments for autofs_point");
441
 
                free(path);
442
 
                return NSS_STATUS_UNKNOWN;
443
 
        }
444
 
 
445
 
        pthread_cleanup_push(argv_cleanup, &tmap);
446
 
        result = read_file_source_instance(ap, &tmap, age);
447
 
        pthread_cleanup_pop(1);
448
 
 
449
 
        map->instance = tmap.instance;
450
 
 
451
 
        return result;
452
 
}
453
 
 
454
 
int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age)
455
 
{
456
 
        struct master_mapent *entry = ap->entry;
457
 
        struct list_head nsslist;
458
 
        struct list_head *head, *p;
459
 
        struct nss_source *this;
460
 
        struct map_source *map;
461
 
        enum nsswitch_status status;
462
 
        unsigned int at_least_one = 0;
463
 
        int result = 0;
464
 
 
465
 
        /*
466
 
         * For each map source (ie. each entry for the mount
467
 
         * point in the master map) do the nss lookup to
468
 
         * locate the map and read it.
469
 
         */
470
 
        if (source)
471
 
                map = source;
472
 
        else
473
 
                map = entry->maps;
474
 
        while (map) {
475
 
                /* Is map source up to date or no longer valid */
476
 
                if (!map->stale || entry->age > map->age) {
477
 
                        map = map->next;
478
 
                        continue;
479
 
                }
480
 
 
481
 
                if (map->type) {
482
 
                        if (!strncmp(map->type, "multi", 5))
483
 
                                debug(ap->logopt, "reading multi map");
484
 
                        else
485
 
                                debug(ap->logopt,
486
 
                                      "reading map %s %s",
487
 
                                       map->type, map->argv[0]);
488
 
                        result = do_read_map(ap, map, age);
489
 
                        map = map->next;
490
 
                        continue;
491
 
                }
492
 
 
493
 
                /* If it starts with a '/' it has to be a file or LDAP map */
494
 
                if (map->argv && *map->argv[0] == '/') {
495
 
                        if (*(map->argv[0] + 1) == '/') {
496
 
                                char *tmp = strdup("ldap");
497
 
                                if (!tmp) {
498
 
                                        map = map->next;
499
 
                                        continue;
500
 
                                }
501
 
                                map->type = tmp;
502
 
                                debug(ap->logopt,
503
 
                                      "reading map %s %s", tmp, map->argv[0]);
504
 
                                result = do_read_map(ap, map, age);
505
 
                        } else {
506
 
                                debug(ap->logopt,
507
 
                                      "reading map file %s", map->argv[0]);
508
 
                                result = read_file_source_instance(ap, map, age);
509
 
                        }
510
 
                        map = map->next;
511
 
                        continue;
512
 
                }
513
 
 
514
 
                INIT_LIST_HEAD(&nsslist);
515
 
 
516
 
                pthread_cleanup_push(nsslist_cleanup, &nsslist);
517
 
                status = nsswitch_parse(&nsslist);
518
 
                pthread_cleanup_pop(0);
519
 
                if (status) {
520
 
                        error(ap->logopt,
521
 
                              "can't to read name service switch config.");
522
 
                        result = 1;
523
 
                        break;
524
 
                }
525
 
 
526
 
                pthread_cleanup_push(nsslist_cleanup, &nsslist);
527
 
                head = &nsslist;
528
 
                list_for_each(p, head) {
529
 
                        this = list_entry(p, struct nss_source, list);
530
 
 
531
 
                        debug(ap->logopt,
532
 
                              "reading map %s %s", this->source, map->argv[0]);
533
 
 
534
 
                        result = read_map_source(this, ap, map, age);
535
 
                        if (result == NSS_STATUS_UNKNOWN)
536
 
                                continue;
537
 
 
538
 
                        /* Don't try to update the map cache if it's unavailable */
539
 
                        if (result == NSS_STATUS_UNAVAIL)
540
 
                                map->stale = 0;
541
 
 
542
 
                        if (result == NSS_STATUS_SUCCESS) {
543
 
                                at_least_one = 1;
544
 
                                result = NSS_STATUS_TRYAGAIN;
545
 
                        }
546
 
 
547
 
                        status = check_nss_result(this, result);
548
 
                        if (status >= 0) {
549
 
                                map = NULL;
550
 
                                break;
551
 
                        }
552
 
 
553
 
                        result = NSS_STATUS_SUCCESS;
554
 
                }
555
 
                pthread_cleanup_pop(1);
556
 
 
557
 
                if (!map)
558
 
                        break;
559
 
 
560
 
                map = map->next;
561
 
        }
562
 
 
563
 
        if (!result || at_least_one)
564
 
                return 1;
565
 
 
566
 
        return 0;
567
 
}
568
 
 
569
 
int lookup_ghost(struct autofs_point *ap, const char *root)
570
 
{
571
 
        struct master_mapent *entry = ap->entry;
572
 
        struct map_source *map;
573
 
        struct mapent_cache *mc;
574
 
        struct mapent *me;
575
 
        char buf[MAX_ERR_BUF];
576
 
        struct stat st;
577
 
        char *fullpath;
578
 
        int ret;
579
 
 
580
 
        if (!strcmp(ap->path, "/-"))
581
 
                return LKP_FAIL | LKP_DIRECT;
582
 
 
583
 
        if (!(ap->flags & MOUNT_FLAG_GHOST))
584
 
                return LKP_INDIRECT;
585
 
 
586
 
        pthread_cleanup_push(master_source_lock_cleanup, entry);
587
 
        master_source_readlock(entry);
588
 
        map = entry->maps;
589
 
        while (map) {
590
 
                /*
591
 
                 * Only consider map sources that have been read since 
592
 
                 * the map entry was last updated.
593
 
                 */
594
 
                if (entry->age > map->age) {
595
 
                        map = map->next;
596
 
                        continue;
597
 
                }
598
 
 
599
 
                mc = map->mc;
600
 
                pthread_cleanup_push(cache_lock_cleanup, mc);
601
 
                cache_readlock(mc);
602
 
                me = cache_enumerate(mc, NULL);
603
 
                while (me) {
604
 
                        if (!strcmp(me->key, "*"))
605
 
                                goto next;
606
 
 
607
 
                        if (*me->key == '/') {
608
 
                                /* It's a busy multi-mount - leave till next time */
609
 
                                if (list_empty(&me->multi_list))
610
 
                                        error(ap->logopt,
611
 
                                              "invalid key %s", me->key);
612
 
                                goto next;
613
 
                        }
614
 
 
615
 
                        fullpath = malloc(strlen(me->key) + strlen(root) + 3);
616
 
                        if (!fullpath) {
617
 
                                warn(ap->logopt, "failed to allocate full path");
618
 
                                goto next;
619
 
                        }
620
 
                        sprintf(fullpath, "%s/%s", root, me->key);
621
 
 
622
 
                        ret = stat(fullpath, &st);
623
 
                        if (ret == -1 && errno != ENOENT) {
624
 
                                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
625
 
                                warn(ap->logopt, "stat error %s", estr);
626
 
                                free(fullpath);
627
 
                                goto next;
628
 
                        }
629
 
 
630
 
                        ret = mkdir_path(fullpath, 0555);
631
 
                        if (ret < 0 && errno != EEXIST) {
632
 
                                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
633
 
                                warn(ap->logopt,
634
 
                                     "mkdir_path %s failed: %s", fullpath, estr);
635
 
                                free(fullpath);
636
 
                                goto next;
637
 
                        }
638
 
 
639
 
                        if (stat(fullpath, &st) != -1) {
640
 
                                me->dev = st.st_dev;
641
 
                                me->ino = st.st_ino;
642
 
                        }
643
 
 
644
 
                        free(fullpath);
645
 
next:
646
 
                        me = cache_enumerate(mc, me);
647
 
                }
648
 
                pthread_cleanup_pop(1);
649
 
                map = map->next;
650
 
        }
651
 
        pthread_cleanup_pop(1);
652
 
 
653
 
        return LKP_INDIRECT;
654
 
}
655
 
 
656
 
int do_lookup_mount(struct autofs_point *ap, struct map_source *map, const char *name, int name_len)
657
 
{
658
 
        struct lookup_mod *lookup;
659
 
        int status;
660
 
 
661
 
        if (!map->lookup) {
662
 
                lookup = open_lookup(map->type, "",
663
 
                                     map->format, map->argc, map->argv);
664
 
                if (!lookup) {
665
 
                        debug(ap->logopt,
666
 
                              "lookup module %s failed", map->type);
667
 
                        return NSS_STATUS_UNAVAIL;
668
 
                }
669
 
                map->lookup = lookup;
670
 
        }
671
 
 
672
 
        lookup = map->lookup;
673
 
 
674
 
        master_source_current_wait(ap->entry);
675
 
        ap->entry->current = map;
676
 
 
677
 
        status = lookup->lookup_mount(ap, name, name_len, lookup->context);
678
 
 
679
 
        return status;
680
 
}
681
 
 
682
 
static int lookup_name_file_source_instance(struct autofs_point *ap, struct map_source *map, const char *name, int name_len)
683
 
{
684
 
        struct map_source *instance;
685
 
        char src_file[] = "file";
686
 
        char src_prog[] = "program";
687
 
        time_t age = time(NULL);
688
 
        struct stat st;
689
 
        char *type, *format;
690
 
 
691
 
        if (stat(map->argv[0], &st) == -1) {
692
 
                debug(ap->logopt, "file map not found");
693
 
                return NSS_STATUS_NOTFOUND;
694
 
        }
695
 
 
696
 
        if (!S_ISREG(st.st_mode))
697
 
                return NSS_STATUS_NOTFOUND;
698
 
 
699
 
        if (st.st_mode & __S_IEXEC)
700
 
                type = src_prog;
701
 
        else
702
 
                type = src_file;
703
 
 
704
 
        format = map->format;
705
 
 
706
 
        instance = master_find_source_instance(map, type, format, 0, NULL);
707
 
        if (!instance) {
708
 
                int argc = map->argc;
709
 
                const char **argv = map->argv;
710
 
                instance = master_add_source_instance(map, type, format, age, argc, argv);
711
 
                if (!instance)
712
 
                        return NSS_STATUS_NOTFOUND;
713
 
                instance->recurse = map->recurse;
714
 
                instance->depth = map->depth;
715
 
        }
716
 
 
717
 
        return do_lookup_mount(ap, instance, name, name_len);
718
 
}
719
 
 
720
 
static int lookup_name_source_instance(struct autofs_point *ap, struct map_source *map, const char *type, const char *name, int name_len)
721
 
{
722
 
        struct map_source *instance;
723
 
        const char *format;
724
 
        time_t age = time(NULL);
725
 
 
726
 
        format = map->format;
727
 
 
728
 
        instance = master_find_source_instance(map, type, format, 0, NULL);
729
 
        if (!instance) {
730
 
                int argc = map->argc;
731
 
                const char **argv = map->argv;
732
 
                instance = master_add_source_instance(map, type, format, age, argc, argv);
733
 
                if (!instance)
734
 
                        return NSS_STATUS_NOTFOUND;
735
 
                instance->recurse = map->recurse;
736
 
                instance->depth = map->depth;
737
 
        }
738
 
 
739
 
        return do_lookup_mount(ap, instance, name, name_len);
740
 
}
741
 
 
742
 
static enum nsswitch_status lookup_map_name(struct nss_source *this,
743
 
                        struct autofs_point *ap, struct map_source *map,
744
 
                        const char *name, int name_len)
745
 
{
746
 
        enum nsswitch_status result;
747
 
        struct map_source tmap;
748
 
        char *path;
749
 
 
750
 
        if (strcasecmp(this->source, "files"))
751
 
                return lookup_name_source_instance(ap, map,
752
 
                                        this->source, name, name_len);
753
 
 
754
 
        /* 
755
 
         * autofs build-in map for nsswitch "files" is "file".
756
 
         * This is a special case as we need to append the
757
 
         * normal location to the map name.
758
 
         * note: we consider it invalid to specify a relative
759
 
         *       path.
760
 
         */
761
 
        if (strchr(map->argv[0], '/')) {
762
 
                error(ap->logopt, "relative path invalid in files map name");
763
 
                return NSS_STATUS_NOTFOUND;
764
 
        }
765
 
 
766
 
        this->source[4] = '\0';
767
 
        tmap.type = this->source;
768
 
        tmap.format = map->format;
769
 
        tmap.mc = map->mc;
770
 
        tmap.instance = map->instance;
771
 
        tmap.recurse = map->recurse;
772
 
        tmap.depth = map->depth;
773
 
        tmap.argc = 0;
774
 
        tmap.argv = NULL;
775
 
 
776
 
        path = malloc(strlen(AUTOFS_MAP_DIR) + strlen(map->argv[0]) + 2);
777
 
        if (!path)
778
 
                return NSS_STATUS_UNKNOWN;
779
 
 
780
 
        strcpy(path, AUTOFS_MAP_DIR);
781
 
        strcat(path, "/");
782
 
        strcat(path, map->argv[0]);
783
 
 
784
 
        if (map->argc >= 1) {
785
 
                tmap.argc = map->argc;
786
 
                tmap.argv = copy_argv(map->argc, map->argv);
787
 
                if (!tmap.argv) {
788
 
                        error(ap->logopt, "failed to copy args");
789
 
                        free(path);
790
 
                        return NSS_STATUS_UNKNOWN;
791
 
                }
792
 
                if (tmap.argv[0])
793
 
                        free((char *) tmap.argv[0]);
794
 
                tmap.argv[0] = path;
795
 
        } else {
796
 
                error(ap->logopt, "invalid arguments for autofs_point");
797
 
                free(path);
798
 
                return NSS_STATUS_UNKNOWN;
799
 
        }
800
 
 
801
 
        result = lookup_name_file_source_instance(ap, &tmap, name, name_len);
802
 
 
803
 
        map->instance = tmap.instance;
804
 
 
805
 
        /* path is freed in free_argv */
806
 
        free_argv(tmap.argc, tmap.argv);
807
 
 
808
 
        return result;
809
 
}
810
 
 
811
 
static void update_negative_cache(struct autofs_point *ap, struct map_source *source, const char *name)
812
 
{
813
 
        struct master_mapent *entry = ap->entry;
814
 
        struct map_source *map;
815
 
        struct mapent *me;
816
 
 
817
 
        /* Don't update negative cache for included maps */ 
818
 
        if (source && source->depth)
819
 
                return;
820
 
 
821
 
        /* Have we recorded the lookup fail for negative caching? */
822
 
        me = lookup_source_mapent(ap, name, LKP_DISTINCT);
823
 
        if (me)
824
 
                /*
825
 
                 *  Already exists in the cache, the mount fail updates
826
 
                 *  will update negative timeout status.
827
 
                 */
828
 
                cache_unlock(me->mc);
829
 
        else {
830
 
                /* Notify only once after fail */
831
 
                logmsg("key \"%s\" not found in map source(s).", name);
832
 
 
833
 
                /* Doesn't exist in any source, just add it somewhere */
834
 
                if (source)
835
 
                        map = source;
836
 
                else
837
 
                        map = entry->maps;
838
 
                if (map) {
839
 
                        time_t now = time(NULL);
840
 
                        int rv = CHE_FAIL;
841
 
 
842
 
                        cache_writelock(map->mc);
843
 
                        rv = cache_update(map->mc, map, name, NULL, now);
844
 
                        if (rv != CHE_FAIL) {
845
 
                                me = cache_lookup_distinct(map->mc, name);
846
 
                                me->status = now + ap->negative_timeout;
847
 
                        }
848
 
                        cache_unlock(map->mc);
849
 
                }
850
 
        }
851
 
        return;
852
 
}
853
 
 
854
 
int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len)
855
 
{
856
 
        struct master_mapent *entry = ap->entry;
857
 
        struct list_head nsslist;
858
 
        struct list_head *head, *p;
859
 
        struct nss_source *this;
860
 
        struct map_source *map;
861
 
        enum nsswitch_status status;
862
 
        int result = 0;
863
 
 
864
 
        /*
865
 
         * For each map source (ie. each entry for the mount
866
 
         * point in the master map) do the nss lookup to
867
 
         * locate the map and lookup the name.
868
 
         */
869
 
        pthread_cleanup_push(master_source_lock_cleanup, entry);
870
 
        master_source_readlock(entry);
871
 
        if (source)
872
 
                map = source;
873
 
        else
874
 
                map = entry->maps;
875
 
        while (map) {
876
 
                /*
877
 
                 * Only consider map sources that have been read since 
878
 
                 * the map entry was last updated.
879
 
                 */
880
 
                if (entry->age > map->age) {
881
 
                        map = map->next;
882
 
                        continue;
883
 
                }
884
 
 
885
 
                sched_yield();
886
 
 
887
 
                if (map->type) {
888
 
                        result = do_lookup_mount(ap, map, name, name_len);
889
 
 
890
 
                        if (result == NSS_STATUS_SUCCESS)
891
 
                                break;
892
 
 
893
 
                        map = map->next;
894
 
                        continue;
895
 
                }
896
 
 
897
 
                /* If it starts with a '/' it has to be a file or LDAP map */
898
 
                if (*map->argv[0] == '/') {
899
 
                        if (*(map->argv[0] + 1) == '/') {
900
 
                                char *tmp = strdup("ldap");
901
 
                                if (!tmp) {
902
 
                                        map = map->next;
903
 
                                        continue;
904
 
                                }
905
 
                                map->type = tmp;
906
 
                                result = do_lookup_mount(ap, map, name, name_len);
907
 
                        } else
908
 
                                result = lookup_name_file_source_instance(ap, map, name, name_len);
909
 
 
910
 
                        if (result == NSS_STATUS_SUCCESS)
911
 
                                break;
912
 
 
913
 
                        map = map->next;
914
 
                        continue;
915
 
                }
916
 
 
917
 
                INIT_LIST_HEAD(&nsslist);
918
 
 
919
 
                status = nsswitch_parse(&nsslist);
920
 
                if (status) {
921
 
                        error(ap->logopt,
922
 
                              "can't to read name service switch config.");
923
 
                        result = 1;
924
 
                        break;
925
 
                }
926
 
 
927
 
                head = &nsslist;
928
 
                list_for_each(p, head) {
929
 
                        this = list_entry(p, struct nss_source, list);
930
 
 
931
 
                        result = lookup_map_name(this, ap, map, name, name_len);
932
 
 
933
 
                        if (result == NSS_STATUS_UNKNOWN) {
934
 
                                map = map->next;
935
 
                                continue;
936
 
                        }
937
 
 
938
 
                        status = check_nss_result(this, result);
939
 
                        if (status >= 0) {
940
 
                                map = NULL;
941
 
                                break;
942
 
                        }
943
 
                }
944
 
 
945
 
                if (!list_empty(&nsslist))
946
 
                        free_sources(&nsslist);
947
 
 
948
 
                if (!map)
949
 
                        break;
950
 
 
951
 
                map = map->next;
952
 
        }
953
 
        if (ap->state != ST_INIT)
954
 
                send_map_update_request(ap);
955
 
        pthread_cleanup_pop(1);
956
 
 
957
 
        /*
958
 
         * The last source lookup will return NSS_STATUS_NOTFOUND if the
959
 
         * map exits and the key has not been found but the map may also
960
 
         * not exist in which case the key is also not found.
961
 
         */
962
 
        if (result == NSS_STATUS_NOTFOUND || result == NSS_STATUS_UNAVAIL)
963
 
                update_negative_cache(ap, source, name);
964
 
 
965
 
        return !result;
966
 
}
967
 
 
968
 
static void lookup_close_lookup_instances(struct map_source *map)
969
 
{
970
 
        struct map_source *instance;
971
 
 
972
 
        instance = map->instance;
973
 
        while (instance) {
974
 
                lookup_close_lookup_instances(instance);
975
 
                instance = instance->next;
976
 
        }
977
 
 
978
 
        if (map->lookup) {
979
 
                close_lookup(map->lookup);
980
 
                map->lookup = NULL;
981
 
        }
982
 
}
983
 
 
984
 
void lookup_close_lookup(struct autofs_point *ap)
985
 
{
986
 
        struct map_source *map;
987
 
 
988
 
        map = ap->entry->maps;
989
 
        if (!map)
990
 
                return;
991
 
 
992
 
        while (map) {
993
 
                lookup_close_lookup_instances(map);
994
 
                map = map->next;
995
 
        }
996
 
 
997
 
        return;
998
 
}
999
 
 
1000
 
static char *make_fullpath(const char *root, const char *key)
1001
 
{
1002
 
        int l;
1003
 
        char *path;
1004
 
 
1005
 
        if (*key == '/') {
1006
 
                l = strlen(key) + 1;
1007
 
                if (l > KEY_MAX_LEN)
1008
 
                        return NULL;
1009
 
                path = malloc(l);
1010
 
                if (!path)
1011
 
                        return NULL;
1012
 
                strcpy(path, key);
1013
 
        } else {
1014
 
                l = strlen(key) + 1 + strlen(root) + 1;
1015
 
                if (l > KEY_MAX_LEN)
1016
 
                        return NULL;
1017
 
                path = malloc(l);
1018
 
                if (!path)
1019
 
                        return NULL;
1020
 
                sprintf(path, "%s/%s", root, key);
1021
 
        }
1022
 
        return path;
1023
 
}
1024
 
 
1025
 
void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, time_t age)
1026
 
{
1027
 
        struct mapent *me, *this;
1028
 
        char *path;
1029
 
        int status = CHE_FAIL;
1030
 
 
1031
 
        me = cache_enumerate(mc, NULL);
1032
 
        while (me) {
1033
 
                struct mapent *valid;
1034
 
                char *key = NULL, *next_key = NULL;
1035
 
 
1036
 
                if (me->age >= age) {
1037
 
                        me = cache_enumerate(mc, me);
1038
 
                        continue;
1039
 
                }
1040
 
 
1041
 
                key = strdup(me->key);
1042
 
                me = cache_enumerate(mc, me);
1043
 
                if (!key || !strcmp(key, "*")) {
1044
 
                        if (key)
1045
 
                                free(key);
1046
 
                        continue;
1047
 
                }
1048
 
 
1049
 
                path = make_fullpath(ap->path, key);
1050
 
                if (!path) {
1051
 
                        warn(ap->logopt, "can't malloc storage for path");
1052
 
                        free(key);
1053
 
                        continue;
1054
 
                }
1055
 
 
1056
 
                /*
1057
 
                 * If this key has another valid entry we want to prune it,
1058
 
                 * even if it's a mount, as the valid entry will take the
1059
 
                 * mount if it is a direct mount or it's just a stale indirect
1060
 
                 * cache entry.
1061
 
                 */
1062
 
                valid = lookup_source_valid_mapent(ap, key, LKP_DISTINCT);
1063
 
                if (!valid &&
1064
 
                    is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
1065
 
                        debug(ap->logopt,
1066
 
                              "prune check posponed, %s mounted", path);
1067
 
                        free(key);
1068
 
                        free(path);
1069
 
                        continue;
1070
 
                }
1071
 
                if (valid)
1072
 
                        cache_unlock(valid->mc);
1073
 
 
1074
 
                if (me)
1075
 
                        next_key = strdup(me->key);
1076
 
 
1077
 
                cache_unlock(mc);
1078
 
 
1079
 
                cache_writelock(mc);
1080
 
                this = cache_lookup_distinct(mc, key);
1081
 
                if (!this) {
1082
 
                        cache_unlock(mc);
1083
 
                        goto next;
1084
 
                }
1085
 
 
1086
 
                if (valid)
1087
 
                        cache_delete(mc, key);
1088
 
                else if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) {
1089
 
                        status = CHE_FAIL;
1090
 
                        if (this->ioctlfd == -1)
1091
 
                                status = cache_delete(mc, key);
1092
 
                        if (status != CHE_FAIL) {
1093
 
                                if (ap->type == LKP_INDIRECT) {
1094
 
                                        if (ap->flags & MOUNT_FLAG_GHOST)
1095
 
                                                rmdir_path(ap, path, ap->dev);
1096
 
                                } else
1097
 
                                        rmdir_path(ap, path, this->dev);
1098
 
                        }
1099
 
                }
1100
 
                cache_unlock(mc);
1101
 
 
1102
 
next:
1103
 
                cache_readlock(mc);
1104
 
                if (next_key) {
1105
 
                        me = cache_lookup_distinct(mc, next_key);
1106
 
                        free(next_key);
1107
 
                }
1108
 
                free(key);
1109
 
                free(path);
1110
 
        }
1111
 
 
1112
 
        return;
1113
 
}
1114
 
 
1115
 
int lookup_prune_cache(struct autofs_point *ap, time_t age)
1116
 
{
1117
 
        struct master_mapent *entry = ap->entry;
1118
 
        struct map_source *map;
1119
 
 
1120
 
        pthread_cleanup_push(master_source_lock_cleanup, entry);
1121
 
        master_source_readlock(entry);
1122
 
 
1123
 
        map = entry->maps;
1124
 
        while (map) {
1125
 
                /* Is the map stale */
1126
 
                if (!map->stale) {
1127
 
                        map = map->next;
1128
 
                        continue;
1129
 
                }
1130
 
                pthread_cleanup_push(cache_lock_cleanup, map->mc);
1131
 
                cache_readlock(map->mc);
1132
 
                lookup_prune_one_cache(ap, map->mc, age);
1133
 
                pthread_cleanup_pop(1);
1134
 
                map->stale = 0;
1135
 
                map = map->next;
1136
 
        }
1137
 
 
1138
 
        pthread_cleanup_pop(1);
1139
 
 
1140
 
        return 1;
1141
 
}
1142
 
 
1143
 
/* Return with cache readlock held */
1144
 
struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *key, unsigned int type)
1145
 
{
1146
 
        struct master_mapent *entry = ap->entry;
1147
 
        struct map_source *map;
1148
 
        struct mapent_cache *mc;
1149
 
        struct mapent *me = NULL;
1150
 
 
1151
 
        map = entry->maps;
1152
 
        while (map) {
1153
 
                /*
1154
 
                 * Only consider map sources that have been read since
1155
 
                 * the map entry was last updated.
1156
 
                 */
1157
 
                if (ap->entry->age > map->age) {
1158
 
                        map = map->next;
1159
 
                        continue;
1160
 
                }
1161
 
 
1162
 
                mc = map->mc;
1163
 
                cache_readlock(mc);
1164
 
                if (type == LKP_DISTINCT)
1165
 
                        me = cache_lookup_distinct(mc, key);
1166
 
                else
1167
 
                        me = cache_lookup(mc, key);
1168
 
                if (me)
1169
 
                        break;
1170
 
                cache_unlock(mc);
1171
 
                map = map->next;
1172
 
        }
1173
 
 
1174
 
        return me;
1175
 
}
1176
 
 
1177
 
/* Return with cache readlock held */
1178
 
struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, unsigned int type)
1179
 
{
1180
 
        struct master_mapent *entry = ap->entry;
1181
 
        struct map_source *map;
1182
 
        struct mapent_cache *mc;
1183
 
        struct mapent *me = NULL;
1184
 
 
1185
 
        map = entry->maps;
1186
 
        while (map) {
1187
 
                mc = map->mc;
1188
 
                cache_readlock(mc);
1189
 
                if (type == LKP_DISTINCT)
1190
 
                        me = cache_lookup_distinct(mc, key);
1191
 
                else
1192
 
                        me = cache_lookup(mc, key);
1193
 
                if (me)
1194
 
                        break;
1195
 
                cache_unlock(mc);
1196
 
                map = map->next;
1197
 
        }
1198
 
 
1199
 
        if (me && me->mc != mc)
1200
 
                error(LOGOPT_ANY, "mismatching mc in cache", me->key);
1201
 
 
1202
 
        return me;
1203
 
}
1204
 
 
1205
 
int lookup_source_close_ioctlfd(struct autofs_point *ap, const char *key)
1206
 
{
1207
 
        struct master_mapent *entry = ap->entry;
1208
 
        struct map_source *map;
1209
 
        struct mapent_cache *mc;
1210
 
        struct mapent *me;
1211
 
        int ret = 0;
1212
 
 
1213
 
        map = entry->maps;
1214
 
        while (map) {
1215
 
                mc = map->mc;
1216
 
                cache_readlock(mc);
1217
 
                me = cache_lookup_distinct(mc, key);
1218
 
                if (me) {
1219
 
                        if (me->ioctlfd != -1) {
1220
 
                                struct ioctl_ops *ops = get_ioctl_ops();
1221
 
                                ops->close(ap->logopt, me->ioctlfd);
1222
 
                                me->ioctlfd = -1;
1223
 
                        }
1224
 
                        cache_unlock(mc);
1225
 
                        ret = 1;
1226
 
                        break;
1227
 
                }
1228
 
                cache_unlock(mc);
1229
 
                map = map->next;
1230
 
        }
1231
 
 
1232
 
        return ret;
1233
 
}
1234