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
);
140 return ((struct mapent
*)NULL
);
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
);
216 return ((struct mapent
*)NULL
);
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 if (me
->map_mntopts
!= NULL
)
604 free(me
->map_mntopts
);
605 if ((me
->map_mntopts
= strdup(entryopts
)) == NULL
)
607 strcpy(mounter
, fstype
);
610 * child options are exactly fstype = somefs, we need to do some
611 * more option pushing work.
613 if (fstype_opt
== TRUE
&&
614 (strcmp(me
->map_mntopts
, NO_OPTS
) == 0)) {
615 free(me
->map_mntopts
);
616 if ((rc
= fstype_opts(me
, opts
, defaultopts
,
617 mapopts
)) != PARSE_OK
)
622 if (((me
->map_fstype
= strdup(fstype
)) == NULL
) ||
623 ((me
->map_mounter
= strdup(mounter
)) == NULL
)) {
624 if (me
->map_fstype
!= NULL
)
625 free(me
->map_fstype
);
626 syslog(LOG_ERR
, "set_mapent_opts: No memory");
634 * Check the option string for an "fstype"
635 * option. If found, return the fstype
636 * and the option string with the fstype
637 * option removed, e.g.
639 * input: "fstype=nfs,ro,nosuid"
643 * Also indicates if the fstype option was present
644 * by setting a flag, if the pointer to the flag
648 get_opts(input
, opts
, fstype
, fstype_opt
)
650 char *opts
; /* output */
651 char *fstype
; /* output */
655 char buf
[MAXOPTSLEN
];
659 (void) strcpy(buf
, input
);
661 while (p
= (char *)strtok_r(pb
, ",", &placeholder
)) {
663 if (strncmp(p
, FSTYPE_EQ
, 7) == 0) {
664 if (fstype_opt
!= NULL
)
666 (void) strcpy(fstype
, p
+ 7);
669 (void) strcat(opts
, ",");
670 (void) strcat(opts
, p
);
676 * fstype_opts(struct mapent *me, char *opts, char *defaultopts,
678 * We need to push global options to the child entry if it is exactly
682 fstype_opts(struct mapent
*me
, char *opts
, char *defaultopts
,
685 char pushentryopts
[AUTOFS_MAXOPTSLEN
];
686 char pushfstype
[MAX_FSLEN
];
688 if (defaultopts
&& *defaultopts
== '-')
692 * the options to push are the global defaults for the entry,
693 * if they exist, or mapopts, if the global defaults for the
694 * entry does not exist.
696 if (strcmp(defaultopts
, opts
) == 0) {
699 get_opts(mapopts
, pushentryopts
, pushfstype
, NULL
);
701 get_opts(defaultopts
, pushentryopts
, pushfstype
, NULL
);
704 me
->map_mntopts
= strdup(pushentryopts
);
706 if (!me
->map_mntopts
) {
707 syslog(LOG_ERR
, "fstype_opts: No memory");
715 * modify_mapents(struct mapent **mapents, char *mapname,
716 * char *mapopts, char *subdir, hiernode *rootnode,
717 * char *key, uint_t isdirect, bool_t mount_access)
718 * modifies the intermediate mapentry list into the final one, and passes
719 * back a pointer to it. The final list may contain faked mapentries for
720 * hiernodes that do not point to a mapentry, or converted mapentries, if
721 * hiernodes that point to a mapentry need to be converted from nfs to autofs.
722 * mounts. Entries that are not directly 1 level below the subdir are removed.
723 * Returns PARSE_OK or PARSE_ERROR
726 modify_mapents(struct mapent
**mapents
, char *mapname
,
727 char *mapopts
, char *subdir
, hiernode
*rootnode
,
728 char *key
, uint_t isdirect
, bool_t mount_access
)
730 struct mapent
*mp
= NULL
;
735 struct mapent
*faked_mapents
= NULL
;
738 * correct the mapentry mntlevel from default -1 to level depending on
739 * position in hierarchy, and build any faked mapentries, if required
740 * at one level below the rootnode given by subdir.
742 if ((rc
= set_and_fake_mapent_mntlevel(rootnode
, subdir
, key
, mapname
,
743 &faked_mapents
, isdirect
, mapopts
, mount_access
)) != PARSE_OK
)
747 * attaches faked mapents to real mapents list. Assumes mapents
751 while (me
->map_next
!= NULL
)
753 me
->map_next
= faked_mapents
;
756 * get rid of nodes marked at level -1
760 if ((me
->map_mntlevel
== -1) || (me
->map_err
) ||
761 (mount_access
== FALSE
&& me
->map_mntlevel
== 0)) {
763 * syslog any errors and free entry
766 dump_mapent_err(me
, key
, mapname
);
768 if (me
== (*mapents
)) {
769 /* special case when head has to be freed */
770 *mapents
= me
->map_next
;
771 if ((*mapents
) == NULL
) {
772 /* something wierd happened */
775 "modify_mapents: level error");
776 return (PARSE_ERROR
);
779 /* separate out the node */
784 mp
->map_next
= me
->map_next
;
793 * convert level 1 mapents that are not already autonodes
796 if (me
->map_mntlevel
== 1 &&
797 (strcmp(me
->map_fstype
, MNTTYPE_AUTOFS
) != 0) &&
798 (me
->map_faked
!= TRUE
)) {
799 if ((rc
= convert_mapent_to_automount(me
, mapname
,
800 mapopts
)) != PARSE_OK
)
803 strcpy(w
, (me
->map_mntpnt
+strlen(subdir
)));
804 strcpy(me
->map_mntpnt
, w
);
810 trace_mapents("modify_mapents:", *mapents
);
816 * set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key,
817 * char *mapname, struct mapent **faked_mapents,
818 * uint_t isdirect, char *mapopts, bool_t mount_access)
819 * sets the mapentry mount levels (depths) with respect to the subdir.
820 * Assigns a value of 0 to the new root. Finds the level1 directories by
821 * calling mark_*_level1_*(). Also cleans off extra /'s in level0 and
822 * level1 map_mntpnts. Note that one level below the new root is an existing
823 * mapentry if there's a mapentry (nfs mount) corresponding to the root,
824 * and the direct subdir set for the root, if there's no mapentry corresponding
825 * to the root (we install autodirs). Returns PARSE_OK or error value.
828 set_and_fake_mapent_mntlevel(hiernode
*rootnode
, char *subdir
, char *key
,
829 char *mapname
, struct mapent
**faked_mapents
,
830 uint_t isdirect
, char *mapopts
, bool_t mount_access
)
832 char dirname
[MAXFILENAMELEN
];
833 char traversed_path
[MAXPATHLEN
]; /* used in building fake mapentries */
835 char *subdir_child
= subdir
;
836 hiernode
*prevnode
= rootnode
;
837 hiernode
*currnode
= rootnode
->subdir
;
839 traversed_path
[0] = '\0';
842 * find and mark the root by tracing down subdir. Use traversed_path
843 * to keep track of how far we go, while guaranteeing that it
844 * contains no '/' at the end. Took some mucking to get that right.
846 if ((rc
= get_dir_from_path(dirname
, &subdir_child
, sizeof (dirname
)))
850 if (dirname
[0] != '\0')
851 sprintf(traversed_path
, "%s/%s", traversed_path
, dirname
);
854 currnode
= rootnode
->subdir
;
855 while (dirname
[0] != '\0' && currnode
!= NULL
) {
856 if (strcmp(currnode
->dirname
, dirname
) == 0) {
858 /* subdir is a child of currnode */
860 currnode
= currnode
->subdir
;
862 if ((rc
= get_dir_from_path(dirname
, &subdir_child
,
863 sizeof (dirname
))) != PARSE_OK
)
865 if (dirname
[0] != '\0')
866 sprintf(traversed_path
, "%s/%s",
867 traversed_path
, dirname
);
870 /* try next leveldir */
872 currnode
= currnode
->leveldir
;
876 if (dirname
[0] != '\0') {
879 "set_and_fake_mapent_mntlevel: subdir=%s error: map=%s",
881 return (PARSE_ERROR
);
885 * see if level of root really points to a mapent and if
886 * have access to that filessystem - call appropriate
887 * routine to mark level 1 nodes, and build faked entries
889 if (prevnode
->mapent
!= NULL
&& mount_access
== TRUE
) {
891 trace_prt(1, " node mountpoint %s\t travpath=%s\n",
892 prevnode
->mapent
->map_mntpnt
, traversed_path
);
895 * Copy traversed path map_mntpnt to get rid of any extra
896 * '/' the map entry may contain.
898 if (strlen(prevnode
->mapent
->map_mntpnt
) <
899 strlen(traversed_path
)) { /* sanity check */
902 "set_and_fake_mapent_mntlevel: path=%s error",
904 return (PARSE_ERROR
);
906 if (strcmp(prevnode
->mapent
->map_mntpnt
, traversed_path
) != 0)
907 strcpy(prevnode
->mapent
->map_mntpnt
, traversed_path
);
909 prevnode
->mapent
->map_mntlevel
= 0; /* root level is 0 */
910 if (currnode
!= NULL
) {
911 if ((rc
= mark_level1_root(currnode
,
912 traversed_path
)) != PARSE_OK
)
915 } else if (currnode
!= NULL
) {
917 trace_prt(1, " No rootnode, travpath=%s\n",
919 if ((rc
= mark_and_fake_level1_noroot(currnode
,
920 traversed_path
, key
, mapname
, faked_mapents
, isdirect
,
921 mapopts
)) != PARSE_OK
)
926 trace_prt(1, "\n\tset_and_fake_mapent_mntlevel\n");
927 trace_hierarchy(rootnode
, 0);
935 * mark_level1_root(hiernode *node, char *traversed_path)
936 * marks nodes upto one level below the rootnode given by subdir
937 * recursively. Called if rootnode points to a mapent.
938 * In this routine, a level 1 node is considered to be the 1st existing
939 * mapentry below the root node, so there's no faking involved.
940 * Returns PARSE_OK or error value
943 mark_level1_root(hiernode
*node
, char *traversed_path
)
945 /* ensure we touch all leveldirs */
948 * mark node level as 1, if one exists - else walk down
949 * subdirs until we find one.
951 if (node
->mapent
== NULL
) {
954 if (node
->subdir
!= NULL
) {
955 sprintf(w
, "%s/%s", traversed_path
,
957 if (mark_level1_root(node
->subdir
, w
)
959 return (PARSE_ERROR
);
963 "mark_level1_root: hierarchy error");
965 return (PARSE_ERROR
);
970 sprintf(w
, "%s/%s", traversed_path
, node
->dirname
);
972 trace_prt(1, " node mntpnt %s\t travpath %s\n",
973 node
->mapent
->map_mntpnt
, w
);
975 /* replace mntpnt with travpath to clean extra '/' */
976 if (strlen(node
->mapent
->map_mntpnt
) < strlen(w
)) {
979 "mark_level1_root: path=%s error",
982 return (PARSE_ERROR
);
984 if (strcmp(node
->mapent
->map_mntpnt
, w
) != 0)
985 strcpy(node
->mapent
->map_mntpnt
, w
);
986 node
->mapent
->map_mntlevel
= 1;
988 node
= node
->leveldir
;
994 * mark_and_fake_level1_noroot(hiernode *node, char *traversed_path,
995 * char *key,char *mapname, struct mapent **faked_mapents,
996 * uint_t isdirect, char *mapopts)
997 * Called if the root of the hierarchy does not point to a mapent. marks nodes
998 * upto one physical level below the rootnode given by subdir. checks if
999 * there's a real mapentry. If not, it builds a faked one (autonode) at that
1000 * point. The faked autonode is direct, with the map being the same as the
1001 * original one from which the call originated. Options are same as that of
1002 * the map and assigned in automount_opts(). Returns PARSE_OK or error value.
1005 mark_and_fake_level1_noroot(hiernode
*node
, char *traversed_path
,
1006 char *key
, char *mapname
, struct mapent
**faked_mapents
,
1007 uint_t isdirect
, char *mapopts
)
1011 char faked_map_mntpnt
[MAXPATHLEN
];
1012 char w1
[MAXPATHLEN
];
1015 while (node
!= NULL
) {
1016 if (node
->mapent
!= NULL
) {
1018 * existing mapentry at level 1 - copy travpath to
1019 * get rid of extra '/' in mntpnt
1021 sprintf(w
, "%s/%s", traversed_path
, node
->dirname
);
1023 trace_prt(1, " node mntpnt=%s\t travpath=%s\n",
1024 node
->mapent
->map_mntpnt
, w
);
1025 if (strlen(node
->mapent
->map_mntpnt
) < strlen(w
)) {
1029 "mark_fake_level1_noroot:path=%s error",
1031 return (PARSE_ERROR
);
1033 if (strcmp(node
->mapent
->map_mntpnt
, w
) != 0)
1034 strcpy(node
->mapent
->map_mntpnt
, w
);
1035 node
->mapent
->map_mntlevel
= 1;
1038 * build the faked autonode
1040 if ((me
= (struct mapent
*)malloc(sizeof (*me
)))
1043 "mark_and_fake_level1_noroot: out of memory");
1046 (void) memset((char *)me
, 0, sizeof (*me
));
1048 if ((me
->map_fs
= (struct mapfs
*)
1049 malloc(sizeof (struct mapfs
))) == NULL
)
1051 (void) memset(me
->map_fs
, 0, sizeof (struct mapfs
));
1059 me
->map_root
= strdup(w1
);
1061 sprintf(faked_map_mntpnt
, "%s/%s", traversed_path
,
1063 me
->map_mntpnt
= strdup(faked_map_mntpnt
);
1064 me
->map_fstype
= strdup(MNTTYPE_AUTOFS
);
1065 me
->map_mounter
= strdup(MNTTYPE_AUTOFS
);
1068 if ((rc
= automount_opts(&me
->map_mntopts
, mapopts
))
1071 me
->map_fs
->mfs_dir
= strdup(mapname
);
1072 me
->map_mntlevel
= 1;
1073 me
->map_modified
= FALSE
;
1074 me
->map_faked
= TRUE
; /* mark as faked */
1075 if (me
->map_root
== NULL
||
1076 me
->map_mntpnt
== NULL
||
1077 me
->map_fstype
== NULL
||
1078 me
->map_mounter
== NULL
||
1079 me
->map_mntopts
== NULL
||
1080 me
->map_fs
->mfs_dir
== NULL
) {
1082 "mark_and_fake_level1_noroot: out of memory");
1083 free_mapent(*faked_mapents
);
1087 if (*faked_mapents
== NULL
)
1088 *faked_mapents
= me
;
1089 else { /* attach to the head */
1090 me
->map_next
= *faked_mapents
;
1091 *faked_mapents
= me
;
1095 node
= node
->leveldir
;
1101 * convert_mapent_to_automount(struct mapent *me, char *mapname,
1103 * change the mapentry me to an automount - free fields first and NULL them
1104 * to avoid freeing again, while freeing the mapentry at a later stage.
1105 * Could have avoided freeing entries here as we don't really look at them.
1106 * Give the converted mapent entry the options that came with the map using
1107 * automount_opts(). Returns PARSE_OK or appropriate error value.
1110 convert_mapent_to_automount(struct mapent
*me
, char *mapname
,
1113 struct mapfs
*mfs
= me
->map_fs
; /* assumes it exists */
1116 /* free relevant entries */
1117 if (mfs
->mfs_host
) {
1118 free(mfs
->mfs_host
);
1119 mfs
->mfs_host
= NULL
;
1121 while (me
->map_fs
->mfs_next
!= NULL
) {
1122 mfs
= me
->map_fs
->mfs_next
;
1124 free(mfs
->mfs_host
);
1127 me
->map_fs
->mfs_next
= mfs
->mfs_next
; /* nulls eventually */
1131 /* replace relevant entries */
1133 free(me
->map_fstype
);
1134 if ((me
->map_fstype
= strdup(MNTTYPE_AUTOFS
)) == NULL
)
1137 if (me
->map_mounter
)
1138 free(me
->map_mounter
);
1139 if ((me
->map_mounter
= strdup(me
->map_fstype
)) == NULL
)
1142 if (me
->map_fs
->mfs_dir
)
1143 free(me
->map_fs
->mfs_dir
);
1144 if ((me
->map_fs
->mfs_dir
= strdup(mapname
)) == NULL
)
1148 if (me
->map_mntopts
)
1149 free(me
->map_mntopts
);
1150 if ((rc
= automount_opts(&me
->map_mntopts
, mapopts
)) != PARSE_OK
)
1153 /* mucked with this entry, set the map_modified field to TRUE */
1154 me
->map_modified
= TRUE
;
1160 "convert_mapent_to_automount: Memory allocation failed");
1165 * automount_opts(char **map_mntopts, char *mapopts)
1166 * modifies automount opts - gets rid of all "indirect" and "direct" strings
1167 * if they exist, and then adds a direct string to force a direct automount.
1168 * Rest of the mapopts stay intact. Returns PARSE_OK or appropriate error.
1171 automount_opts(char **map_mntopts
, char *mapopts
)
1177 char buf
[AUTOFS_MAXOPTSLEN
];
1179 char *addopt
= "direct";
1181 len
= strlen(mapopts
)+ strlen(addopt
)+2; /* +2 for ",", '\0' */
1182 if (len
> AUTOFS_MAXOPTSLEN
) {
1184 "option string %s too long (max=%d)", mapopts
,
1185 AUTOFS_MAXOPTSLEN
-8);
1186 return (PARSE_ERROR
);
1189 if (((*map_mntopts
) = ((char *)malloc(len
))) == NULL
) {
1190 syslog(LOG_ERR
, "automount_opts: Memory allocation failed");
1193 memset(*map_mntopts
, 0, len
);
1195 strcpy(buf
, mapopts
);
1197 while ((opt
= strtok_r(opts
, ",", &placeholder
)) != NULL
) {
1200 /* remove trailing and leading spaces */
1201 while (isspace(*opt
))
1203 len
= strlen(opt
)-1;
1204 while (isspace(opt
[len
]))
1208 * if direct or indirect found, get rid of it, else put it
1211 if ((strcmp(opt
, "indirect") == 0) ||
1212 (strcmp(opt
, "direct") == 0))
1214 if (*map_mntopts
[0] != '\0')
1215 strcat(*map_mntopts
, ",");
1216 strcat(*map_mntopts
, opt
);
1219 /* add the direct string at the end */
1220 if (*map_mntopts
[0] != '\0')
1221 strcat(*map_mntopts
, ",");
1222 strcat(*map_mntopts
, addopt
);
1228 * parse_fsinfo(char *mapname, struct mapent *mapents)
1229 * parses the filesystem information stored in me->map_fsw and me->map_fswq
1230 * and calls appropriate filesystem parser.
1231 * Returns PARSE_OK or an appropriate error value.
1234 parse_fsinfo(char *mapname
, struct mapent
*mapents
)
1236 struct mapent
*me
= mapents
;
1239 int wordsz
= MAXPATHLEN
;
1242 while (me
!= NULL
) {
1245 if (strcmp(me
->map_fstype
, MNTTYPE_NFS
) == 0) {
1246 err
= parse_nfs(mapname
, me
, me
->map_fsw
,
1247 me
->map_fswq
, &bufp
, &bufq
, wordsz
);
1249 err
= parse_special(me
, me
->map_fsw
, me
->map_fswq
,
1250 &bufp
, &bufq
, wordsz
);
1253 if (err
!= PARSE_OK
|| *me
->map_fsw
!= '\0' ||
1254 *me
->map_fswq
!= '\0') {
1258 "parse_fsinfo: mount location error %s",
1260 return (PARSE_ERROR
);
1267 trace_mapents("parse_fsinfo:", mapents
);
1274 * This function parses the map entry for a nfs type file system
1275 * The input is the string lp (and lq) which can be one of the
1277 * a) host[(penalty)][,host[(penalty)]]... :/directory
1278 * b) host[(penalty)]:/directory[ host[(penalty)]:/directory]...
1279 * This routine constructs a mapfs link-list for each of
1280 * the hosts and the corresponding file system. The list
1281 * is then attatched to the mapent struct passed in.
1284 parse_nfs(mapname
, me
, fsw
, fswq
, lp
, lq
, wsize
)
1286 char *mapname
, *fsw
, *fswq
, **lp
, **lq
;
1289 struct mapfs
*mfs
, **mfsp
;
1291 char *hl
, hostlist
[1024], *hlq
, hostlistq
[1024];
1292 char hostname_and_penalty
[MXHOSTNAMELEN
+5];
1293 char *hn
, *hnq
, hostname
[MXHOSTNAMELEN
+1];
1294 char dirname
[MAXPATHLEN
+1], subdir
[MAXPATHLEN
+1];
1295 char qbuff
[MAXPATHLEN
+1], qbuff1
[MAXPATHLEN
+1];
1296 char pbuff
[10], pbuffq
[10];
1299 char wq
[MAXPATHLEN
];
1306 * there may be more than one entry in the map list. Get the
1307 * first one. Use temps to handle the word information and
1308 * copy back into fsw and fswq fields when done.
1312 if (getword(w
, wq
, lp
, lq
, ' ', wsize
) == -1)
1313 return (PARSE_ERROR
);
1314 while (*w
&& *w
!= '/') {
1320 if (getword(hostlist
, hostlistq
, &wlp
, &wlq
, ':',
1321 sizeof (hostlist
)) == -1)
1322 return (PARSE_ERROR
);
1326 if (strcmp(hostlist
, "nfs") != 0)
1329 if (getword(dirname
, qbuff
, &wlp
, &wlq
, ':',
1330 sizeof (dirname
)) == -1)
1331 return (PARSE_ERROR
);
1332 if (*dirname
== '\0')
1335 if (maybe_url
== TRUE
&& strncmp(dirname
, "//", 2) != 0)
1339 * See the next block comment ("Once upon a time ...") to
1340 * understand this. It turns the deprecated concept
1341 * of "subdir mounts" produced some useful code for handling
1342 * the possibility of a ":port#" in the URL.
1344 if (maybe_url
== FALSE
)
1352 * Once upon time, before autofs, there was support for
1353 * "subdir mounts". The idea was to "economize" the
1354 * number of mounts, so if you had a number of entries
1355 * all referring to a common subdirectory, e.g.
1357 * carol seasons:/export/home11/carol
1358 * ted seasons:/export/home11/ted
1359 * alice seasons:/export/home11/alice
1361 * then you could tell the automounter to mount a
1362 * common mountpoint which was delimited by the second
1365 * carol seasons:/export/home11:carol
1366 * ted seasons:/export/home11:ted
1367 * alice seasons:/export/home11:alice
1369 * The automounter would mount seasons:/export/home11
1370 * then for any other map entry that referenced the same
1371 * directory it would build a symbolic link that
1372 * appended the remainder of the path after the second
1373 * colon, i.e. once the common subdir was mounted, then
1374 * other directories could be accessed just by link
1375 * building - no further mounts required.
1377 * In theory the "mount saving" idea sounded good. In
1378 * practice the saving didn't amount to much and the
1379 * symbolic links confused people because the common
1380 * mountpoint had to have a pseudonym.
1382 * To remain backward compatible with the existing
1383 * maps, we interpret a second colon as a slash.
1385 if (getword(subdir
+1, qbuff
+1, &wlp
, &wlq
, ':',
1386 sizeof (subdir
)) == -1)
1387 return (PARSE_ERROR
);
1390 (void) strcat(dirname
, subdir
);
1392 hl
= hostlist
; hlq
= hostlistq
;
1397 if (getword(hostname_and_penalty
, qbuff
, &hl
, &hlq
, ',',
1398 sizeof (hostname_and_penalty
)) == -1)
1399 return (PARSE_ERROR
);
1400 if (!*hostname_and_penalty
)
1407 hn
= hostname_and_penalty
;
1409 if (getword(hostname
, qbuff1
, &hn
, &hnq
, '(',
1410 sizeof (hostname
)) == -1)
1411 return (PARSE_ERROR
);
1412 if (hostname
[0] == '\0')
1415 if (strcmp(hostname
, hostname_and_penalty
) == 0) {
1420 if (getword(pbuff
, pbuffq
, &hn
, &hnq
, ')',
1421 sizeof (pbuff
)) == -1)
1422 return (PARSE_ERROR
);
1426 penalty
= atoi(pbuff
);
1428 mfs
= (struct mapfs
*)malloc(sizeof (*mfs
));
1431 "parse_nfs: Memory allocation failed");
1432 return (PARSE_ERROR
);
1434 (void) memset(mfs
, 0, sizeof (*mfs
));
1436 mfsp
= &mfs
->mfs_next
;
1438 if (maybe_url
== TRUE
) {
1444 path
= strchr(host
, '/');
1447 "parse_nfs: illegal nfs url syntax: %s",
1450 return (PARSE_ERROR
);
1453 sport
= strchr(host
, ':');
1455 if (sport
!= NULL
&& sport
< path
) {
1457 mfs
->mfs_port
= atoi(sport
+1);
1459 if (mfs
->mfs_port
> USHRT_MAX
) {
1461 "parse_nfs: invalid "
1462 "port number (%d) in "
1466 return (PARSE_ERROR
);
1475 mfs
->mfs_flags
|= MFS_URL
;
1477 mfs
->mfs_host
= strdup(host
);
1478 mfs
->mfs_dir
= strdup(path
);
1480 mfs
->mfs_host
= strdup(hostname
);
1481 mfs
->mfs_dir
= strdup(dirname
);
1484 mfs
->mfs_penalty
= penalty
;
1485 if (mfs
->mfs_host
== NULL
|| mfs
->mfs_dir
== NULL
) {
1487 "parse_nfs: Memory allocation failed");
1488 return (PARSE_ERROR
);
1492 * We check host_cnt to make sure we haven't parsed an entry
1493 * with no host information.
1495 if (host_cnt
== 0) {
1497 "parse_nfs: invalid host specified - bad entry "
1500 return (PARSE_ERROR
);
1502 if (getword(w
, wq
, lp
, lq
, ' ', wsize
) == -1)
1503 return (PARSE_ERROR
);
1512 syslog(LOG_ERR
, "parse_nfs: bad entry in map %s \"%s\"", mapname
, w
);
1513 return (PARSE_ERROR
);
1517 parse_special(me
, w
, wq
, lp
, lq
, wsize
)
1519 char *w
, *wq
, **lp
, **lq
;
1522 char devname
[MAXPATHLEN
+ 1], qbuf
[MAXPATHLEN
+ 1];
1528 if (getword(devname
, qbuf
, &wlp
, &wlq
, ' ', sizeof (devname
)) == -1)
1529 return (PARSE_ERROR
);
1530 if (devname
[0] == '\0')
1531 return (PARSE_ERROR
);
1533 mfs
= (struct mapfs
*)malloc(sizeof (struct mapfs
));
1535 return (PARSE_ERROR
);
1536 (void) memset(mfs
, 0, sizeof (*mfs
));
1539 * A device name that begins with a slash could
1540 * be confused with a mountpoint path, hence use
1541 * a colon to escape a device string that begins
1542 * with a slash, e.g.
1544 * foo -ro /bar foo:/bar
1548 * would confuse the parser. The second instance
1553 mfs
->mfs_dir
= strdup(&devname
[devname
[0] == ':']);
1554 if (mfs
->mfs_dir
== NULL
)
1555 return (PARSE_ERROR
);
1557 if (getword(w
, wq
, lp
, lq
, ' ', wsize
) == -1)
1558 return (PARSE_ERROR
);
1563 * get_dir_from_path(char *dir, char **path, int dirsz)
1564 * gets the directory name dir from path for max string of length dirsz.
1565 * A modification of the getword routine. Assumes the delimiter is '/'
1566 * and that excess /'s are redundant.
1567 * Returns PARSE_OK or PARSE_ERROR
1570 get_dir_from_path(char *dir
, char **path
, int dirsz
)
1578 "get_dir_from_path: invalid directory size %d", dirsz
);
1579 return (PARSE_ERROR
);
1582 /* get rid of leading /'s in path */
1583 while (**path
== '/')
1586 /* now at a word or at the end of path */
1587 while ((**path
) && ((**path
) != '/')) {
1591 "get_dir_from_path: max pathlength exceeded %d", dirsz
);
1592 return (PARSE_ERROR
);
1594 *dir
++ = *(*path
)++;
1599 /* get rid of trailing /'s in path */
1600 while (**path
== '/')
1607 * alloc_hiernode(hiernode **newnode, char *dirname)
1608 * allocates a new hiernode corresponding to a new directory entry
1609 * in the hierarchical structure, and passes a pointer to it back
1610 * to the calling program.
1611 * Returns PARSE_OK or appropriate error value.
1614 alloc_hiernode(hiernode
**newnode
, char *dirname
)
1616 if ((*newnode
= (hiernode
*)malloc(sizeof (hiernode
))) == NULL
) {
1617 syslog(LOG_ERR
, "alloc_hiernode: Memory allocation failed");
1621 memset(((char *)*newnode
), 0, sizeof (hiernode
));
1622 strcpy(((*newnode
)->dirname
), dirname
);
1627 * free_hiernode(hiernode *node)
1628 * frees the allocated hiernode given the head of the structure
1629 * recursively calls itself until it frees entire structure.
1633 free_hiernode(hiernode
*node
)
1635 hiernode
*currnode
= node
;
1636 hiernode
*prevnode
= NULL
;
1638 while (currnode
!= NULL
) {
1639 if (currnode
->subdir
!= NULL
)
1640 free_hiernode(currnode
->subdir
);
1641 prevnode
= currnode
;
1642 currnode
= currnode
->leveldir
;
1643 free((void*)prevnode
);
1648 * free_mapent(struct mapent *)
1649 * free the mapentry and its fields
1659 while (me
->map_fs
) {
1662 free(mfs
->mfs_host
);
1666 free(mfs
->mfs_args
);
1668 freenetconfigent(mfs
->mfs_nconf
);
1669 me
->map_fs
= mfs
->mfs_next
;
1676 free(me
->map_mntpnt
);
1677 if (me
->map_mntopts
)
1678 free(me
->map_mntopts
);
1680 free(me
->map_fstype
);
1681 if (me
->map_mounter
)
1682 free(me
->map_mounter
);
1695 * trace_mapents(struct mapent *mapents)
1696 * traces through the mapentry structure and prints it element by element
1700 trace_mapents(char *s
, struct mapent
*mapents
)
1705 trace_prt(1, "\n\t%s\n", s
);
1706 for (me
= mapents
; me
; me
= me
->map_next
) {
1707 trace_prt(1, " (%s,%s)\t %s%s -%s\n",
1708 me
->map_fstype
? me
->map_fstype
: "",
1709 me
->map_mounter
? me
->map_mounter
: "",
1710 me
->map_root
? me
->map_root
: "",
1711 me
->map_mntpnt
? me
->map_mntpnt
: "",
1712 me
->map_mntopts
? me
->map_mntopts
: "");
1713 for (mfs
= me
->map_fs
; mfs
; mfs
= mfs
->mfs_next
)
1714 trace_prt(0, "\t\t%s:%s\n",
1715 mfs
->mfs_host
? mfs
->mfs_host
: "",
1716 mfs
->mfs_dir
? mfs
->mfs_dir
: "");
1718 trace_prt(1, "\tme->map_fsw=%s\n",
1719 me
->map_fsw
? me
->map_fsw
:"",
1720 me
->map_fswq
? me
->map_fsw
:"");
1721 trace_prt(1, "\t mntlevel=%d\t%s\t%s err=%d\n",
1723 me
->map_modified
? "modify=TRUE":"modify=FALSE",
1724 me
->map_faked
? "faked=TRUE":"faked=FALSE",
1730 * trace_hierarchy(hiernode *node)
1731 * traces the allocated hiernode given the head of the structure
1732 * recursively calls itself until it traces entire structure.
1733 * the first call made at the root is made with a zero level.
1734 * nodelevel is simply used to print tab and make the tracing clean.
1738 trace_hierarchy(hiernode
*node
, int nodelevel
)
1740 hiernode
*currnode
= node
;
1743 while (currnode
!= NULL
) {
1744 if (currnode
->subdir
!= NULL
) {
1745 for (i
= 0; i
< nodelevel
; i
++)
1747 trace_prt(0, "\t(%s, ",
1748 currnode
->dirname
? currnode
->dirname
:"");
1749 if (currnode
->mapent
) {
1750 trace_prt(0, "%d, %s)\n",
1751 currnode
->mapent
->map_mntlevel
,
1752 currnode
->mapent
->map_mntopts
?
1753 currnode
->mapent
->map_mntopts
:"");
1756 trace_prt(0, " ,)\n");
1758 trace_hierarchy(currnode
->subdir
, nodelevel
);
1760 for (i
= 0; i
< nodelevel
; i
++)
1762 trace_prt(0, "\t(%s, ",
1763 currnode
->dirname
? currnode
->dirname
:"");
1764 if (currnode
->mapent
) {
1765 trace_prt(0, "%d, %s)\n",
1766 currnode
->mapent
->map_mntlevel
,
1767 currnode
->mapent
->map_mntopts
?
1768 currnode
->mapent
->map_mntopts
:"");
1771 trace_prt(0, ", )\n");
1773 currnode
= currnode
->leveldir
;
1778 do_mapent_hosts(mapopts
, host
, isdirect
)
1779 char *mapopts
, *host
;
1783 struct mapent
*me
, *ms
, *mp
;
1785 struct exportnode
*ex
= NULL
;
1786 struct exportnode
*exlist
, *texlist
, **texp
, *exnext
;
1787 struct timeval timeout
;
1788 enum clnt_stat clnt_stat
;
1789 char name
[MAXPATHLEN
];
1790 char entryopts
[MAXOPTSLEN
];
1791 char fstype
[32], mounter
[32];
1792 int exlen
, duplicate
;
1793 struct mnttab mb
; /* needed for hasmntopt() to get nfs version */
1794 rpcvers_t nfsvers
; /* version in map options, 0 if not there */
1795 rpcvers_t vers
, versmin
; /* used to negotiate nfs vers in pingnfs() */
1800 trace_prt(1, " do_mapent_hosts: host %s\n", host
);
1802 /* check for special case: host is me */
1804 if (self_check(host
)) {
1805 ms
= (struct mapent
*)malloc(sizeof (*ms
));
1808 (void) memset((char *)ms
, 0, sizeof (*ms
));
1809 (void) strcpy(fstype
, MNTTYPE_NFS
);
1810 get_opts(mapopts
, entryopts
, fstype
, NULL
);
1811 ms
->map_mntopts
= strdup(entryopts
);
1812 if (ms
->map_mntopts
== NULL
)
1814 ms
->map_mounter
= strdup(fstype
);
1815 if (ms
->map_mounter
== NULL
)
1817 ms
->map_fstype
= strdup(MNTTYPE_NFS
);
1818 if (ms
->map_fstype
== NULL
)
1824 (void) strcpy(name
, "/");
1825 (void) strcat(name
, host
);
1827 ms
->map_root
= strdup(name
);
1828 if (ms
->map_root
== NULL
)
1830 ms
->map_mntpnt
= strdup("");
1831 if (ms
->map_mntpnt
== NULL
)
1833 mfs
= (struct mapfs
*)malloc(sizeof (*mfs
));
1836 (void) memset((char *)mfs
, 0, sizeof (*mfs
));
1838 mfs
->mfs_host
= strdup(host
);
1839 if (mfs
->mfs_host
== NULL
)
1841 mfs
->mfs_dir
= strdup("/");
1842 if (mfs
->mfs_dir
== NULL
)
1845 /* initialize mntlevel and modify */
1846 ms
->map_mntlevel
= -1;
1847 ms
->map_modified
= FALSE
;
1848 ms
->map_faked
= FALSE
;
1852 " do_mapent_hosts: self-host %s OK\n", host
);
1858 * Call pingnfs. Note that we can't have replicated hosts in /net.
1859 * XXX - we would like to avoid duplicating the across the wire calls
1860 * made here in nfsmount(). The pingnfs cache should help avoid it.
1862 mb
.mnt_mntopts
= mapopts
;
1863 foundvers
= nopt(&mb
, MNTOPT_VERS
, (int *)&nfsvers
);
1866 if (set_versrange(nfsvers
, &vers
, &versmin
) != 0) {
1867 syslog(LOG_ERR
, "Incorrect NFS version specified for %s", host
);
1868 return ((struct mapent
*)NULL
);
1870 if (pingnfs(host
, get_retry(mapopts
) + 1, &vers
, versmin
, 0, FALSE
,
1871 NULL
, NULL
) != RPC_SUCCESS
)
1872 return ((struct mapent
*)NULL
);
1874 retries
= get_retry(mapopts
);
1877 /* get export list of host */
1878 cl
= clnt_create(host
, MOUNTPROG
, MOUNTVERS
, "circuit_v");
1880 cl
= clnt_create(host
, MOUNTPROG
, MOUNTVERS
, "datagram_v");
1883 "do_mapent_hosts: %s %s", host
, clnt_spcreateerror(""));
1884 return ((struct mapent
*)NULL
);
1889 add_alloc("CLNT_HANDLE", cl
, 0, __FILE__
, __LINE__
);
1890 add_alloc("AUTH_HANDLE", cl
->cl_auth
, 0,
1891 __FILE__
, __LINE__
);
1894 timeout
.tv_usec
= 0;
1895 timeout
.tv_sec
= 25;
1896 if (clnt_stat
= clnt_call(cl
, MOUNTPROC_EXPORT
, xdr_void
, 0,
1897 xdr_exports
, (caddr_t
)&ex
, timeout
)) {
1899 if (retries
-- > 0) {
1906 "do_mapent_hosts: %s: export list: %s",
1907 host
, clnt_sperrno(clnt_stat
));
1909 drop_alloc("CLNT_HANDLE", cl
, __FILE__
, __LINE__
);
1910 drop_alloc("AUTH_HANDLE", cl
->cl_auth
,
1911 __FILE__
, __LINE__
);
1914 return ((struct mapent
*)NULL
);
1918 drop_alloc("CLNT_HANDLE", cl
, __FILE__
, __LINE__
);
1919 drop_alloc("AUTH_HANDLE", cl
->cl_auth
,
1920 __FILE__
, __LINE__
);
1927 gettext(" getmapent_hosts: null export list\n"));
1928 return ((struct mapent
*)NULL
);
1931 /* now sort by length of names - to get mount order right */
1937 for (; ex
; ex
= exnext
) {
1938 exnext
= ex
->ex_next
;
1939 exlen
= strlen(ex
->ex_dir
);
1941 for (texp
= &texlist
; *texp
; texp
= &((*texp
)->ex_next
)) {
1942 if (exlen
< (int)strlen((*texp
)->ex_dir
))
1944 duplicate
= (strcmp(ex
->ex_dir
, (*texp
)->ex_dir
) == 0);
1946 /* disregard duplicate entry */
1952 ex
->ex_next
= *texp
;
1958 (void) strcpy(fstype
, MNTTYPE_NFS
);
1959 get_opts(mapopts
, entryopts
, fstype
, NULL
);
1960 (void) strcpy(mounter
, fstype
);
1962 /* Now create a mapent from the export list */
1966 for (ex
= exlist
; ex
; ex
= ex
->ex_next
) {
1968 me
= (struct mapent
*)malloc(sizeof (*me
));
1971 (void) memset((char *)me
, 0, sizeof (*me
));
1981 (void) strcpy(name
, "/");
1982 (void) strcat(name
, host
);
1984 me
->map_root
= strdup(name
);
1985 if (me
->map_root
== NULL
)
1989 if (strcmp(ex
->ex_dir
, "/") != 0) {
1990 if (*(ex
->ex_dir
) != '/')
1991 (void) strcpy(name
, "/");
1992 (void) strcat(name
, ex
->ex_dir
);
1994 me
->map_mntpnt
= strdup(name
);
1995 if (me
->map_mntpnt
== NULL
)
1998 me
->map_fstype
= strdup(fstype
);
1999 if (me
->map_fstype
== NULL
)
2001 me
->map_mounter
= strdup(mounter
);
2002 if (me
->map_mounter
== NULL
)
2004 me
->map_mntopts
= strdup(entryopts
);
2005 if (me
->map_mntopts
== NULL
)
2008 mfs
= (struct mapfs
*)malloc(sizeof (*mfs
));
2011 (void) memset((char *)mfs
, 0, sizeof (*mfs
));
2013 mfs
->mfs_host
= strdup(host
);
2014 if (mfs
->mfs_host
== NULL
)
2016 mfs
->mfs_dir
= strdup(ex
->ex_dir
);
2017 if (mfs
->mfs_dir
== NULL
)
2020 /* initialize mntlevel and modify values */
2021 me
->map_mntlevel
= -1;
2022 me
->map_modified
= FALSE
;
2023 me
->map_faked
= FALSE
;
2028 trace_prt(1, " do_mapent_hosts: host %s OK\n", host
);
2033 syslog(LOG_ERR
, "do_mapent_hosts: Memory allocation failed");
2036 return ((struct mapent
*)NULL
);
2042 struct exportnode
*ex
;
2044 struct groupnode
*groups
, *tmpgroups
;
2047 groups
= ex
->ex_groups
;
2049 free(groups
->gr_name
);
2050 tmpgroups
= groups
->gr_next
;
2051 free((char *)groups
);
2059 struct exportnode
*ex
;
2061 struct exportnode
*tmpex
;
2064 tmpex
= ex
->ex_next
;
2070 static const char uatfs_err
[] = "submount under fstype=autofs not supported";
2072 * dump_mapent_err(struct mapent *me, char *key, char *mapname)
2073 * syslog appropriate error in mapentries.
2075 static void dump_mapent_err(struct mapent
*me
, char *key
, char *mapname
)
2077 switch (me
->map_err
) {
2081 "map=%s key=%s mntpnt=%s: no error");
2085 "mountpoint %s in map %s key %s not mounted: %s",
2086 me
->map_mntpnt
, mapname
, key
, uatfs_err
);
2091 "map=%s key=%s mntpnt=%s: unknown mapentry error");