~ubuntu-branches/debian/wheezy/autofs/wheezy

« back to all changes in this revision

Viewing changes to modules/parse_sun.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2008-03-08 01:36:09 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20080308013609-cvs4f2ecoyoism02
Tags: 4.1.4+debian-2.1
* Non-maintainer upload.
* High-urgency upload for RC bugfix.
* Add -DLDAP_DEPRECATED to CFLAGS, to fix compatibility with OpenLDAP
  2.4 on 64-bit architectures.  Closes: #463419.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ident "$Id: parse_sun.c,v 1.28 2005/04/05 12:42:42 raven Exp $"
 
2
/* ----------------------------------------------------------------------- *
 
3
 *   
 
4
 *  parse_sun.c - module for Linux automountd to parse a Sun-format
 
5
 *                automounter map
 
6
 * 
 
7
 *   Copyright 1997 Transmeta Corporation - All Rights Reserved
 
8
 *   Copyright 2000 Jeremy Fitzhardinge <jeremy@goop.org>
 
9
 *   Copyright 2004, 2005 Ian Kent <raven@themaw.net>
 
10
 *
 
11
 *   This program is free software; you can redistribute it and/or modify
 
12
 *   it under the terms of the GNU General Public License as published by
 
13
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
 
14
 *   USA; either version 2 of the License, or (at your option) any later
 
15
 *   version; incorporated herein by reference.
 
16
 *
 
17
 * ----------------------------------------------------------------------- */
 
18
 
 
19
#include <stdio.h>
 
20
#include <malloc.h>
 
21
#include <errno.h>
 
22
#include <netdb.h>
 
23
#include <fcntl.h>
 
24
#include <unistd.h>
 
25
#include <stdlib.h>
 
26
#include <syslog.h>
 
27
#include <string.h>
 
28
#include <syslog.h>
 
29
#include <ctype.h>
 
30
#include <sys/param.h>
 
31
#include <sys/socket.h>
 
32
#include <sys/types.h>
 
33
#include <sys/stat.h>
 
34
#include <sys/utsname.h>
 
35
#include <netinet/in.h>
 
36
 
 
37
#define MODULE_PARSE
 
38
#include "automount.h"
 
39
 
 
40
#define MODPREFIX "parse(sun): "
 
41
 
 
42
int parse_version = AUTOFS_PARSE_VERSION;       /* Required by protocol */
 
43
 
 
44
static struct mount_mod *mount_nfs = NULL;
 
45
static int init_ctr = 0;
 
46
 
 
47
struct substvar {
 
48
        char *def;              /* Define variable */
 
49
        char *val;              /* Value to replace with */
 
50
        struct substvar *next;
 
51
};
 
52
 
 
53
struct parse_context {
 
54
        char *optstr;           /* Mount options */
 
55
        struct substvar *subst; /* $-substitutions */
 
56
        int slashify_colons;    /* Change colons to slashes? */
 
57
};
 
58
 
 
59
struct multi_mnt {
 
60
        char *path;
 
61
        char *options;
 
62
        char *location;
 
63
        struct multi_mnt *next;
 
64
};
 
65
 
 
66
struct utsname un;
 
67
char processor[65];             /* Not defined on Linux, so we make our own */
 
68
 
 
69
/* Predefined variables: tail of link chain */
 
70
static struct substvar
 
71
        sv_arch   = {"ARCH",   un.machine,  NULL },
 
72
        sv_cpu    = {"CPU",    processor,   &sv_arch},
 
73
        sv_host   = {"HOST",   un.nodename, &sv_cpu},
 
74
        sv_osname = {"OSNAME", un.sysname,  &sv_host},
 
75
        sv_osrel  = {"OSREL",  un.release,  &sv_osname},
 
76
        sv_osvers = {"OSVERS", un.version,  &sv_osrel
 
77
};
 
78
 
 
79
/* Default context pattern */
 
80
 
 
81
static char *child_args = NULL;
 
82
static struct parse_context default_context = {
 
83
        NULL,                   /* No mount options */
 
84
        &sv_osvers,             /* The substvar predefined variables */
 
85
        1                       /* Do slashify_colons */
 
86
};
 
87
 
 
88
/* Free all storage associated with this context */
 
89
static void kill_context(struct parse_context *ctxt)
 
90
{
 
91
        struct substvar *sv, *nsv;
 
92
 
 
93
        sv = ctxt->subst;
 
94
 
 
95
        while (sv != &sv_osvers) {
 
96
                nsv = sv->next;
 
97
                free(sv);
 
98
                sv = nsv;
 
99
        }
 
100
 
 
101
        if (ctxt->optstr)
 
102
                free(ctxt->optstr);
 
103
 
 
104
        free(ctxt);
 
105
}
 
106
 
 
107
 
 
108
/* Find the $-variable matching a certain string fragment */
 
109
static const struct substvar *findvar(const struct substvar *sv, const char *str, int len)
 
