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.
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.
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]
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.
33 #include <sys/types.h>
35 #include <sys/param.h>
38 #include <netinet/in.h>
40 #include <sys/tiuser.h>
46 #include <rpcsvc/mount.h>
49 #include "automount.h"
52 * This structure is used to determine the hierarchical
53 * relationship between directories
55 typedef struct _hiernode
{
56 char dirname
[MAXFILENAMELEN
+1];
57 struct _hiernode
*subdir
;
58 struct _hiernode
*leveldir
;
59 struct mapent
*mapent
;
62 void free_mapent(struct mapent
*);
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 **,
83 static int parse_special(struct mapent
*, char *, char *, char **, char **,
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 *);
96 #define PARSE_ERROR -1
100 * mapentry error type defininitions
102 #define MAPENT_NOERR 0
103 #define MAPENT_UATFS 1
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.
118 parse_entry(char *key
, char *mapname
, char *mapopts
, struct mapline
*ml
,
119 char *subdir
, uint_t isdirect
, bool_t mount_access
)
122 char defaultopts
[AUTOFS_MAXOPTSLEN
];
124 struct mapent
*mapents
= NULL
;
125 hiernode
*rootnode
= NULL
;
126 char *lp
= ml
->linebuf
;
129 trace_prt(1, " mapline: %s\n", ml
->linebuf
);
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.
136 for (p
= key
; *p
!= '\0'; p
++) {
139 "parse_entry: bad key in map %s: %s", mapname
, key
);
145 * select the appropriate parser, and build the mapentry list
147 if (strcmp(lp
, "-hosts") == 0) {
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.
153 mapents
= do_mapent_hosts(mapopts
, key
, isdirect
);
154 if (mapents
== NULL
) /* nothing to free */
158 trace_mapents("do_mapent_hosts:(return)", mapents
);
160 if (hierarchical_sort(mapents
, &rootnode
, key
, mapname
)
167 if (mapline_to_mapent(&mapents
, ml
, key
, mapname
,
168 mapopts
, defaultopts
, isdirect
) != PARSE_OK
)
174 if (hierarchical_sort(mapents
, &rootnode
, key
, mapname
)
178 if (push_options(rootnode
, defaultopts
, mapopts
,
179 MAPENT_NOERR
) != PARSE_OK
)
183 trace_prt(1, "\n\tpush_options (return)\n");
184 trace_prt(0, "\tdefault options=%s\n", defaultopts
);
185 trace_hierarchy(rootnode
, 0);
188 if (parse_fsinfo(mapname
, mapents
) != PARSE_OK
)
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).
197 if (modify_mapents(&mapents
, mapname
, mapopts
, subdir
,
198 rootnode
, key
, isdirect
, mount_access
) != PARSE_OK
)
202 * XXX: its dangerous to use rootnode after modify mapents as
203 * it may be pointing to mapents that have been freed
205 if (rootnode
!= NULL
)
206 free_hiernode(rootnode
);
211 syslog(LOG_ERR
, "parse_entry: mapentry parse error: map=%s key=%s",
213 free_mapent(mapents
);
214 if (rootnode
!= NULL
)
215 free_hiernode(rootnode
);
221 * mapline_to_mapent(struct mapent **mapents, struct mapline *ml,
222 * char *key, char *mapname, char *mapopts, char *defaultopts,
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.
233 mapline_to_mapent(struct mapent
**mapents
, struct mapline
*ml
, char *key
,
234 char *mapname
, char *mapopts
, char *defaultopts
,
237 struct mapent
*me
= NULL
;
244 char *lp
= ml
->linebuf
;
245 char *lq
= ml
->lineqbuf
;
247 /* do any macro expansions that are required to complete ml */
248 if (macro_expand(key
, lp
, lq
, LINESZ
)) {
250 "mapline_to_mapent: map %s: line too long (max %d chars)",
251 mapname
, LINESZ
- 1);
252 return (PARSE_ERROR
);
254 if (trace
> 3 && (strcmp(ml
->linebuf
, lp
) != 0))
256 " mapline_to_mapent: (expanded) mapline (%s,%s)\n",
257 ml
->linebuf
, ml
->lineqbuf
);
259 /* init the head of mapentry list to null */
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.
269 if (getword(w
, wq
, &lp
, &lq
, ' ', sizeof (w
)) == -1)
270 return (PARSE_ERROR
);
272 strcpy(defaultopts
, w
);
273 if (getword(w
, wq
, &lp
, &lq
, ' ', sizeof (w
)) == -1)
274 return (PARSE_ERROR
);
276 strcpy(defaultopts
, mapopts
);
279 * implied is true if there is no '/'
280 * We need the same code path if we have an smbfs mount.
282 implied
= (*w
!= '/') || (strstr(defaultopts
, "fstype=smbfs") != NULL
);
283 while (*w
== '/' || implied
) {
285 if ((me
= (struct mapent
*)malloc(sizeof (*me
))) == NULL
)
287 (void) memset((char *)me
, 0, sizeof (*me
));
288 if (*mapents
== NULL
) /* special case of head */
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().
305 if ((me
->map_root
= strdup(w1
)) == NULL
)
308 /* mntpnt is empty for the mount root */
309 if (strcmp(w
, "/") == 0 || implied
)
310 me
->map_mntpnt
= strdup("");
312 me
->map_mntpnt
= strdup(w
);
313 if (me
->map_mntpnt
== NULL
)
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
323 if (implied
) /* must be a mount filesystem */
326 if (getword(w
, wq
, &lp
, &lq
, ' ', sizeof (w
)) == -1)
327 return (PARSE_ERROR
);
330 if ((me
->map_mntopts
= strdup(w
)) == NULL
)
332 if (getword(w
, wq
, &lp
, &lq
, ' ',
334 return (PARSE_ERROR
);
339 * must be a mount filesystem or a set of filesystems at
342 if (w
[0] == '\0' || w
[0] == '-') {
344 "mapline_to_mapent: bad location=%s map=%s key=%s",
346 return (PARSE_ERROR
);
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.
357 if (((me
->map_fsw
= strdup(w
)) == NULL
) ||
358 ((me
->map_fswq
= strdup(wq
)) == NULL
))
362 * the next word, if any, is either another mount point or a
363 * mount filesystem if more than one server is listed.
365 if (getword(w
, wq
, &lp
, &lq
, ' ', sizeof (w
)) == -1)
366 return (PARSE_ERROR
);
367 while (*w
&& *w
!= '/') { /* more than 1 server listed */
370 len
= strlen(me
->map_fsw
) + strlen(w
) + 4;
371 if ((fsw
= (char *)malloc(len
)) == NULL
)
373 sprintf(fsw
, "%s %s", me
->map_fsw
, w
);
376 len
= strlen(me
->map_fswq
) + strlen(wq
) + 4;
377 if ((fswq
= (char *)malloc(len
)) == NULL
)
379 sprintf(fswq
, "%s %s", me
->map_fswq
, wq
);
382 if (getword(w
, wq
, &lp
, &lq
, ' ', sizeof (w
)) == -1)
383 return (PARSE_ERROR
);
386 /* initialize flags */
387 me
->map_mntlevel
= -1;
388 me
->map_modified
= FALSE
;
389 me
->map_faked
= FALSE
;
390 me
->map_err
= MAPENT_NOERR
;
395 if (*mapents
== NULL
|| w
[0] != '\0') { /* sanity check */
397 if (*mapents
== NULL
)
399 "mapline_to_mapent: parsed with null mapents");
402 "mapline_to_mapent: parsed nononempty w=%s", w
);
404 return (PARSE_ERROR
);
408 trace_mapents("mapline_to_mapent:", *mapents
);
413 syslog(LOG_ERR
, "mapline_to_mapent: Memory allocation failed");
418 * hierarchical_sort(struct mapent *mapents, hiernode **rootnode, char *key
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
427 hierarchical_sort(struct mapent
*mapents
, hiernode
**rootnode
, char *key
,
430 hiernode
*prevnode
, *currnode
, *newnode
;
432 char dirname
[MAXFILENAMELEN
];
435 struct mapent
*me
= mapents
;
437 /* allocate the rootnode with a default path of "" */
439 if ((rc
= alloc_hiernode(rootnode
, "")) != PARSE_OK
)
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.
451 path
= me
->map_mntpnt
;
453 if ((rc
= get_dir_from_path(dirname
, &path
,
454 sizeof (dirname
))) != PARSE_OK
)
457 prevnode
= *rootnode
;
458 currnode
= (*rootnode
)->subdir
;
460 while (dirname
[0] != '\0') {
461 if (currnode
!= NULL
) {
462 if (strcmp(currnode
->dirname
, dirname
) == 0) {
464 * match found - mntpnt is a child of
468 currnode
= currnode
->subdir
;
471 currnode
= currnode
->leveldir
;
473 if (currnode
== NULL
) {
475 * No more leveldirs to match.
478 if ((rc
= alloc_hiernode
482 prevnode
->leveldir
= newnode
;
484 currnode
= newnode
->subdir
;
486 /* try this leveldir */
491 /* no more subdirs to match. Add a new one */
492 if ((rc
= alloc_hiernode(&newnode
,
493 dirname
)) != PARSE_OK
)
495 prevnode
->subdir
= newnode
;
497 currnode
= newnode
->subdir
;
499 if ((rc
= get_dir_from_path(dirname
, &path
,
500 sizeof (dirname
))) != PARSE_OK
)
504 if (prevnode
->mapent
!= NULL
) {
505 /* duplicate mntpoint found */
507 "hierarchical_sort: duplicate mntpnt map=%s key=%s",
509 return (PARSE_ERROR
);
512 /* provide a pointer from node to mapent */
513 prevnode
->mapent
= me
;
518 trace_prt(1, "\n\thierarchical_sort:\n");
519 trace_hierarchy(*rootnode
, 0); /* 0 is rootnode's level */
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.
536 push_options(hiernode
*node
, char *defaultopts
, char *mapopts
, int err
)
539 struct mapent
*me
= NULL
;
541 /* ensure that all the dirs at a level are passed the default options */
542 while (node
!= NULL
) {
544 if (me
!= NULL
) { /* not all nodes point to a mapentry */
546 if ((rc
= set_mapent_opts(me
, me
->map_mntopts
,
547 defaultopts
, mapopts
)) != PARSE_OK
)
551 /* push the options to subdirs */
552 if (node
->subdir
!= NULL
) {
553 if (node
->mapent
&& strcmp(node
->mapent
->map_fstype
,
554 MNTTYPE_AUTOFS
) == 0)
556 if ((rc
= push_options(node
->subdir
, defaultopts
,
557 mapopts
, err
)) != PARSE_OK
)
560 node
= node
->leveldir
;
565 #define FSTYPE "fstype"
566 #define FSTYPE_EQ "fstype="
570 * set_mapent_opts(struct mapent *me, char *opts, char *defaultopts,
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.
578 set_mapent_opts(struct mapent
*me
, char *opts
, char *defaultopts
,
581 char entryopts
[AUTOFS_MAXOPTSLEN
];
582 char fstype
[MAX_FSLEN
], mounter
[MAX_FSLEN
];
584 bool_t fstype_opt
= FALSE
;
586 strcpy(fstype
, MNTTYPE_NFS
); /* default */
588 /* set options to default options, if none exist for this entry */
591 if (defaultopts
== NULL
) { /* NULL opts for entry */
592 strcpy(mounter
, fstype
);
599 /* separate opts into fstype and (other) entrypopts */
600 get_opts(opts
, entryopts
, fstype
, &fstype_opt
);
602 /* replace any existing opts */
603 free(me
->map_mntopts
);
604 if ((me
->map_mntopts
= strdup(entryopts
)) == NULL
)
606 strcpy(mounter
, fstype
);
609 * child options are exactly fstype = somefs, we need to do some
610 * more option pushing work.
612 if (fstype_opt
== TRUE
&&
613 (strcmp(me
->map_mntopts
, NO_OPTS
) == 0)) {
614 free(me
->map_mntopts
);
615 if ((rc
= fstype_opts(me
, opts
, defaultopts
,
616 mapopts
)) != PARSE_OK
)
621 if (((me
->map_fstype
= strdup(fstype
)) == NULL
) ||
622 ((me
->map_mounter
= strdup(mounter
)) == NULL
)) {
623 free(me
->map_fstype
);
624 syslog(LOG_ERR
, "set_mapent_opts: No memory");
632 * Check the option string for an "fstype"
633 * option. If found, return the fstype
634 * and the option string with the fstype
635 * option removed, e.g.
637 * input: "fstype=nfs,ro,nosuid"
641 * Also indicates if the fstype option was present
642 * by setting a flag, if the pointer to the flag
646 get_opts(input
, opts
, fstype
, fstype_opt
)
648 char *opts
; /* output */
649 char *fstype
; /* output */
653 char buf
[MAXOPTSLEN
];
657 (void) strcpy(buf
, input
);
659 while (p
= (char *)strtok_r(pb
, ",", &placeholder
)) {
661 if (strncmp(p
, FSTYPE_EQ
, 7) == 0) {
662 if (fstype_opt
!= NULL
)
664 (void) strcpy(fstype
, p
+ 7);
667 (void) strcat(opts
, ",");
668 (void) strcat(opts
, p
);
674 * fstype_opts(struct mapent *me, char *opts, char *defaultopts,
676 * We need to push global options to the child entry if it is exactly
680 fstype_opts(struct mapent
*me
, char *opts
, char *defaultopts
,
683 char pushentryopts
[AUTOFS_MAXOPTSLEN
];
684 char pushfstype
[MAX_FSLEN
];
686 if (defaultopts
&& *defaultopts
== '-')
690 * the options to push are the global defaults for the entry,
691 * if they exist, or mapopts, if the global defaults for the
692 * entry does not exist.
694 if (strcmp(defaultopts
, opts
) == 0) {
697 get_opts(mapopts
, pushentryopts
, pushfstype
, NULL
);
699 get_opts(defaultopts
, pushentryopts
, pushfstype
, NULL
);
702 me
->map_mntopts
= strdup(pushentryopts
);
704 if (!me
->map_mntopts
) {
705 syslog(LOG_ERR
, "fstype_opts: No memory");
713 * modify_mapents(struct mapent **mapents, char *mapname,
714 * char *mapopts, char *subdir, hiernode *rootnode,
715 * char *key, uint_t isdirect, bool_t mount_access)
716 * modifies the intermediate mapentry list into the final one, and passes
717 * back a pointer to it. The final list may contain faked mapentries for
718 * hiernodes that do not point to a mapentry, or converted mapentries, if
719 * hiernodes that point to a mapentry need to be converted from nfs to autofs.
720 * mounts. Entries that are not directly 1 level below the subdir are removed.
721 * Returns PARSE_OK or PARSE_ERROR
724 modify_mapents(struct mapent
**mapents
, char *mapname
,
725 char *mapopts
, char *subdir
, hiernode
*rootnode
,
726 char *key
, uint_t isdirect
, bool_t mount_access
)
728 struct mapent
*mp
= NULL
;
733 struct mapent
*faked_mapents
= NULL
;
736 * correct the mapentry mntlevel from default -1 to level depending on
737 * position in hierarchy, and build any faked mapentries, if required
738 * at one level below the rootnode given by subdir.
740 if ((rc
= set_and_fake_mapent_mntlevel(rootnode
, subdir
, key
, mapname
,
741 &faked_mapents
, isdirect
, mapopts
, mount_access
)) != PARSE_OK
)
745 * attaches faked mapents to real mapents list. Assumes mapents
749 while (me
->map_next
!= NULL
)
751 me
->map_next
= faked_mapents
;
754 * get rid of nodes marked at level -1
758 if ((me
->map_mntlevel
== -1) || (me
->map_err
) ||
759 (mount_access
== FALSE
&& me
->map_mntlevel
== 0)) {
761 * syslog any errors and free entry
764 dump_mapent_err(me
, key
, mapname
);
766 if (me
== (*mapents
)) {
767 /* special case when head has to be freed */
768 *mapents
= me
->map_next
;
769 if ((*mapents
) == NULL
) {
770 /* something wierd happened */
773 "modify_mapents: level error");
774 return (PARSE_ERROR
);
777 /* separate out the node */
782 mp
->map_next
= me
->map_next
;
791 * convert level 1 mapents that are not already autonodes
794 if (me
->map_mntlevel
== 1 &&
795 (strcmp(me
->map_fstype
, MNTTYPE_AUTOFS
) != 0) &&
796 (me
->map_faked
!= TRUE
)) {
797 if ((rc
= convert_mapent_to_automount(me
, mapname
,
798 mapopts
)) != PARSE_OK
)
801 strcpy(w
, (me
->map_mntpnt
+strlen(subdir
)));
802 strcpy(me
->map_mntpnt
, w
);
808 trace_mapents("modify_mapents:", *mapents
);
814 * set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key,
815 * char *mapname, struct mapent **faked_mapents,
816 * uint_t isdirect, char *mapopts, bool_t mount_access)
817 * sets the mapentry mount levels (depths) with respect to the subdir.
818 * Assigns a value of 0 to the new root. Finds the level1 directories by
819 * calling mark_*_level1_*(). Also cleans off extra /'s in level0 and
820 * level1 map_mntpnts. Note that one level below the new root is an existing
821 * mapentry if there's a mapentry (nfs mount) corresponding to the root,
822 * and the direct subdir set for the root, if there's no mapentry corresponding
823 * to the root (we install autodirs). Returns PARSE_OK or error value.
826 set_and_fake_mapent_mntlevel(hiernode
*rootnode
, char *subdir
, char *key
,
827 char *mapname
, struct mapent
**faked_mapents
,
828 uint_t isdirect
, char *mapopts
, bool_t mount_access
)
830 char dirname
[MAXFILENAMELEN
];
831 char traversed_path
[MAXPATHLEN
]; /* used in building fake mapentries */
833 char *subdir_child
= subdir
;
834 hiernode
*prevnode
= rootnode
;
835 hiernode
*currnode
= rootnode
->subdir
;
837 traversed_path
[0] = '\0';
840 * find and mark the root by tracing down subdir. Use traversed_path
841 * to keep track of how far we go, while guaranteeing that it
842 * contains no '/' at the end. Took some mucking to get that right.
844 if ((rc
= get_dir_from_path(dirname
, &subdir_child
, sizeof (dirname
)))
848 if (dirname
[0] != '\0')
849 sprintf(traversed_path
, "%s/%s", traversed_path
, dirname
);
852 currnode
= rootnode
->subdir
;
853 while (dirname
[0] != '\0' && currnode
!= NULL
) {
854 if (strcmp(currnode
->dirname
, dirname
) == 0) {
856 /* subdir is a child of currnode */
858 currnode
= currnode
->subdir
;
860 if ((rc
= get_dir_from_path(dirname
, &subdir_child
,
861 sizeof (dirname
))) != PARSE_OK
)
863 if (dirname
[0] != '\0')
864 sprintf(traversed_path
, "%s/%s",
865 traversed_path
, dirname
);
868 /* try next leveldir */
870 currnode
= currnode
->leveldir
;
874 if (dirname
[0] != '\0') {
877 "set_and_fake_mapent_mntlevel: subdir=%s error: map=%s",
879 return (PARSE_ERROR
);
883 * see if level of root really points to a mapent and if
884 * have access to that filessystem - call appropriate
885 * routine to mark level 1 nodes, and build faked entries
887 if (prevnode
->mapent
!= NULL
&& mount_access
== TRUE
) {
889 trace_prt(1, " node mountpoint %s\t travpath=%s\n",
890 prevnode
->mapent
->map_mntpnt
, traversed_path
);
893 * Copy traversed path map_mntpnt to get rid of any extra
894 * '/' the map entry may contain.
896 if (strlen(prevnode
->mapent
->map_mntpnt
) <
897 strlen(traversed_path
)) { /* sanity check */
900 "set_and_fake_mapent_mntlevel: path=%s error",
902 return (PARSE_ERROR
);
904 if (strcmp(prevnode
->mapent
->map_mntpnt
, traversed_path
) != 0)
905 strcpy(prevnode
->mapent
->map_mntpnt
, traversed_path
);
907 prevnode
->mapent
->map_mntlevel
= 0; /* root level is 0 */
908 if (currnode
!= NULL
) {
909 if ((rc
= mark_level1_root(currnode
,
910 traversed_path
)) != PARSE_OK
)
913 } else if (currnode
!= NULL
) {
915 trace_prt(1, " No rootnode, travpath=%s\n",
917 if ((rc
= mark_and_fake_level1_noroot(currnode
,
918 traversed_path
, key
, mapname
, faked_mapents
, isdirect
,
919 mapopts
)) != PARSE_OK
)
924 trace_prt(1, "\n\tset_and_fake_mapent_mntlevel\n");
925 trace_hierarchy(rootnode
, 0);
933 * mark_level1_root(hiernode *node, char *traversed_path)
934 * marks nodes upto one level below the rootnode given by subdir
935 * recursively. Called if rootnode points to a mapent.
936 * In this routine, a level 1 node is considered to be the 1st existing
937 * mapentry below the root node, so there's no faking involved.
938 * Returns PARSE_OK or error value
941 mark_level1_root(hiernode
*node
, char *traversed_path
)
943 /* ensure we touch all leveldirs */
946 * mark node level as 1, if one exists - else walk down
947 * subdirs until we find one.
949 if (node
->mapent
== NULL
) {
952 if (node
->subdir
!= NULL
) {
953 sprintf(w
, "%s/%s", traversed_path
,
955 if (mark_level1_root(node
->subdir
, w
)
957 return (PARSE_ERROR
);
961 "mark_level1_root: hierarchy error");
963 return (PARSE_ERROR
);
968 sprintf(w
, "%s/%s", traversed_path
, node
->dirname
);
970 trace_prt(1, " node mntpnt %s\t travpath %s\n",
971 node
->mapent
->map_mntpnt
, w
);
973 /* replace mntpnt with travpath to clean extra '/' */
974 if (strlen(node
->mapent
->map_mntpnt
) < strlen(w
)) {
977 "mark_level1_root: path=%s error",
980 return (PARSE_ERROR
);
982 if (strcmp(node
->mapent
->map_mntpnt
, w
) != 0)
983 strcpy(node
->mapent
->map_mntpnt
, w
);
984 node
->mapent
->map_mntlevel
= 1;
986 node
= node
->leveldir
;
992 * mark_and_fake_level1_noroot(hiernode *node, char *traversed_path,
993 * char *key,char *mapname, struct mapent **faked_mapents,
994 * uint_t isdirect, char *mapopts)
995 * Called if the root of the hierarchy does not point to a mapent. marks nodes
996 * upto one physical level below the rootnode given by subdir. checks if
997 * there's a real mapentry. If not, it builds a faked one (autonode) at that
998 * point. The faked autonode is direct, with the map being the same as the
999 * original one from which the call originated. Options are same as that of
1000 * the map and assigned in automount_opts(). Returns PARSE_OK or error value.
1003 mark_and_fake_level1_noroot(hiernode
*node
, char *traversed_path
,
1004 char *key
, char *mapname
, struct mapent
**faked_mapents
,
1005 uint_t isdirect
, char *mapopts
)
1009 char faked_map_mntpnt
[MAXPATHLEN
];
1010 char w1
[MAXPATHLEN
];
1013 while (node
!= NULL
) {
1014 if (node
->mapent
!= NULL
) {
1016 * existing mapentry at level 1 - copy travpath to
1017 * get rid of extra '/' in mntpnt
1019 sprintf(w
, "%s/%s", traversed_path
, node
->dirname
);
1021 trace_prt(1, " node mntpnt=%s\t travpath=%s\n",
1022 node
->mapent
->map_mntpnt
, w
);
1023 if (strlen(node
->mapent
->map_mntpnt
) < strlen(w
)) {
1027 "mark_fake_level1_noroot:path=%s error",
1029 return (PARSE_ERROR
);
1031 if (strcmp(node
->mapent
->map_mntpnt
, w
) != 0)
1032 strcpy(node
->mapent
->map_mntpnt
, w
);
1033 node
->mapent
->map_mntlevel
= 1;
1036 * build the faked autonode
1038 if ((me
= (struct mapent
*)malloc(sizeof (*me
)))
1041 "mark_and_fake_level1_noroot: out of memory");
1044 (void) memset((char *)me
, 0, sizeof (*me
));
1046 if ((me
->map_fs
= (struct mapfs
*)
1047 malloc(sizeof (struct mapfs
))) == NULL
)
1049 (void) memset(me
->map_fs
, 0, sizeof (struct mapfs
));
1057 me
->map_root
= strdup(w1
);
1059 sprintf(faked_map_mntpnt
, "%s/%s", traversed_path
,
1061 me
->map_mntpnt
= strdup(faked_map_mntpnt
);
1062 me
->map_fstype
= strdup(MNTTYPE_AUTOFS
);
1063 me
->map_mounter
= strdup(MNTTYPE_AUTOFS
);
1066 if ((rc
= automount_opts(&me
->map_mntopts
, mapopts
))
1069 me
->map_fs
->mfs_dir
= strdup(mapname
);
1070 me
->map_mntlevel
= 1;
1071 me
->map_modified
= FALSE
;
1072 me
->map_faked
= TRUE
; /* mark as faked */
1073 if (me
->map_root
== NULL
||
1074 me
->map_mntpnt
== NULL
||
1075 me
->map_fstype
== NULL
||
1076 me
->map_mounter
== NULL
||
1077 me
->map_mntopts
== NULL
||
1078 me
->map_fs
->mfs_dir
== NULL
) {
1080 "mark_and_fake_level1_noroot: out of memory");
1081 free_mapent(*faked_mapents
);
1085 if (*faked_mapents
== NULL
)
1086 *faked_mapents
= me
;
1087 else { /* attach to the head */
1088 me
->map_next
= *faked_mapents
;
1089 *faked_mapents
= me
;
1093 node
= node
->leveldir
;
1099 * convert_mapent_to_automount(struct mapent *me, char *mapname,
1101 * change the mapentry me to an automount - free fields first and NULL them
1102 * to avoid freeing again, while freeing the mapentry at a later stage.
1103 * Could have avoided freeing entries here as we don't really look at them.
1104 * Give the converted mapent entry the options that came with the map using
1105 * automount_opts(). Returns PARSE_OK or appropriate error value.
1108 convert_mapent_to_automount(struct mapent
*me
, char *mapname
,
1111 struct mapfs
*mfs
= me
->map_fs
; /* assumes it exists */
1114 /* free relevant entries */
1115 if (mfs
->mfs_host
) {
1116 free(mfs
->mfs_host
);
1117 mfs
->mfs_host
= NULL
;
1119 while (me
->map_fs
->mfs_next
!= NULL
) {
1120 mfs
= me
->map_fs
->mfs_next
;
1121 free(mfs
->mfs_host
);
1123 me
->map_fs
->mfs_next
= mfs
->mfs_next
; /* nulls eventually */
1127 /* replace relevant entries */
1128 free(me
->map_fstype
);
1129 if ((me
->map_fstype
= strdup(MNTTYPE_AUTOFS
)) == NULL
)
1132 free(me
->map_mounter
);
1133 if ((me
->map_mounter
= strdup(me
->map_fstype
)) == NULL
)
1136 free(me
->map_fs
->mfs_dir
);
1137 if ((me
->map_fs
->mfs_dir
= strdup(mapname
)) == NULL
)
1141 free(me
->map_mntopts
);
1142 if ((rc
= automount_opts(&me
->map_mntopts
, mapopts
)) != PARSE_OK
)
1145 /* mucked with this entry, set the map_modified field to TRUE */
1146 me
->map_modified
= TRUE
;
1152 "convert_mapent_to_automount: Memory allocation failed");
1157 * automount_opts(char **map_mntopts, char *mapopts)
1158 * modifies automount opts - gets rid of all "indirect" and "direct" strings
1159 * if they exist, and then adds a direct string to force a direct automount.
1160 * Rest of the mapopts stay intact. Returns PARSE_OK or appropriate error.
1163 automount_opts(char **map_mntopts
, char *mapopts
)
1169 char buf
[AUTOFS_MAXOPTSLEN
];
1171 char *addopt
= "direct";
1173 len
= strlen(mapopts
)+ strlen(addopt
)+2; /* +2 for ",", '\0' */
1174 if (len
> AUTOFS_MAXOPTSLEN
) {
1176 "option string %s too long (max=%d)", mapopts
,
1177 AUTOFS_MAXOPTSLEN
-8);
1178 return (PARSE_ERROR
);
1181 if (((*map_mntopts
) = ((char *)malloc(len
))) == NULL
) {
1182 syslog(LOG_ERR
, "automount_opts: Memory allocation failed");
1185 memset(*map_mntopts
, 0, len
);
1187 strcpy(buf
, mapopts
);
1189 while ((opt
= strtok_r(opts
, ",", &placeholder
)) != NULL
) {
1192 /* remove trailing and leading spaces */
1193 while (isspace(*opt
))
1195 len
= strlen(opt
)-1;
1196 while (isspace(opt
[len
]))
1200 * if direct or indirect found, get rid of it, else put it
1203 if ((strcmp(opt
, "indirect") == 0) ||
1204 (strcmp(opt
, "direct") == 0))
1206 if (*map_mntopts
[0] != '\0')
1207 strcat(*map_mntopts
, ",");
1208 strcat(*map_mntopts
, opt
);
1211 /* add the direct string at the end */
1212 if (*map_mntopts
[0] != '\0')
1213 strcat(*map_mntopts
, ",");
1214 strcat(*map_mntopts
, addopt
);
1220 * parse_fsinfo(char *mapname, struct mapent *mapents)
1221 * parses the filesystem information stored in me->map_fsw and me->map_fswq
1222 * and calls appropriate filesystem parser.
1223 * Returns PARSE_OK or an appropriate error value.
1226 parse_fsinfo(char *mapname
, struct mapent
*mapents
)
1228 struct mapent
*me
= mapents
;
1231 int wordsz
= MAXPATHLEN
;
1234 while (me
!= NULL
) {
1237 if (strcmp(me
->map_fstype
, MNTTYPE_NFS
) == 0) {
1238 err
= parse_nfs(mapname
, me
, me
->map_fsw
,
1239 me
->map_fswq
, &bufp
, &bufq
, wordsz
);
1241 err
= parse_special(me
, me
->map_fsw
, me
->map_fswq
,
1242 &bufp
, &bufq
, wordsz
);
1245 if (err
!= PARSE_OK
|| *me
->map_fsw
!= '\0' ||
1246 *me
->map_fswq
!= '\0') {
1250 "parse_fsinfo: mount location error %s",
1252 return (PARSE_ERROR
);
1259 trace_mapents("parse_fsinfo:", mapents
);
1266 * This function parses the map entry for a nfs type file system
1267 * The input is the string lp (and lq) which can be one of the
1269 * a) host[(penalty)][,host[(penalty)]]... :/directory
1270 * b) host[(penalty)]:/directory[ host[(penalty)]:/directory]...
1271 * This routine constructs a mapfs link-list for each of
1272 * the hosts and the corresponding file system. The list
1273 * is then attatched to the mapent struct passed in.
1276 parse_nfs(mapname
, me
, fsw
, fswq
, lp
, lq
, wsize
)
1278 char *mapname
, *fsw
, *fswq
, **lp
, **lq
;
1281 struct mapfs
*mfs
, **mfsp
;
1283 char *hl
, hostlist
[1024], *hlq
, hostlistq
[1024];
1284 char hostname_and_penalty
[MXHOSTNAMELEN
+5];
1285 char *hn
, *hnq
, hostname
[MXHOSTNAMELEN
+1];
1286 char dirname
[MAXPATHLEN
+1], subdir
[MAXPATHLEN
+1];
1287 char qbuff
[MAXPATHLEN
+1], qbuff1
[MAXPATHLEN
+1];
1288 char pbuff
[10], pbuffq
[10];
1291 char wq
[MAXPATHLEN
];
1298 * there may be more than one entry in the map list. Get the
1299 * first one. Use temps to handle the word information and
1300 * copy back into fsw and fswq fields when done.
1304 if (getword(w
, wq
, lp
, lq
, ' ', wsize
) == -1)
1305 return (PARSE_ERROR
);
1306 while (*w
&& *w
!= '/') {
1312 if (getword(hostlist
, hostlistq
, &wlp
, &wlq
, ':',
1313 sizeof (hostlist
)) == -1)
1314 return (PARSE_ERROR
);
1318 if (strcmp(hostlist
, "nfs") != 0)
1321 if (getword(dirname
, qbuff
, &wlp
, &wlq
, ':',
1322 sizeof (dirname
)) == -1)
1323 return (PARSE_ERROR
);
1324 if (*dirname
== '\0')
1327 if (maybe_url
== TRUE
&& strncmp(dirname
, "//", 2) != 0)
1331 * See the next block comment ("Once upon a time ...") to
1332 * understand this. It turns the deprecated concept
1333 * of "subdir mounts" produced some useful code for handling
1334 * the possibility of a ":port#" in the URL.
1336 if (maybe_url
== FALSE
)
1344 * Once upon time, before autofs, there was support for
1345 * "subdir mounts". The idea was to "economize" the
1346 * number of mounts, so if you had a number of entries
1347 * all referring to a common subdirectory, e.g.
1349 * carol seasons:/export/home11/carol
1350 * ted seasons:/export/home11/ted
1351 * alice seasons:/export/home11/alice
1353 * then you could tell the automounter to mount a
1354 * common mountpoint which was delimited by the second
1357 * carol seasons:/export/home11:carol
1358 * ted seasons:/export/home11:ted
1359 * alice seasons:/export/home11:alice
1361 * The automounter would mount seasons:/export/home11
1362 * then for any other map entry that referenced the same
1363 * directory it would build a symbolic link that
1364 * appended the remainder of the path after the second
1365 * colon, i.e. once the common subdir was mounted, then
1366 * other directories could be accessed just by link
1367 * building - no further mounts required.
1369 * In theory the "mount saving" idea sounded good. In
1370 * practice the saving didn't amount to much and the
1371 * symbolic links confused people because the common
1372 * mountpoint had to have a pseudonym.
1374 * To remain backward compatible with the existing
1375 * maps, we interpret a second colon as a slash.
1377 if (getword(subdir
+1, qbuff
+1, &wlp
, &wlq
, ':',
1378 sizeof (subdir
)) == -1)
1379 return (PARSE_ERROR
);
1382 (void) strcat(dirname
, subdir
);
1384 hl
= hostlist
; hlq
= hostlistq
;
1389 if (getword(hostname_and_penalty
, qbuff
, &hl
, &hlq
, ',',
1390 sizeof (hostname_and_penalty
)) == -1)
1391 return (PARSE_ERROR
);
1392 if (!*hostname_and_penalty
)
1399 hn
= hostname_and_penalty
;
1401 if (getword(hostname
, qbuff1
, &hn
, &hnq
, '(',
1402 sizeof (hostname
)) == -1)
1403 return (PARSE_ERROR
);
1404 if (hostname
[0] == '\0')
1407 if (strcmp(hostname
, hostname_and_penalty
) == 0) {
1412 if (getword(pbuff
, pbuffq
, &hn
, &hnq
, ')',
1413 sizeof (pbuff
)) == -1)
1414 return (PARSE_ERROR
);
1418 penalty
= atoi(pbuff
);
1420 mfs
= (struct mapfs
*)malloc(sizeof (*mfs
));
1423 "parse_nfs: Memory allocation failed");
1424 return (PARSE_ERROR
);
1426 (void) memset(mfs
, 0, sizeof (*mfs
));
1428 mfsp
= &mfs
->mfs_next
;
1430 if (maybe_url
== TRUE
) {
1436 path
= strchr(host
, '/');
1439 "parse_nfs: illegal nfs url syntax: %s",
1442 return (PARSE_ERROR
);
1445 sport
= strchr(host
, ':');
1447 if (sport
!= NULL
&& sport
< path
) {
1449 mfs
->mfs_port
= atoi(sport
+1);
1451 if (mfs
->mfs_port
> USHRT_MAX
) {
1453 "parse_nfs: invalid "
1454 "port number (%d) in "
1458 return (PARSE_ERROR
);
1467 mfs
->mfs_flags
|= MFS_URL
;
1469 mfs
->mfs_host
= strdup(host
);
1470 mfs
->mfs_dir
= strdup(path
);
1472 mfs
->mfs_host
= strdup(hostname
);
1473 mfs
->mfs_dir
= strdup(dirname
);
1476 mfs
->mfs_penalty
= penalty
;
1477 if (mfs
->mfs_host
== NULL
|| mfs
->mfs_dir
== NULL
) {
1479 "parse_nfs: Memory allocation failed");
1480 return (PARSE_ERROR
);
1484 * We check host_cnt to make sure we haven't parsed an entry
1485 * with no host information.
1487 if (host_cnt
== 0) {
1489 "parse_nfs: invalid host specified - bad entry "
1492 return (PARSE_ERROR
);
1494 if (getword(w
, wq
, lp
, lq
, ' ', wsize
) == -1)
1495 return (PARSE_ERROR
);
1504 syslog(LOG_ERR
, "parse_nfs: bad entry in map %s \"%s\"", mapname
, w
);
1505 return (PARSE_ERROR
);
1509 parse_special(me
, w
, wq
, lp
, lq
, wsize
)
1511 char *w
, *wq
, **lp
, **lq
;
1514 char devname
[MAXPATHLEN
+ 1], qbuf
[MAXPATHLEN
+ 1];
1520 if (getword(devname
, qbuf
, &wlp
, &wlq
, ' ', sizeof (devname
)) == -1)
1521 return (PARSE_ERROR
);
1522 if (devname
[0] == '\0')
1523 return (PARSE_ERROR
);
1525 mfs
= (struct mapfs
*)malloc(sizeof (struct mapfs
));
1527 return (PARSE_ERROR
);
1528 (void) memset(mfs
, 0, sizeof (*mfs
));
1531 * A device name that begins with a slash could
1532 * be confused with a mountpoint path, hence use
1533 * a colon to escape a device string that begins
1534 * with a slash, e.g.
1536 * foo -ro /bar foo:/bar
1540 * would confuse the parser. The second instance
1545 mfs
->mfs_dir
= strdup(&devname
[devname
[0] == ':']);
1546 if (mfs
->mfs_dir
== NULL
)
1547 return (PARSE_ERROR
);
1549 if (getword(w
, wq
, lp
, lq
, ' ', wsize
) == -1)
1550 return (PARSE_ERROR
);
1555 * get_dir_from_path(char *dir, char **path, int dirsz)
1556 * gets the directory name dir from path for max string of length dirsz.
1557 * A modification of the getword routine. Assumes the delimiter is '/'
1558 * and that excess /'s are redundant.
1559 * Returns PARSE_OK or PARSE_ERROR
1562 get_dir_from_path(char *dir
, char **path
, int dirsz
)
1570 "get_dir_from_path: invalid directory size %d", dirsz
);
1571 return (PARSE_ERROR
);
1574 /* get rid of leading /'s in path */
1575 while (**path
== '/')
1578 /* now at a word or at the end of path */
1579 while ((**path
) && ((**path
) != '/')) {
1583 "get_dir_from_path: max pathlength exceeded %d", dirsz
);
1584 return (PARSE_ERROR
);
1586 *dir
++ = *(*path
)++;
1591 /* get rid of trailing /'s in path */
1592 while (**path
== '/')
1599 * alloc_hiernode(hiernode **newnode, char *dirname)
1600 * allocates a new hiernode corresponding to a new directory entry
1601 * in the hierarchical structure, and passes a pointer to it back
1602 * to the calling program.
1603 * Returns PARSE_OK or appropriate error value.
1606 alloc_hiernode(hiernode
**newnode
, char *dirname
)
1608 if ((*newnode
= (hiernode
*)malloc(sizeof (hiernode
))) == NULL
) {
1609 syslog(LOG_ERR
, "alloc_hiernode: Memory allocation failed");
1613 memset(((char *)*newnode
), 0, sizeof (hiernode
));
1614 strcpy(((*newnode
)->dirname
), dirname
);
1619 * free_hiernode(hiernode *node)
1620 * frees the allocated hiernode given the head of the structure
1621 * recursively calls itself until it frees entire structure.
1625 free_hiernode(hiernode
*node
)
1627 hiernode
*currnode
= node
;
1628 hiernode
*prevnode
= NULL
;
1630 while (currnode
!= NULL
) {
1631 if (currnode
->subdir
!= NULL
)
1632 free_hiernode(currnode
->subdir
);
1633 prevnode
= currnode
;
1634 currnode
= currnode
->leveldir
;
1635 free((void*)prevnode
);
1640 * free_mapent(struct mapent *)
1641 * free the mapentry and its fields
1651 while (me
->map_fs
) {
1653 free(mfs
->mfs_host
);
1655 free(mfs
->mfs_args
);
1657 freenetconfigent(mfs
->mfs_nconf
);
1658 me
->map_fs
= mfs
->mfs_next
;
1663 free(me
->map_mntpnt
);
1664 free(me
->map_mntopts
);
1665 free(me
->map_fstype
);
1666 free(me
->map_mounter
);
1677 * trace_mapents(struct mapent *mapents)
1678 * traces through the mapentry structure and prints it element by element
1682 trace_mapents(char *s
, struct mapent
*mapents
)
1687 trace_prt(1, "\n\t%s\n", s
);
1688 for (me
= mapents
; me
; me
= me
->map_next
) {
1689 trace_prt(1, " (%s,%s)\t %s%s -%s\n",
1690 me
->map_fstype
? me
->map_fstype
: "",
1691 me
->map_mounter
? me
->map_mounter
: "",
1692 me
->map_root
? me
->map_root
: "",
1693 me
->map_mntpnt
? me
->map_mntpnt
: "",
1694 me
->map_mntopts
? me
->map_mntopts
: "");
1695 for (mfs
= me
->map_fs
; mfs
; mfs
= mfs
->mfs_next
)
1696 trace_prt(0, "\t\t%s:%s\n",
1697 mfs
->mfs_host
? mfs
->mfs_host
: "",
1698 mfs
->mfs_dir
? mfs
->mfs_dir
: "");
1700 trace_prt(1, "\tme->map_fsw=%s\n",
1701 me
->map_fsw
? me
->map_fsw
:"",
1702 me
->map_fswq
? me
->map_fsw
:"");
1703 trace_prt(1, "\t mntlevel=%d\t%s\t%s err=%d\n",
1705 me
->map_modified
? "modify=TRUE":"modify=FALSE",
1706 me
->map_faked
? "faked=TRUE":"faked=FALSE",
1712 * trace_hierarchy(hiernode *node)
1713 * traces the allocated hiernode given the head of the structure
1714 * recursively calls itself until it traces entire structure.
1715 * the first call made at the root is made with a zero level.
1716 * nodelevel is simply used to print tab and make the tracing clean.
1720 trace_hierarchy(hiernode
*node
, int nodelevel
)
1722 hiernode
*currnode
= node
;
1725 while (currnode
!= NULL
) {
1726 if (currnode
->subdir
!= NULL
) {
1727 for (i
= 0; i
< nodelevel
; i
++)
1729 trace_prt(0, "\t(%s, ",
1730 currnode
->dirname
? currnode
->dirname
:"");
1731 if (currnode
->mapent
) {
1732 trace_prt(0, "%d, %s)\n",
1733 currnode
->mapent
->map_mntlevel
,
1734 currnode
->mapent
->map_mntopts
?
1735 currnode
->mapent
->map_mntopts
:"");
1738 trace_prt(0, " ,)\n");
1740 trace_hierarchy(currnode
->subdir
, nodelevel
);
1742 for (i
= 0; i
< nodelevel
; i
++)
1744 trace_prt(0, "\t(%s, ",
1745 currnode
->dirname
? currnode
->dirname
:"");
1746 if (currnode
->mapent
) {
1747 trace_prt(0, "%d, %s)\n",
1748 currnode
->mapent
->map_mntlevel
,
1749 currnode
->mapent
->map_mntopts
?
1750 currnode
->mapent
->map_mntopts
:"");
1753 trace_prt(0, ", )\n");
1755 currnode
= currnode
->leveldir
;
1760 do_mapent_hosts(mapopts
, host
, isdirect
)
1761 char *mapopts
, *host
;
1765 struct mapent
*me
, *ms
, *mp
;
1767 struct exportnode
*ex
= NULL
;
1768 struct exportnode
*exlist
, *texlist
, **texp
, *exnext
;
1769 struct timeval timeout
;
1770 enum clnt_stat clnt_stat
;
1771 char name
[MAXPATHLEN
];
1772 char entryopts
[MAXOPTSLEN
];
1773 char fstype
[32], mounter
[32];
1774 int exlen
, duplicate
;
1775 struct mnttab mb
; /* needed for hasmntopt() to get nfs version */
1776 rpcvers_t nfsvers
; /* version in map options, 0 if not there */
1777 rpcvers_t vers
, versmin
; /* used to negotiate nfs vers in pingnfs() */
1782 trace_prt(1, " do_mapent_hosts: host %s\n", host
);
1784 /* check for special case: host is me */
1786 if (self_check(host
)) {
1787 ms
= (struct mapent
*)malloc(sizeof (*ms
));
1790 (void) memset((char *)ms
, 0, sizeof (*ms
));
1791 (void) strcpy(fstype
, MNTTYPE_NFS
);
1792 get_opts(mapopts
, entryopts
, fstype
, NULL
);
1793 ms
->map_mntopts
= strdup(entryopts
);
1794 if (ms
->map_mntopts
== NULL
)
1796 ms
->map_mounter
= strdup(fstype
);
1797 if (ms
->map_mounter
== NULL
)
1799 ms
->map_fstype
= strdup(MNTTYPE_NFS
);
1800 if (ms
->map_fstype
== NULL
)
1806 (void) strcpy(name
, "/");
1807 (void) strcat(name
, host
);
1809 ms
->map_root
= strdup(name
);
1810 if (ms
->map_root
== NULL
)
1812 ms
->map_mntpnt
= strdup("");
1813 if (ms
->map_mntpnt
== NULL
)
1815 mfs
= (struct mapfs
*)malloc(sizeof (*mfs
));
1818 (void) memset((char *)mfs
, 0, sizeof (*mfs
));
1820 mfs
->mfs_host
= strdup(host
);
1821 if (mfs
->mfs_host
== NULL
)
1823 mfs
->mfs_dir
= strdup("/");
1824 if (mfs
->mfs_dir
== NULL
)
1827 /* initialize mntlevel and modify */
1828 ms
->map_mntlevel
= -1;
1829 ms
->map_modified
= FALSE
;
1830 ms
->map_faked
= FALSE
;
1834 " do_mapent_hosts: self-host %s OK\n", host
);
1840 * Call pingnfs. Note that we can't have replicated hosts in /net.
1841 * XXX - we would like to avoid duplicating the across the wire calls
1842 * made here in nfsmount(). The pingnfs cache should help avoid it.
1844 mb
.mnt_mntopts
= mapopts
;
1845 foundvers
= nopt(&mb
, MNTOPT_VERS
, (int *)&nfsvers
);
1848 if (set_versrange(nfsvers
, &vers
, &versmin
) != 0) {
1849 syslog(LOG_ERR
, "Incorrect NFS version specified for %s", host
);
1852 if (pingnfs(host
, get_retry(mapopts
) + 1, &vers
, versmin
, 0, FALSE
,
1853 NULL
, NULL
) != RPC_SUCCESS
)
1856 retries
= get_retry(mapopts
);
1859 /* get export list of host */
1860 cl
= clnt_create(host
, MOUNTPROG
, MOUNTVERS
, "circuit_v");
1862 cl
= clnt_create(host
, MOUNTPROG
, MOUNTVERS
, "datagram_v");
1865 "do_mapent_hosts: %s %s", host
, clnt_spcreateerror(""));
1871 add_alloc("CLNT_HANDLE", cl
, 0, __FILE__
, __LINE__
);
1872 add_alloc("AUTH_HANDLE", cl
->cl_auth
, 0,
1873 __FILE__
, __LINE__
);
1876 timeout
.tv_usec
= 0;
1877 timeout
.tv_sec
= 25;
1878 if (clnt_stat
= clnt_call(cl
, MOUNTPROC_EXPORT
, xdr_void
, 0,
1879 xdr_exports
, (caddr_t
)&ex
, timeout
)) {
1881 if (retries
-- > 0) {
1888 "do_mapent_hosts: %s: export list: %s",
1889 host
, clnt_sperrno(clnt_stat
));
1891 drop_alloc("CLNT_HANDLE", cl
, __FILE__
, __LINE__
);
1892 drop_alloc("AUTH_HANDLE", cl
->cl_auth
,
1893 __FILE__
, __LINE__
);
1900 drop_alloc("CLNT_HANDLE", cl
, __FILE__
, __LINE__
);
1901 drop_alloc("AUTH_HANDLE", cl
->cl_auth
,
1902 __FILE__
, __LINE__
);
1909 gettext(" getmapent_hosts: null export list\n"));
1913 /* now sort by length of names - to get mount order right */
1916 for (; ex
; ex
= exnext
) {
1917 exnext
= ex
->ex_next
;
1918 exlen
= strlen(ex
->ex_dir
);
1920 for (texp
= &texlist
; *texp
; texp
= &((*texp
)->ex_next
)) {
1921 if (exlen
< (int)strlen((*texp
)->ex_dir
))
1923 duplicate
= (strcmp(ex
->ex_dir
, (*texp
)->ex_dir
) == 0);
1925 /* disregard duplicate entry */
1931 ex
->ex_next
= *texp
;
1937 (void) strcpy(fstype
, MNTTYPE_NFS
);
1938 get_opts(mapopts
, entryopts
, fstype
, NULL
);
1939 (void) strcpy(mounter
, fstype
);
1941 /* Now create a mapent from the export list */
1945 for (ex
= exlist
; ex
; ex
= ex
->ex_next
) {
1947 me
= (struct mapent
*)malloc(sizeof (*me
));
1950 (void) memset((char *)me
, 0, sizeof (*me
));
1960 (void) strcpy(name
, "/");
1961 (void) strcat(name
, host
);
1963 me
->map_root
= strdup(name
);
1964 if (me
->map_root
== NULL
)
1968 if (strcmp(ex
->ex_dir
, "/") != 0) {
1969 if (*(ex
->ex_dir
) != '/')
1970 (void) strcpy(name
, "/");
1971 (void) strcat(name
, ex
->ex_dir
);
1973 me
->map_mntpnt
= strdup(name
);
1974 if (me
->map_mntpnt
== NULL
)
1977 me
->map_fstype
= strdup(fstype
);
1978 if (me
->map_fstype
== NULL
)
1980 me
->map_mounter
= strdup(mounter
);
1981 if (me
->map_mounter
== NULL
)
1983 me
->map_mntopts
= strdup(entryopts
);
1984 if (me
->map_mntopts
== NULL
)
1987 mfs
= (struct mapfs
*)malloc(sizeof (*mfs
));
1990 (void) memset((char *)mfs
, 0, sizeof (*mfs
));
1992 mfs
->mfs_host
= strdup(host
);
1993 if (mfs
->mfs_host
== NULL
)
1995 mfs
->mfs_dir
= strdup(ex
->ex_dir
);
1996 if (mfs
->mfs_dir
== NULL
)
1999 /* initialize mntlevel and modify values */
2000 me
->map_mntlevel
= -1;
2001 me
->map_modified
= FALSE
;
2002 me
->map_faked
= FALSE
;
2007 trace_prt(1, " do_mapent_hosts: host %s OK\n", host
);
2012 syslog(LOG_ERR
, "do_mapent_hosts: Memory allocation failed");
2021 struct exportnode
*ex
;
2023 struct groupnode
*groups
, *tmpgroups
;
2026 groups
= ex
->ex_groups
;
2028 free(groups
->gr_name
);
2029 tmpgroups
= groups
->gr_next
;
2030 free((char *)groups
);
2038 struct exportnode
*ex
;
2040 struct exportnode
*tmpex
;
2043 tmpex
= ex
->ex_next
;
2049 static const char uatfs_err
[] = "submount under fstype=autofs not supported";
2051 * dump_mapent_err(struct mapent *me, char *key, char *mapname)
2052 * syslog appropriate error in mapentries.
2054 static void dump_mapent_err(struct mapent
*me
, char *key
, char *mapname
)
2056 switch (me
->map_err
) {
2060 "map=%s key=%s mntpnt=%s: no error");
2064 "mountpoint %s in map %s key %s not mounted: %s",
2065 me
->map_mntpnt
, mapname
, key
, uatfs_err
);
2070 "map=%s key=%s mntpnt=%s: unknown mapentry error");