1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * autod_parse.c
23 *
24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 */
28
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <syslog.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/param.h>
36 #include <errno.h>
37 #include <pwd.h>
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #include <sys/tiuser.h>
41 #include <locale.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <thread.h>
45 #include <rpc/rpc.h>
46 #include <rpcsvc/mount.h>
47 #include <fcntl.h>
48 #include <limits.h>
49 #include "automount.h"
50
51 /*
52 * This structure is used to determine the hierarchical
53 * relationship between directories
54 */
55 typedef struct _hiernode {
56 char dirname[MAXFILENAMELEN+1];
57 struct _hiernode *subdir;
58 struct _hiernode *leveldir;
59 struct mapent *mapent;
60 } hiernode;
61
62 void free_mapent(struct mapent *);
63
64 static int mapline_to_mapent(struct mapent **, struct mapline *, char *, char *,
65 char *, char *, uint_t);
66 static int hierarchical_sort(struct mapent *, hiernode **, char *, char *);
67 static int push_options(hiernode *, char *, char *, int);
68 static int set_mapent_opts(struct mapent *, char *, char *, char *);
69 static void get_opts(char *, char *, char *, bool_t *);
70 static int fstype_opts(struct mapent *, char *, char *, char *);
71 static int modify_mapents(struct mapent **, char *, char *, char *, hiernode *,
72 char *, uint_t, bool_t);
73 static int set_and_fake_mapent_mntlevel(hiernode *, char *, char *, char *,
74 struct mapent **, uint_t, char *, bool_t);
75 static int mark_level1_root(hiernode *, char *);
76 static int mark_and_fake_level1_noroot(hiernode *, char *, char *, char *,
77 struct mapent **, uint_t i, char *);
78 static int convert_mapent_to_automount(struct mapent *, char *, char *);
79 static int automount_opts(char **, char *);
80 static int parse_fsinfo(char *, struct mapent *);
81 static int parse_nfs(char *, struct mapent *, char *, char *, char **, char **,
82 int);
83 static int parse_special(struct mapent *, char *, char *, char **, char **,
84 int);
85 static int get_dir_from_path(char *, char **, int);
86 static int alloc_hiernode(hiernode **, char *);
87 static void free_hiernode(hiernode *);
88 static void trace_mapents(char *, struct mapent *);
89 static void trace_hierarchy(hiernode *, int);
90 static struct mapent *do_mapent_hosts(char *, char *, uint_t);
91 static void freeex_ent(struct exportnode *);
92 static void freeex(struct exportnode *);
93 static void dump_mapent_err(struct mapent *, char *, char *);
94
95 #define PARSE_OK 0
96 #define PARSE_ERROR -1
97 #define MAX_FSLEN 32
98
99 /*
100 * mapentry error type defininitions
101 */
102 #define MAPENT_NOERR 0
103 #define MAPENT_UATFS 1
104
105 /*
106 * parse_entry(char *key, char *mapname, char *mapopts, struct mapline *ml,
107 * char *subdir, uint_t isdirect, bool_t mount_access)
108 * Parses the data in ml to build a mapentry list containing the information
109 * for the mounts/lookups to be performed. Builds an intermediate mapentry list
110 * by processing ml, hierarchically sorts (builds a tree of) the list according
111 * to mountpoint. Then pushes options down the hierarchy, and fills in the mount
112 * file system. Finally, modifies the intermediate list depending on how far
113 * in the hierarchy the current request is (uses subdir). Deals with special
114 * case of /net map parsing.
115 * Returns a pointer to the head of the mapentry list.
116 */
117 struct mapent *
parse_entry(char * key,char * mapname,char * mapopts,struct mapline * ml,char * subdir,uint_t isdirect,bool_t mount_access)118 parse_entry(char *key, char *mapname, char *mapopts, struct mapline *ml,
119 char *subdir, uint_t isdirect, bool_t mount_access)
120 {
121 char *p;
122 char defaultopts[AUTOFS_MAXOPTSLEN];
123
124 struct mapent *mapents = NULL;
125 hiernode *rootnode = NULL;
126 char *lp = ml->linebuf;
127
128 if (trace > 1)
129 trace_prt(1, " mapline: %s\n", ml->linebuf);
130
131 /*
132 * Assure the key is only one token long.
133 * This prevents options from sneaking in through the
134 * command line or corruption of /etc/mnttab.
135 */
136 for (p = key; *p != '\0'; p++) {
137 if (isspace(*p)) {
138 syslog(LOG_ERR,
139 "parse_entry: bad key in map %s: %s", mapname, key);
140 return ((struct mapent *)NULL);
141 }
142 }
143
144 /*
145 * select the appropriate parser, and build the mapentry list
146 */
147 if (strcmp(lp, "-hosts") == 0) {
148 /*
149 * the /net parser - uses do_mapent_hosts to build mapents.
150 * The mapopts are considered default for every entry, so we
151 * don't push options down hierarchies.
152 */
153 mapents = do_mapent_hosts(mapopts, key, isdirect);
154 if (mapents == NULL) /* nothing to free */
155 return (mapents);
156
157 if (trace > 3)
158 trace_mapents("do_mapent_hosts:(return)", mapents);
159
160 if (hierarchical_sort(mapents, &rootnode, key, mapname)
161 != PARSE_OK)
162 goto parse_error;
163 } else {
164 /*
165 * all other parsing
166 */
167 if (mapline_to_mapent(&mapents, ml, key, mapname,
168 mapopts, defaultopts, isdirect) != PARSE_OK)
169 goto parse_error;
170
171 if (mapents == NULL)
172 return (mapents);
173
174 if (hierarchical_sort(mapents, &rootnode, key, mapname)
175 != PARSE_OK)
176 goto parse_error;
177
178 if (push_options(rootnode, defaultopts, mapopts,
179 MAPENT_NOERR) != PARSE_OK)
180 goto parse_error;
181
182 if (trace > 3) {
183 trace_prt(1, "\n\tpush_options (return)\n");
184 trace_prt(0, "\tdefault options=%s\n", defaultopts);
185 trace_hierarchy(rootnode, 0);
186 };
187
188 if (parse_fsinfo(mapname, mapents) != PARSE_OK)
189 goto parse_error;
190 }
191
192 /*
193 * Modify the mapentry list. We *must* do this only after
194 * the mapentry list is completely built (since we need to
195 * have parse_fsinfo called first).
196 */
197 if (modify_mapents(&mapents, mapname, mapopts, subdir,
198 rootnode, key, isdirect, mount_access) != PARSE_OK)
199 goto parse_error;
200
201 /*
202 * XXX: its dangerous to use rootnode after modify mapents as
203 * it may be pointing to mapents that have been freed
204 */
205 if (rootnode != NULL)
206 free_hiernode(rootnode);
207
208 return (mapents);
209
210 parse_error:
211 syslog(LOG_ERR, "parse_entry: mapentry parse error: map=%s key=%s",
212 mapname, key);
213 free_mapent(mapents);
214 if (rootnode != NULL)
215 free_hiernode(rootnode);
216 return ((struct mapent *)NULL);
217 }
218
219
220 /*
221 * mapline_to_mapent(struct mapent **mapents, struct mapline *ml,
222 * char *key, char *mapname, char *mapopts, char *defaultopts,
223 * uint_t isdirect)
224 * Parses the mapline information in ml word by word to build an intermediate
225 * mapentry list, which is passed back to the caller. The mapentries may have
226 * holes (example no options), as they are completed only later. The logic is
227 * awkward, but needed to provide the supported flexibility in the map entries.
228 * (especially the first line). Note that the key is the full pathname of the
229 * directory to be mounted in a direct map, and ml is the mapentry beyond key.
230 * Returns PARSE_OK or an appropriate error value.
231 */
232 static int
mapline_to_mapent(struct mapent ** mapents,struct mapline * ml,char * key,char * mapname,char * mapopts,char * defaultopts,uint_t isdirect)233 mapline_to_mapent(struct mapent **mapents, struct mapline *ml, char *key,
234 char *mapname, char *mapopts, char *defaultopts,
235 uint_t isdirect)
236 {
237 struct mapent *me = NULL;
238 struct mapent *mp;
239 char w[MAXPATHLEN];
240 char wq[MAXPATHLEN];
241 char w1[MAXPATHLEN];
242 int implied;
243
244 char *lp = ml->linebuf;
245 char *lq = ml->lineqbuf;
246
247 /* do any macro expansions that are required to complete ml */
248 if (macro_expand(key, lp, lq, LINESZ)) {
249 syslog(LOG_ERR,
250 "mapline_to_mapent: map %s: line too long (max %d chars)",
251 mapname, LINESZ - 1);
252 return (PARSE_ERROR);
253 }
254 if (trace > 3 && (strcmp(ml->linebuf, lp) != 0))
255 trace_prt(1,
256 " mapline_to_mapent: (expanded) mapline (%s,%s)\n",
257 ml->linebuf, ml->lineqbuf);
258
259 /* init the head of mapentry list to null */
260 *mapents = NULL;
261
262 /*
263 * Get the first word - its either a '-' if default options provided,
264 * a '/', if the mountroot is implicitly provided, or a mount filesystem
265 * if the mountroot is implicit. Note that if the first word begins with
266 * a '-' then the second must be read and it must be a mountpoint or a
267 * mount filesystem. Use mapopts if no default opts are provided.
268 */
269 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
270 return (PARSE_ERROR);
271 if (*w == '-') {
272 strcpy(defaultopts, w);
273 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
274 return (PARSE_ERROR);
275 } else
276 strcpy(defaultopts, mapopts);
277
278 /*
279 * implied is true if there is no '/'
280 * We need the same code path if we have an smbfs mount.
281 */
282 implied = (*w != '/') || (strstr(defaultopts, "fstype=smbfs") != NULL);
283 while (*w == '/' || implied) {
284 mp = me;
285 if ((me = (struct mapent *)malloc(sizeof (*me))) == NULL)
286 goto alloc_failed;
287 (void) memset((char *)me, 0, sizeof (*me));
288 if (*mapents == NULL) /* special case of head */
289 *mapents = me;
290 else
291 mp->map_next = me;
292
293 /*
294 * direct maps get an empty string as root - to be filled
295 * by the entire path later. Indirect maps get /key as the
296 * map root. Note that xfn maps don't care about the root
297 * - they override it in getmapent_fn().
298 */
299 if (isdirect) {
300 *w1 = '\0';
301 } else {
302 strcpy(w1, "/");
303 strcat(w1, key);
304 }
305 if ((me->map_root = strdup(w1)) == NULL)
306 goto alloc_failed;
307
308 /* mntpnt is empty for the mount root */
309 if (strcmp(w, "/") == 0 || implied)
310 me->map_mntpnt = strdup("");
311 else
312 me->map_mntpnt = strdup(w);
313 if (me->map_mntpnt == NULL)
314 goto alloc_failed;
315
316 /*
317 * If implied, the word must be a mount filesystem,
318 * and its already read in; also turn off implied - its
319 * not applicable except for the mount root. Else,
320 * read another (or two) words depending on if there's
321 * an option.
322 */
323 if (implied) /* must be a mount filesystem */
324 implied = 0;
325 else {
326 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
327 return (PARSE_ERROR);
328 if (w[0] == '-') {
329 /* mount options */
330 if ((me->map_mntopts = strdup(w)) == NULL)
331 goto alloc_failed;
332 if (getword(w, wq, &lp, &lq, ' ',
333 sizeof (w)) == -1)
334 return (PARSE_ERROR);
335 }
336 }
337
338 /*
339 * must be a mount filesystem or a set of filesystems at
340 * this point.
341 */
342 if (w[0] == '\0' || w[0] == '-') {
343 syslog(LOG_ERR,
344 "mapline_to_mapent: bad location=%s map=%s key=%s",
345 w, mapname, key);
346 return (PARSE_ERROR);
347 }
348
349 /*
350 * map_fsw and map_fswq hold information which will be
351 * used to determine filesystem information at a later
352 * point. This is required since we can only find out
353 * about the mount file system after the directories
354 * are hierarchically sorted and options have been pushed
355 * down the hierarchies.
356 */
357 if (((me->map_fsw = strdup(w)) == NULL) ||
358 ((me->map_fswq = strdup(wq)) == NULL))
359 goto alloc_failed;
360
361 /*
362 * the next word, if any, is either another mount point or a
363 * mount filesystem if more than one server is listed.
364 */
365 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
366 return (PARSE_ERROR);
367 while (*w && *w != '/') { /* more than 1 server listed */
368 int len;
369 char *fsw, *fswq;
370 len = strlen(me->map_fsw) + strlen(w) + 4;
371 if ((fsw = (char *)malloc(len)) == NULL)
372 goto alloc_failed;
373 sprintf(fsw, "%s %s", me->map_fsw, w);
374 free(me->map_fsw);
375 me->map_fsw = fsw;
376 len = strlen(me->map_fswq) + strlen(wq) + 4;
377 if ((fswq = (char *)malloc(len)) == NULL)
378 goto alloc_failed;
379 sprintf(fswq, "%s %s", me->map_fswq, wq);
380 free(me->map_fswq);
381 me->map_fswq = fswq;
382 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
383 return (PARSE_ERROR);
384 }
385
386 /* initialize flags */
387 me->map_mntlevel = -1;
388 me->map_modified = FALSE;
389 me->map_faked = FALSE;
390 me->map_err = MAPENT_NOERR;
391
392 me->map_next = NULL;
393 }
394
395 if (*mapents == NULL || w[0] != '\0') { /* sanity check */
396 if (verbose) {
397 if (*mapents == NULL)
398 syslog(LOG_ERR,
399 "mapline_to_mapent: parsed with null mapents");
400 else
401 syslog(LOG_ERR,
402 "mapline_to_mapent: parsed nononempty w=%s", w);
403 }
404 return (PARSE_ERROR);
405 }
406
407 if (trace > 3)
408 trace_mapents("mapline_to_mapent:", *mapents);
409
410 return (PARSE_OK);
411
412 alloc_failed:
413 syslog(LOG_ERR, "mapline_to_mapent: Memory allocation failed");
414 return (ENOMEM);
415 }
416
417 /*
418 * hierarchical_sort(struct mapent *mapents, hiernode **rootnode, char *key
419 * char *mapname)
420 * sorts the mntpnts in each mapent to build a hierarchy of nodes, with
421 * with the rootnode being the mount root. The hierarchy is setup as
422 * levels, and subdirs below each level. Provides a link from node to
423 * the relevant mapentry.
424 * Returns PARSE_OK or appropriate error value
425 */
426 static int
hierarchical_sort(struct mapent * mapents,hiernode ** rootnode,char * key,char * mapname)427 hierarchical_sort(struct mapent *mapents, hiernode **rootnode, char *key,
428 char *mapname)
429 {
430 hiernode *prevnode, *currnode, *newnode;
431 char *path;
432 char dirname[MAXFILENAMELEN];
433
434 int rc = PARSE_OK;
435 struct mapent *me = mapents;
436
437 /* allocate the rootnode with a default path of "" */
438 *rootnode = NULL;
439 if ((rc = alloc_hiernode(rootnode, "")) != PARSE_OK)
440 return (rc);
441
442 /*
443 * walk through mapents - for each mapent, locate the position
444 * within the hierarchy by walking across leveldirs, and
445 * subdirs of matched leveldirs. Starts one level below
446 * the root (assumes an implicit match with rootnode).
447 * XXX - this could probably be done more cleanly using recursion.
448 */
449 while (me != NULL) {
450
451 path = me->map_mntpnt;
452
453 if ((rc = get_dir_from_path(dirname, &path,
454 sizeof (dirname))) != PARSE_OK)
455 return (rc);
456
457 prevnode = *rootnode;
458 currnode = (*rootnode)->subdir;
459
460 while (dirname[0] != '\0') {
461 if (currnode != NULL) {
462 if (strcmp(currnode->dirname, dirname) == 0) {
463 /*
464 * match found - mntpnt is a child of
465 * this node
466 */
467 prevnode = currnode;
468 currnode = currnode->subdir;
469 } else {
470 prevnode = currnode;
471 currnode = currnode->leveldir;
472
473 if (currnode == NULL) {
474 /*
475 * No more leveldirs to match.
476 * Add a new one
477 */
478 if ((rc = alloc_hiernode
479 (&newnode, dirname))
480 != PARSE_OK)
481 return (rc);
482 prevnode->leveldir = newnode;
483 prevnode = newnode;
484 currnode = newnode->subdir;
485 } else {
486 /* try this leveldir */
487 continue;
488 }
489 }
490 } else {
491 /* no more subdirs to match. Add a new one */
492 if ((rc = alloc_hiernode(&newnode,
493 dirname)) != PARSE_OK)
494 return (rc);
495 prevnode->subdir = newnode;
496 prevnode = newnode;
497 currnode = newnode->subdir;
498 }
499 if ((rc = get_dir_from_path(dirname, &path,
500 sizeof (dirname))) != PARSE_OK)
501 return (rc);
502 }
503
504 if (prevnode->mapent != NULL) {
505 /* duplicate mntpoint found */
506 syslog(LOG_ERR,
507 "hierarchical_sort: duplicate mntpnt map=%s key=%s",
508 mapname, key);
509 return (PARSE_ERROR);
510 }
511
512 /* provide a pointer from node to mapent */
513 prevnode->mapent = me;
514 me = me->map_next;
515 }
516
517 if (trace > 3) {
518 trace_prt(1, "\n\thierarchical_sort:\n");
519 trace_hierarchy(*rootnode, 0); /* 0 is rootnode's level */
520 }
521
522 return (rc);
523 }
524
525 /*
526 * push_options(hiernode *node, char *opts, char *mapopts, int err)
527 * Pushes the options down a hierarchical structure. Works recursively from the
528 * root, which is passed in on the first call. Uses a replacement policy.
529 * If a node points to a mapentry, and it has an option, then thats the option
530 * for that mapentry. Else, the node's mapent inherits the option from the
531 * default (which may be the global option for the entry or mapopts).
532 * err is useful in flagging entries with errors in pushing options.
533 * returns PARSE_OK or appropriate error value.
534 */
535 static int
push_options(hiernode * node,char * defaultopts,char * mapopts,int err)536 push_options(hiernode *node, char *defaultopts, char *mapopts, int err)
537 {
538 int rc = PARSE_OK;
539 struct mapent *me = NULL;
540
541 /* ensure that all the dirs at a level are passed the default options */
542 while (node != NULL) {
543 me = node->mapent;
544 if (me != NULL) { /* not all nodes point to a mapentry */
545 me->map_err = err;
546 if ((rc = set_mapent_opts(me, me->map_mntopts,
547 defaultopts, mapopts)) != PARSE_OK)
548 return (rc);
549 }
550
551 /* push the options to subdirs */
552 if (node->subdir != NULL) {
553 if (node->mapent && strcmp(node->mapent->map_fstype,
554 MNTTYPE_AUTOFS) == 0)
555 err = MAPENT_UATFS;
556 if ((rc = push_options(node->subdir, defaultopts,
557 mapopts, err)) != PARSE_OK)
558 return (rc);
559 }
560 node = node->leveldir;
561 }
562 return (rc);
563 }
564
565 #define FSTYPE "fstype"
566 #define FSTYPE_EQ "fstype="
567 #define NO_OPTS ""
568
569 /*
570 * set_mapent_opts(struct mapent *me, char *opts, char *defaultopts,
571 * char *mapopts)
572 * sets the mapentry's options, fstype and mounter fields by separating
573 * out the fstype part from the opts. Use default options if opts is NULL.
574 * Note taht defaultopts may be the same as mapopts.
575 * Returns PARSE_OK or appropriate error value.
576 */
577 static int
set_mapent_opts(struct mapent * me,char * opts,char * defaultopts,char * mapopts)578 set_mapent_opts(struct mapent *me, char *opts, char *defaultopts,
579 char *mapopts)
580 {
581 char entryopts[AUTOFS_MAXOPTSLEN];
582 char fstype[MAX_FSLEN], mounter[MAX_FSLEN];
583 int rc = PARSE_OK;
584 bool_t fstype_opt = FALSE;
585
586 strcpy(fstype, MNTTYPE_NFS); /* default */
587
588 /* set options to default options, if none exist for this entry */
589 if (opts == NULL) {
590 opts = defaultopts;
591 if (defaultopts == NULL) { /* NULL opts for entry */
592 strcpy(mounter, fstype);
593 goto done;
594 }
595 }
596 if (*opts == '-')
597 opts++;
598
599 /* separate opts into fstype and (other) entrypopts */
600 get_opts(opts, entryopts, fstype, &fstype_opt);
601
602 /* replace any existing opts */
603 if (me->map_mntopts != NULL)
604 free(me->map_mntopts);
605 if ((me->map_mntopts = strdup(entryopts)) == NULL)
606 return (ENOMEM);
607 strcpy(mounter, fstype);
608
609 /*
610 * child options are exactly fstype = somefs, we need to do some
611 * more option pushing work.
612 */
613 if (fstype_opt == TRUE &&
614 (strcmp(me->map_mntopts, NO_OPTS) == 0)) {
615 free(me->map_mntopts);
616 if ((rc = fstype_opts(me, opts, defaultopts,
617 mapopts)) != PARSE_OK)
618 return (rc);
619 }
620
621 done:
622 if (((me->map_fstype = strdup(fstype)) == NULL) ||
623 ((me->map_mounter = strdup(mounter)) == NULL)) {
624 if (me->map_fstype != NULL)
625 free(me->map_fstype);
626 syslog(LOG_ERR, "set_mapent_opts: No memory");
627 return (ENOMEM);
628 }
629
630 return (rc);
631 }
632
633 /*
634 * Check the option string for an "fstype"
635 * option. If found, return the fstype
636 * and the option string with the fstype
637 * option removed, e.g.
638 *
639 * input: "fstype=nfs,ro,nosuid"
640 * opts: "ro,nosuid"
641 * fstype: "nfs"
642 *
643 * Also indicates if the fstype option was present
644 * by setting a flag, if the pointer to the flag
645 * is not NULL.
646 */
647 static void
get_opts(char * input,char * opts,char * fstype,bool_t * fstype_opt)648 get_opts(char *input, char *opts, char *fstype, bool_t *fstype_opt)
649 {
650 char *p, *pb;
651 char buf[MAXOPTSLEN];
652 char *placeholder;
653
654 *opts = '\0';
655 (void) strcpy(buf, input);
656 pb = buf;
657 while (p = (char *)strtok_r(pb, ",", &placeholder)) {
658 pb = NULL;
659 if (strncmp(p, FSTYPE_EQ, 7) == 0) {
660 if (fstype_opt != NULL)
661 *fstype_opt = TRUE;
662 (void) strcpy(fstype, p + 7);
663 } else {
664 if (*opts)
665 (void) strcat(opts, ",");
666 (void) strcat(opts, p);
667 }
668 }
669 }
670
671 /*
672 * fstype_opts(struct mapent *me, char *opts, char *defaultopts,
673 * char *mapopts)
674 * We need to push global options to the child entry if it is exactly
675 * fstype=somefs.
676 */
677 static int
fstype_opts(struct mapent * me,char * opts,char * defaultopts,char * mapopts)678 fstype_opts(struct mapent *me, char *opts, char *defaultopts,
679 char *mapopts)
680 {
681 char pushentryopts[AUTOFS_MAXOPTSLEN];
682 char pushfstype[MAX_FSLEN];
683
684 if (defaultopts && *defaultopts == '-')
685 defaultopts++;
686
687 /*
688 * the options to push are the global defaults for the entry,
689 * if they exist, or mapopts, if the global defaults for the
690 * entry does not exist.
691 */
692 if (strcmp(defaultopts, opts) == 0) {
693 if (*mapopts == '-')
694 mapopts++;
695 get_opts(mapopts, pushentryopts, pushfstype, NULL);
696 } else {
697 get_opts(defaultopts, pushentryopts, pushfstype, NULL);
698 }
699
700 me->map_mntopts = strdup(pushentryopts);
701
702 if (!me->map_mntopts) {
703 syslog(LOG_ERR, "fstype_opts: No memory");
704 return (ENOMEM);
705 }
706
707 return (PARSE_OK);
708 }
709
710 /*
711 * modify_mapents(struct mapent **mapents, char *mapname,
712 * char *mapopts, char *subdir, hiernode *rootnode,
713 * char *key, uint_t isdirect, bool_t mount_access)
714 * modifies the intermediate mapentry list into the final one, and passes
715 * back a pointer to it. The final list may contain faked mapentries for
716 * hiernodes that do not point to a mapentry, or converted mapentries, if
717 * hiernodes that point to a mapentry need to be converted from nfs to autofs.
718 * mounts. Entries that are not directly 1 level below the subdir are removed.
719 * Returns PARSE_OK or PARSE_ERROR
720 */
721 static int
modify_mapents(struct mapent ** mapents,char * mapname,char * mapopts,char * subdir,hiernode * rootnode,char * key,uint_t isdirect,bool_t mount_access)722 modify_mapents(struct mapent **mapents, char *mapname,
723 char *mapopts, char *subdir, hiernode *rootnode,
724 char *key, uint_t isdirect, bool_t mount_access)
725 {
726 struct mapent *mp = NULL;
727 char w[MAXPATHLEN];
728
729 struct mapent *me;
730 int rc = PARSE_OK;
731 struct mapent *faked_mapents = NULL;
732
733 /*
734 * correct the mapentry mntlevel from default -1 to level depending on
735 * position in hierarchy, and build any faked mapentries, if required
736 * at one level below the rootnode given by subdir.
737 */
738 if ((rc = set_and_fake_mapent_mntlevel(rootnode, subdir, key, mapname,
739 &faked_mapents, isdirect, mapopts, mount_access)) != PARSE_OK)
740 return (rc);
741
742 /*
743 * attaches faked mapents to real mapents list. Assumes mapents
744 * is not NULL.
745 */
746 me = *mapents;
747 while (me->map_next != NULL)
748 me = me->map_next;
749 me->map_next = faked_mapents;
750
751 /*
752 * get rid of nodes marked at level -1
753 */
754 me = *mapents;
755 while (me != NULL) {
756 if ((me->map_mntlevel == -1) || (me->map_err) ||
757 (mount_access == FALSE && me->map_mntlevel == 0)) {
758 /*
759 * syslog any errors and free entry
760 */
761 if (me->map_err)
762 dump_mapent_err(me, key, mapname);
763
764 if (me == (*mapents)) {
765 /* special case when head has to be freed */
766 *mapents = me->map_next;
767 if ((*mapents) == NULL) {
768 /* something wierd happened */
769 if (verbose)
770 syslog(LOG_ERR,
771 "modify_mapents: level error");
772 return (PARSE_ERROR);
773 }
774
775 /* separate out the node */
776 me->map_next = NULL;
777 free_mapent(me);
778 me = *mapents;
779 } else {
780 mp->map_next = me->map_next;
781 me->map_next = NULL;
782 free_mapent(me);
783 me = mp->map_next;
784 }
785 continue;
786 }
787
788 /*
789 * convert level 1 mapents that are not already autonodes
790 * to autonodes
791 */
792 if (me->map_mntlevel == 1 &&
793 (strcmp(me->map_fstype, MNTTYPE_AUTOFS) != 0) &&
794 (me->map_faked != TRUE)) {
795 if ((rc = convert_mapent_to_automount(me, mapname,
796 mapopts)) != PARSE_OK)
797 return (rc);
798 }
799 strcpy(w, (me->map_mntpnt+strlen(subdir)));
800 strcpy(me->map_mntpnt, w);
801 mp = me;
802 me = me->map_next;
803 }
804
805 if (trace > 3)
806 trace_mapents("modify_mapents:", *mapents);
807
808 return (PARSE_OK);
809 }
810
811 /*
812 * set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key,
813 * char *mapname, struct mapent **faked_mapents,
814 * uint_t isdirect, char *mapopts, bool_t mount_access)
815 * sets the mapentry mount levels (depths) with respect to the subdir.
816 * Assigns a value of 0 to the new root. Finds the level1 directories by
817 * calling mark_*_level1_*(). Also cleans off extra /'s in level0 and
818 * level1 map_mntpnts. Note that one level below the new root is an existing
819 * mapentry if there's a mapentry (nfs mount) corresponding to the root,
820 * and the direct subdir set for the root, if there's no mapentry corresponding
821 * to the root (we install autodirs). Returns PARSE_OK or error value.
822 */
823 static int
set_and_fake_mapent_mntlevel(hiernode * rootnode,char * subdir,char * key,char * mapname,struct mapent ** faked_mapents,uint_t isdirect,char * mapopts,bool_t mount_access)824 set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key,
825 char *mapname, struct mapent **faked_mapents,
826 uint_t isdirect, char *mapopts, bool_t mount_access)
827 {
828 char dirname[MAXFILENAMELEN];
829 char traversed_path[MAXPATHLEN]; /* used in building fake mapentries */
830
831 char *subdir_child = subdir;
832 hiernode *prevnode = rootnode;
833 hiernode *currnode = rootnode->subdir;
834 int rc = PARSE_OK;
835 traversed_path[0] = '\0';
836
837 /*
838 * find and mark the root by tracing down subdir. Use traversed_path
839 * to keep track of how far we go, while guaranteeing that it
840 * contains no '/' at the end. Took some mucking to get that right.
841 */
842 if ((rc = get_dir_from_path(dirname, &subdir_child, sizeof (dirname)))
843 != PARSE_OK)
844 return (rc);
845
846 if (dirname[0] != '\0') {
847 if (strlcat(traversed_path, "/", sizeof (traversed_path)) >=
848 sizeof (traversed_path))
849 return (PARSE_ERROR);
850 if (strlcat(traversed_path, dirname, sizeof (traversed_path)) >=
851 sizeof (traversed_path))
852 return (PARSE_ERROR);
853 }
854
855 prevnode = rootnode;
856 currnode = rootnode->subdir;
857 while (dirname[0] != '\0' && currnode != NULL) {
858 if (strcmp(currnode->dirname, dirname) == 0) {
859
860 /* subdir is a child of currnode */
861 prevnode = currnode;
862 currnode = currnode->subdir;
863
864 if ((rc = get_dir_from_path(dirname, &subdir_child,
865 sizeof (dirname))) != PARSE_OK)
866 return (rc);
867 if (dirname[0] != '\0') {
868 if (strlcat(traversed_path, "/",
869 sizeof (traversed_path)) >=
870 sizeof (traversed_path))
871 return (PARSE_ERROR);
872 if (strlcat(traversed_path, dirname,
873 sizeof (traversed_path)) >=
874 sizeof (traversed_path))
875 return (PARSE_ERROR);
876 }
877 } else {
878 /* try next leveldir */
879 prevnode = currnode;
880 currnode = currnode->leveldir;
881 }
882 }
883
884 if (dirname[0] != '\0') {
885 if (verbose)
886 syslog(LOG_ERR,
887 "set_and_fake_mapent_mntlevel: subdir=%s error: map=%s",
888 subdir, mapname);
889 return (PARSE_ERROR);
890 }
891
892 /*
893 * see if level of root really points to a mapent and if
894 * have access to that filessystem - call appropriate
895 * routine to mark level 1 nodes, and build faked entries
896 */
897 if (prevnode->mapent != NULL && mount_access == TRUE) {
898 if (trace > 3)
899 trace_prt(1, " node mountpoint %s\t travpath=%s\n",
900 prevnode->mapent->map_mntpnt, traversed_path);
901
902 /*
903 * Copy traversed path map_mntpnt to get rid of any extra
904 * '/' the map entry may contain.
905 */
906 if (strlen(prevnode->mapent->map_mntpnt) <
907 strlen(traversed_path)) { /* sanity check */
908 if (verbose)
909 syslog(LOG_ERR,
910 "set_and_fake_mapent_mntlevel: path=%s error",
911 traversed_path);
912 return (PARSE_ERROR);
913 }
914 if (strcmp(prevnode->mapent->map_mntpnt, traversed_path) != 0)
915 strcpy(prevnode->mapent->map_mntpnt, traversed_path);
916
917 prevnode->mapent->map_mntlevel = 0; /* root level is 0 */
918 if (currnode != NULL) {
919 if ((rc = mark_level1_root(currnode,
920 traversed_path)) != PARSE_OK)
921 return (rc);
922 }
923 } else if (currnode != NULL) {
924 if (trace > 3)
925 trace_prt(1, " No rootnode, travpath=%s\n",
926 traversed_path);
927 if ((rc = mark_and_fake_level1_noroot(currnode,
928 traversed_path, key, mapname, faked_mapents, isdirect,
929 mapopts)) != PARSE_OK)
930 return (rc);
931 }
932
933 if (trace > 3) {
934 trace_prt(1, "\n\tset_and_fake_mapent_mntlevel\n");
935 trace_hierarchy(rootnode, 0);
936 }
937
938 return (rc);
939 }
940
941
942 /*
943 * mark_level1_root(hiernode *node, char *traversed_path)
944 * marks nodes upto one level below the rootnode given by subdir
945 * recursively. Called if rootnode points to a mapent.
946 * In this routine, a level 1 node is considered to be the 1st existing
947 * mapentry below the root node, so there's no faking involved.
948 * Returns PARSE_OK or error value
949 */
950 static int
mark_level1_root(hiernode * node,char * traversed_path)951 mark_level1_root(hiernode *node, char *traversed_path)
952 {
953 /* ensure we touch all leveldirs */
954 while (node) {
955 /*
956 * mark node level as 1, if one exists - else walk down
957 * subdirs until we find one.
958 */
959 if (node->mapent == NULL) {
960 char w[MAXPATHLEN];
961
962 if (node->subdir != NULL) {
963 sprintf(w, "%s/%s", traversed_path,
964 node->dirname);
965 if (mark_level1_root(node->subdir, w)
966 == PARSE_ERROR)
967 return (PARSE_ERROR);
968 } else {
969 if (verbose) {
970 syslog(LOG_ERR,
971 "mark_level1_root: hierarchy error");
972 }
973 return (PARSE_ERROR);
974 }
975 } else {
976 char w[MAXPATHLEN];
977
978 sprintf(w, "%s/%s", traversed_path, node->dirname);
979 if (trace > 3)
980 trace_prt(1, " node mntpnt %s\t travpath %s\n",
981 node->mapent->map_mntpnt, w);
982
983 /* replace mntpnt with travpath to clean extra '/' */
984 if (strlen(node->mapent->map_mntpnt) < strlen(w)) {
985 if (verbose) {
986 syslog(LOG_ERR,
987 "mark_level1_root: path=%s error",
988 traversed_path);
989 }
990 return (PARSE_ERROR);
991 }
992 if (strcmp(node->mapent->map_mntpnt, w) != 0)
993 strcpy(node->mapent->map_mntpnt, w);
994 node->mapent->map_mntlevel = 1;
995 }
996 node = node->leveldir;
997 }
998 return (PARSE_OK);
999 }
1000
1001 /*
1002 * mark_and_fake_level1_noroot(hiernode *node, char *traversed_path,
1003 * char *key,char *mapname, struct mapent **faked_mapents,
1004 * uint_t isdirect, char *mapopts)
1005 * Called if the root of the hierarchy does not point to a mapent. marks nodes
1006 * upto one physical level below the rootnode given by subdir. checks if
1007 * there's a real mapentry. If not, it builds a faked one (autonode) at that
1008 * point. The faked autonode is direct, with the map being the same as the
1009 * original one from which the call originated. Options are same as that of
1010 * the map and assigned in automount_opts(). Returns PARSE_OK or error value.
1011 */
1012 static int
mark_and_fake_level1_noroot(hiernode * node,char * traversed_path,char * key,char * mapname,struct mapent ** faked_mapents,uint_t isdirect,char * mapopts)1013 mark_and_fake_level1_noroot(hiernode *node, char *traversed_path,
1014 char *key, char *mapname, struct mapent **faked_mapents,
1015 uint_t isdirect, char *mapopts)
1016 {
1017 struct mapent *me;
1018 int rc = 0;
1019 char faked_map_mntpnt[MAXPATHLEN];
1020 char w1[MAXPATHLEN];
1021 char w[MAXPATHLEN];
1022
1023 while (node != NULL) {
1024 if (node->mapent != NULL) {
1025 /*
1026 * existing mapentry at level 1 - copy travpath to
1027 * get rid of extra '/' in mntpnt
1028 */
1029 sprintf(w, "%s/%s", traversed_path, node->dirname);
1030 if (trace > 3)
1031 trace_prt(1, " node mntpnt=%s\t travpath=%s\n",
1032 node->mapent->map_mntpnt, w);
1033 if (strlen(node->mapent->map_mntpnt) < strlen(w)) {
1034 /* sanity check */
1035 if (verbose)
1036 syslog(LOG_ERR,
1037 "mark_fake_level1_noroot:path=%s error",
1038 traversed_path);
1039 return (PARSE_ERROR);
1040 }
1041 if (strcmp(node->mapent->map_mntpnt, w) != 0)
1042 strcpy(node->mapent->map_mntpnt, w);
1043 node->mapent->map_mntlevel = 1;
1044 } else {
1045 /*
1046 * build the faked autonode
1047 */
1048 if ((me = (struct mapent *)malloc(sizeof (*me)))
1049 == NULL) {
1050 syslog(LOG_ERR,
1051 "mark_and_fake_level1_noroot: out of memory");
1052 return (ENOMEM);
1053 }
1054 (void) memset((char *)me, 0, sizeof (*me));
1055
1056 if ((me->map_fs = (struct mapfs *)
1057 malloc(sizeof (struct mapfs))) == NULL)
1058 return (ENOMEM);
1059 (void) memset(me->map_fs, 0, sizeof (struct mapfs));
1060
1061 if (isdirect) {
1062 *w1 = '\0';
1063 } else {
1064 strcpy(w1, "/");
1065 strcat(w1, key);
1066 }
1067 me->map_root = strdup(w1);
1068
1069 sprintf(faked_map_mntpnt, "%s/%s", traversed_path,
1070 node->dirname);
1071 me->map_mntpnt = strdup(faked_map_mntpnt);
1072 me->map_fstype = strdup(MNTTYPE_AUTOFS);
1073 me->map_mounter = strdup(MNTTYPE_AUTOFS);
1074
1075 /* set options */
1076 if ((rc = automount_opts(&me->map_mntopts, mapopts))
1077 != PARSE_OK)
1078 return (rc);
1079 me->map_fs->mfs_dir = strdup(mapname);
1080 me->map_mntlevel = 1;
1081 me->map_modified = FALSE;
1082 me->map_faked = TRUE; /* mark as faked */
1083 if (me->map_root == NULL ||
1084 me->map_mntpnt == NULL ||
1085 me->map_fstype == NULL ||
1086 me->map_mounter == NULL ||
1087 me->map_mntopts == NULL ||
1088 me->map_fs->mfs_dir == NULL) {
1089 syslog(LOG_ERR,
1090 "mark_and_fake_level1_noroot: out of memory");
1091 free_mapent(*faked_mapents);
1092 return (ENOMEM);
1093 }
1094
1095 if (*faked_mapents == NULL)
1096 *faked_mapents = me;
1097 else { /* attach to the head */
1098 me->map_next = *faked_mapents;
1099 *faked_mapents = me;
1100 }
1101 node->mapent = me;
1102 }
1103 node = node->leveldir;
1104 }
1105 return (rc);
1106 }
1107
1108 /*
1109 * convert_mapent_to_automount(struct mapent *me, char *mapname,
1110 * char *mapopts)
1111 * change the mapentry me to an automount - free fields first and NULL them
1112 * to avoid freeing again, while freeing the mapentry at a later stage.
1113 * Could have avoided freeing entries here as we don't really look at them.
1114 * Give the converted mapent entry the options that came with the map using
1115 * automount_opts(). Returns PARSE_OK or appropriate error value.
1116 */
1117 static int
convert_mapent_to_automount(struct mapent * me,char * mapname,char * mapopts)1118 convert_mapent_to_automount(struct mapent *me, char *mapname,
1119 char *mapopts)
1120 {
1121 struct mapfs *mfs = me->map_fs; /* assumes it exists */
1122 int rc = PARSE_OK;
1123
1124 /* free relevant entries */
1125 if (mfs->mfs_host) {
1126 free(mfs->mfs_host);
1127 mfs->mfs_host = NULL;
1128 }
1129 while (me->map_fs->mfs_next != NULL) {
1130 mfs = me->map_fs->mfs_next;
1131 if (mfs->mfs_host)
1132 free(mfs->mfs_host);
1133 if (mfs->mfs_dir)
1134 free(mfs->mfs_dir);
1135 me->map_fs->mfs_next = mfs->mfs_next; /* nulls eventually */
1136 free((void*)mfs);
1137 }
1138
1139 /* replace relevant entries */
1140 if (me->map_fstype)
1141 free(me->map_fstype);
1142 if ((me->map_fstype = strdup(MNTTYPE_AUTOFS)) == NULL)
1143 goto alloc_failed;
1144
1145 if (me->map_mounter)
1146 free(me->map_mounter);
1147 if ((me->map_mounter = strdup(me->map_fstype)) == NULL)
1148 goto alloc_failed;
1149
1150 if (me->map_fs->mfs_dir)
1151 free(me->map_fs->mfs_dir);
1152 if ((me->map_fs->mfs_dir = strdup(mapname)) == NULL)
1153 goto alloc_failed;
1154
1155 /* set options */
1156 if (me->map_mntopts)
1157 free(me->map_mntopts);
1158 if ((rc = automount_opts(&me->map_mntopts, mapopts)) != PARSE_OK)
1159 return (rc);
1160
1161 /* mucked with this entry, set the map_modified field to TRUE */
1162 me->map_modified = TRUE;
1163
1164 return (rc);
1165
1166 alloc_failed:
1167 syslog(LOG_ERR,
1168 "convert_mapent_to_automount: Memory allocation failed");
1169 return (ENOMEM);
1170 }
1171
1172 /*
1173 * automount_opts(char **map_mntopts, char *mapopts)
1174 * modifies automount opts - gets rid of all "indirect" and "direct" strings
1175 * if they exist, and then adds a direct string to force a direct automount.
1176 * Rest of the mapopts stay intact. Returns PARSE_OK or appropriate error.
1177 */
1178 static int
automount_opts(char ** map_mntopts,char * mapopts)1179 automount_opts(char **map_mntopts, char *mapopts)
1180 {
1181 char *opts;
1182 char *opt;
1183 int len;
1184 char *placeholder;
1185 char buf[AUTOFS_MAXOPTSLEN];
1186
1187 char *addopt = "direct";
1188
1189 len = strlen(mapopts)+ strlen(addopt)+2; /* +2 for ",", '\0' */
1190 if (len > AUTOFS_MAXOPTSLEN) {
1191 syslog(LOG_ERR,
1192 "option string %s too long (max=%d)", mapopts,
1193 AUTOFS_MAXOPTSLEN-8);
1194 return (PARSE_ERROR);
1195 }
1196
1197 if (((*map_mntopts) = ((char *)malloc(len))) == NULL) {
1198 syslog(LOG_ERR, "automount_opts: Memory allocation failed");
1199 return (ENOMEM);
1200 }
1201 memset(*map_mntopts, 0, len);
1202
1203 strcpy(buf, mapopts);
1204 opts = buf;
1205 while ((opt = strtok_r(opts, ",", &placeholder)) != NULL) {
1206 opts = NULL;
1207
1208 /* remove trailing and leading spaces */
1209 while (isspace(*opt))
1210 opt++;
1211 len = strlen(opt)-1;
1212 while (isspace(opt[len]))
1213 opt[len--] = '\0';
1214
1215 /*
1216 * if direct or indirect found, get rid of it, else put it
1217 * back
1218 */
1219 if ((strcmp(opt, "indirect") == 0) ||
1220 (strcmp(opt, "direct") == 0))
1221 continue;
1222 if (*map_mntopts[0] != '\0')
1223 strcat(*map_mntopts, ",");
1224 strcat(*map_mntopts, opt);
1225 }
1226
1227 /* add the direct string at the end */
1228 if (*map_mntopts[0] != '\0')
1229 strcat(*map_mntopts, ",");
1230 strcat(*map_mntopts, addopt);
1231
1232 return (PARSE_OK);
1233 }
1234
1235 /*
1236 * parse_fsinfo(char *mapname, struct mapent *mapents)
1237 * parses the filesystem information stored in me->map_fsw and me->map_fswq
1238 * and calls appropriate filesystem parser.
1239 * Returns PARSE_OK or an appropriate error value.
1240 */
1241 static int
parse_fsinfo(char * mapname,struct mapent * mapents)1242 parse_fsinfo(char *mapname, struct mapent *mapents)
1243 {
1244 struct mapent *me = mapents;
1245 char *bufp;
1246 char *bufq;
1247 int wordsz = MAXPATHLEN;
1248 int err = 0;
1249
1250 while (me != NULL) {
1251 bufp = "";
1252 bufq = "";
1253 if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) {
1254 err = parse_nfs(mapname, me, me->map_fsw,
1255 me->map_fswq, &bufp, &bufq, wordsz);
1256 } else {
1257 err = parse_special(me, me->map_fsw, me->map_fswq,
1258 &bufp, &bufq, wordsz);
1259 }
1260
1261 if (err != PARSE_OK || *me->map_fsw != '\0' ||
1262 *me->map_fswq != '\0') {
1263 /* sanity check */
1264 if (verbose)
1265 syslog(LOG_ERR,
1266 "parse_fsinfo: mount location error %s",
1267 me->map_fsw);
1268 return (PARSE_ERROR);
1269 }
1270
1271 me = me->map_next;
1272 }
1273
1274 if (trace > 3) {
1275 trace_mapents("parse_fsinfo:", mapents);
1276 }
1277
1278 return (PARSE_OK);
1279 }
1280
1281 /*
1282 * This function parses the map entry for a nfs type file system
1283 * The input is the string lp (and lq) which can be one of the
1284 * following forms:
1285 * a) host[(penalty)][,host[(penalty)]]... :/directory
1286 * b) host[(penalty)]:/directory[ host[(penalty)]:/directory]...
1287 * This routine constructs a mapfs link-list for each of
1288 * the hosts and the corresponding file system. The list
1289 * is then attatched to the mapent struct passed in.
1290 */
1291 int
parse_nfs(char * mapname,struct mapent * me,char * fsw,char * fswq,char ** lp,char ** lq,int wsize)1292 parse_nfs(char *mapname, struct mapent *me, char *fsw, char *fswq,
1293 char **lp, char **lq, int wsize)
1294 {
1295 struct mapfs *mfs, **mfsp;
1296 char *wlp, *wlq;
1297 char *hl, hostlist[1024], *hlq, hostlistq[1024];
1298 char hostname_and_penalty[MXHOSTNAMELEN+5];
1299 char *hn, *hnq, hostname[MXHOSTNAMELEN+1];
1300 char dirname[MAXPATHLEN+1], subdir[MAXPATHLEN+1];
1301 char qbuff[MAXPATHLEN+1], qbuff1[MAXPATHLEN+1];
1302 char pbuff[10], pbuffq[10];
1303 int penalty;
1304 char w[MAXPATHLEN];
1305 char wq[MAXPATHLEN];
1306 int host_cnt;
1307
1308 mfsp = &me->map_fs;
1309 *mfsp = NULL;
1310
1311 /*
1312 * there may be more than one entry in the map list. Get the
1313 * first one. Use temps to handle the word information and
1314 * copy back into fsw and fswq fields when done.
1315 */
1316 *lp = fsw;
1317 *lq = fswq;
1318 if (getword(w, wq, lp, lq, ' ', wsize) == -1)
1319 return (PARSE_ERROR);
1320 while (*w && *w != '/') {
1321 bool_t maybe_url;
1322
1323 maybe_url = TRUE;
1324
1325 wlp = w; wlq = wq;
1326 if (getword(hostlist, hostlistq, &wlp, &wlq, ':',
1327 sizeof (hostlist)) == -1)
1328 return (PARSE_ERROR);
1329 if (!*hostlist)
1330 goto bad_entry;
1331
1332 if (strcmp(hostlist, "nfs") != 0)
1333 maybe_url = FALSE;
1334
1335 if (getword(dirname, qbuff, &wlp, &wlq, ':',
1336 sizeof (dirname)) == -1)
1337 return (PARSE_ERROR);
1338 if (*dirname == '\0')
1339 goto bad_entry;
1340
1341 if (maybe_url == TRUE && strncmp(dirname, "//", 2) != 0)
1342 maybe_url = FALSE;
1343
1344 /*
1345 * See the next block comment ("Once upon a time ...") to
1346 * understand this. It turns the deprecated concept
1347 * of "subdir mounts" produced some useful code for handling
1348 * the possibility of a ":port#" in the URL.
1349 */
1350 if (maybe_url == FALSE)
1351 *subdir = '/';
1352 else
1353 *subdir = ':';
1354
1355 *qbuff = ' ';
1356
1357 /*
1358 * Once upon time, before autofs, there was support for
1359 * "subdir mounts". The idea was to "economize" the
1360 * number of mounts, so if you had a number of entries
1361 * all referring to a common subdirectory, e.g.
1362 *
1363 * carol seasons:/export/home11/carol
1364 * ted seasons:/export/home11/ted
1365 * alice seasons:/export/home11/alice
1366 *
1367 * then you could tell the automounter to mount a
1368 * common mountpoint which was delimited by the second
1369 * colon:
1370 *
1371 * carol seasons:/export/home11:carol
1372 * ted seasons:/export/home11:ted
1373 * alice seasons:/export/home11:alice
1374 *
1375 * The automounter would mount seasons:/export/home11
1376 * then for any other map entry that referenced the same
1377 * directory it would build a symbolic link that
1378 * appended the remainder of the path after the second
1379 * colon, i.e. once the common subdir was mounted, then
1380 * other directories could be accessed just by link
1381 * building - no further mounts required.
1382 *
1383 * In theory the "mount saving" idea sounded good. In
1384 * practice the saving didn't amount to much and the
1385 * symbolic links confused people because the common
1386 * mountpoint had to have a pseudonym.
1387 *
1388 * To remain backward compatible with the existing
1389 * maps, we interpret a second colon as a slash.
1390 */
1391 if (getword(subdir+1, qbuff+1, &wlp, &wlq, ':',
1392 sizeof (subdir)) == -1)
1393 return (PARSE_ERROR);
1394
1395 if (*(subdir+1))
1396 (void) strcat(dirname, subdir);
1397
1398 hl = hostlist; hlq = hostlistq;
1399
1400 host_cnt = 0;
1401 for (;;) {
1402
1403 if (getword(hostname_and_penalty, qbuff, &hl, &hlq, ',',
1404 sizeof (hostname_and_penalty)) == -1)
1405 return (PARSE_ERROR);
1406 if (!*hostname_and_penalty)
1407 break;
1408
1409 host_cnt++;
1410 if (host_cnt > 1)
1411 maybe_url = FALSE;
1412
1413 hn = hostname_and_penalty;
1414 hnq = qbuff;
1415 if (getword(hostname, qbuff1, &hn, &hnq, '(',
1416 sizeof (hostname)) == -1)
1417 return (PARSE_ERROR);
1418 if (hostname[0] == '\0')
1419 goto bad_entry;
1420
1421 if (strcmp(hostname, hostname_and_penalty) == 0) {
1422 penalty = 0;
1423 } else {
1424 maybe_url = FALSE;
1425 hn++; hnq++;
1426 if (getword(pbuff, pbuffq, &hn, &hnq, ')',
1427 sizeof (pbuff)) == -1)
1428 return (PARSE_ERROR);
1429 if (!*pbuff)
1430 penalty = 0;
1431 else
1432 penalty = atoi(pbuff);
1433 }
1434 mfs = (struct mapfs *)malloc(sizeof (*mfs));
1435 if (mfs == NULL) {
1436 syslog(LOG_ERR,
1437 "parse_nfs: Memory allocation failed");
1438 return (PARSE_ERROR);
1439 }
1440 (void) memset(mfs, 0, sizeof (*mfs));
1441 *mfsp = mfs;
1442 mfsp = &mfs->mfs_next;
1443
1444 if (maybe_url == TRUE) {
1445 char *host;
1446 char *path;
1447 char *sport;
1448
1449 host = dirname+2;
1450 path = strchr(host, '/');
1451 if (path == NULL) {
1452 syslog(LOG_ERR, "parse_nfs: illegal "
1453 "nfs url syntax: %s", host);
1454
1455 return (PARSE_ERROR);
1456 }
1457 *path = '\0';
1458 sport = strchr(host, ':');
1459
1460 if (sport != NULL && sport < path) {
1461 *sport = '\0';
1462 mfs->mfs_port = atoi(sport+1);
1463
1464 if (mfs->mfs_port > USHRT_MAX) {
1465 syslog(LOG_ERR,
1466 "parse_nfs: invalid "
1467 "port number (%d) in "
1468 "NFS URL",
1469 mfs->mfs_port);
1470
1471 return (PARSE_ERROR);
1472 }
1473
1474 }
1475
1476 path++;
1477 if (*path == '\0')
1478 path = ".";
1479
1480 mfs->mfs_flags |= MFS_URL;
1481
1482 mfs->mfs_host = strdup(host);
1483 mfs->mfs_dir = strdup(path);
1484 } else {
1485 mfs->mfs_host = strdup(hostname);
1486 mfs->mfs_dir = strdup(dirname);
1487 }
1488
1489 mfs->mfs_penalty = penalty;
1490 if (mfs->mfs_host == NULL || mfs->mfs_dir == NULL) {
1491 syslog(LOG_ERR,
1492 "parse_nfs: Memory allocation failed");
1493 return (PARSE_ERROR);
1494 }
1495 }
1496 /*
1497 * We check host_cnt to make sure we haven't parsed an entry
1498 * with no host information.
1499 */
1500 if (host_cnt == 0) {
1501 syslog(LOG_ERR,
1502 "parse_nfs: invalid host specified - bad entry "
1503 "in map %s \"%s\"",
1504 mapname, w);
1505 return (PARSE_ERROR);
1506 }
1507 if (getword(w, wq, lp, lq, ' ', wsize) == -1)
1508 return (PARSE_ERROR);
1509 }
1510
1511 strcpy(fsw, w);
1512 strcpy(fswq, wq);
1513
1514 return (PARSE_OK);
1515
1516 bad_entry:
1517 syslog(LOG_ERR, "parse_nfs: bad entry in map %s \"%s\"", mapname, w);
1518 return (PARSE_ERROR);
1519 }
1520
1521 static int
parse_special(struct mapent * me,char * w,char * wq,char ** lp,char ** lq,int wsize)1522 parse_special(struct mapent *me, char *w, char *wq, char **lp, char **lq,
1523 int wsize)
1524 {
1525 char devname[MAXPATHLEN + 1], qbuf[MAXPATHLEN + 1];
1526 char *wlp, *wlq;
1527 struct mapfs *mfs;
1528
1529 wlp = w;
1530 wlq = wq;
1531 if (getword(devname, qbuf, &wlp, &wlq, ' ', sizeof (devname)) == -1)
1532 return (PARSE_ERROR);
1533 if (devname[0] == '\0')
1534 return (PARSE_ERROR);
1535
1536 mfs = malloc(sizeof (struct mapfs));
1537 if (mfs == NULL)
1538 return (PARSE_ERROR);
1539 (void) memset(mfs, 0, sizeof (*mfs));
1540
1541 /*
1542 * A device name that begins with a slash could
1543 * be confused with a mountpoint path, hence use
1544 * a colon to escape a device string that begins
1545 * with a slash, e.g.
1546 *
1547 * foo -ro /bar foo:/bar
1548 * and
1549 * foo -ro /dev/sr0
1550 *
1551 * would confuse the parser. The second instance
1552 * must use a colon:
1553 *
1554 * foo -ro :/dev/sr0
1555 */
1556 mfs->mfs_dir = strdup(&devname[devname[0] == ':']);
1557 if (mfs->mfs_dir == NULL)
1558 return (PARSE_ERROR);
1559 me->map_fs = mfs;
1560 if (getword(w, wq, lp, lq, ' ', wsize) == -1)
1561 return (PARSE_ERROR);
1562 return (0);
1563 }
1564
1565 /*
1566 * get_dir_from_path(char *dir, char **path, int dirsz)
1567 * gets the directory name dir from path for max string of length dirsz.
1568 * A modification of the getword routine. Assumes the delimiter is '/'
1569 * and that excess /'s are redundant.
1570 * Returns PARSE_OK or PARSE_ERROR
1571 */
1572 static int
get_dir_from_path(char * dir,char ** path,int dirsz)1573 get_dir_from_path(char *dir, char **path, int dirsz)
1574 {
1575 char *tmp = dir;
1576 int count = dirsz;
1577
1578 if (dirsz <= 0) {
1579 if (verbose)
1580 syslog(LOG_ERR,
1581 "get_dir_from_path: invalid directory size %d", dirsz);
1582 return (PARSE_ERROR);
1583 }
1584
1585 /* get rid of leading /'s in path */
1586 while (**path == '/')
1587 (*path)++;
1588
1589 /* now at a word or at the end of path */
1590 while ((**path) && ((**path) != '/')) {
1591 if (--count <= 0) {
1592 *tmp = '\0';
1593 syslog(LOG_ERR,
1594 "get_dir_from_path: max pathlength exceeded %d", dirsz);
1595 return (PARSE_ERROR);
1596 }
1597 *dir++ = *(*path)++;
1598 }
1599
1600 *dir = '\0';
1601
1602 /* get rid of trailing /'s in path */
1603 while (**path == '/')
1604 (*path)++;
1605
1606 return (PARSE_OK);
1607 }
1608
1609 /*
1610 * alloc_hiernode(hiernode **newnode, char *dirname)
1611 * allocates a new hiernode corresponding to a new directory entry
1612 * in the hierarchical structure, and passes a pointer to it back
1613 * to the calling program.
1614 * Returns PARSE_OK or appropriate error value.
1615 */
1616 static int
alloc_hiernode(hiernode ** newnode,char * dirname)1617 alloc_hiernode(hiernode **newnode, char *dirname)
1618 {
1619 if ((*newnode = (hiernode *)malloc(sizeof (hiernode))) == NULL) {
1620 syslog(LOG_ERR, "alloc_hiernode: Memory allocation failed");
1621 return (ENOMEM);
1622 }
1623
1624 memset(((char *)*newnode), 0, sizeof (hiernode));
1625 strcpy(((*newnode)->dirname), dirname);
1626 return (PARSE_OK);
1627 }
1628
1629 /*
1630 * free_hiernode(hiernode *node)
1631 * frees the allocated hiernode given the head of the structure
1632 * recursively calls itself until it frees entire structure.
1633 * Returns nothing.
1634 */
1635 static void
free_hiernode(hiernode * node)1636 free_hiernode(hiernode *node)
1637 {
1638 hiernode *currnode = node;
1639 hiernode *prevnode = NULL;
1640
1641 while (currnode != NULL) {
1642 if (currnode->subdir != NULL)
1643 free_hiernode(currnode->subdir);
1644 prevnode = currnode;
1645 currnode = currnode->leveldir;
1646 free((void*)prevnode);
1647 }
1648 }
1649
1650 /*
1651 * free_mapent(struct mapent *)
1652 * free the mapentry and its fields
1653 */
1654 void
free_mapent(struct mapent * me)1655 free_mapent(struct mapent *me)
1656 {
1657 struct mapfs *mfs;
1658 struct mapent *m;
1659
1660 while (me) {
1661 while (me->map_fs) {
1662 mfs = me->map_fs;
1663 if (mfs->mfs_host)
1664 free(mfs->mfs_host);
1665 if (mfs->mfs_dir)
1666 free(mfs->mfs_dir);
1667 if (mfs->mfs_args)
1668 free(mfs->mfs_args);
1669 if (mfs->mfs_nconf)
1670 freenetconfigent(mfs->mfs_nconf);
1671 me->map_fs = mfs->mfs_next;
1672 free(mfs);
1673 }
1674
1675 if (me->map_root)
1676 free(me->map_root);
1677 if (me->map_mntpnt)
1678 free(me->map_mntpnt);
1679 if (me->map_mntopts)
1680 free(me->map_mntopts);
1681 if (me->map_fstype)
1682 free(me->map_fstype);
1683 if (me->map_mounter)
1684 free(me->map_mounter);
1685 if (me->map_fsw)
1686 free(me->map_fsw);
1687 if (me->map_fswq)
1688 free(me->map_fswq);
1689
1690 m = me;
1691 me = me->map_next;
1692 free(m);
1693 }
1694 }
1695
1696 /*
1697 * trace_mapents(struct mapent *mapents)
1698 * traces through the mapentry structure and prints it element by element
1699 * returns nothing
1700 */
1701 static void
trace_mapents(char * s,struct mapent * mapents)1702 trace_mapents(char *s, struct mapent *mapents)
1703 {
1704 struct mapfs *mfs;
1705 struct mapent *me;
1706
1707 trace_prt(1, "\n\t%s\n", s);
1708 for (me = mapents; me; me = me->map_next) {
1709 trace_prt(1, " (%s,%s)\t %s%s -%s\n",
1710 me->map_fstype ? me->map_fstype : "",
1711 me->map_mounter ? me->map_mounter : "",
1712 me->map_root ? me->map_root : "",
1713 me->map_mntpnt ? me->map_mntpnt : "",
1714 me->map_mntopts ? me->map_mntopts : "");
1715 for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next)
1716 trace_prt(0, "\t\t%s:%s\n",
1717 mfs->mfs_host ? mfs->mfs_host: "",
1718 mfs->mfs_dir ? mfs->mfs_dir : "");
1719
1720 trace_prt(1, "\tme->map_fsw=%s\n",
1721 me->map_fsw ? me->map_fsw:"",
1722 me->map_fswq ? me->map_fsw:"");
1723 trace_prt(1, "\t mntlevel=%d\t%s\t%s err=%d\n",
1724 me->map_mntlevel,
1725 me->map_modified ? "modify=TRUE":"modify=FALSE",
1726 me->map_faked ? "faked=TRUE":"faked=FALSE",
1727 me->map_err);
1728 }
1729 }
1730
1731 /*
1732 * trace_hierarchy(hiernode *node)
1733 * traces the allocated hiernode given the head of the structure
1734 * recursively calls itself until it traces entire structure.
1735 * the first call made at the root is made with a zero level.
1736 * nodelevel is simply used to print tab and make the tracing clean.
1737 * Returns nothing.
1738 */
1739 static void
trace_hierarchy(hiernode * node,int nodelevel)1740 trace_hierarchy(hiernode *node, int nodelevel)
1741 {
1742 hiernode *currnode = node;
1743 int i;
1744
1745 while (currnode != NULL) {
1746 if (currnode->subdir != NULL) {
1747 for (i = 0; i < nodelevel; i++)
1748 trace_prt(0, "\t");
1749 trace_prt(0, "\t(%s, ", currnode->dirname);
1750 if (currnode->mapent) {
1751 trace_prt(0, "%d, %s)\n",
1752 currnode->mapent->map_mntlevel,
1753 currnode->mapent->map_mntopts ?
1754 currnode->mapent->map_mntopts:"");
1755 }
1756 else
1757 trace_prt(0, " ,)\n");
1758 nodelevel++;
1759 trace_hierarchy(currnode->subdir, nodelevel);
1760 } else {
1761 for (i = 0; i < nodelevel; i++)
1762 trace_prt(0, "\t");
1763 trace_prt(0, "\t(%s, ", currnode->dirname);
1764 if (currnode->mapent) {
1765 trace_prt(0, "%d, %s)\n",
1766 currnode->mapent->map_mntlevel,
1767 currnode->mapent->map_mntopts ?
1768 currnode->mapent->map_mntopts:"");
1769 }
1770 else
1771 trace_prt(0, ", )\n");
1772 }
1773 currnode = currnode->leveldir;
1774 }
1775 }
1776
1777 struct mapent *
do_mapent_hosts(char * mapopts,char * host,uint_t isdirect)1778 do_mapent_hosts(char *mapopts, char *host, uint_t isdirect)
1779 {
1780 CLIENT *cl;
1781 struct mapent *me, *ms, *mp;
1782 struct mapfs *mfs;
1783 struct exportnode *ex = NULL;
1784 struct exportnode *exlist, *texlist, **texp, *exnext;
1785 struct timeval timeout;
1786 enum clnt_stat clnt_stat;
1787 char name[MAXPATHLEN];
1788 char entryopts[MAXOPTSLEN];
1789 char fstype[32], mounter[32];
1790 int exlen, duplicate;
1791 struct mnttab mb; /* needed for hasmntopt() to get nfs version */
1792 rpcvers_t nfsvers; /* version in map options, 0 if not there */
1793 rpcvers_t vers, versmin; /* used to negotiate nfs vers in pingnfs() */
1794 int retries, delay;
1795 int foundvers;
1796
1797 if (trace > 1)
1798 trace_prt(1, " do_mapent_hosts: host %s\n", host);
1799
1800 /* check for special case: host is me */
1801
1802 if (self_check(host)) {
1803 ms = (struct mapent *)malloc(sizeof (*ms));
1804 if (ms == NULL)
1805 goto alloc_failed;
1806 (void) memset((char *)ms, 0, sizeof (*ms));
1807 (void) strcpy(fstype, MNTTYPE_NFS);
1808 get_opts(mapopts, entryopts, fstype, NULL);
1809 ms->map_mntopts = strdup(entryopts);
1810 if (ms->map_mntopts == NULL)
1811 goto alloc_failed;
1812 ms->map_mounter = strdup(fstype);
1813 if (ms->map_mounter == NULL)
1814 goto alloc_failed;
1815 ms->map_fstype = strdup(MNTTYPE_NFS);
1816 if (ms->map_fstype == NULL)
1817 goto alloc_failed;
1818
1819 if (isdirect)
1820 name[0] = '\0';
1821 else {
1822 (void) strcpy(name, "/");
1823 (void) strcat(name, host);
1824 }
1825 ms->map_root = strdup(name);
1826 if (ms->map_root == NULL)
1827 goto alloc_failed;
1828 ms->map_mntpnt = strdup("");
1829 if (ms->map_mntpnt == NULL)
1830 goto alloc_failed;
1831 mfs = (struct mapfs *)malloc(sizeof (*mfs));
1832 if (mfs == NULL)
1833 goto alloc_failed;
1834 (void) memset((char *)mfs, 0, sizeof (*mfs));
1835 ms->map_fs = mfs;
1836 mfs->mfs_host = strdup(host);
1837 if (mfs->mfs_host == NULL)
1838 goto alloc_failed;
1839 mfs->mfs_dir = strdup("/");
1840 if (mfs->mfs_dir == NULL)
1841 goto alloc_failed;
1842
1843 /* initialize mntlevel and modify */
1844 ms->map_mntlevel = -1;
1845 ms->map_modified = FALSE;
1846 ms->map_faked = FALSE;
1847
1848 if (trace > 1)
1849 trace_prt(1,
1850 " do_mapent_hosts: self-host %s OK\n", host);
1851
1852 return (ms);
1853 }
1854
1855 /*
1856 * Call pingnfs. Note that we can't have replicated hosts in /net.
1857 * XXX - we would like to avoid duplicating the across the wire calls
1858 * made here in nfsmount(). The pingnfs cache should help avoid it.
1859 */
1860 mb.mnt_mntopts = mapopts;
1861 foundvers = nopt(&mb, MNTOPT_VERS, (int *)&nfsvers);
1862 if (!foundvers)
1863 nfsvers = 0;
1864 if (set_versrange(nfsvers, &vers, &versmin) != 0) {
1865 syslog(LOG_ERR, "Incorrect NFS version specified for %s", host);
1866 return (NULL);
1867 }
1868 if (pingnfs(host, get_retry(mapopts) + 1, &vers, versmin, 0, FALSE,
1869 NULL, NULL) != RPC_SUCCESS)
1870 return (NULL);
1871
1872 retries = get_retry(mapopts);
1873 delay = INITDELAY;
1874 retry:
1875 /* get export list of host */
1876 cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "circuit_v");
1877 if (cl == NULL) {
1878 cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "datagram_v");
1879 if (cl == NULL) {
1880 syslog(LOG_ERR,
1881 "do_mapent_hosts: %s %s", host, clnt_spcreateerror(""));
1882 return (NULL);
1883 }
1884
1885 }
1886 #ifdef MALLOC_DEBUG
1887 add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__);
1888 add_alloc("AUTH_HANDLE", cl->cl_auth, 0, __FILE__, __LINE__);
1889 #endif
1890
1891 timeout.tv_usec = 0;
1892 timeout.tv_sec = 25;
1893 if (clnt_stat = clnt_call(cl, MOUNTPROC_EXPORT, xdr_void, 0,
1894 xdr_exports, (caddr_t)&ex, timeout)) {
1895
1896 if (retries-- > 0) {
1897 clnt_destroy(cl);
1898 DELAY(delay);
1899 goto retry;
1900 }
1901
1902 syslog(LOG_ERR,
1903 "do_mapent_hosts: %s: export list: %s",
1904 host, clnt_sperrno(clnt_stat));
1905 #ifdef MALLOC_DEBUG
1906 drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__);
1907 drop_alloc("AUTH_HANDLE", cl->cl_auth, __FILE__, __LINE__);
1908 #endif
1909 clnt_destroy(cl);
1910 return ((struct mapent *)NULL);
1911 }
1912
1913 #ifdef MALLOC_DEBUG
1914 drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__);
1915 drop_alloc("AUTH_HANDLE", cl->cl_auth, __FILE__, __LINE__);
1916 #endif
1917 clnt_destroy(cl);
1918
1919 if (ex == NULL) {
1920 if (trace > 1)
1921 trace_prt(1,
1922 gettext(" getmapent_hosts: null export list\n"));
1923 return ((struct mapent *)NULL);
1924 }
1925
1926 /* now sort by length of names - to get mount order right */
1927 exlist = ex;
1928 texlist = NULL;
1929 for (; ex; ex = exnext) {
1930 exnext = ex->ex_next;
1931 exlen = strlen(ex->ex_dir);
1932 duplicate = 0;
1933 for (texp = &texlist; *texp; texp = &((*texp)->ex_next)) {
1934 if (exlen < (int)strlen((*texp)->ex_dir))
1935 break;
1936 duplicate = (strcmp(ex->ex_dir, (*texp)->ex_dir) == 0);
1937 if (duplicate) {
1938 /* disregard duplicate entry */
1939 freeex_ent(ex);
1940 break;
1941 }
1942 }
1943 if (!duplicate) {
1944 ex->ex_next = *texp;
1945 *texp = ex;
1946 }
1947 }
1948 exlist = texlist;
1949
1950 (void) strcpy(fstype, MNTTYPE_NFS);
1951 get_opts(mapopts, entryopts, fstype, NULL);
1952 (void) strcpy(mounter, fstype);
1953
1954 /* Now create a mapent from the export list */
1955 ms = NULL;
1956 me = NULL;
1957
1958 for (ex = exlist; ex; ex = ex->ex_next) {
1959 mp = me;
1960 me = (struct mapent *)malloc(sizeof (*me));
1961 if (me == NULL)
1962 goto alloc_failed;
1963 (void) memset((char *)me, 0, sizeof (*me));
1964
1965 if (ms == NULL)
1966 ms = me;
1967 else
1968 mp->map_next = me;
1969
1970 if (isdirect)
1971 name[0] = '\0';
1972 else {
1973 (void) strcpy(name, "/");
1974 (void) strcat(name, host);
1975 }
1976 me->map_root = strdup(name);
1977 if (me->map_root == NULL)
1978 goto alloc_failed;
1979
1980 *name = '\0';
1981 if (strcmp(ex->ex_dir, "/") != 0) {
1982 if (*(ex->ex_dir) != '/')
1983 (void) strcpy(name, "/");
1984 (void) strcat(name, ex->ex_dir);
1985 }
1986 me->map_mntpnt = strdup(name);
1987 if (me->map_mntpnt == NULL)
1988 goto alloc_failed;
1989
1990 me->map_fstype = strdup(fstype);
1991 if (me->map_fstype == NULL)
1992 goto alloc_failed;
1993 me->map_mounter = strdup(mounter);
1994 if (me->map_mounter == NULL)
1995 goto alloc_failed;
1996 me->map_mntopts = strdup(entryopts);
1997 if (me->map_mntopts == NULL)
1998 goto alloc_failed;
1999
2000 mfs = (struct mapfs *)malloc(sizeof (*mfs));
2001 if (mfs == NULL)
2002 goto alloc_failed;
2003 (void) memset((char *)mfs, 0, sizeof (*mfs));
2004 me->map_fs = mfs;
2005 mfs->mfs_host = strdup(host);
2006 if (mfs->mfs_host == NULL)
2007 goto alloc_failed;
2008 mfs->mfs_dir = strdup(ex->ex_dir);
2009 if (mfs->mfs_dir == NULL)
2010 goto alloc_failed;
2011
2012 /* initialize mntlevel and modify values */
2013 me->map_mntlevel = -1;
2014 me->map_modified = FALSE;
2015 me->map_faked = FALSE;
2016 }
2017 freeex(exlist);
2018
2019 if (trace > 1)
2020 trace_prt(1, " do_mapent_hosts: host %s OK\n", host);
2021
2022 return (ms);
2023
2024 alloc_failed:
2025 syslog(LOG_ERR, "do_mapent_hosts: Memory allocation failed");
2026 free_mapent(ms);
2027 freeex(exlist);
2028 return (NULL);
2029 }
2030
2031
2032 static void
freeex_ent(struct exportnode * ex)2033 freeex_ent(struct exportnode *ex)
2034 {
2035 struct groupnode *groups, *tmpgroups;
2036
2037 free(ex->ex_dir);
2038 groups = ex->ex_groups;
2039 while (groups) {
2040 free(groups->gr_name);
2041 tmpgroups = groups->gr_next;
2042 free((char *)groups);
2043 groups = tmpgroups;
2044 }
2045 free(ex);
2046 }
2047
2048 static void
freeex(struct exportnode * ex)2049 freeex(struct exportnode *ex)
2050 {
2051 struct exportnode *tmpex;
2052
2053 while (ex) {
2054 tmpex = ex->ex_next;
2055 freeex_ent(ex);
2056 ex = tmpex;
2057 }
2058 }
2059
2060 static const char uatfs_err[] = "submount under fstype=autofs not supported";
2061 /*
2062 * dump_mapent_err(struct mapent *me, char *key, char *mapname)
2063 * syslog appropriate error in mapentries.
2064 */
dump_mapent_err(struct mapent * me,char * key,char * mapname)2065 static void dump_mapent_err(struct mapent *me, char *key, char *mapname)
2066 {
2067 switch (me->map_err) {
2068 case MAPENT_NOERR:
2069 if (verbose)
2070 syslog(LOG_ERR,
2071 "map=%s key=%s mntpnt=%s: no error");
2072 break;
2073 case MAPENT_UATFS:
2074 syslog(LOG_ERR,
2075 "mountpoint %s in map %s key %s not mounted: %s",
2076 me->map_mntpnt, mapname, key, uatfs_err);
2077 break;
2078 default:
2079 if (verbose)
2080 syslog(LOG_ERR,
2081 "map=%s key=%s mntpnt=%s: unknown mapentry error");
2082 }
2083 }
2084