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

« back to all changes in this revision

Viewing changes to .pc/autofs-5.0.5-fix-parse_sun-module-init.patch/modules/parse_sun.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
 
 *  parse_sun.c - module for Linux automountd to parse a Sun-format
4
 
 *                automounter map
5
 
 * 
6
 
 *   Copyright 1997 Transmeta Corporation - All Rights Reserved
7
 
 *   Copyright 2000 Jeremy Fitzhardinge <jeremy@goop.org>
8
 
 *   Copyright 2004, 2005 Ian Kent <raven@themaw.net>
9
 
 *
10
 
 *   This program is free software; you can redistribute it and/or modify
11
 
 *   it under the terms of the GNU General Public License as published by
12
 
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
13
 
 *   USA; either version 2 of the License, or (at your option) any later
14
 
 *   version; incorporated herein by reference.
15
 
 *
16
 
 * ----------------------------------------------------------------------- */
17
 
 
18
 
#include <stdio.h>
19
 
#include <malloc.h>
20
 
#include <netdb.h>
21
 
#include <stdlib.h>
22
 
#include <string.h>
23
 
#include <ctype.h>
24
 
#include <limits.h>
25
 
#include <sys/param.h>
26
 
#include <sys/socket.h>
27
 
#include <sys/types.h>
28
 
#include <sys/stat.h>
29
 
#include <sys/vfs.h>
30
 
#include <sys/utsname.h>
31
 
#include <netinet/in.h>
32
 
#include <sys/mount.h>
33
 
#include <linux/fs.h>
34
 
 
35
 
#define MODULE_PARSE
36
 
#include "automount.h"
37
 
 
38
 
#define MODPREFIX "parse(sun): "
39
 
 
40
 
#define MOUNT_MOVE_NONE         0x00
41
 
#define MOUNT_MOVE_AUTOFS       0x01
42
 
#define MOUNT_MOVE_OTHER        0x02
43
 
 
44
 
int parse_version = AUTOFS_PARSE_VERSION;       /* Required by protocol */
45
 
 
46
 
static struct mount_mod *mount_nfs = NULL;
47
 
static int init_ctr = 0;
48
 
 
49
 
extern const char *global_options;
50
 
 
51
 
struct parse_context {
52
 
        char *optstr;           /* Mount options */
53
 
        char *macros;           /* Map wide macro defines */
54
 
        struct substvar *subst; /* $-substitutions */
55
 
        int slashify_colons;    /* Change colons to slashes? */
56
 
};
57
 
 
58
 
struct multi_mnt {
59
 
        char *path;
60
 
        char *options;
61
 
        char *location;
62
 
        struct multi_mnt *next;
63
 
};
64
 
 
65
 
/* Default context */
66
 
 
67
 
static struct parse_context default_context = {
68
 
        NULL,                   /* No mount options */
69
 
        NULL,                   /* No map wide macros */
70
 
        NULL,                   /* The substvar local vars table */
71
 
        1                       /* Do slashify_colons */
72
 
};
73
 
 
74
 
int destroy_logpri_fifo(struct autofs_point *ap);
75
 
static char *concat_options(char *left, char *right);
76
 
 
77
 
/* Free all storage associated with this context */
78
 
static void kill_context(struct parse_context *ctxt)
79
 
{
80
 
        macro_lock();
81
 
        macro_free_table(ctxt->subst);
82
 
        macro_unlock();
83
 
        if (ctxt->optstr)
84
 
                free(ctxt->optstr);
85
 
        if (ctxt->macros)
86
 
                free(ctxt->macros);
87
 
        free(ctxt);
88
 
}
89
 
 
90
 
static struct substvar *addstdenv(struct substvar *sv)
91
 
{
92
 
        struct substvar *list = sv;
93
 
        struct thread_stdenv_vars *tsv;
94
 
        char numbuf[16];
95
 
 
96
 
        tsv = pthread_getspecific(key_thread_stdenv_vars);
97
 
        if (tsv) {
98
 
                int ret;
99
 
                long num;
100
 
 
101
 
                num = (long) tsv->uid;
102
 
                ret = sprintf(numbuf, "%ld", num);
103
 
                if (ret > 0)
104
 
                        list = macro_addvar(list, "UID", 3, numbuf);
105
 
                num = (long) tsv->gid;
106
 
                ret = sprintf(numbuf, "%ld", num);
107
 
                if (ret > 0)
108
 
                        list = macro_addvar(list, "GID", 3, numbuf);
109
 
                list = macro_addvar(list, "USER", 4, tsv->user);
110
 
                list = macro_addvar(list, "GROUP", 5, tsv->group);
111
 
                list = macro_addvar(list, "HOME", 4, tsv->home);
112
 
        }
113
 
        return list;
114
 
}
115
 
 
116
 
static struct substvar *removestdenv(struct substvar *sv)
117
 
{
118
 
        struct substvar *list = sv;
119
 
 
120
 
        list = macro_removevar(list, "UID", 3);
121
 
        list = macro_removevar(list, "USER", 4);
122
 
        list = macro_removevar(list, "HOME", 4);
123
 
        list = macro_removevar(list, "GID", 3);
124
 
        list = macro_removevar(list, "GROUP", 5);
125
 
        return list;
126
 
}
127
 
 
128
 
/* 
129
 
 * $- and &-expand a Sun-style map entry and return the length of the entry.
130
 
 * If "dst" is NULL, just count the length.
131
 
 */
132
 
int expandsunent(const char *src, char *dst, const char *key,
133
 
                 const struct substvar *svc, int slashify_colons)
134
 
{
135
 
        const struct substvar *sv;
136
 
        int len, l, seen_colons;
137
 
        const char *p;
138
 
        char ch;
139
 
 
140
 
        len = 0;
141
 
        seen_colons = 0;
142
 
 
143
 
        while ((ch = *src++)) {
144
 
                switch (ch) {
145
 
                case '&':
146
 
                        l = strlen(key);
147
 
                        /*
148
 
                         * In order to ensure that any spaces in the key
149
 
                         * re preserved, we need to escape them here.
150
 
                         */
151
 
                        if (strchr(key, ' ')) {
152
 
                                const char *keyp = key;
153
 
                                while (*keyp) {
154
 
                                        if (isspace(*keyp)) {
155
 
                                                if (dst) {
156
 
                                                        *dst++ = '\\';
157
 
                                                        *dst++ = *keyp++;
158
 
                                                } else
159
 
                                                        keyp++;
160
 
                                                l++;
161
 
                                        } else {
162
 
                                                if (dst)
163
 
                                                        *dst++ = *keyp++;
164
 
                                                else
165
 
                                                        keyp++;
166
 
                                        }
167
 
                                }
168
 
                        } else {
169
 
                                if (dst) {
170
 
                                        strcpy(dst, key);
171
 
                                        dst += l;
172
 
                                }
173
 
                        }
174
 
                        len += l;
175
 
                        break;
176
 
 
177
 
                case '$':
178
 
                        if (*src == '{') {
179
 
                                p = strchr(++src, '}');
180
 
                                if (!p) {
181
 
                                        /* Ignore rest of string */
182
 
                                        if (dst)
183
 
                                                *dst = '\0';
184
 
                                        return len;
185
 
                                }
186
 
                                sv = macro_findvar(svc, src, p - src);
187
 
                                if (sv) {
188
 
                                        l = strlen(sv->val);
189
 
                                        if (dst) {
190
 
                                                strcpy(dst, sv->val);
191
 
                                                dst += l;
192
 
                                        }
193
 
                                        len += l;
194
 
                                }
195
 
                                src = p + 1;
196
 
                        } else {
197
 
                                p = src;
198
 
                                while (isalnum(*p) || *p == '_')
199
 
                                        p++;
200
 
                                sv = macro_findvar(svc, src, p - src);
201
 
                                if (sv) {
202
 
                                        l = strlen(sv->val);
203
 
                                        if (dst) {
204
 
                                                strcpy(dst, sv->val);
205
 
                                                dst += l;
206
 
                                        }
207
 
                                        len += l;
208
 
                                }
209
 
                                src = p;
210
 
                        }
211
 
                        break;
212
 
 
213
 
                case '\\':
214
 
                        len++;
215
 
                        if (dst)
216
 
                                *dst++ = ch;
217
 
 
218
 
                        if (*src) {
219
 
                                len++;
220
 
                                if (dst)
221
 
                                        *dst++ = *src;
222
 
                                src++;
223
 
                        }
224
 
                        break;
225
 
 
226
 
                case '"':
227
 
                        len++;
228
 
                        if (dst)
229
 
                                *dst++ = ch;
230
 
 
231
 
                        while (*src && *src != '"') {
232
 
                                len++;
233
 
                                if (dst)
234
 
                                        *dst++ = *src;
235
 
                                src++;
236
 
                        }
237
 
                        if (*src && dst) {
238
 
                                len++;
239
 
                                *dst++ = *src++;
240
 
                        }
241
 
                        break;
242
 
 
243
 
                case ':':
244
 
                        if (dst)
245
 
                                *(dst++) = 
246
 
                                  (seen_colons && slashify_colons) ? '/' : ':';
247
 
                        len++;
248
 
                        /* Were looking for the colon preceeding a path */
249
 
                        if (*src == '/')
250
 
                                seen_colons = 1;
251
 
                        break;
252
 
 
253
 
                default:
254
 
                        if (isspace(ch))
255
 
                                seen_colons = 0;
256
 
 
257
 
                        if (dst)
258
 
                                *(dst++) = ch;
259
 
                        len++;
260
 
                        break;
261
 
                }
262
 
        }
263
 
        if (dst)
264
 
                *dst = '\0';
265
 
        return len;
266
 
}
267
 
 
268
 
