1
/* ----------------------------------------------------------------------- *
3
* parse_sun.c - module for Linux automountd to parse a Sun-format
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>
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.
16
* ----------------------------------------------------------------------- */
25
#include <sys/param.h>
26
#include <sys/socket.h>
27
#include <sys/types.h>
30
#include <sys/utsname.h>
31
#include <netinet/in.h>
32
#include <sys/mount.h>
36
#include "automount.h"
38
#define MODPREFIX "parse(sun): "
40
#define MOUNT_MOVE_NONE 0x00
41
#define MOUNT_MOVE_AUTOFS 0x01
42
#define MOUNT_MOVE_OTHER 0x02
44
int parse_version = AUTOFS_PARSE_VERSION; /* Required by protocol */
46
static struct mount_mod *mount_nfs = NULL;
47
static int init_ctr = 0;
49
extern const char *global_options;
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? */
62
struct multi_mnt *next;
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 */
74
int destroy_logpri_fifo(struct autofs_point *ap);
75
static char *concat_options(char *left, char *right);
77
/* Free all storage associated with this context */
78
static void kill_context(struct parse_context *ctxt)
81
macro_free_table(ctxt->subst);
90
static struct substvar *addstdenv(struct substvar *sv)
92
struct substvar *list = sv;
93
struct thread_stdenv_vars *tsv;
96
tsv = pthread_getspecific(key_thread_stdenv_vars);
101
num = (long) tsv->uid;
102
ret = sprintf(numbuf, "%ld", num);
104
list = macro_addvar(list, "UID", 3, numbuf);
105
num = (long) tsv->gid;
106
ret = sprintf(numbuf, "%ld", num);
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);
116
static struct substvar *removestdenv(struct substvar *sv)
118
struct substvar *list = sv;
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);
129
* $- and &-expand a Sun-style map entry and return the length of the entry.
130
* If "dst" is NULL, just count the length.
132
int expandsunent(const char *src, char *dst, const char *key,
133
const struct substvar *svc, int slashify_colons)
135
const struct substvar *sv;
136
int len, l, seen_colons;
143
while ((ch = *src++)) {
148
* In order to ensure that any spaces in the key
149
* re preserved, we need to escape them here.
151
if (strchr(key, ' ')) {
152
const char *keyp = key;
154
if (isspace(*keyp)) {
179
p = strchr(++src, '}');
181
/* Ignore rest of string */
186
sv = macro_findvar(svc, src, p - src);
190
strcpy(dst, sv->val);
198
while (isalnum(*p) || *p == '_')
200
sv = macro_findvar(svc, src, p - src);
204
strcpy(dst, sv->val);
231
while (*src && *src != '"') {
246
(seen_colons && slashify_colons) ? '/' : ':';
248
/* Were looking for the colon preceeding a path */
268
int parse_init(int argc, const char *const *argv, void **context)
270
struct parse_context *ctxt;
271
char buf[MAX_ERR_BUF];
272
char *noptstr, *def, *val, *macros, *gbl_options;
274
int optlen, len, offset;
276
unsigned int append_options;
278
/* Get processor information for predefined escapes */
283
/* Set up context and escape chain */
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);
291
*context = (void *) ctxt;
293
*ctxt = default_context;
296
/* Look for options and capture, and create new defines if we need to */
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]) {
304
def = strdup(argv[i] + 2);
306
def = strdup(argv[i]);
311
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
312
logerr(MODPREFIX "strdup: %s", estr);
316
val = strchr(def, '=');
324
ctxt->subst = macro_addvar(ctxt->subst,
325
def, strlen(def), val);
329
/* we use 5 for the "-D", "=", "," and the null */
331
len = strlen(ctxt->macros) + strlen(def) + strlen(val);
332
macros = realloc(ctxt->macros, len + 5);
338
} else { /* No comma, so only +4 */
339
len = strlen(def) + strlen(val);
340
macros = malloc(len + 4);
347
ctxt->macros = macros;
349
strcat(ctxt->macros, "-D");
350
strcat(ctxt->macros, def);
351
strcat(ctxt->macros, "=");
352
strcat(ctxt->macros, val);
357
if (!strncmp(argv[i] + 2, "no-", 3)) {
365
if (!strmcmp(xopt, "slashify-colons", 1))
366
ctxt->slashify_colons = bval;
369
MODPREFIX "unknown option: %s",
375
MODPREFIX "unknown option: %s", argv[i]);
379
offset = (argv[i][0] == '-' ? 1 : 0);
380
len = strlen(argv[i] + offset);
383
(char *) realloc(ctxt->optstr, optlen + len + 2);
385
noptstr[optlen] = ',';
386
strcpy(noptstr + optlen + 1, argv[i] + offset);
390
noptstr = (char *) malloc(len + 1);
392
strcpy(noptstr, argv[i] + offset);
397
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
399
logerr(MODPREFIX "%s", estr);
403
ctxt->optstr = noptstr;
408
if (global_options) {
409
if (ctxt->optstr && strstr(ctxt->optstr, global_options))
411
gbl_options = strdup(global_options);
415
append_options = defaults_get_append_options();
416
if (append_options) {
417
char *tmp = concat_options(gbl_options, ctxt->optstr);
419
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
420
logerr(MODPREFIX "concat_options: %s", estr);
426
ctxt->optstr = gbl_options;
433
MODPREFIX "init gathered global options: %s", ctxt->optstr);
435
/* We only need this once. NFS mounts are so common that we cache
438
if ((mount_nfs = open_mount("nfs", MODPREFIX))) {
452
static const char *parse_options(const char *str, char **ret, unsigned int logopt)
454
const char *cp = str;
463
len = chunklen(cp, 0);
464
*ret = dequote(cp, len, logopt);
469
static char *concat_options(char *left, char *right)
471
char buf[MAX_ERR_BUF];
474
if (left == NULL || *left == '\0') {
480
if (right == NULL || *right == '\0') {
486
ret = malloc(strlen(left) + strlen(right) + 2);
489
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
490
logerr(MODPREFIX "malloc: %s", estr);
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)
509
char *fstype = "nfs"; /* Default filesystem type */
516
if (*options == '\0')
523
int len = strlen(options) + 1;
525
noptions = np = alloca(len);
528
/* Extract fstype= pseudo option */
529
for (comma = options; *comma != '\0';) {
532
while (*comma == ',')
537
while (*comma != '\0' && *comma != ',')
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) {
547
} else if (strncmp("strict", cp, 6) == 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;
557
} else if (strncmp("bg", cp, 2) == 0 ||
558
strncmp("nofg", cp, 4) == 0) {
561
memcpy(np, cp, comma - cp + 1);
562
np += comma - cp + 1;
566
if (np > noptions + len) {
567
warn(ap->logopt, MODPREFIX "options string truncated");
576
if (!strcmp(fstype, "autofs") && ctxt->macros) {
577
char *noptions = NULL;
580
noptions = alloca(strlen(ctxt->macros) + 1);
583
int len = strlen(options) + strlen(ctxt->macros) + 2;
584
noptions = alloca(len);
587
strcpy(noptions, options);
588
strcat(noptions, ",");
593
strcat(noptions, ctxt->macros);
597
MODPREFIX "alloca failed for options");
601
mountpoint = alloca(namelen + 1);
602
sprintf(mountpoint, "%.*s", namelen, name);
604
type = ap->entry->maps->type;
605
if (type && !strcmp(type, "hosts")) {
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;
612
if (suid || dev || nointr) {
613
char *tmp = alloca(len + suid + dev + nointr + 1);
615
error(ap->logopt, MODPREFIX
616
"alloca failed for options");
622
strcpy(tmp, options);
624
strcat(tmp, ",nosuid");
626
strcat(tmp, ",nodev");
628
strcat(tmp, ",intr");
632
char *tmp = alloca(18);
635
MODPREFIX "alloca failed for options");
640
strcpy(tmp, "nosuid,nodev,intr");
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);
651
debug(ap->logopt, MODPREFIX
652
"mounting root %s, mountpoint %s, "
653
"what %s, fstype %s, options %s",
654
root, mountpoint, what, fstype, options);
656
rv = mount_nfs->mount_mount(ap, root, mountpoint, strlen(mountpoint),
657
what, fstype, options, mount_nfs->context);
659
what = alloca(loclen + 1);
662
memcpy(what, loc + 1, loclen);
665
memcpy(what, loc, loclen);
669
debug(ap->logopt, MODPREFIX
670
"mounting root %s, mountpoint %s, "
671
"what %s, fstype %s, options %s",
672
root, mountpoint, what, fstype, options);
674
/* Generic mount routine */
675
rv = do_mount(ap, root, mountpoint, strlen(mountpoint), what, fstype,
678
pthread_setcancelstate(cur_state, NULL);
687
* Scan map entry looking for evidence it has multiple key/mapent
690
static int check_is_multi(const char *mapent)
692
const char *p = mapent;
694
int not_first_chunk = 0;
697
logerr(MODPREFIX "unexpected NULL map entry pointer");
704
/* If first character is "/" it's a multi-mount */
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
719
if (not_first_chunk) {
722
if (*p == '/' || *p == '-') {
734
* Expect either a path or location
735
* after which it's a multi mount.
737
p += chunklen(p, check_colon(p));
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,
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;
757
source = ap->entry->current;
758
ap->entry->current = NULL;
759
master_source_current_signal(ap->entry);
763
if (!*path || !*loc) {
765
MODPREFIX "syntax error in offset %s -> %s", path, loc);
769
p_len = strlen(path);
770
/* Trailing '/' causes us pain */
772
while (p_len > 1 && path[p_len - 1] == '/')
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");
780
strcpy(m_key, m_root);
781
strncat(m_key, path, p_len);
782
m_key[m_key_len] = '\0';
786
m_options_len = strlen(myoptions) + 2;
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");
795
strcpy(m_mapent, "-");
796
strcat(m_mapent, myoptions);
797
strcat(m_mapent, " ");
798
strcat(m_mapent, loc);
800
strcpy(m_mapent, loc);
802
ret = cache_add_offset(mc, name, m_key, m_mapent, age);
804
debug(ap->logopt, MODPREFIX
805
"added multi-mount offset %s -> %s", path, m_mapent);
807
warn(ap->logopt, MODPREFIX
808
"syntax error or duplicate offset %s -> %s", path, loc);
813
static int validate_location(char *loc)
817
/* We don't know much about these */
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 "]".
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 == ']'))
838
if (*ptr && !strncmp(ptr, ":/", 2))
842
/* Must always be something following */
849
static int parse_mapent(const char *ent, char *g_options, char **options, char **location, int logopt)
851
char buf[MAX_ERR_BUF];
853
char *myoptions, *loc;
858
myoptions = strdup(g_options);
860
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
861
error(logopt, MODPREFIX "strdup: %s", estr);
865
/* Local options are appended to per-map options */
868
char *tmp, *newopt = NULL;
870
p = parse_options(p, &newopt, logopt);
871
if (newopt && strstr(newopt, myoptions)) {
875
tmp = concat_options(myoptions, newopt);
878
estr = strerror_r(errno, buf, MAX_ERR_BUF);
879
error(logopt, MODPREFIX
880
"concat_options: %s", estr);
893
debug(logopt, MODPREFIX "gathered options: %s", myoptions);
895
l = chunklen(p, check_colon(p));
896
loc = dequote(p, l, logopt);
898
warn(logopt, MODPREFIX "possible missing location");
903
/* Location can't begin with a '/' */
905
warn(logopt, MODPREFIX "error location begins with \"/\"");
911
if (!validate_location(loc)) {
912
warn(logopt, MODPREFIX "invalid location %s", loc);
918
debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc);
923
while (*p && ((*p == '"' && *(p + 1) != '/') || (*p != '"' && *p != '/'))) {
924
char *tmp, *ent_chunk;
926
l = chunklen(p, check_colon(p));
927
ent_chunk = dequote(p, l, logopt);
929
warn(logopt, MODPREFIX "null location or out of memory");
935
/* Location can't begin with a '/' */
938
MODPREFIX "error location begins with \"/\"");
945
if (!validate_location(ent_chunk)) {
947
MODPREFIX "invalid location %s", ent_chunk);
954
debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent_chunk);
956
tmp = realloc(loc, strlen(loc) + l + 2);
958
error(logopt, MODPREFIX "out of memory");
967
strcat(loc, ent_chunk);
975
*options = myoptions;
981
static int move_mount(struct autofs_point *ap,
982
const char *mm_tmp_root, const char *mm_root,
985
char buf[MAX_ERR_BUF];
988
if (move == MOUNT_MOVE_NONE)
991
err = mkdir_path(mm_root, 0555);
992
if (err < 0 && errno != EEXIST) {
994
"failed to create move target mount point %s", mm_root);
998
if (move == MOUNT_MOVE_AUTOFS)
999
err = mount(mm_tmp_root, mm_root, NULL, MS_MOVE, NULL);
1001
err = spawn_mount(ap->logopt,
1002
"--move", mm_tmp_root, mm_root, NULL);
1004
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1006
"failed to move mount from %s to %s: %s",
1007
mm_tmp_root, mm_root, estr);
1012
"moved mount tree from %s to %s", mm_tmp_root, mm_root);
1017
static void cleanup_multi_root(struct autofs_point *ap, const char *root,
1018
const char *path, unsigned int move)
1020
if (move == MOUNT_MOVE_NONE)
1023
if (move == MOUNT_MOVE_OTHER)
1024
spawn_umount(ap->logopt, root, NULL);
1026
struct ioctl_ops *ops = get_ioctl_ops();
1027
struct autofs_point *submount;
1029
mounts_mutex_lock(ap);
1030
submount = __master_find_submount(ap, path);
1032
mounts_mutex_unlock(ap);
1036
alarm_delete(submount);
1037
st_remove_tasks(submount);
1038
st_wait_state(submount, ST_READY);
1040
submount->parent->submnt_count--;
1041
list_del_init(&submount->mounts);
1043
ops->catatonic(submount->logopt, submount->ioctlfd);
1045
mounts_mutex_unlock(ap);
1047
if (submount->thid) {
1048
pthread_cancel(submount->thid);
1049
close_mount_fds(submount);
1051
destroy_logpri_fifo(submount);
1052
master_free_mapent_sources(submount->entry, 1);
1053
master_free_mapent(ap->entry);
1059
static void cleanup_multi_triggers(struct autofs_point *ap,
1060
struct mapent *me, const char *root, int start,
1063
char path[PATH_MAX + 1];
1064
char offset[PATH_MAX + 1];
1065
char *poffset = offset;
1067
struct list_head *mm_root, *pos;
1068
const char o_root[] = "/";
1069
const char *mm_base;
1071
mm_root = &me->multi->multi_list;
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)
1088
strcat(path, poffset);
1090
error(ap->logopt, "error recovering from mount fail");
1091
error(ap->logopt, "cannot umount offset %s", path);
1098
static int check_fstype_autofs_option(const char *options)
1104
* Look for fstype= in options and return true if
1105
* the last occurrence is fstype=autofs.
1108
tokbuf = alloca(strlen(options) + 2);
1109
strcpy(tokbuf, options);
1110
tok = strtok_r(tokbuf, ",", &tokbuf);
1113
if (strstr(tok, "fstype=")) {
1114
if (strstr(tok, "autofs"))
1119
} while ((tok = strtok_r(NULL, ",", &tokbuf)));
1125
static int mount_subtree(struct autofs_point *ap, struct mapent *me,
1126
const char *name, char *loc, char *options, void *ctxt)
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;
1141
move = MOUNT_MOVE_NONE;
1143
if (*mm_key == '/') {
1145
start = strlen(mm_key);
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);
1153
mm_root_len = strlen(mm_root);
1155
mnt_tmp_root = NULL;
1156
if (ap->flags & MOUNT_FLAG_REMOUNT) {
1158
mnt_root_len = mm_root_len;
1160
mnt_root = mkdtemp(t_dir);
1163
mnt_root_len = strlen(mnt_root);
1164
mnt_tmp_root = (char *) mnt_root;
1167
if (me == me->multi) {
1169
/* destination = mm_root */
1173
/* Mount root offset if it exists */
1174
ro = cache_lookup_offset(mm_base, mm_base, strlen(mm_root), &me->multi_list);
1176
char *myoptions, *ro_loc, *tmp;
1177
int namelen = name ? strlen(name) : 0;
1181
rv = parse_mapent(ro->mapent,
1182
options, &myoptions, &ro_loc, ap->logopt);
1185
MODPREFIX "failed to parse root offset");
1186
cache_delete_offset_list(me->mc, name);
1189
ro_len = strlen(ro_loc);
1191
if (!(ap->flags & MOUNT_FLAG_REMOUNT)) {
1192
move = MOUNT_MOVE_OTHER;
1193
if (check_fstype_autofs_option(myoptions))
1194
move = MOUNT_MOVE_AUTOFS;
1197
tmp = alloca(mnt_root_len + 1);
1198
strcpy(tmp, mnt_root);
1199
tmp[mnt_root_len] = '/';
1200
tmp[mnt_root_len + 1] = '\0';
1203
rv = sun_mount(ap, root, name, namelen, ro_loc, ro_len, myoptions, ctxt);
1209
if (ro && rv == 0) {
1210
ret = mount_multi_triggers(ap, me, mnt_root, start, mm_base);
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);
1218
} else if (rv <= 0) {
1219
move = MOUNT_MOVE_NONE;
1220
ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
1222
error(ap->logopt, MODPREFIX
1223
"failed to mount offset triggers");
1224
cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
1229
int loclen = strlen(loc);
1230
int namelen = strlen(name);
1232
if (!(ap->flags & MOUNT_FLAG_REMOUNT)) {
1233
move = MOUNT_MOVE_OTHER;
1234
if (check_fstype_autofs_option(options))
1235
move = MOUNT_MOVE_AUTOFS;
1238
/* name = mm_root + mm_base */
1239
/* destination = mm_root + mm_base = name */
1241
mm_base = &me->key[start];
1243
rv = sun_mount(ap, mnt_root, name, namelen, loc, loclen, options, ctxt);
1245
ret = mount_multi_triggers(ap, me->multi, mnt_root, start, mm_base);
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);
1253
} else if (rv < 0) {
1254
char *mm_root_base = alloca(strlen(mm_root) + strlen(mm_base) + 1);
1256
move = MOUNT_MOVE_NONE;
1258
strcpy(mm_root_base, mm_root);
1259
strcat(mm_root_base, mm_base);
1261
ret = mount_multi_triggers(ap, me->multi, mm_root_base, start, mm_base);
1263
error(ap->logopt, MODPREFIX
1264
"failed to mount offset triggers");
1265
cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
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);
1278
rmdir(mnt_tmp_root);
1280
/* Mount for base of tree failed */
1285
* Convert fail on nonstrict, non-empty multi-mount
1288
if (rv < 0 && ret > 0)
1295
rmdir(mnt_tmp_root);
1302
* [-options] location [location] ...
1303
* [-options] [mountpoint [-options] location [location] ... ]...
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.
1312
int parse_mount(struct autofs_point *ap, const char *name,
1313
int name_len, const char *mapent, void *context)
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;
1322
int mapent_len, rv = 0;
1324
int slashify = ctxt->slashify_colons;
1325
unsigned int append_options;
1327
source = ap->entry->current;
1328
ap->entry->current = NULL;
1329
master_source_current_signal(ap->entry);
1334
warn(ap->logopt, MODPREFIX "error: empty map entry");
1338
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
1341
ctxt->subst = addstdenv(ctxt->subst);
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);
1348
pthread_setcancelstate(cur_state, NULL);
1352
pmapent = alloca(mapent_len + 1);
1354
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1355
logerr(MODPREFIX "alloca: %s", estr);
1356
ctxt->subst = removestdenv(ctxt->subst);
1358
pthread_setcancelstate(cur_state, NULL);
1361
pmapent[mapent_len] = '\0';
1363
expandsunent(mapent, pmapent, name, ctxt->subst, slashify);
1364
ctxt->subst = removestdenv(ctxt->subst);
1367
pthread_setcancelstate(cur_state, NULL);
1369
debug(ap->logopt, MODPREFIX "expanded entry: %s", pmapent);
1371
append_options = defaults_get_append_options();
1372
options = strdup(ctxt->optstr ? ctxt->optstr : "");
1374
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1375
logerr(MODPREFIX "strdup: %s", estr);
1379
p = skipspace(pmapent);
1381
/* Deal with 0 or more options */
1383
char *tmp, *mnt_options = NULL;
1386
char *noptions = NULL;
1388
p = parse_options(p, &noptions, ap->logopt);
1389
if (mnt_options && noptions && strstr(noptions, mnt_options)) {
1391
mnt_options = noptions;
1393
tmp = concat_options(mnt_options, noptions);
1395
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1397
MODPREFIX "concat_options: %s", estr);
1409
} while (*p == '-');
1411
if (options && !append_options) {
1416
if (append_options) {
1417
if (options && mnt_options && strstr(mnt_options, options)) {
1419
options = mnt_options;
1421
tmp = concat_options(options, mnt_options);
1423
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1424
error(ap->logopt, MODPREFIX "concat_options: %s", estr);
1434
options = mnt_options;
1437
debug(ap->logopt, MODPREFIX "gathered options: %s", options);
1439
if (check_is_multi(p)) {
1440
char *m_root = NULL;
1442
time_t age = time(NULL);
1445
/* If name starts with "/" it's a direct mount */
1447
m_root_len = name_len;
1448
m_root = alloca(m_root_len + 1);
1450
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1452
logerr(MODPREFIX "alloca: %s", estr);
1455
strcpy(m_root, name);
1457
m_root_len = strlen(ap->path) + name_len + 1;
1458
m_root = alloca(m_root_len + 1);
1460
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
1462
logerr(MODPREFIX "alloca: %s", estr);
1465
strcpy(m_root, ap->path);
1466
strcat(m_root, "/");
1467
strcat(m_root, name);
1470
cache_writelock(mc);
1471
me = cache_lookup_distinct(mc, name);
1475
* Not in the cache, perhaps it's a program map
1476
* or one that doesn't support enumeration
1478
ret = cache_add(mc, source, name, mapent, time(NULL));
1479
if (ret == CHE_FAIL) {
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.
1492
cache_multi_writelock(me);
1493
cache_delete_offset_list(mc, name);
1494
cache_multi_unlock(me);
1499
me = cache_lookup_distinct(mc, name);
1501
/* So we know we're the multi-mount root */
1510
MODPREFIX "can't find multi root %s", name);
1514
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
1515
cache_multi_writelock(me);
1516
/* It's a multi-mount; deal with it */
1518
char *path, *myoptions, *loc;
1521
if ((*p == '"' && *(p + 1) != '/') || (*p != '"' && *p != '/')) {
1523
path = dequote("/", 1, ap->logopt);
1525
MODPREFIX "dequote(\"/\") -> %s", path);
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);
1534
warn(ap->logopt, MODPREFIX "null path or out of memory");
1535
cache_delete_offset_list(mc, name);
1536
cache_multi_unlock(me);
1539
pthread_setcancelstate(cur_state, NULL);
1546
l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
1548
cache_delete_offset_list(mc, name);
1549
cache_multi_unlock(me);
1553
pthread_setcancelstate(cur_state, NULL);
1560
master_source_current_wait(ap->entry);
1561
ap->entry->current = source;
1563
status = add_offset_entry(ap, name,
1565
path, myoptions, loc, age);
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);
1576
pthread_setcancelstate(cur_state, NULL);
1583
} while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
1586
* We've got the ordered list of multi-mount entries so go
1587
* through and set the parent entry of each
1589
cache_set_parents(me);
1591
rv = mount_subtree(ap, me, name, NULL, options, ctxt);
1593
cache_multi_unlock(me);
1597
pthread_setcancelstate(cur_state, NULL);
1601
/* Normal (and non-root multi-mount) entries */
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.
1613
(me = cache_lookup_distinct(mc, name)) && me->multi) {
1618
warn(ap->logopt, MODPREFIX "out of memory");
1621
cache_multi_writelock(me);
1622
rv = mount_subtree(ap, me, name, loc, options, ctxt);
1623
cache_multi_unlock(me);
1631
l = chunklen(p, check_colon(p));
1632
loc = dequote(p, l, ap->logopt);
1635
warn(ap->logopt, MODPREFIX "null location or out of memory");
1639
/* Location can't begin with a '/' */
1644
MODPREFIX "error location begins with \"/\"");
1648
if (!validate_location(loc)) {
1649
warn(ap->logopt, MODPREFIX "invalid location %s", loc);
1656
MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc);
1664
l = chunklen(p, check_colon(p));
1665
ent = dequote(p, l, ap->logopt);
1670
MODPREFIX "null location or out of memory");
1674
if (!validate_location(ent)) {
1676
MODPREFIX "invalid location %s", loc);
1684
MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent);
1686
tmp = realloc(loc, strlen(loc) + l + 2);
1691
error(ap->logopt, MODPREFIX "out of memory");
1705
loclen = strlen(loc);
1710
MODPREFIX "entry %s is empty!", name);
1715
MODPREFIX "core of entry: options=%s, loc=%.*s",
1716
options, loclen, loc);
1718
if (!strcmp(ap->path, "/-"))
1719
rv = sun_mount(ap, name, name, name_len,
1720
loc, loclen, options, ctxt);
1722
rv = sun_mount(ap, ap->path, name, name_len,
1723
loc, loclen, options, ctxt);
1727
pthread_setcancelstate(cur_state, NULL);
1732
int parse_done(void *context)
1735
struct parse_context *ctxt = (struct parse_context *) context;
1737
if (--init_ctr == 0) {
1738
rv = close_mount(mount_nfs);