110
{
 
111
#ifdef ENABLE_EXT_ENV
 
112
        /* holds one env var */
 
113
        static struct substvar sv_env = { NULL, NULL,  NULL };
 
114
        static char *substvar_env;
 
115
        char etmp[512];
 
116
#endif
 
117
 
 
118
        while (sv) {
 
119
                if (!strncmp(str, sv->def, len) && sv->def[len] == '\0')
 
120
                        return sv;
 
121
                sv = sv->next;
 
122
        }
 
123
 
 
124
#ifdef ENABLE_EXT_ENV
 
125
        /* builtin map failed, try the $ENV */
 
126
        memcpy(etmp, str, len);
 
127
        etmp[len]='\0';
 
128
 
 
129
        if ((substvar_env=getenv(etmp)) != NULL) {
 
130
                sv_env.val = substvar_env;
 
131
                return(&sv_env);
 
132
        }
 
133
#endif
 
134
 
 
135
        return NULL;
 
136
}
 
137
 
 
138
/* 
 
139
 * $- and &-expand a Sun-style map entry and return the length of the entry.
 
140
 * If "dst" is NULL, just count the length.
 
141
 */
 
142
int expandsunent(const char *src, char *dst, const char *key,
 
143
                 const struct substvar *svc, int slashify_colons)
 
144
{
 
145
        const struct substvar *sv;
 
146
        int len, l, seen_colons;
 
147
        const char *p;
 
148
        char ch;
 
149
 
 
150
        len = 0;
 
151
        seen_colons = 0;
 
152
 
 
153
        while ((ch = *src++)) {
 
154
                switch (ch) {
 
155
                case '&':
 
156
                        l = strlen(key);
 
157
                        if (dst) {
 
158
                                strcpy(dst, key);
 
159
                                dst += l;
 
160
                        }
 
161
                        len += l;
 
162
                        break;
 
163
 
 
164
                case '$':
 
165
                        if (*src == '{') {
 
166
                                p = strchr(++src, '}');
 
167
                                if (!p) {
 
168
                                        /* Ignore rest of string */
 
169
                                        if (dst)
 
170
                                                *dst = '\0';
 
171
                                        return len;
 
172
                                }
 
173
                                sv = findvar(svc, src, p - src);
 
174
                                if (sv) {
 
175
                                        l = strlen(sv->val);
 
176
                                        if (dst) {
 
177
                                                strcpy(dst, sv->val);
 
178
                                                dst += l;
 
179
                                        }
 
180
                                        len += l;
 
181
                                }
 
182
                                src = p + 1;
 
183
                        } else {
 
184
                                p = src;
 
185
                                while (isalnum(*p) || *p == '_')
 
186
                                        p++;
 
187
                                sv = findvar(svc, src, p - src);
 
188
                                if (sv) {
 
189
                                        l = strlen(sv->val);
 
190
                                        if (dst) {
 
191
                                                strcpy(dst, sv->val);
 
192
                                                dst += l;
 
193
                                        }
 
194
                                        len += l;
 
195
                                }
 
196
                                src = p;
 
197
                        }
 
198
                        break;
 
199
 
 
200
                case '\\':
 
201
                        len++;
 
202
                        if (dst)
 
203
                                *dst++ = ch;
 
204
 
 
205
                        if (*src) {
 
206
                                len++;
 
207
                                if (dst)
 
208
                                        *dst++ = *src;
 
209
                                src++;
 
210
                        }
 
211
                        break;
 
212
 
 
213
                case ':':
 
214
                        if (dst)
 
215
                                *(dst++) = 
 
216
                                  (seen_colons && slashify_colons) ? '/' : ':';
 
217
                        len++;
 
218
                        seen_colons = 1;
 
219
                        break;
 
220
 
 
221
                default:
 
222
                        if (isspace(ch))
 
223
                                seen_colons = 0;
 
224
 
 
225
                        if (dst)
 
226
                                *(dst++) = ch;
 
227
                        len++;
 
228
                        break;
 
229
                }
 
230
        }
 
231
        if (dst)
 
232
                *dst = '\0';
 
233
        return len;
 
234
}
 
235
 
 
236
/*
 
237
 * Skip whitespace in a string; if we hit a #, consider the rest of the
 
238
 * entry a comment.
 
239
 */
 
240
const char *skipspace(const char *whence)
 
241
{
 
242
        while (1) {
 
243
                switch (*whence) {
 
244
                case ' ':
 
245
                case '\b':
 
246
                case '\t':
 
247
                case '\n':
 
248
                case '\v':
 
249
                case '\f':
 
250
                case '\r':
 
251
                        whence++;
 
252
                        break;
 
253
                case '#':       /* comment: skip to end of string */
 
254
                        while (*whence != '\0')
 
255
                                whence++;
 
256
                        /* FALLTHROUGH */
 
257
 
 
258
                default:
 
259
                        return whence;
 
260
                }
 
261
        }
 
262
}
 