int parse_init(int argc, const char *const *argv, void **context)
269
 
{
270
 
        struct parse_context *ctxt;
271
 
        char buf[MAX_ERR_BUF];
272
 
        char *noptstr, *def, *val, *macros, *gbl_options;
273
 
        const char *xopt;
274
 
        int optlen, len, offset;
275
 
        int i, bval;
276
 
        unsigned int append_options;
277
 
 
278
 
        /* Get processor information for predefined escapes */
279
 
 
280
 
        if (!init_ctr)
281
 
                macro_init();
282
 
 
283
 
        /* Set up context and escape chain */
284
 
 
285
 
        if (!(ctxt = (struct parse_context *) malloc(sizeof(struct parse_context)))) {
286
 
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
287
 
                logerr(MODPREFIX "malloc: %s", estr);
288
 
                *context = NULL;
289
 
                return 1;
290
 
        }
291
 
        *context = (void *) ctxt;
292
 
 
293
 
        *ctxt = default_context;
294
 
        optlen = 0;
295
 
 
296
 
        /* Look for options and capture, and create new defines if we need to */
297
 
 
298
 
        for (i = 0; i < argc; i++) {
299
 
                if (argv[i][0] == '-' &&
300
 
                   (argv[i][1] == 'D' || argv[i][1] == '-') ) {
301
 
                        switch (argv[i][1]) {
302
 
                        case 'D':
303
 
                                if (argv[i][2])
304
 
                                        def = strdup(argv[i] + 2);
305
 
                                else if (++i < argc)
306
 
                                        def = strdup(argv[i]);
307
 
                                else
308
 
                                        break;
309
 
 
310
 
                                if (!def) {
311
 
                                        char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
312
 
                                        logerr(MODPREFIX "strdup: %s", estr);
313
 
                                        break;
314
 
                                }
315
 
 
316
 
                                val = strchr(def, '=');
317
 
                                if (val)
318
 
                                        *(val++) = '\0';
319
 
                                else
320
 
                                        val = "";
321
 
 
322
 
                                macro_lock();
323
 
 
324
 
                                ctxt->subst = macro_addvar(ctxt->subst,
325
 
                                                        def, strlen(def), val);
326
 
 
327
 
                                macro_unlock();
328
 
 
329
 
                                /* we use 5 for the "-D", "=", "," and the null */
330
 
                                if (ctxt->macros) {
331
 
                                        len = strlen(ctxt->macros) + strlen(def) + strlen(val);
332
 
                                        macros = realloc(ctxt->macros, len + 5);
333
 
                                        if (!macros) {
334
 
                                                free(def);
335
 
                                                break;
336
 
                                        }
337
 
                                        strcat(macros, ",");
338
 
                                } else { /* No comma, so only +4 */
339
 
                                        len = strlen(def) + strlen(val);
340
 
                                        macros = malloc(len + 4);
341
 
                                        if (!macros) {
342
 
                                                free(def);
343
 
                                                break;
344
 
                                        }
345
 
                                        *macros = '\0';
346
 
                                }
347
 
                                ctxt->macros = macros;
348
 
 
349
 
                                strcat(ctxt->macros, "-D");
350
 
                                strcat(ctxt->macros, def);
351
 
                                strcat(ctxt->macros, "=");
352
 
                                strcat(ctxt->macros, val);
353
 
                                free(def);
354
 
                                break;
355
 
 
356
 
                        case '-':
357
 
                                if (!strncmp(argv[i] + 2, "no-", 3)) {
358
 
                                        xopt = argv[i] + 5;
359
 
                                        bval = 0;
360
 
                                } else {
361
 
                                        xopt = argv[i] + 2;
362
 
                                        bval = 1;
363
 
                                }
364
 
 
365
 
                                if (!strmcmp(xopt, "slashify-colons", 1))
366
 
                                        ctxt->slashify_colons = bval;
367
 
                                else
368
 
                                        error(LOGOPT_ANY,
369
 
                                              MODPREFIX "unknown option: %s",
370
 
                                              argv[i]);
371
 
                                break;
372
 
 
373
 
                        default:
374
 
                                error(LOGOPT_ANY,
375
 
                                      MODPREFIX "unknown option: %s", argv[i]);
376
 
                                break;
377
 
                        }
378
 
                } else {
379
 
                        offset = (argv[i][0] == '-' ? 1 : 0);
380
 
                        len = strlen(argv[i] + offset);
381
 
                        if (ctxt->optstr) {
382
 
                                noptstr =
383
 
                                    (char *) realloc(ctxt->optstr, optlen + len + 2);
384
 
                                if (noptstr) {
385
 
                                        noptstr[optlen] = ',';
386
 
                                        strcpy(noptstr + optlen + 1, argv[i] + offset);
387
 
                                        optlen += len + 1;
388
 
                                }
389
 
                        } else {
390
 
                                noptstr = (char *) malloc(len + 1);
391
 
                                if (noptstr) {
392
 
                                        strcpy(noptstr, argv[i] + offset);
393
 
                                        optlen = len;
394
 
                                }
395
 
                        }
396
 
                        if (!noptstr) {
397
 
                                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
398
 
                                kill_context(ctxt);
399
 
                                logerr(MODPREFIX "%s", estr);
400
 
                                *context = NULL;
401
 
                                return 1;
402
 
                        }
403
 
                        ctxt->optstr = noptstr;
404
 
                }
405
 
        }
406
 
 
407
 
        gbl_options = NULL;
408
 
        if (global_options) {
409
 
                if (ctxt->optstr && strstr(ctxt->optstr, global_options))
410
 
                        goto options_done;
411
 
                gbl_options = strdup(global_options);
412
 
        }
413
 
 
414
 
        if (gbl_options) {
415
 
                append_options = defaults_get_append_options();
416
 
                if (append_options) {
417
 
                        char *tmp = concat_options(gbl_options, ctxt->optstr);
418
 
                        if (!tmp) {
419
 
                                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
420
 
                                logerr(MODPREFIX "concat_options: %s", estr);
421
 
                                free(gbl_options);
422
 
                        } else
423
 
                                ctxt->optstr = tmp;
424
 
                } else {
425
 
                        if (!ctxt->optstr)
426
 
                                ctxt->optstr = gbl_options;
427
 
                        else
428
 
                                free(gbl_options);
429
 
                }
430
 
        }
431
 
options_done:
432
 
        debug(LOGOPT_NONE,
433
 
              MODPREFIX "init gathered global options: %s", ctxt->optstr);
434
 
 
435
 
        /* We only need this once.  NFS mounts are so common that we cache
436
 
           this module. */
437
 
        if (!mount_nfs) {
438
 
                if ((mount_nfs = open_mount("nfs", MODPREFIX))) {
439
 
                        init_ctr++;
440
 
                        return 0;
441
 
                } else {
442
 
                        kill_context(ctxt);
443
 
                        *context = NULL;
444
 
                        return 1;
445
 
                }
446
 
        } else {
447
 
                init_ctr++;
448
 
                return 0;
449
 
        }
450
 
}
451
 
 
452
 
static const char *parse_options(const char *str, char **ret, unsigned int logopt)
453
 
