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