263
 
 
264
/*
 
265
 * Check a string to see if a colon appears before the next '/'.
 
266
 */
 
267
int check_colon(const char *str)
 
268
{
 
269
        char *ptr = (char *) str;
 
270
 
 
271
        while (*ptr && *ptr != ':' && *ptr != '/') {
 
272
                ptr++;
 
273
        }
 
274
 
 
275
        if (!*ptr || *ptr == '/')
 
276
                return 0;
 
277
 
 
278
        return 1;
 
279
}
 
280
 
 
281
/* Get the length of a chunk delimitered by whitespace */
 
282
int chunklen(const char *whence, int expect_colon)
 
283
{
 
284
        int n = 0;
 
285
        int quote = 0;
 
286
 
 
287
        for (; *whence; whence++, n++) {
 
288
                switch (*whence) {
 
289
                case '\\':
 
290
                        if( quote ) {
 
291
                                break;
 
292
                        } else {
 
293
                                quote = 1;
 
294
                                continue;
 
295
                        }
 
296
                case ':':
 
297
                        if (expect_colon)
 
298
                                expect_colon = 0;
 
299
                        continue;
 
300
                case ' ':
 
301
                case '\t':
 
302
                        /* Skip space or tab if we expect a colon */
 
303
                        if (expect_colon)
 
304
                                continue;
 
305
                case '\b':
 
306
                case '\n':
 
307
                case '\v':
 
308
                case '\f':
 
309
                case '\r':
 
310
                case '#':
 
311
                case '\0':
 
312
                        if (!quote)
 
313
                                return n;
 
314
                        /* FALLTHROUGH */
 
315
                default:
 
316
                        break;
 
317
                }
 
318
                quote = 0;
 
319
        }
 
320
 
 
321
        return n;
 
322
}
 
323
 
 
324
/*
 
325
 * Compare str with pat.  Return 0 if compare equal or
 
326
 * str is an abbreviation of pat of no less than mchr characters.
 
327
 */
 
328
int strmcmp(const char *str, const char *pat, int mchr)
 
329
{
 
330
        int nchr = 0;
 
331
 
 
332
        while (*str == *pat) {
 
333
                if (!*str)
 
334
                        return 0;
 
335
                str++;
 
336
                pat++;
 
337
                nchr++;
 
338
        }
 
339
 
 
340
        if (!*str && nchr > mchr)
 
341
                return 0;
 
342
 
 
343
        return *pat - *str;
 
344
}
 
345
 
 
346
int parse_init(int argc, const char *const *argv, void **context)
 