{
454
 
        const char *cp = str;
455
 
        int len;
456
 
 
457
 
        if (*cp++ != '-')
458
 
                return str;
459
 
 
460
 
        if (*ret != NULL)
461
 
                free(*ret);
462
 
 
463
 
        len = chunklen(cp, 0);
464
 
        *ret = dequote(cp, len, logopt);
465
 
 
466
 
        return cp + len;
467
 
}
468
 
 
469
 
static char *concat_options(char *left, char *right)
470
 
{
471
 
        char buf[MAX_ERR_BUF];
472
 
        char *ret;
473
 
 
474
 
        if (left == NULL || *left == '\0') {
475
 
                ret = strdup(right);
476
 
                free(right);
477
 
                return ret;
478
 
        }
479
 
 
480
 
        if (right == NULL || *right == '\0') {
481
 
                ret = strdup(left);
482
 
                free(left);
483
 
                return ret;
484
 
        }
485
 
 
486
 
        ret = malloc(strlen(left) + strlen(right) + 2);
487
 
 
488
 
        if (ret == NULL) {
489
 
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
490
 
                logerr(MODPREFIX "malloc: %s", estr);
491
 
                return NULL;
492
 
        }
493
 
 
494
 
        strcpy(ret, left);
495
 
        strcat(ret, ",");
496
 
        strcat(ret, right);
497
 
 
498
 
        free(left);
499
 
        free(right);
500
 
 
501
 
        return ret;
502
 
}
503
 
 
504
 
static int sun_mount(struct autofs_point *ap, const char *root,
505
 
                        const char *name, int namelen,
506
 
                        const char *loc, int loclen, const char *options,
507
 
                        struct parse_context *ctxt)
508
 
{
509
 
        char *fstype = "nfs";   /* Default filesystem type */
510
 
        int nonstrict = 1;
511
 
        int rv, cur_state;
512
 
        char *mountpoint;
513
 
        char *what;
514
 
        char *type;
515
 
 
516
 
        if (*options == '\0')
517
 
                options = NULL;
518
 
 
519
 
        if (options) {
520
 
                char *noptions;
521
 
                const char *comma;
522
 
                char *np;
523
 
                int len = strlen(options) + 1;
524
 
 
525
 
                noptions = np = alloca(len);
526
 
                *np = '\0';
527
 
 
528
 
                /* Extract fstype= pseudo option */
529
 
                for (comma = options; *comma != '\0';) {
530
 
                        const char *cp;
531
 
 
532
 
                        while (*comma == ',')
533
 
                                comma++;
534
 
 
535
 
                        cp = comma;
536
 
 
537
 
                        while (*comma != '\0' && *comma != ',')
538
 
                                comma++;
539
 
 
540
 
                        if (strncmp("fstype=", cp, 7) == 0) {
541
 
                                int typelen = comma - (cp + 7);
542
 
                                fstype = alloca(typelen + 1);
543
 
                                memcpy(fstype, cp + 7, typelen);
544
 
                                fstype[typelen] = '\0';
545
 
                        } else if (strncmp("nonstrict", cp, 9) == 0) {
546
 
                                nonstrict = 1;
547
 
                        } else if (strncmp("strict", cp, 6) == 0) {
548
 
                                nonstrict = 0;
549
 
                        } else if (strncmp("nobrowse", cp, 8) == 0 ||
550
 
                                   strncmp("browse", cp, 6) == 0 ||
551
 
                                   strncmp("timeout=", cp, 8) == 0) {
552
 
                                if (strcmp(fstype, "autofs") == 0 ||
553
 
                                    strstr(cp, "fstype=autofs")) {
554
 
                                        memcpy(np, cp, comma - cp + 1);
555
 
                                        np += comma - cp + 1;
556
 
                                }
557
 
                        } else if (strncmp("bg", cp, 2) == 0 ||
558
 
                                   strncmp("nofg", cp, 4) == 0) {
559
 
                                continue;
560
 
                        } else {
561
 
                                memcpy(np, cp, comma - cp + 1);
562
 
                                np += comma - cp + 1;
563
 
                        }
564
 
                }
565
 
 
566
 
                if (np > noptions + len) {
567
 
                        warn(ap->logopt, MODPREFIX "options string truncated");
568
 
                        np[len] = '\0';
569
 
                } else
570
 
                        *(np - 1) = '\0';
571
 
 
572
 
                options = noptions;
573
 
        }
574
 
 
575
 
 
576
 
        if (!strcmp(fstype, "autofs") && ctxt->macros) {
577
 
                char *noptions = NULL;
578
 
 
579
 
                if (!options) {
580
 
                        noptions = alloca(strlen(ctxt->macros) + 1);
581
 
                        *noptions = '\0';
582
 
                } else {
583
 
                        int len = strlen(options) + strlen(ctxt->macros) + 2;
584
 
                        noptions = alloca(len);
585
 
 
586
 
                        if (noptions) {
587
 
                                strcpy(noptions, options);
588
 
                                strcat(noptions, ",");
589
 
                        }
590
 
                }
591
 
 
592
 
                if (noptions) {
593
 
                        strcat(noptions, ctxt->macros);
594
 
                        options = noptions;
595
 
                } else {
596
 
                        error(ap->logopt,
597
 
                              MODPREFIX "alloca failed for options");
598
 
                }
599
 
        }
600
 
 
601
 
        mountpoint = alloca(namelen + 1);
602
 
        sprintf(mountpoint, "%.*s", namelen, name);
603
 
 
604
 
        type = ap->entry->maps->type;
605
 
        if (type && !strcmp(type, "hosts")) {
606
 
                if (options) {
607
 
                        int len = strlen(options);
608
 
                        int suid = strstr(options, "suid") ? 0 : 7;
609
 
                        int dev = strstr(options, "dev") ? 0 : 6;
610
 
                        int nointr = strstr(options, "nointr") ? 0 : 5;
611
 
 
612
 
                        if (suid || dev || nointr) {
613
 
                                char *tmp = alloca(len + suid + dev + nointr + 1);
614
 
                                if (!tmp) {
615
 
                                        error(ap->logopt, MODPREFIX
616
 
                                              "alloca failed for options");
617
 
                                        if (nonstrict)
618
 
                                                return -1;
619
 
                                        return 1;
620
 
                                }
621
 
 
622
 
                                strcpy(tmp, options);
623
 
                                if (suid)
624
 
                                        strcat(tmp, ",nosuid");
625
 
                                if (dev)
626
 
                                        strcat(tmp, ",nodev");
627
 
                                if (nointr)
628
 
                                        strcat(tmp, ",intr");
629
 
                                options = tmp;
630
 
                        }
631
 
                } else {
632
 
                        char *tmp = alloca(18);
633
 
                        if (!tmp) {
634
 
                                error(ap->logopt,
635
 
                                      MODPREFIX "alloca failed for options");
636
 
                                if (nonstrict)
637
 
                                        return -1;
638
 
                                return 1;
639
 
                        }
640
 
                        strcpy(tmp, "nosuid,nodev,intr");
641
 
                        options = tmp;
642
 
                }
643
 
        }
644
 
 
645
 
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
646
 
        if (!strcmp(fstype, "nfs") || !strcmp(fstype, "nfs4")) {
647
 
                what = alloca(loclen + 1);
648
 
                memcpy(what, loc, loclen);
649
 
                what[loclen] = '\0';
650
 
 
651
 
                debug(ap->logopt, MODPREFIX
652
 
                      "mounting root %s, mountpoint %s, "
653
 
                      "what %s, fstype %s, options %s",
654
 
                      root, mountpoint, what, fstype, options);
655
 
 
656
 
                rv = mount_nfs->mount_mount(ap, root, mountpoint, strlen(mountpoint),
657
 
                                            what, fstype, options, mount_nfs->context);
658
 
        } else {
659
 
                what = alloca(loclen + 1);
660
 
                if (*loc == ':') {
661
 
                        loclen--;
662
 
                        memcpy(what, loc + 1, loclen);
663
 
                        what[loclen] = '\0';
664
 
                } else {
665
 
                        memcpy(what, loc, loclen);
666
 
                        what[loclen] = '\0';
667
 
                }
668
 
 
669
 
                debug(ap->logopt, MODPREFIX
670
 
                      "mounting root %s, mountpoint %s, "
671
 
                      "what %s, fstype %s, options %s",
672
 
                      root, mountpoint, what, fstype, options);
673
 
 
674
 
                /* Generic mount routine */
675
 
                rv = do_mount(ap, root, mountpoint, strlen(mountpoint), what, fstype,
676
 
                              options);
677
 
        }
678
 
        pthread_setcancelstate(cur_state, NULL);
679
 
 
680
 
        if (nonstrict && rv)
681
 
                return -rv;
682
 
 
683
 
        return rv;
684
 
}
685
 
 
686
 
/*
687
 
 * Scan map entry looking for evidence it has multiple key/mapent
688
 
 * pairs.
689
 
 */
690
 
static int check_is_multi(const char *mapent)
691
 
{
692
 
        const char *p = mapent;
693
 
        int multi = 0;
694
 
        int not_first_chunk = 0;
695
 
 
696
 
        if (!p) {
697
 
                logerr(MODPREFIX "unexpected NULL map entry pointer");
698
 
                return 0;
699
 
        }
700
 
 
701
 
        if (*p == '"')
702
 
                p++;
703
 
 
704
 
        /* If first character is "/" it's a multi-mount */
705
 
        if (*p == '/')
706
 
                return 1;
707
 
 
708
 
        while (*p) {
709
 
                p = skipspace(p);
710
 
 
711
 
                /*
712
 
                 * After the first chunk there can be additional
713
 
                 * locations (possibly not multi) or possibly an
714
 
                 * options string if the first entry includes the
715
 
                 * optional '/' (is multi). Following this any
716
 
                 * path that begins with '/' indicates a mutil-mount
717
 
                 * entry.
718
 
                 */
719
 
                if (not_first_chunk) {
720
 
                        if (*p == '"')
721
 
                                p++;
722
 
                        if (*p == '/' || *p == '-') {
723
 
                                multi = 1;
724
 
                                break;
725
 
                        }
726
 
                }
727
 
 
728
 
                while (*p == '-') {
729
 
                        p += chunklen(p, 0);
730
 
                        p = skipspace(p);
731
 
                }
732
 
 
733
 
                /*
734
 
                 * Expect either a path or location
735
 
                 * after which it's a multi mount.
736
 
                 */
737
 
                p += chunklen(p, check_colon(p));
738
 
                not_first_chunk++;
739
 
        }
740
 
 
741
 
        return multi;
742
 
}
743
 
 
744
 
static int
745
 
add_offset_entry(struct autofs_point *ap, const char *name,
746
 
                 const char *m_root, int m_root_len,
747
 
                 const char *path, const char *myoptions, const char *loc,
748
 
                 time_t age)
749
 
{
750
 
        struct map_source *source;
751
 
        struct mapent_cache *mc;
752
 
        char m_key[PATH_MAX + 1];
753
 
        char m_mapent[MAPENT_MAX_LEN + 1];
754
 
        int p_len, m_key_len, m_options_len, m_mapent_len;
755
 
        int ret;
756
 
 
757
 
        source = ap->entry->current;
758
 
        ap->entry->current = NULL;
759
 
        master_source_current_signal(ap->entry);
760
 
 
761
 
        mc = source->mc;
762
 
 
763
 
        if (!*path || !*loc) {
764
 
                error(ap->logopt,
765
 
                      MODPREFIX "syntax error in offset %s -> %s", path, loc);
766
 
                return CHE_FAIL;
767
 
        }
768
 
 
769
 
        p_len = strlen(path);
770
 
        /* Trailing '/' causes us pain */
771
 
        if (p_len > 1) {
772
 
                while (p_len > 1 && path[p_len - 1] == '/')
773
 
                        p_len--;
774
 
        }
775
 
        m_key_len = m_root_len + p_len;
776
 
        if (m_key_len > PATH_MAX) {
777
 
                error(ap->logopt, MODPREFIX "multi mount key too long");
778
 
                return CHE_FAIL;
779
 
        }
780
 
        strcpy(m_key, m_root);
781
 
        strncat(m_key, path, p_len);
782
 
        m_key[m_key_len] = '\0';
783
 
 
784
 
        m_options_len = 0;
785
 
        if (*myoptions)
786
 
                m_options_len = strlen(myoptions) + 2;
787
 
 
788
 
        m_mapent_len = strlen(loc);
789
 
        if (m_mapent_len + m_options_len > MAPENT_MAX_LEN) {
790
 
                error(ap->logopt, MODPREFIX "multi mount mapent too long");
791
 
                return CHE_FAIL;
792
 
        }
793
 
 
794
 
        if (*myoptions) {
795
 
                strcpy(m_mapent, "-");
796
 
                strcat(m_mapent, myoptions);
797
 
                strcat(m_mapent, " ");
798
 
                strcat(m_mapent, loc);
799
 
        } else
800
 
                strcpy(m_mapent, loc);
801
 
 
802
 
        ret = cache_add_offset(mc, name, m_key, m_mapent, age);
803
 
        if (ret == CHE_OK)
804
 
                debug(ap->logopt, MODPREFIX
805
 
                      "added multi-mount offset %s -> %s", path, m_mapent);
806
 
        else
807
 
                warn(ap->logopt, MODPREFIX
808
 
                      "syntax error or duplicate offset %s -> %s", path, loc);
809
 
 
810
 
        return ret;
811
 
}
812
 
 
813
 
static int validate_location(char *loc)
814
 
{
815
 
        char *ptr = loc;
816
 
 
817
 
        /* We don't know much about these */
818
 
        if (*ptr == ':')
819
 
                return 1;
820
 
 
821
 
        /*
822
 
         * If a ':/' is present now it must be a host name, except
823
 
         * for those special file systems like sshfs which use "#"
824
 
         * and "@" in the host name part and ipv6 addresses that
825
 
         * have ":", "[" and "]".
826
 
         */
827
 
        if (check_colon(ptr)) {
828
 
                while (*ptr && strncmp(ptr, ":/", 2)) {
829
 
                        if (!(isalnum(*ptr) ||
830
 
                            *ptr == '-' || *ptr == '.' || *ptr == '_' ||
831
 
                            *ptr == ',' || *ptr == '(' || *ptr == ')' ||
832
 
                            *ptr == '#' || *ptr == '@' || *ptr == ':' ||
833
 
                            *ptr == '[' || *ptr == ']'))
834
 
                                return 0;
835
 
                        ptr++;
836
 
                }
837
 
 
838
 
                if (*ptr && !strncmp(ptr, ":/", 2))
839
 
                        ptr++;
840
 
        }
841
 
 
842
 
        /* Must always be something following */
843
 
        if (!*ptr)
844
 
                return 0;
845
 
 
846
 
        return 1;
847
 
}
848
 
 
849
 
static int parse_mapent(const char *ent, char *g_options, char **options, char **location, int logopt)
850
 
{
851
 
        char buf[MAX_ERR_BUF];
852
 
        const char *p;
853
 
        char *myoptions, *loc;
854
 
        int l;
855
 
 
856
 
        p = ent;
857
 
 
858
 
        myoptions = strdup(g_options);
859
 
        if (!myoptions) {
860
 
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
861
 
                error(logopt, MODPREFIX "strdup: %s", estr);
862
 
                return 0;
863
 
        }
864
 
 
865
 
        /* Local options are appended to per-map options */
866
 
        if (*p == '-') {
867
 
                do {
868
 
                        char *tmp, *newopt = NULL;
869
 
 
870
 
                        p = parse_options(p, &newopt, logopt);
871
 
                        if (newopt && strstr(newopt, myoptions)) {
872
 
                                free(myoptions);
873
 
                                myoptions = newopt;
874
 
                        } else {
875
 
                                tmp = concat_options(myoptions, newopt);
876
 
                                if (!tmp) {
877
 
                                        char *estr;
878
 
                                        estr = strerror_r(errno, buf, MAX_ERR_BUF);
879
 
                                        error(logopt, MODPREFIX
880
 
                                              "concat_options: %s", estr);
881
 
                                        if (newopt)
882
 
                                                free(newopt);
883
 
                                        free(myoptions);
884
 
                                        return 0;
885
 
                                }
886
 
                                myoptions = tmp;
887
 
                        }
888
 
 
889
 
                        p = skipspace(p);
890
 
                } while (*p == '-');
891
 
        }
892
 
 
893
 
        debug(logopt, MODPREFIX "gathered options: %s", myoptions);
894
 
 
895
 
        l = chunklen(p, check_colon(p));
896
 
        loc = dequote(p, l, logopt);
897
 
        if (!loc) {
898
 
                warn(logopt, MODPREFIX "possible missing location");
899
 
                free(myoptions);
900
 
                return 0;
901
 
        }
902
 
 
903
 
        /* Location can't begin with a '/' */
904
 
        if (*p == '/') {
905
 
                warn(logopt, MODPREFIX "error location begins with \"/\"");
906
 
                free(myoptions);
907
 
                free(loc);
908
 
                return 0;
909
 
        }
910
 
 
911
 
        if (!validate_location(loc)) {
912
 
                warn(logopt, MODPREFIX "invalid location %s", loc);
913
 
                free(myoptions);
914
 
                free(loc);
915
 
                return 0;
916
 
        }
917
 
 
918
 
        debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc);