347
{
 
348
        struct parse_context *ctxt;
 
349
        struct substvar *sv;
 
350
        char *noptstr;
 
351
        const char *xopt;
 
352
        int optlen, len;
 
353
        int i, bval;
 
354
 
 
355
        /* Get processor information for predefined escapes */
 
356
 
 
357
        if (!init_ctr) {
 
358
                uname(&un);
 
359
                /* uname -p is not defined on Linux.  Make it the same as uname -m,
 
360
                   except make it return i386 on all x86 (x >= 3) */
 
361
                strcpy(processor, un.machine);
 
362
                if (processor[0] == 'i' && processor[1] >= '3' &&
 
363
                    !strcmp(processor + 2, "86"))
 
364
                        processor[1] = '3';
 
365
        }
 
366
 
 
367
        /* Set up context and escape chain */
 
368
 
 
369
        if (!(ctxt = (struct parse_context *) malloc(sizeof(struct parse_context)))) {
 
370
                crit(MODPREFIX "malloc: %m");
 
371
                return 1;
 
372
        }
 
373
        *context = (void *) ctxt;
 
374
 
 
375
        *ctxt = default_context;
 
376
        optlen = 0;
 
377
 
 
378
        /* Look for options and capture, and create new defines if we need to */
 
379
 
 
380
        for (i = 0; i < argc; i++) {
 
381
                if (argv[i][0] == '-' &&
 
382
                   (argv[i][1] == 'D' || argv[i][1] == '-') ) {
 
383
                        switch (argv[i][1]) {
 
384
                        case 'D':
 
385
                                sv = malloc(sizeof(struct substvar));
 
386
                                if (!sv) {
 
387
                                        error(MODPREFIX "malloc: %m");
 
388
                                        break;
 
389
                                }
 
390
                                if (argv[i][2])
 
391
                                        sv->def = strdup(argv[i] + 2);
 
392
                                else if (++i < argc)
 
393
                                        sv->def = strdup(argv[i]);
 
394
                                else {
 
395
                                        free(sv);
 
396
                                        break;
 
397
                                }
 
398
 
 
399
                                if (!sv->def) {
 
400
                                        error(MODPREFIX "strdup: %m");
 
401
                                        free(sv);
 
402
                                } else {
 
403
                                        sv->val = strchr(sv->def, '=');
 
404
                                        if (sv->val)
 
405
                                                *(sv->val++) = '\0';
 
406
                                        else
 
407
                                                sv->val = "";
 
408
                                        /* we use 5 for the "-D", the "=", and the null */
 
409
                                        if (child_args) {
 
410
                                                child_args = realloc(child_args, strlen(child_args) + strlen(sv->def) + strlen(sv->val) + 5);
 
411
                                                strcat(child_args, ",");
 
412
                                        }
 
413
                                        else { /* No comma, so only +4 */
 
414
                                                child_args = malloc(strlen(sv->def) + strlen(sv->val) + 4);
 
415
                                                *child_args = '\0';
 
416
                                        }
 
417
                                        strcat(child_args, "-D");
 
418
                                        strcat(child_args, sv->def);
 
419
                                        strcat(child_args, "=");
 
420
                                        strcat(child_args, sv->val);
 
421
                                        sv->next = ctxt->subst;
 
422
                                        ctxt->subst = sv;
 
423
                                }
 
424
                                break;
 
425
 
 
426
                        case '-':
 
427
                                if (!strncmp(argv[i] + 2, "no-", 3)) {
 
428
                                        xopt = argv[i] + 5;
 
429
                                        bval = 0;
 
430
                                } else {
 
431
                                        xopt = argv[i] + 2;
 
432
                                        bval = 1;
 
433
                                }
 
434
 
 
435
                                if (!strmcmp(xopt, "slashify-colons", 1))
 
436
                                        ctxt->slashify_colons = bval;
 
437
                                else
 
438
                                        error(MODPREFIX "unknown option: %s",
 
439
                                              argv[i]);
 
440
 
 
441
                                break;
 
442
 
 
443
                        default:
 
444
                                error(MODPREFIX "unknown option: %s", argv[i]);
 
445
                                break;
 
446
                        }
 
447
                } else {
 
448
                        int offset = (argv[i][0] == '-' ? 1 : 0);
 
449
                        len = strlen(argv[i] + offset);
 
450
                        if (ctxt->optstr) {
 
451
                                noptstr =
 
452
                                    (char *) realloc(ctxt->optstr, optlen + len + 2);
 
453
                                if (!noptstr)
 
454
                                        break;
 
455
                                noptstr[optlen] = ',';
 
456
                                strcpy(noptstr + optlen + 1, argv[i] + offset);
 
457
                                optlen += len + 1;
 
458
                        } else {
 
459
                                noptstr = (char *) malloc(len + 1);
 
460
                                strcpy(noptstr, argv[i] + offset);
 
461
                                optlen = len;
 
462
                        }
 
463
                        if (!noptstr) {
 
464
                                kill_context(ctxt);
 
465
                                crit(MODPREFIX "%m");
 
466
                                return 1;
 
467
                        }
 
468
                        ctxt->optstr = noptstr;
 
469
                        debug(MODPREFIX "init gathered options: %s",
 
470
                              ctxt->optstr);
 
471
                }
 
472
        }
 
473
 
 
474
        /* We only need this once.  NFS mounts are so common that we cache
 
475
           this module. */
 
476
        if (!mount_nfs)
 
477
                if ((mount_nfs = open_mount("nfs", MODPREFIX))) {
 
478
                        init_ctr++;
 
479
                        return 0;
 
480
                } else {
 
481
                        kill_context(ctxt);
 
482
                        return 1;
 
483
        } else {
 
484
                init_ctr++;
 
485
                return 0;
 
486
        }
 
487
}
 
488
 
 
489
static char *dequote(const char *str, int strlen)
 
490
{
 
491
        char *ret = malloc(strlen + 1);
 
492
        char *cp = ret;
 
493
        const char *scp;
 
494
        int origlen = strlen;
 
495
        int quote = 0;
 
496
 
 
497
        if (ret == NULL)
 
498
                return NULL;
 
499
 
 
500
        for (scp = str; strlen > 0 && *scp; scp++, strlen--) {
 
501
                if (*scp == '\\' && !quote ) {
 
502
                        quote = 1;
 
503
                        continue;
 
504
                }
 
505
                quote = 0;
 
506
                *cp++ = *scp;
 
507
        }
 
508
        *cp = '\0';
 
509
 
 
510
        debug(MODPREFIX "dequote(\"%.*s\") -> %s", origlen, str, ret);
 
511
 
 
512
        return ret;
 
513
}
 
514
 
 
515
static const char *parse_options(const char *str, char **ret)
 
516
{
 
517
        const char *cp = str;
 
518
        int len;
 
519
 
 
520
        if (*cp++ != '-')
 
521
                return str;
 
522
 
 
523
        if (*ret != NULL)
 
524
                free(*ret);
 
525
 
 
526
        *ret = dequote(cp, len = chunklen(cp, 0));
 
527
 
 
528
        return cp + len;
 
529
}
 
530
 
 
531
static char *concat_options(char *left, char *right)
 
532
{
 
533
        char *ret;
 
534
 
 
535
        if (left == NULL || *left == '\0') {
 
536
                free(left);
 
537
                ret = strdup(right);
 
538
                return ret;
 
539
        }
 
540
 
 
541
        if (right == NULL || *right == '\0') {
 
542
                free(right);
 
543
                return strdup(left);
 
544
        }
 
545
 
 
546
        ret = malloc(strlen(left) + strlen(right) + 2);
 
547
 
 
548
        if (ret == NULL) {
 
549
                error(MODPREFIX "concat_options malloc: %m");
 
550
                return NULL;
 
551
        }
 
552
 
 
553
        sprintf(ret, "%s,%s", left, right);
 
554
 
 
555
        free(left);
 
556
        free(right);
 
557
 
 
558
        return ret;
 
559
}
 
560
 
 
561
static int sun_mount(const char *root, const char *name, int namelen,
 
562
                     const char *loc, int loclen, const char *options)
 
563
{
 
564
        char *fstype = "nfs";   /* Default filesystem type */
 
565
        int nonstrict = 1;
 
566
        int rv;
 
567
        char *mountpoint;
 
568
        char *what;
 
569
 
 
570
        if (*options == '\0')
 
571
                options = NULL;
 
572
 
 
573
        if (options) {
 
574
                char *noptions;
 
575
                const char *comma;
 
576
                char *np;
 
577
                int len = strlen(options) + 1;
 
578
 
 
579
                noptions = np = alloca(len);
 
580
                *np = '\0';
 
581
 
 
582
                /* Extract fstype= pseudo option */
 
583
                for (comma = options; *comma != '\0';) {
 
584
                        const char *cp;
 
585
 
 
586
                        while (*comma == ',')
 
587
                                comma++;
 
588
 
 
589
                        cp = comma;
 
590
 
 
591
                        while (*comma != '\0' && *comma != ',')
 
592
                                comma++;
 
593
 
 
594
                        if (strncmp("fstype=", cp, 7) == 0) {
 
595
                                int typelen = comma - (cp + 7);
 
596
                                fstype = alloca(typelen + 1);
 
597
                                memcpy(fstype, cp + 7, typelen);
 
598
                                fstype[typelen] = '\0';
 
599
                        } else if (strncmp("strict", cp, 6) == 0) {
 
600
                                nonstrict = 0;
 
601
                        } else if (strncmp("nonstrict", cp, 9) == 0) {
 
602
                                nonstrict = 1;
 
603
                        } else {
 
604
                                memcpy(np, cp, comma - cp + 1);
 
605
                                np += comma - cp + 1;
 
606
                        }
 
607
                }
 
608
 
 
609
                if (np > noptions + len) {
 
610
                        warn(MODPREFIX "options string truncated");
 
611
                        np[len] = '\0';
 
612
                } else
 
613
                        *(np - 1) = '\0';
 
614
 
 
615
                options = noptions;
 
616
        }
 
617
 
 
618
 
 
619
        if (child_args && !strcmp(fstype, "autofs")) {
 
620
                char *noptions;
 
621
 
 
622
                if (!options) {
 
623
                        noptions = alloca(strlen(child_args) + 1);
 
624
                        *noptions = '\0';
 
625
                } else {
 
626
                        noptions = alloca(strlen(options) + strlen(child_args) + 2);
 
627
 
 
628
                        if (noptions) {
 
629
                                strcpy(noptions, options);
 
630
                                strcat(noptions, ",");
 
631
                        }
 
632
                }
 
633
 
 
634
                if (noptions) {
 
635
                        strcat(noptions, child_args);
 
636
                        options = noptions;
 
637
                } else {
 
638
                        error(MODPREFIX "alloca failed for options");
 
639
                }
 
640
        }
 
641
 
 
642
        while (*name == '/') {
 
643
                name++;
 
644
                namelen--;
 
645
        }
 
646
 
 
647
        mountpoint = alloca(namelen + 1);
 
648
        sprintf(mountpoint, "%.*s", namelen, name);
 
649
 
 
650
        what = alloca(loclen + 1);
 
651
        memcpy(what, loc, loclen);
 
652
        what[loclen] = '\0';
 
653
 
 
654
        if (!strcmp(fstype, "autofs") && strchr(loc, ':') == NULL) {
 
655
                char mtype[7];
 
656
                int mtype_len;
 
657
 
 
658
                if (loc[0] == '/') {
 
659
                        mtype_len = 5;
 
660
                        if (loc[1] == '/')
 
661
                                strcpy(mtype, "ldap:");
 
662
                        else
 
663
                                strcpy(mtype, "file:");
 
664
                } else {
 
665
                        mtype_len = 3;
 
666
                        strcpy(mtype, "yp:");
 
667
                }
 
668
 
 
669
                what = alloca(loclen + mtype_len + 1);
 
670
                memcpy(what, mtype, mtype_len);
 
671
                memcpy(what + mtype_len, loc, loclen);
 
672
                what[loclen + mtype_len] = '\0';
 
673
        } else {
 
674
                what = alloca(loclen + 1);
 
675
                memcpy(what, loc, loclen);
 
676
                what[loclen] = '\0';
 
677
        }
 
678
 
 
679
        debug(MODPREFIX
 
680
            "mounting root %s, mountpoint %s, what %s, fstype %s, options %s\n",
 
681
            root, mountpoint, what, fstype, options);
 
682
 
 
683
        if (!strcmp(fstype, "nfs")) {
 
684
                rv = mount_nfs->mount_mount(root, mountpoint, strlen(mountpoint),
 
685
                                            what, fstype, options, mount_nfs->context);
 
686
        } else {
 
687
                /* Generic mount routine */
 
688
                rv = do_mount(root, mountpoint, strlen(mountpoint), what, fstype,
 
689
                              options);
 
690
        }
 
691
 
 
692
        if (nonstrict && rv)
 
693
                return -rv;
 
694
 
 
695
        return rv;
 
696
}
 