919
 
 
920
 
        p += l;
921
 
        p = skipspace(p);
922
 
 
923
 
        while (*p && ((*p == '"' && *(p + 1) != '/') || (*p != '"' && *p != '/'))) {
924
 
                char *tmp, *ent_chunk;
925
 
 
926
 
                l = chunklen(p, check_colon(p));
927
 
                ent_chunk = dequote(p, l, logopt);
928
 
                if (!ent_chunk) {
929
 
                        warn(logopt, MODPREFIX "null location or out of memory");
930
 
                        free(myoptions);
931
 
                        free(loc);
932
 
                        return 0;
933
 
                }
934
 
 
935
 
                /* Location can't begin with a '/' */
936
 
                if (*p == '/') {
937
 
                        warn(logopt,
938
 
                              MODPREFIX "error location begins with \"/\"");
939
 
                        free(ent_chunk);
940
 
                        free(myoptions);
941
 
                        free(loc);
942
 
                        return 0;
943
 
                }
944
 
 
945
 
                if (!validate_location(ent_chunk)) {
946
 
                        warn(logopt,
947
 
                              MODPREFIX "invalid location %s", ent_chunk);
948
 
                        free(ent_chunk);
949
 
                        free(myoptions);
950
 
                        free(loc);
951
 
                        return 0;
952
 
                }
953
 
 
954
 
                debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent_chunk);
955
 
 
956
 
                tmp = realloc(loc, strlen(loc) + l + 2);
957
 
                if (!tmp) {
958
 
                        error(logopt, MODPREFIX "out of memory");
959
 
                        free(ent_chunk);
960
 
                        free(myoptions);
961
 
                        free(loc);
962
 
                        return 0;
963
 
                }
964
 
                loc = tmp;
965
 
 
966
 
                strcat(loc, " ");
967
 
                strcat(loc, ent_chunk);
968
 
 
969
 
                free(ent_chunk);
970
 
 
971
 
                p += l;
972
 
                p = skipspace(p);
973
 
        }
974
 
 
975
 
        *options = myoptions;
976
 
        *location = loc;
977
 
 
978
 
        return (p - ent);
979
 
}
980
 
 
981
 
static int move_mount(struct autofs_point *ap,
982
 
                      const char *mm_tmp_root, const char *mm_root,
983
 
                      unsigned int move)
984
 
{
985
 
        char buf[MAX_ERR_BUF];
986
 
        int err;
987
 
 
988
 
        if (move == MOUNT_MOVE_NONE)
989
 
                return 1;
990
 
 
991
 
        err = mkdir_path(mm_root, 0555);
992
 
        if (err < 0 && errno != EEXIST) {
993
 
                error(ap->logopt,
994
 
                      "failed to create move target mount point %s", mm_root);
995
 
                return 0;
996
 
        }
997
 
 
998
 
        if (move == MOUNT_MOVE_AUTOFS)
999
 
                err = mount(mm_tmp_root, mm_root, NULL, MS_MOVE, NULL);
1000
 
        else
1001
 
                err = spawn_mount(ap->logopt,
1002
 
                                  "--move", mm_tmp_root, mm_root, NULL);
1003
 
        if (err) {
1004
 
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1005
 
                error(ap->logopt,
1006
 
                      "failed to move mount from %s to %s: %s",
1007
 
                      mm_tmp_root, mm_root, estr);
1008
 
                return 0;
1009
 
        }
1010
 
 
1011
 
        debug(ap->logopt,
1012
 
              "moved mount tree from %s to %s", mm_tmp_root, mm_root);
1013
 
 
1014
 
        return 1;
1015
 
}
1016
 
 
1017
 
static void cleanup_multi_root(struct autofs_point *ap, const char *root,
1018
 
                                         const char *path, unsigned int move)
1019
 
{
1020
 
        if (move == MOUNT_MOVE_NONE)
1021
 
                return;
1022
 
 
1023
 
        if (move == MOUNT_MOVE_OTHER)
1024
 
                spawn_umount(ap->logopt, root, NULL);
1025
 
        else {
1026
 
                struct ioctl_ops *ops = get_ioctl_ops();
1027
 
                struct autofs_point *submount;
1028
 
 
1029
 
                mounts_mutex_lock(ap);
1030
 
                submount = __master_find_submount(ap, path);
1031
 
                if (!submount) {
1032
 
                        mounts_mutex_unlock(ap);
1033
 
                        return;
1034
 
                }
1035
 
 
1036
 
                alarm_delete(submount);
1037
 
                st_remove_tasks(submount);
1038
 
                st_wait_state(submount, ST_READY);
1039
 
 
1040
 
                submount->parent->submnt_count--;
1041
 
                list_del_init(&submount->mounts);
1042
 
 
1043
 
                ops->catatonic(submount->logopt, submount->ioctlfd);
1044
 
 
1045
 
                mounts_mutex_unlock(ap);
1046
 
 
1047
 
                if (submount->thid) {
1048
 
                        pthread_cancel(submount->thid);
1049
 
                        close_mount_fds(submount);
1050
 
                        umount(root);
1051
 
                        destroy_logpri_fifo(submount);
1052
 
                        master_free_mapent_sources(submount->entry, 1);
1053
 
                        master_free_mapent(ap->entry);
1054
 
                }
1055
 
        }
1056
 
        return;
1057
 
}
1058
 
 
1059
 
static void cleanup_multi_triggers(struct autofs_point *ap,
1060
 
                            struct mapent *me, const char *root, int start,
1061
 
                            const char *base)
1062
 
{
1063
 
        char path[PATH_MAX + 1];
1064
 
        char offset[PATH_MAX + 1];
1065
 
        char *poffset = offset;
1066
 
        struct mapent *oe;
1067
 
        struct list_head *mm_root, *pos;
1068
 
        const char o_root[] = "/";
1069
 
        const char *mm_base;
1070
 
 
1071
 
        mm_root = &me->multi->multi_list;
1072
 
 
1073
 
        if (!base)
1074
 
                mm_base = o_root;
1075
 
        else
1076
 
                mm_base = base;
1077
 
 
1078
 
        pos = NULL;
1079
 
 
1080
 
        /* Make sure "none" of the offsets have an active mount. */
1081
 
        while ((poffset = cache_get_offset(mm_base, poffset, start, mm_root, &pos))) {
1082
 
                oe = cache_lookup_offset(mm_base, poffset, start, &me->multi_list);
1083
 
                /* root offset is a special case */
1084
 
                if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
1085
 
                        continue;
1086
 
 
1087
 
                strcpy(path, root);
1088
 
                strcat(path, poffset);
1089
 
                if (umount(path)) {
1090
 
                        error(ap->logopt, "error recovering from mount fail");
1091
 
                        error(ap->logopt, "cannot umount offset %s", path);
1092
 
                }
1093
 
        }
1094
 
 
1095
 
        return;
1096
 
}
1097
 
 
1098
 
static int check_fstype_autofs_option(const char *options)
1099
 
{
1100
 
        char *tok, *tokbuf;
1101
 
        int found;
1102
 
 
1103
 
        /*
1104
 
         * Look for fstype= in options and return true if
1105
 
         * the last occurrence is fstype=autofs.
1106
 
         */
1107
 
        found = 0;
1108
 
        tokbuf = alloca(strlen(options) + 2);
1109
 
        strcpy(tokbuf, options);
1110
 
        tok = strtok_r(tokbuf, ",", &tokbuf);
1111
 
        if (tok) {
1112
 
                do {
1113
 
                        if (strstr(tok, "fstype=")) {
1114
 
                                if (strstr(tok, "autofs"))
1115
 
                                        found = 1;
1116
 
                                else
1117
 
                                        found = 0;
1118
 
                        }
1119
 
                } while ((tok = strtok_r(NULL, ",", &tokbuf)));
1120
 
        }
1121
 
 
1122
 
        return found;
1123
 
}
1124
 
 
1125
 
static int mount_subtree(struct autofs_point *ap, struct mapent *me,
1126
 
                         const char *name, char *loc, char *options, void *ctxt)
1127
 
{
1128
 
        struct mapent *mm;
1129
 
        struct mapent *ro;
1130
 
        char t_dir[] = "/tmp/autoXXXXXX";
1131
 
        char *mnt_tmp_root, *mm_root, *mm_base, *mm_key;
1132
 
        const char *mnt_root, *target;
1133
 
        unsigned int mm_root_len, mnt_root_len;
1134
 
        int start, ret = 0, rv;
1135
 
        unsigned int move;
1136
 
 
1137
 
        rv = 0;
1138
 
 
1139
 
        mm = me->multi;
1140
 
        mm_key = mm->key;
1141
 
        move = MOUNT_MOVE_NONE;
1142
 
 
1143
 
        if (*mm_key == '/') {
1144
 
                mm_root = mm_key;
1145
 
                start = strlen(mm_key);
1146
 
        } else {
1147
 
                start = strlen(ap->path) + strlen(mm_key) + 1;
1148
 
                mm_root = alloca(start + 3);
1149
 
                strcpy(mm_root, ap->path);
1150
 
                strcat(mm_root, "/");
1151
 
                strcat(mm_root, mm_key);
1152
 
        }
1153
 
        mm_root_len = strlen(mm_root);
1154
 
 
1155
 
        mnt_tmp_root = NULL;
1156
 
        if (ap->flags & MOUNT_FLAG_REMOUNT) {
1157
 
                mnt_root = mm_root;
1158
 
                mnt_root_len = mm_root_len;
1159
 
        } else {
1160
 
                mnt_root = mkdtemp(t_dir);
1161
 
                if (!mnt_root)
1162
 
                        return 1;
1163
 
                mnt_root_len = strlen(mnt_root);
1164
 
                mnt_tmp_root = (char *) mnt_root;
1165
 
        }
1166
 
 
1167
 
        if (me == me->multi) {
1168
 
                /* name = NULL */
1169
 
                /* destination = mm_root */
1170
 
                target = mm_root;
1171
 
                mm_base = "/";
1172
 
 
1173
 
                /* Mount root offset if it exists */
1174
 
                ro = cache_lookup_offset(mm_base, mm_base, strlen(mm_root), &me->multi_list);
1175
 
                if (ro) {
1176
 
                        char *myoptions, *ro_loc, *tmp;
1177
 
                        int namelen = name ? strlen(name) : 0;
1178
 
                        const char *root;
1179
 
                        int ro_len;
1180
 
 
1181
 
                        rv = parse_mapent(ro->mapent,
1182
 
                                options, &myoptions, &ro_loc, ap->logopt);
1183
 
                        if (!rv) {
1184
 
                                warn(ap->logopt,
1185
 
                                      MODPREFIX "failed to parse root offset");
1186
 
                                cache_delete_offset_list(me->mc, name);
1187
 
                                goto error_out;
1188
 
                        }
1189
 
                        ro_len = strlen(ro_loc);
1190
 
 
1191
 
                        if (!(ap->flags & MOUNT_FLAG_REMOUNT)) {
1192
 
                                move = MOUNT_MOVE_OTHER;
1193
 
                                if (check_fstype_autofs_option(myoptions))
1194
 
                                        move = MOUNT_MOVE_AUTOFS;
1195
 
                        }
1196
 
 
1197
 
                        tmp = alloca(mnt_root_len + 1);
1198
 
                        strcpy(tmp, mnt_root);
1199
 
                        tmp[mnt_root_len] = '/';
1200
 
                        tmp[mnt_root_len + 1] = '\0';
1201
 
                        root = tmp;
1202
 
 
1203
 
                        rv = sun_mount(ap, root, name, namelen, ro_loc, ro_len, myoptions, ctxt);
1204
 
 
1205
 
                        free(myoptions);
1206
 
                        free(ro_loc);
1207
 
                }
1208
 
 
1209
 
                if (ro && rv == 0) {
1210
 
                        ret = mount_multi_triggers(ap, me, mnt_root, start, mm_base);
1211
 
                        if (ret == -1) {
1212
 
                                error(ap->logopt, MODPREFIX
1213
 
                                         "failed to mount offset triggers");
1214
 
                                cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
1215
 
                                cleanup_multi_root(ap, mnt_root, mm_root, move);
1216
 
                                goto error_out;
1217
 
                        }
1218
 
                } else if (rv <= 0) {
1219
 
                        move = MOUNT_MOVE_NONE;
1220
 
                        ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
1221
 
                        if (ret == -1) {
1222
 
                                error(ap->logopt, MODPREFIX
1223
 
                                         "failed to mount offset triggers");
1224
 
                                cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
1225
 
                                goto error_out;
1226
 
                        }
1227
 
                }
1228
 
        } else {
1229
 
                int loclen = strlen(loc);
1230
 
                int namelen = strlen(name);
1231
 
 
1232
 
                if (!(ap->flags & MOUNT_FLAG_REMOUNT)) {
1233
 
                        move = MOUNT_MOVE_OTHER;
1234
 
                        if (check_fstype_autofs_option(options))
1235
 
                                move = MOUNT_MOVE_AUTOFS;
1236
 
                }
1237
 
 
1238
 
                /* name = mm_root + mm_base */
1239
 
                /* destination = mm_root + mm_base = name */
1240
 
                target = name;
1241
 
                mm_base = &me->key[start];
1242
 
 
1243
 
                rv = sun_mount(ap, mnt_root, name, namelen, loc, loclen, options, ctxt);
1244
 
                if (rv == 0) {
1245
 
                        ret = mount_multi_triggers(ap, me->multi, mnt_root, start, mm_base);
1246
 
                        if (ret == -1) {
1247
 
                                error(ap->logopt, MODPREFIX
1248
 
                                         "failed to mount offset triggers");
1249
 
                                cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
1250
 
                                cleanup_multi_root(ap, mnt_root, mm_root, move);
1251
 
                                goto error_out;
1252
 
                        }
1253
 
                } else if (rv < 0) {
1254
 
                        char *mm_root_base = alloca(strlen(mm_root) + strlen(mm_base) + 1);
1255
 
        
1256
 
                        move = MOUNT_MOVE_NONE;
1257
 
 
1258
 
                        strcpy(mm_root_base, mm_root);
1259
 
                        strcat(mm_root_base, mm_base);
1260
 
 
1261
 
                        ret = mount_multi_triggers(ap, me->multi, mm_root_base, start, mm_base);
1262
 
                        if (ret == -1) {
1263
 
                                error(ap->logopt, MODPREFIX
1264
 
                                         "failed to mount offset triggers");
1265
 
                                cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
1266
 
                                goto error_out;
1267
 
                        }
1268
 
                }
1269
 
        }
1270
 
 
1271
 
        if (!move_mount(ap, mnt_root, target, move)) {
1272
 
                cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
1273
 
                cleanup_multi_root(ap, mnt_root, mm_root, move);
1274
 
                goto error_out;
1275
 
        }
1276
 
 
1277
 
        if (mnt_tmp_root)
1278
 
                rmdir(mnt_tmp_root);
1279
 
 
1280
 
        /* Mount for base of tree failed */
1281
 
        if (rv > 0)
1282
 
                return rv;
1283
 
 
1284
 
        /*
1285
 
         * Convert fail on nonstrict, non-empty multi-mount
1286
 
         * to success
1287
 
         */
1288
 
        if (rv < 0 && ret > 0)
1289
 
                rv = 0;
1290
 
 
1291
 
        return rv;
1292
 
 
1293
 
error_out:
1294
 
        if (mnt_tmp_root)
1295
 
                rmdir(mnt_tmp_root);
1296
 
 
1297
 
        return 1;
1298
 
}
1299
 
 
1300
 
/*
1301
 
 * syntax is:
1302
 
 *      [-options] location [location] ...
1303
 
 *      [-options] [mountpoint [-options] location [location] ... ]...
1304
 
 *
1305
 
 * There are three ways this routine can be called. One where we parse
1306
 
 * offsets in a multi-mount entry adding them to the cache for later lookups.
1307
 
 * Another where we parse a multi-mount entry looking for a root offset mount
1308
 
 * and mount it if it exists and also mount its offsets down to the first
1309
 
 * level nexting point. Finally to mount non multi-mounts and to mount a
1310
 
 * lower level multi-mount nesting point and its offsets.
1311
 
 */
1312
 
int parse_mount(struct autofs_point *ap, const char *name,
1313
 
                int name_len, const char *mapent, void *context)
1314
 