697
 
 
698
/*
 
699
 * Build list of mounts in shortest -> longest order.
 
700
 * Pass in list head and return list head.
 
701
 */
 
702
struct multi_mnt *multi_add_list(struct multi_mnt *list,
 
703
                                 char *path, char *options, char *location)
 
704
{
 
705
        struct multi_mnt *mmptr, *new, *old = NULL;
 
706
        int plen;
 
707
 
 
708
        if (!path || !options || !location)
 
709
                return NULL;
 
710
 
 
711
        new = malloc(sizeof(struct multi_mnt));
 
712
        if (!new)
 
713
                return NULL;
 
714
 
 
715
        new->path = path;
 
716
        new->options = options;
 
717
        new->location = location;
 
718
 
 
719
        plen = strlen(path);
 
720
        mmptr = list;
 
721
        while (mmptr) {
 
722
                if (plen <= strlen(mmptr->path))
 
723
                        break;
 
724
                old = mmptr;
 
725
                mmptr = mmptr->next;
 
726
        }
 
727
 
 
728
        if (old)
 
729
                old->next = new;
 
730
        new->next = mmptr;
 
731
 
 
732
        return old ? list : new;
 
733
}
 
734
 
 
735
void multi_free_list(struct multi_mnt *list)
 
736
{
 
737
        struct multi_mnt *next;
 
738
 
 
739
        if (!list)
 
740
                return;
 
741
 
 
742
        next = list;
 
743
        while (next) {
 
744
                struct multi_mnt *this = next;
 
745
 
 
746
                next = this->next;
 
747
 
 
748
                if (this->path)
 
749
                        free(this->path);
 
750
 
 
751
                if (this->options)
 
752
                        free(this->options);
 
753
 
 
754
                if (this->location)
 
755
                        free(this->location);
 
756
 
 
757
                free(this);
 
758
        }
 
759
}
 
760
 
 
761
/*
 
762
 * Scan map entry looking for evidence it has multiple key/mapent
 
763
 * pairs.
 
764
 */
 
765
static int check_is_multi(const char *mapent)
 
766
{
 
767
        const char *p = (char *) mapent;
 
768
        int multi = 0;
 
769
        int first_chunk = 0;
 
770
 
 
771
        while (*p) {
 
772
                p = skipspace(p);
 
773
 
 
774
                /*
 
775
                 * After the first chunk there can be additional
 
776
                 * locations (possibly not multi) or possibly an
 
777
                 * options string if the first entry includes the
 
778
                 * optional '/' (is multi). Following this any
 
779
                 * path that begins with '/' indicates a mutil-mount
 
780
                 * entry.
 
781
                 */
 
782
                if (first_chunk) {
 
783
                        if (*p == '/' || *p == '-') {
 
784
                                multi = 1;
 
785
                                break;
 
786
                        }
 
787
                }
 
788
 
 
789
                while (*p == '-') {
 
790
                        p += chunklen(p, 0);
 
791
                        p = skipspace(p);
 
792
                }
 
793
 
 
794
                /*
 
795
                 * Expect either a path or location
 
796
                 * after which it's a multi mount.
 
797
                 */
 
798
                p += chunklen(p, check_colon(p));
 
799
                first_chunk++;
 
800
        }
 
801
 
 
802
        return multi;
 
803
}
 
804
 
 
805
/*
 
806
 * syntax is:
 
807
 *      [-options] location [location] ...
 
808
 *      [-options] [mountpoint [-options] location [location] ... ]...
 
809
 */
 
810
int parse_mount(const char *root, const char *name,
 
811
                int name_len, const char *mapent, void *context)
 
812
{
 
813
        struct parse_context *ctxt = (struct parse_context *) context;
 
814
        char *pmapent, *options;
 
815
        const char *p;
 
816
        int mapent_len, rv;
 
817
        int optlen;
 
818
 
 
819
        mapent_len = expandsunent(mapent, NULL, name, ctxt->subst, ctxt->slashify_colons);
 
820
        pmapent = alloca(mapent_len + 1);
 
821
        if (!pmapent) {
 
822
                error(MODPREFIX "alloca: %m");
 
823
                return 1;
 
824
        }
 
825
        pmapent[mapent_len] = '\0';
 
826
 
 
827
        expandsunent(mapent, pmapent, name, ctxt->subst, ctxt->slashify_colons);
 
828
 
 
829
        debug(MODPREFIX "expanded entry: %s", pmapent);
 
830
 
 
831
        options = strdup(ctxt->optstr ? ctxt->optstr : "");
 
832
        if (!options) {
 
833
                error(MODPREFIX "strdup: %m");
 
834
                return 1;
 
835
        }
 
836
        optlen = strlen(options);
 
837
 
 
838
        p = skipspace(pmapent);
 
839
 
 
840
        /* Deal with 0 or more options */
 
841
        if (*p == '-') {
 
842
                do {
 
843
                        char *noptions = NULL;
 
844
 
 
845
                        p = parse_options(p, &noptions);
 
846
                        options = concat_options(options, noptions);
 
847
 
 
848
                        if (options == NULL) {
 
849
                                error(MODPREFIX "concat_options: %m");
 
850
                                return 1;
 
851
                        }
 
852
                        p = skipspace(p);
 
853
                } while (*p == '-');
 
854
        }
 
855
 
 
856
        debug(MODPREFIX "gathered options: %s", options);
 
857
 
 
858
        if (check_is_multi(p)) {
 
859
                struct multi_mnt *list, *head = NULL;
 
860
                char *multi_root;
 
861
                int l;
 
862
 
 
863
                multi_root = alloca(strlen(root) + name_len + 2);
 
864
                if (!multi_root) {
 
865
                        error(MODPREFIX "alloca: %m");
 
866
                        free(options);
 
867
                        return 1;
 
868
                }
 
869
 
 
870
                strcpy(multi_root, root);
 
871
                strcat(multi_root, "/");
 
872
                strcat(multi_root, name);
 
873
 
 
874
                /* It's a multi-mount; deal with it */
 
875
                do {
 
876
                        char *myoptions = strdup(options);
 
877
                        char *path, *loc;
 
878
 
 
879
                        if (myoptions == NULL) {
 
880
                                error(MODPREFIX "multi strdup: %m");
 
881
                                free(options);
 
882
                                multi_free_list(head);
 
883
                                return 1;
 
884
                        }
 
885
 
 
886
                        path = dequote(p, l = chunklen(p, 0));
 
887
                        if (!path) {
 
888
                                error(MODPREFIX "out of memory");
 
889
                                free(myoptions);
 
890
                                free(options);
 
891
                                multi_free_list(head);
 
892
                                return 1;
 
893
                        }
 
894
 
 
895
                        p += l;
 
896
                        p = skipspace(p);
 
897
 
 
898
                        /* Local options are appended to per-map options */
 
899
                        if (*p == '-') {
 
900
                                do {
 
901
                                        char *newopt = NULL;
 
902
 
 
903
                                        p = parse_options(p, &newopt);
 
904
                                        myoptions = concat_options(myoptions, newopt);
 
905
 
 
906
                                        if (myoptions == NULL) {
 
907
                                                error(MODPREFIX
 
908
                                                    "multi concat_options: %m");
 
909
                                                free(options);
 
910
                                                free(path);
 
911
                                                multi_free_list(head);
 
912
                                                return 1;
 
913
                                        }
 
914
                                        p = skipspace(p);
 
915
                                } while (*p == '-');
 
916
                        }
 
917
 
 
918
                        /* Skip over colon escape */
 
919
                        if (*p == ':')
 
920
                                p++;
 
921
 
 
922
                        loc = dequote(p, l = chunklen(p, check_colon(p)));
 
923
                        if (!loc) {
 
924
                                error(MODPREFIX "out of memory");
 
925
                                free(path);
 
926
                                free(myoptions);
 
927
                                free(options);
 
928
                                multi_free_list(head);
 
929
                                return 1;
 
930
                        }
 
931
 
 
932
                        p += l;
 
933
                        p = skipspace(p);
 
934
 
 
935
                        while (*p && *p != '/') {
 
936
                                char *ent;
 
937
 
 
938
                                ent = dequote(p, l = chunklen(p, check_colon(p)));
 
939
                                if (!ent) {
 
940
                                        error(MODPREFIX "out of memory");
 
941
                                        free(path);
 
942
                                        free(myoptions);
 
943
                                        free(options);
 
944
                                        multi_free_list(head);
 
945
                                        return 1;
 
946
                                }
 
947
 
 
948
                                loc = realloc(loc, strlen(loc) + l + 2);
 
949
                                if (!loc) {
 
950
                                        error(MODPREFIX "out of memory");
 
951
                                        free(ent);
 
952
                                        free(path);
 
953
                                        free(myoptions);
 
954
                                        free(options);
 
955
                                        multi_free_list(head);
 
956
                                        return 1;
 
957
                                }
 
958
 
 
959
                                strcat(loc, " ");
 
960
                                strcat(loc, ent);
 
961
 
 
962
                                free(ent);
 
963
 
 
964
                                p += l;
 
965
                                p = skipspace(p);
 
966
                        }
 
967
 
 
968
                        list = head;
 
969
                        head = multi_add_list(list, path, myoptions, loc);
 
970
                        if (!head) {
 
971
                                free(loc);
 
972
                                free(path);
 
973
                                free(options);
 
974
                                free(myoptions);
 
975
                                multi_free_list(list);
 
976
                                return 1;
 
977
                        }
 
978
                } while (*p == '/');
 
979
 
 
980
                list = head;
 
981
                while (list) {
 
982
                        debug(MODPREFIX
 
983
                              "multimount: %.*s on %.*s with options %s",
 
984
                              strlen(list->location), list->location,
 
985
                              strlen(list->path), list->path, list->options);
 
986
 
 
987
                        rv = sun_mount(multi_root,
 
988
                                       list->path, strlen(list->path),
 
989
                                       list->location, strlen(list->location),
 
990
                                       list->options);
 
991
 
 
992
                        /* Convert non-strict failure into success */
 
993
                        if (rv < 0) {
 
994
                                rv = 0;
 
995
                                debug("parse_mount: ignoring failure of non-strict mount");
 
996
                        } else if (rv > 0)
 
997
                                break;
 
998
 
 
999
                        list = list->next;
 
1000
                }
 
1001
 
 
1002
                multi_free_list(head);
 
1003
 
 
1004
                free(options);
 
1005
                return rv;
 
1006
        } else {
 
1007
                /* Normal (non-multi) entries */
 
1008
                char *loc;
 
1009
                int loclen;
 
1010
                int l;
 
1011
 
 
1012
                if (*p == ':')
 
1013
                        p++;    /* Sun escape for entries starting with / */
 
1014
 
 
1015
                loc = dequote(p, l = chunklen(p, check_colon(p)));
 
1016
                if (!loc) {
 
1017
                        error(MODPREFIX "out of memory");
 
1018
                        free(options);
 
1019
                        return 1;
 
1020
                }
 
1021
 
 
1022
                p += l;
 
1023
                p = skipspace(p);
 
1024
 
 
1025
                while (*p) {
 
1026
                        char *ent;
 
1027
 
 
1028
                        ent = dequote(p, l = chunklen(p, check_colon(p)));
 
1029
                        if (!ent) {
 
1030
                                error(MODPREFIX "out of memory");
 
1031
                                free(options);
 
1032
                                return 1;
 
1033
                        }
 
1034
 
 
1035
                        loc = realloc(loc, strlen(loc) + l + 2);
 
1036
                        if (!loc) {
 
1037
                                error(MODPREFIX "out of memory");
 
1038
                                free(ent);
 
1039
                                free(options);
 
1040
                                return 1;
 
1041
                        }
 
1042
 
 
1043
                        strcat(loc, " ");
 
1044
                        strcat(loc, ent);
 
1045
 
 
1046
                        free(ent);
 
1047
 
 
1048
                        p += l;
 
1049
                        p = skipspace(p);
 
1050
                }
 
1051
 
 
1052
                loclen = strlen(loc);
 
1053
                if (loclen == 0) {
 
1054
                        error(MODPREFIX "entry %s is empty!", name);
 
1055
                        free(loc);
 
1056
                        free(options);
 
1057
                        return 1;
 
1058
                }
 
1059
 
 
1060
                debug(MODPREFIX "core of entry: options=%s, loc=%.*s",
 
1061
                      options, loclen, loc);
 
1062
 
 
1063
                rv = sun_mount(root, name, name_len, loc, loclen, options);
 
1064
                /* non-strict failure to normal failure for ordinary mount */
 
1065
                if (rv < 0)
 
1066
                        rv = -rv;
 
1067
                        
 
1068
                free(loc);
 
1069
                free(options);
 
1070
        }
 
1071
 
 
1072
        return rv;
 
1073
}
 
1074
 
 
1075
int parse_done(void *context)
 
1076
{
 
1077
        int rv = 0;
 
1078
        struct parse_context *ctxt = (struct parse_context *) context;
 
1079
 
 
1080
        if (--init_ctr == 0) {
 
1081
                rv = close_mount(mount_nfs);
 
1082
                mount_nfs = NULL;
 
1083
        }
 
1084
        kill_context(ctxt);
 
1085
        return rv;
 
1086
}