{
1315
 
        struct parse_context *ctxt = (struct parse_context *) context;
1316
 
        char buf[MAX_ERR_BUF];
1317
 
        struct map_source *source;
1318
 
        struct mapent_cache *mc;
1319
 
        struct mapent *me = NULL;
1320
 
        char *pmapent, *options;
1321
 
        const char *p;
1322
 
        int mapent_len, rv = 0;
1323
 
        int cur_state;
1324
 
        int slashify = ctxt->slashify_colons;
1325
 
        unsigned int append_options;
1326
 
 
1327
 
        source = ap->entry->current;
1328
 
        ap->entry->current = NULL;
1329
 
        master_source_current_signal(ap->entry);
1330
 
 
1331
 
        mc = source->mc;
1332
 
 
1333
 
        if (!mapent) {
1334
 
                warn(ap->logopt, MODPREFIX "error: empty map entry");
1335
 
                return 1;
1336
 
        }
1337
 
 
1338
 
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
1339
 
        macro_lock();
1340
 
 
1341
 
        ctxt->subst = addstdenv(ctxt->subst);
1342
 
 
1343
 
        mapent_len = expandsunent(mapent, NULL, name, ctxt->subst, slashify);
1344
 
        if (mapent_len == 0) {
1345
 
                error(ap->logopt, MODPREFIX "failed to expand map entry");
1346
 
                ctxt->subst = removestdenv(ctxt->subst);
1347
 
                macro_unlock();
1348
 
                pthread_setcancelstate(cur_state, NULL);
1349
 
                return 1;
1350
 
        }
1351
 
 
1352
 
        pmapent = alloca(mapent_len + 1);
1353
 
        if (!pmapent) { 
1354
 
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1355
 
                logerr(MODPREFIX "alloca: %s", estr);
1356
 
                ctxt->subst = removestdenv(ctxt->subst);
1357
 
                macro_unlock();
1358
 
                pthread_setcancelstate(cur_state, NULL);
1359
 
                return 1;
1360
 
        }
1361
 
        pmapent[mapent_len] = '\0';
1362
 
 
1363
 
        expandsunent(mapent, pmapent, name, ctxt->subst, slashify);
1364
 
        ctxt->subst = removestdenv(ctxt->subst);
1365
 
 
1366
 
        macro_unlock();
1367
 
        pthread_setcancelstate(cur_state, NULL);
1368
 
 
1369
 
        debug(ap->logopt, MODPREFIX "expanded entry: %s", pmapent);
1370
 
 
1371
 
        append_options = defaults_get_append_options();
1372
 
        options = strdup(ctxt->optstr ? ctxt->optstr : "");
1373
 
        if (!options) {
1374
 
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1375
 
                logerr(MODPREFIX "strdup: %s", estr);
1376
 
                return 1;
1377
 
        }
1378
 
 
1379
 
        p = skipspace(pmapent);
1380
 
 
1381
 
        /* Deal with 0 or more options */
1382
 
        if (*p == '-') {
1383
 
                char *tmp, *mnt_options = NULL;
1384
 
 
1385
 
                do {
1386
 
                        char *noptions = NULL;
1387
 
 
1388
 
                        p = parse_options(p, &noptions, ap->logopt);
1389
 
                        if (mnt_options && noptions && strstr(noptions, mnt_options)) {
1390
 
                                free(mnt_options);
1391
 
                                mnt_options = noptions;
1392
 
                        } else {
1393
 
                                tmp = concat_options(mnt_options, noptions);
1394
 
                                if (!tmp) {
1395
 
                                        char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1396
 
                                        error(ap->logopt,
1397
 
                                              MODPREFIX "concat_options: %s", estr);
1398
 
                                        if (noptions)
1399
 
                                                free(noptions);
1400
 
                                        if (mnt_options)
1401
 
                                                free(mnt_options);
1402
 
                                        free(options);
1403
 
                                        return 1;
1404
 
                                }
1405
 
                                mnt_options = tmp;
1406
 
                        }
1407
 
 
1408
 
                        p = skipspace(p);
1409
 
                } while (*p == '-');
1410
 
 
1411
 
                if (options && !append_options) {
1412
 
                        free(options);
1413
 
                        options = NULL;
1414
 
                }
1415
 
 
1416
 
                if (append_options) {
1417
 
                        if (options && mnt_options && strstr(mnt_options, options)) {
1418
 
                                free(options);
1419
 
                                options = mnt_options;
1420
 
                        } else {
1421
 
                                tmp = concat_options(options, mnt_options);
1422
 
                                if (!tmp) {
1423
 
                                        char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1424
 
                                        error(ap->logopt, MODPREFIX "concat_options: %s", estr);
1425
 
                                        if (options)
1426
 
                                                free(options);
1427
 
                                        if (mnt_options)
1428
 
                                                free(mnt_options);
1429
 
                                        return 1;
1430
 
                                }
1431
 
                                options = tmp;
1432
 
                        }
1433
 
                } else
1434
 
                        options = mnt_options;
1435
 
        }
1436
 
 
1437
 
        debug(ap->logopt, MODPREFIX "gathered options: %s", options);
1438
 
 
1439
 
        if (check_is_multi(p)) {
1440
 
                char *m_root = NULL;
1441
 
                int m_root_len;
1442
 
                time_t age = time(NULL);
1443
 
                int l;
1444
 
 
1445
 
                /* If name starts with "/" it's a direct mount */
1446
 
                if (*name == '/') {
1447
 
                        m_root_len = name_len;
1448
 
                        m_root = alloca(m_root_len + 1);
1449
 
                        if (!m_root) {
1450
 
                                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1451
 
                                free(options);
1452
 
                                logerr(MODPREFIX "alloca: %s", estr);
1453
 
                                return 1;
1454
 
                        }
1455
 
                        strcpy(m_root, name);
1456
 
                } else {
1457
 
                        m_root_len = strlen(ap->path) + name_len + 1;
1458
 
                        m_root = alloca(m_root_len + 1);
1459
 
                        if (!m_root) {
1460
 
                                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1461
 
                                free(options);
1462
 
                                logerr(MODPREFIX "alloca: %s", estr);
1463
 
                                return 1;
1464
 
                        }
1465
 
                        strcpy(m_root, ap->path);
1466
 
                        strcat(m_root, "/");
1467
 
                        strcat(m_root, name);
1468
 
                }
1469
 
 
1470
 
                cache_writelock(mc);
1471
 
                me = cache_lookup_distinct(mc, name);
1472
 
                if (!me) {
1473
 
                        int ret;
1474
 
                        /*
1475
 
                         * Not in the cache, perhaps it's a program map
1476
 
                         * or one that doesn't support enumeration
1477
 
                         */
1478
 
                        ret = cache_add(mc, source, name, mapent, time(NULL));
1479
 
                        if (ret == CHE_FAIL) {
1480
 
                                cache_unlock(mc);
1481
 
                                free(options);
1482
 
                                return 1;
1483
 
                        }
1484
 
                } else {
1485
 
                        /*
1486
 
                         * If the entry exists it must not have any existing
1487
 
                         * multi-mount subordinate entries since we are
1488
 
                         * mounting this afresh. We need to do this to allow
1489
 
                         * us to fail on the check for duplicate offsets in
1490
 
                         * we don't know when submounts go away.
1491
 
                         */
1492
 
                        cache_multi_writelock(me);
1493
 
                        cache_delete_offset_list(mc, name);
1494
 
                        cache_multi_unlock(me);
1495
 
                }
1496
 
                cache_unlock(mc);
1497
 
 
1498
 
                cache_readlock(mc);
1499
 
                me = cache_lookup_distinct(mc, name);
1500
 
                if (me) {
1501
 
                        /* So we know we're the multi-mount root */
1502
 
                        if (!me->multi)
1503
 
                                me->multi = me;
1504
 
                }
1505
 
 
1506
 
                if (!me) {
1507
 
                        free(options);
1508
 
                        cache_unlock(mc);
1509
 
                        error(ap->logopt,
1510
 
                              MODPREFIX "can't find multi root %s", name);
1511
 
                        return 1;
1512
 
                }
1513
 
 
1514
 
                pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
1515
 
                cache_multi_writelock(me);
1516
 
                /* It's a multi-mount; deal with it */
1517
 
                do {
1518
 
                        char *path, *myoptions, *loc;
1519
 
                        int status;
1520
 
 
1521
 
                        if ((*p == '"' && *(p + 1) != '/') || (*p != '"' && *p != '/')) {
1522
 
                                l = 0;
1523
 
                                path = dequote("/", 1, ap->logopt);
1524
 
                                debug(ap->logopt,
1525
 
                                      MODPREFIX "dequote(\"/\") -> %s", path);
1526
 
                        } else {
1527
 
                                l = span_space(p, mapent_len - (p - pmapent));
1528
 
                                path = sanitize_path(p, l, LKP_MULTI, ap->logopt);
1529
 
                                debug(ap->logopt, MODPREFIX
1530
 
                                      "dequote(\"%.*s\") -> %s", l, p, path);
1531
 
                        }
1532
 
 
1533
 
                        if (!path) {
1534
 
                                warn(ap->logopt, MODPREFIX "null path or out of memory");
1535
 
                                cache_delete_offset_list(mc, name);
1536
 
                                cache_multi_unlock(me);
1537
 
                                cache_unlock(mc);
1538
 
                                free(options);
1539
 
                                pthread_setcancelstate(cur_state, NULL);
1540
 
                                return 1;
1541
 
                        }
1542
 
 
1543
 
                        p += l;
1544
 
                        p = skipspace(p);
1545
 
 
1546
 
                        l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
1547
 
                        if (!l) {
1548
 
                                cache_delete_offset_list(mc, name);
1549
 
                                cache_multi_unlock(me);
1550
 
                                cache_unlock(mc);
1551
 
                                free(path);
1552
 
                                free(options);
1553
 
                                pthread_setcancelstate(cur_state, NULL);
1554
 
                                return 1;
1555
 
                        }
1556
 
 
1557
 
                        p += l;
1558
 
                        p = skipspace(p);
1559
 
 
1560
 
                        master_source_current_wait(ap->entry);
1561
 
                        ap->entry->current = source;
1562
 
 
1563
 
                        status = add_offset_entry(ap, name,
1564
 
                                                m_root, m_root_len,
1565
 
                                                path, myoptions, loc, age);
1566
 
 
1567
 
                        if (status != CHE_OK) {
1568
 
                                warn(ap->logopt, MODPREFIX "error adding multi-mount");
1569
 
                                cache_delete_offset_list(mc, name);
1570
 
                                cache_multi_unlock(me);
1571
 
                                cache_unlock(mc);
1572
 
                                free(path);
1573
 
                                free(options);
1574
 
                                free(myoptions);
1575
 
                                free(loc);
1576
 
                                pthread_setcancelstate(cur_state, NULL);
1577
 
                                return 1;
1578
 
                        }
1579
 
 
1580
 
                        free(loc);
1581
 
                        free(path);
1582
 
                        free(myoptions);
1583
 
                } while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
1584
 
 
1585
 
                /*
1586
 
                 * We've got the ordered list of multi-mount entries so go
1587
 
                 * through and set the parent entry of each
1588
 
                 */
1589
 
                cache_set_parents(me);
1590
 
 
1591
 
                rv = mount_subtree(ap, me, name, NULL, options, ctxt);
1592
 
 
1593
 
                cache_multi_unlock(me);
1594
 
                cache_unlock(mc);
1595
 
 
1596
 
                free(options);
1597
 
                pthread_setcancelstate(cur_state, NULL);
1598
 
 
1599
 
                return rv;
1600
 
        } else {
1601
 
                /* Normal (and non-root multi-mount) entries */
1602
 
                char *loc;
1603
 
                int loclen;
1604
 
                int l;
1605
 
 
1606
 
                /*
1607
 
                 * If this is an offset belonging to a multi-mount entry
1608
 
                 * it's already been parsed (above) and any option string
1609
 
                 * has already been stripped so just use the remainder.
1610
 
                 */
1611
 
                cache_readlock(mc);
1612
 
                if (*name == '/' &&
1613
 
                   (me = cache_lookup_distinct(mc, name)) && me->multi) {
1614
 
                        loc = strdup(p);
1615
 
                        if (!loc) {
1616
 
                                free(options);
1617
 
                                cache_unlock(mc);
1618
 
                                warn(ap->logopt, MODPREFIX "out of memory");
1619
 
                                return 1;
1620
 
                        }
1621
 
                        cache_multi_writelock(me);
1622
 
                        rv = mount_subtree(ap, me, name, loc, options, ctxt);
1623
 
                        cache_multi_unlock(me);
1624
 
                        cache_unlock(mc);
1625
 
                        free(loc);
1626
 
                        free(options);
1627
 
                        return rv;
1628
 
                }
1629
 
                cache_unlock(mc);
1630
 
 
1631
 
                l = chunklen(p, check_colon(p));
1632
 
                loc = dequote(p, l, ap->logopt);
1633
 
                if (!loc) {
1634
 
                        free(options);
1635
 
                        warn(ap->logopt, MODPREFIX "null location or out of memory");
1636
 
                        return 1;
1637
 
                }
1638
 
 
1639
 
                /* Location can't begin with a '/' */
1640
 
                if (*p == '/') {
1641
 
                        free(options);
1642
 
                        free(loc);
1643
 
                        warn(ap->logopt,
1644
 
                              MODPREFIX "error location begins with \"/\"");
1645
 
                        return 1;
1646
 
                }
1647
 
 
1648
 
                if (!validate_location(loc)) {
1649
 
                        warn(ap->logopt, MODPREFIX "invalid location %s", loc);
1650
 
                        free(loc);
1651
 
                        free(options);
1652
 
                        return 1;
1653
 
                }
1654
 
 
1655
 
                debug(ap->logopt,
1656
 
                      MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc);
1657
 
 
1658
 
                p += l;
1659
 
                p = skipspace(p);
1660
 
 
1661
 
                while (*p) {
1662
 
                        char *tmp, *ent;
1663
 
 
1664
 
                        l = chunklen(p, check_colon(p));
1665
 
                        ent = dequote(p, l, ap->logopt);
1666
 
                        if (!ent) {
1667
 
                                free(loc);
1668
 
                                free(options);
1669
 
                                warn(ap->logopt,
1670
 
                                     MODPREFIX "null location or out of memory");
1671
 
                                return 1;
1672
 
                        }
1673
 
 
1674
 
                        if (!validate_location(ent)) {
1675
 
                                warn(ap->logopt,
1676
 
                                     MODPREFIX "invalid location %s", loc);
1677
 
                                free(ent);
1678
 
                                free(loc);
1679
 
                                free(options);
1680
 
                                return 1;
1681
 
                        }
1682
 
 
1683
 
                        debug(ap->logopt,
1684
 
                              MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent);
1685
 
 
1686
 
                        tmp = realloc(loc, strlen(loc) + l + 2);
1687
 
                        if (!tmp) {
1688
 
                                free(ent);
1689
 
                                free(loc);
1690
 
                                free(options);
1691
 
                                error(ap->logopt, MODPREFIX "out of memory");
1692
 
                                return 1;
1693
 
                        }
1694
 
                        loc = tmp;
1695
 
 
1696
 
                        strcat(loc, " ");
1697
 
                        strcat(loc, ent);
1698
 
 
1699
 
                        free(ent);
1700
 
 
1701
 
                        p += l;
1702
 
                        p = skipspace(p);
1703
 
                }
1704
 
 
1705
 
                loclen = strlen(loc);
1706
 
                if (loclen == 0) {
1707
 
                        free(loc);
1708
 
                        free(options);
1709
 
                        error(ap->logopt,
1710
 
                              MODPREFIX "entry %s is empty!", name);
1711
 
                        return 1;
1712
 
                }
1713
 
 
1714
 
                debug(ap->logopt,
1715
 
                      MODPREFIX "core of entry: options=%s, loc=%.*s",
1716
 
                      options, loclen, loc);
1717
 
 
1718
 
                if (!strcmp(ap->path, "/-"))
1719
 
                        rv = sun_mount(ap, name, name, name_len,
1720
 
                                       loc, loclen, options, ctxt);
1721
 
                else
1722
 
                        rv = sun_mount(ap, ap->path, name, name_len,
1723
 
                                       loc, loclen, options, ctxt);
1724
 
 
1725
 
                free(loc);
1726
 
                free(options);
1727
 
                pthread_setcancelstate(cur_state, NULL);
1728
 
        }
1729
 
        return rv;
1730
 
}
1731
 
 
1732
 
int parse_done(void *context)
1733
 
{
1734
 
        int rv = 0;
1735
 
        struct parse_context *ctxt = (struct parse_context *) context;
1736
 
 
1737
 
        if (--init_ctr == 0) {
1738
 
                rv = close_mount(mount_nfs);
1739
 
                mount_nfs = NULL;
1740
 
        }
1741
 
        if (ctxt)
1742
 
                kill_context(ctxt);
1743
 
 
1744
 
        return rv;
1745
 
}