xref: /titanic_51/usr/src/cmd/fs.d/autofs/ns_fnreaddir.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * ns_fnreaddir.c
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1995 - 1996, by Sun Microsystems, Inc.
26*7c478bd9Sstevel@tonic-gate  * All rights reserved.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <string.h>
34*7c478bd9Sstevel@tonic-gate #include <syslog.h>
35*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
36*7c478bd9Sstevel@tonic-gate #include <xfn/xfn.h>
37*7c478bd9Sstevel@tonic-gate #include "automount.h"
38*7c478bd9Sstevel@tonic-gate #include "ns_fnutils.h"
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate /*
42*7c478bd9Sstevel@tonic-gate  * Given the name of an XFN map, create a list of the map entries for a
43*7c478bd9Sstevel@tonic-gate  * given user.  Set error to zero on success.
44*7c478bd9Sstevel@tonic-gate  *
45*7c478bd9Sstevel@tonic-gate  *	extern void
46*7c478bd9Sstevel@tonic-gate  *	getmapkeys_fn(const char *map, struct dir_entry **, int *error,
47*7c478bd9Sstevel@tonic-gate  *	    int *cache_time, uid_t);
48*7c478bd9Sstevel@tonic-gate  */
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate /*
51*7c478bd9Sstevel@tonic-gate  * Given a multi-component composite name, construct the corresponding
52*7c478bd9Sstevel@tonic-gate  * context handle and the context handle of its prefix.  The prefix is
53*7c478bd9Sstevel@tonic-gate  * that part of the name up to (and possibly including) the last slash
54*7c478bd9Sstevel@tonic-gate  * in the name.  Return zero on success.
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  * eg:	user/jane/service  =>  user/jane + service
57*7c478bd9Sstevel@tonic-gate  *	org/ssi.eng/user   =>  org/ssi.eng/ + user
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate static int
60*7c478bd9Sstevel@tonic-gate get_contexts(const FN_composite_name_t *, FN_ctx_t **ctxp,
61*7c478bd9Sstevel@tonic-gate     FN_ctx_t **prefix_ctxp, FN_ctx_t *init_ctx, FN_status_t *);
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate /*
64*7c478bd9Sstevel@tonic-gate  * Split a multi-component composite name into its last component and
65*7c478bd9Sstevel@tonic-gate  * its other components.  Return zero on success.
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate static int
68*7c478bd9Sstevel@tonic-gate split_cname(const FN_composite_name_t *name, FN_composite_name_t **last,
69*7c478bd9Sstevel@tonic-gate     FN_composite_name_t **lead);
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /*
72*7c478bd9Sstevel@tonic-gate  * Given a context and its prefix context (defined above), determine
73*7c478bd9Sstevel@tonic-gate  * whether the context, its NNS context, or both should be listed.
74*7c478bd9Sstevel@tonic-gate  * (The syntaxes of the contexts are used to help make this
75*7c478bd9Sstevel@tonic-gate  * determination.)  Add the subdirectories of the appropriate
76*7c478bd9Sstevel@tonic-gate  * context(s) to the dir_entry list.  Return zero on success.
77*7c478bd9Sstevel@tonic-gate  *
78*7c478bd9Sstevel@tonic-gate  * eg:	"ls /xfn/user		=>  list context only
79*7c478bd9Sstevel@tonic-gate  *	"ls /xfn/org/ssi.eng"	=>  list NNS only
80*7c478bd9Sstevel@tonic-gate  *	"ls /xfn/.../c=us"	=>  list context and NNS
81*7c478bd9Sstevel@tonic-gate  */
82*7c478bd9Sstevel@tonic-gate static int
83*7c478bd9Sstevel@tonic-gate list_ctx_and_or_nns(FN_ctx_t *ctx, FN_ctx_t *prefix_ctx, struct dir_entry **,
84*7c478bd9Sstevel@tonic-gate     FN_status_t *);
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate /*
87*7c478bd9Sstevel@tonic-gate  * Given a context and its prefix context (defined above), return true
88*7c478bd9Sstevel@tonic-gate  * if the NNS of the context should be listed but the context itself
89*7c478bd9Sstevel@tonic-gate  * should not.
90*7c478bd9Sstevel@tonic-gate  */
91*7c478bd9Sstevel@tonic-gate static bool_t
92*7c478bd9Sstevel@tonic-gate need_nns_only(FN_ctx_t *ctx, FN_ctx_t *prefix_ctx, FN_status_t *);
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /*
95*7c478bd9Sstevel@tonic-gate  * Return true if both the given context and its NNS should be listed.
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate static bool_t
98*7c478bd9Sstevel@tonic-gate need_ctx_and_nns(FN_ctx_t *, FN_status_t *);
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate /*
101*7c478bd9Sstevel@tonic-gate  * Add the subdirectories of a context to the dir_entry list.  Return
102*7c478bd9Sstevel@tonic-gate  * zero on success.
103*7c478bd9Sstevel@tonic-gate  */
104*7c478bd9Sstevel@tonic-gate static int
105*7c478bd9Sstevel@tonic-gate list_ctx(FN_ctx_t *, struct dir_entry **, FN_status_t *);
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * Given a context and its name relative to the root of its rightmost
109*7c478bd9Sstevel@tonic-gate  * naming system, add the context's subdirectories to the dir_entry
110*7c478bd9Sstevel@tonic-gate  * list.  If syntax is non-NULL recursively list names until a context
111*7c478bd9Sstevel@tonic-gate  * with a different syntax is encountered, otherwise list one level
112*7c478bd9Sstevel@tonic-gate  * only.  May modify "name".  Return zero on success.
113*7c478bd9Sstevel@tonic-gate  *
114*7c478bd9Sstevel@tonic-gate  * eg:  For the context org/eng with syntax "dot-separated, right-to-left",
115*7c478bd9Sstevel@tonic-gate  * the compound name "eng" would be passed in, and the following might
116*7c478bd9Sstevel@tonic-gate  * be added to the dir_entry list:
117*7c478bd9Sstevel@tonic-gate  * 	ssi.eng
118*7c478bd9Sstevel@tonic-gate  *	feds.ssi.eng
119*7c478bd9Sstevel@tonic-gate  * 	ste.eng
120*7c478bd9Sstevel@tonic-gate  */
121*7c478bd9Sstevel@tonic-gate static int
122*7c478bd9Sstevel@tonic-gate list_ctx_aux(FN_ctx_t *, FN_compound_name_t *name, const FN_attrset_t *syntax,
123*7c478bd9Sstevel@tonic-gate     struct dir_entry **, FN_status_t *);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate /*
126*7c478bd9Sstevel@tonic-gate  * Add a name to a dir_entry list.  Return zero on success.
127*7c478bd9Sstevel@tonic-gate  */
128*7c478bd9Sstevel@tonic-gate static int
129*7c478bd9Sstevel@tonic-gate add_name_to_dirlist(const FN_compound_name_t *, struct dir_entry **);
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate /*
132*7c478bd9Sstevel@tonic-gate  * Return true if a set of syntax attributes correspond to a
133*7c478bd9Sstevel@tonic-gate  * hierarchical namespace with a slash separator.  Return false on
134*7c478bd9Sstevel@tonic-gate  * error.
135*7c478bd9Sstevel@tonic-gate  */
136*7c478bd9Sstevel@tonic-gate static bool_t
137*7c478bd9Sstevel@tonic-gate slash_hierarchy(const FN_attrset_t *syntax);
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate /*
140*7c478bd9Sstevel@tonic-gate  * Return true if a set of syntax attributes correspond to a
141*7c478bd9Sstevel@tonic-gate  * hierarchical namespace with a separator other than a slash.
142*7c478bd9Sstevel@tonic-gate  * Return false on error.
143*7c478bd9Sstevel@tonic-gate  */
144*7c478bd9Sstevel@tonic-gate static bool_t
145*7c478bd9Sstevel@tonic-gate non_slash_hierarchy(const FN_attrset_t *syntax);
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /*
148*7c478bd9Sstevel@tonic-gate  * Return true if two syntax attribute sets are equal.
149*7c478bd9Sstevel@tonic-gate  */
150*7c478bd9Sstevel@tonic-gate static bool_t
151*7c478bd9Sstevel@tonic-gate syntax_attrs_equal(const FN_attrset_t *, const FN_attrset_t *);
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate /*
154*7c478bd9Sstevel@tonic-gate  * Return a value of a given attribute in an attribute set, or NULL
155*7c478bd9Sstevel@tonic-gate  * on error.
156*7c478bd9Sstevel@tonic-gate  */
157*7c478bd9Sstevel@tonic-gate static const FN_attrvalue_t *
158*7c478bd9Sstevel@tonic-gate get_attrval(const FN_attrset_t *, const FN_identifier_t *attr_id);
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate /*
161*7c478bd9Sstevel@tonic-gate  * Lookup a name and return the corresponding context handle.  On
162*7c478bd9Sstevel@tonic-gate  * error return NULL and, if "log" is true or the error is transient,
163*7c478bd9Sstevel@tonic-gate  * log an error message.
164*7c478bd9Sstevel@tonic-gate  */
165*7c478bd9Sstevel@tonic-gate static FN_ctx_t *
166*7c478bd9Sstevel@tonic-gate lookup_ctx(FN_ctx_t *, const FN_composite_name_t *, bool_t log, FN_status_t *);
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate /*
170*7c478bd9Sstevel@tonic-gate  * Unlike during a lookup or mount, transient errors are tolerated.  A
171*7c478bd9Sstevel@tonic-gate  * potentially transient error during a readdir() (such as no response
172*7c478bd9Sstevel@tonic-gate  * from an X.500 server) could result in an incomplete listing, but at
173*7c478bd9Sstevel@tonic-gate  * least readdir() will return everything that it can.  Note that it
174*7c478bd9Sstevel@tonic-gate  * is still possible to mount a directory that for some reason did not
175*7c478bd9Sstevel@tonic-gate  * show up in a prior readdir().
176*7c478bd9Sstevel@tonic-gate  */
177*7c478bd9Sstevel@tonic-gate void
178*7c478bd9Sstevel@tonic-gate getmapkeys_fn(const char *map, struct dir_entry **entries_p, int *error,
179*7c478bd9Sstevel@tonic-gate     int *cache_time, uid_t uid)
180*7c478bd9Sstevel@tonic-gate {
181*7c478bd9Sstevel@tonic-gate 	FN_composite_name_t	*name;
182*7c478bd9Sstevel@tonic-gate 	FN_status_t		*status;
183*7c478bd9Sstevel@tonic-gate 	FN_ctx_t		*init_ctx;
184*7c478bd9Sstevel@tonic-gate 	FN_ctx_t		*ctx;
185*7c478bd9Sstevel@tonic-gate 	FN_ctx_t		*prefix_ctx;
186*7c478bd9Sstevel@tonic-gate 	struct dir_entry	*p;
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	*cache_time = RDDIR_CACHE_TIME;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	if ((init_fn() != 0) || (status = fn_status_create()) == NULL) {
191*7c478bd9Sstevel@tonic-gate 		log_mem_failure();
192*7c478bd9Sstevel@tonic-gate 		*error = -1;
193*7c478bd9Sstevel@tonic-gate 		return;
194*7c478bd9Sstevel@tonic-gate 	}
195*7c478bd9Sstevel@tonic-gate 	init_ctx = _fn_ctx_handle_from_initial_with_uid(uid, 0, status);
196*7c478bd9Sstevel@tonic-gate 	if (init_ctx == NULL) {
197*7c478bd9Sstevel@tonic-gate 		logstat(status, "", "No initial context");
198*7c478bd9Sstevel@tonic-gate 		fn_status_destroy(status);
199*7c478bd9Sstevel@tonic-gate 		return;
200*7c478bd9Sstevel@tonic-gate 	}
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	if (strcmp(map, FNPREFIX) == 0) {
203*7c478bd9Sstevel@tonic-gate 		/*
204*7c478bd9Sstevel@tonic-gate 		 * List the initial context.
205*7c478bd9Sstevel@tonic-gate 		 * Contents of initial ctx is user-relative
206*7c478bd9Sstevel@tonic-gate 		 */
207*7c478bd9Sstevel@tonic-gate 		*cache_time = 0;
208*7c478bd9Sstevel@tonic-gate 		*error = list_ctx(init_ctx, entries_p, status);
209*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(map, FNPREFIX "/_dns") == 0) {
210*7c478bd9Sstevel@tonic-gate 		/* Cannot list DNS; report success but no entries. */
211*7c478bd9Sstevel@tonic-gate 		*cache_time = 1000000;	/* no sense trying again */
212*7c478bd9Sstevel@tonic-gate 		*error = 0;
213*7c478bd9Sstevel@tonic-gate 	} else {
214*7c478bd9Sstevel@tonic-gate 		if (strcmp(map, FNPREFIX "/...") == 0) {
215*7c478bd9Sstevel@tonic-gate 			/* List X.500 but not DNS. */
216*7c478bd9Sstevel@tonic-gate 			name = new_cname("_x500");
217*7c478bd9Sstevel@tonic-gate 		} else {
218*7c478bd9Sstevel@tonic-gate 			name = new_cname(map + FNPREFIXLEN + 1);
219*7c478bd9Sstevel@tonic-gate 		}
220*7c478bd9Sstevel@tonic-gate 		if (name == NULL) {
221*7c478bd9Sstevel@tonic-gate 			*error = -1;
222*7c478bd9Sstevel@tonic-gate 		} else if (fn_composite_name_count(name) == 1) {
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 			/* List an atomic name. */
225*7c478bd9Sstevel@tonic-gate 			ctx = lookup_ctx(init_ctx, name, TRUE, status);
226*7c478bd9Sstevel@tonic-gate 			if (ctx != NULL) {
227*7c478bd9Sstevel@tonic-gate 				*error = list_ctx_and_or_nns(ctx, init_ctx,
228*7c478bd9Sstevel@tonic-gate 				    entries_p, status);
229*7c478bd9Sstevel@tonic-gate 				fn_ctx_handle_destroy(ctx);
230*7c478bd9Sstevel@tonic-gate 			} else {
231*7c478bd9Sstevel@tonic-gate 				*error = -1;
232*7c478bd9Sstevel@tonic-gate 			}
233*7c478bd9Sstevel@tonic-gate 		} else {
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 			/* List a multi-component name. */
236*7c478bd9Sstevel@tonic-gate 			*error = get_contexts(name, &ctx, &prefix_ctx,
237*7c478bd9Sstevel@tonic-gate 			    init_ctx, status);
238*7c478bd9Sstevel@tonic-gate 			if (*error == 0) {
239*7c478bd9Sstevel@tonic-gate 				*error = list_ctx_and_or_nns(ctx, prefix_ctx,
240*7c478bd9Sstevel@tonic-gate 				    entries_p, status);
241*7c478bd9Sstevel@tonic-gate 				fn_ctx_handle_destroy(ctx);
242*7c478bd9Sstevel@tonic-gate 				fn_ctx_handle_destroy(prefix_ctx);
243*7c478bd9Sstevel@tonic-gate 			}
244*7c478bd9Sstevel@tonic-gate 		}
245*7c478bd9Sstevel@tonic-gate 		fn_composite_name_destroy(name);
246*7c478bd9Sstevel@tonic-gate 	}
247*7c478bd9Sstevel@tonic-gate 	fn_status_destroy(status);
248*7c478bd9Sstevel@tonic-gate 	fn_ctx_handle_destroy(init_ctx);
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	if (*error == 0) {
251*7c478bd9Sstevel@tonic-gate 		/*
252*7c478bd9Sstevel@tonic-gate 		 * create the binary tree of entries
253*7c478bd9Sstevel@tonic-gate 		 */
254*7c478bd9Sstevel@tonic-gate 		for (p = *entries_p; p != NULL; p = p->next)
255*7c478bd9Sstevel@tonic-gate 			btree_enter(entries_p, p);
256*7c478bd9Sstevel@tonic-gate 	}
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate static int
261*7c478bd9Sstevel@tonic-gate get_contexts(const FN_composite_name_t *name, FN_ctx_t **ctxp,
262*7c478bd9Sstevel@tonic-gate     FN_ctx_t **prefix_ctxp, FN_ctx_t *init_ctx, FN_status_t *status)
263*7c478bd9Sstevel@tonic-gate {
264*7c478bd9Sstevel@tonic-gate 	FN_composite_name_t	*prefix = NULL;
265*7c478bd9Sstevel@tonic-gate 	FN_composite_name_t	*suffix = NULL;
266*7c478bd9Sstevel@tonic-gate 	FN_ctx_t		*nns_ctx;
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	/*
269*7c478bd9Sstevel@tonic-gate 	 * Break a name such as "pre/fix/suffix" into "pre/fix/" and
270*7c478bd9Sstevel@tonic-gate 	 * "suffix".  If that fails, try "pre/fix" and "suffix".  This
271*7c478bd9Sstevel@tonic-gate 	 * can be more efficient than doing it the reverse order.
272*7c478bd9Sstevel@tonic-gate 	 */
273*7c478bd9Sstevel@tonic-gate 	if (split_cname(name, &suffix, &prefix) != 0) {
274*7c478bd9Sstevel@tonic-gate 		return (-1);
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 	*ctxp = NULL;
277*7c478bd9Sstevel@tonic-gate 	*prefix_ctxp = lookup_ctx(init_ctx, prefix, TRUE, status);
278*7c478bd9Sstevel@tonic-gate 	fn_composite_name_destroy(prefix);
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	if (*prefix_ctxp != NULL) {
281*7c478bd9Sstevel@tonic-gate 		nns_ctx = lookup_ctx(*prefix_ctxp, slash_cname, FALSE, status);
282*7c478bd9Sstevel@tonic-gate 		if (nns_ctx != NULL) {
283*7c478bd9Sstevel@tonic-gate 			*ctxp = lookup_ctx(nns_ctx, suffix, FALSE, status);
284*7c478bd9Sstevel@tonic-gate 			if (*ctxp != NULL) {
285*7c478bd9Sstevel@tonic-gate 				fn_ctx_handle_destroy(*prefix_ctxp);
286*7c478bd9Sstevel@tonic-gate 				*prefix_ctxp = nns_ctx;
287*7c478bd9Sstevel@tonic-gate 			} else {
288*7c478bd9Sstevel@tonic-gate 				fn_ctx_handle_destroy(nns_ctx);
289*7c478bd9Sstevel@tonic-gate 			}
290*7c478bd9Sstevel@tonic-gate 		}
291*7c478bd9Sstevel@tonic-gate 		if (*ctxp == NULL) {
292*7c478bd9Sstevel@tonic-gate 			*ctxp =
293*7c478bd9Sstevel@tonic-gate 			    lookup_ctx(*prefix_ctxp, suffix, FALSE, status);
294*7c478bd9Sstevel@tonic-gate 		}
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate 	fn_composite_name_destroy(suffix);
297*7c478bd9Sstevel@tonic-gate 	return (*ctxp != NULL ? 0 : -1);
298*7c478bd9Sstevel@tonic-gate }
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate static int
302*7c478bd9Sstevel@tonic-gate split_cname(const FN_composite_name_t *name, FN_composite_name_t **last,
303*7c478bd9Sstevel@tonic-gate     FN_composite_name_t **lead)
304*7c478bd9Sstevel@tonic-gate {
305*7c478bd9Sstevel@tonic-gate 	void	*iter;
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	(void) fn_composite_name_last(name, &iter);
308*7c478bd9Sstevel@tonic-gate 	*last = fn_composite_name_suffix(name, iter);
309*7c478bd9Sstevel@tonic-gate 	*lead = fn_composite_name_prefix(name, iter);
310*7c478bd9Sstevel@tonic-gate 	if (*last == NULL || *lead == NULL) {
311*7c478bd9Sstevel@tonic-gate 		log_mem_failure();
312*7c478bd9Sstevel@tonic-gate 		fn_composite_name_destroy(*last);
313*7c478bd9Sstevel@tonic-gate 		fn_composite_name_destroy(*lead);
314*7c478bd9Sstevel@tonic-gate 		return (-1);
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate 	return (0);
317*7c478bd9Sstevel@tonic-gate }
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate static int
321*7c478bd9Sstevel@tonic-gate list_ctx_and_or_nns(FN_ctx_t *ctx, FN_ctx_t *prefix_ctx,
322*7c478bd9Sstevel@tonic-gate     struct dir_entry **entries_p, FN_status_t *status)
323*7c478bd9Sstevel@tonic-gate {
324*7c478bd9Sstevel@tonic-gate 	FN_ctx_t	*nns_ctx;
325*7c478bd9Sstevel@tonic-gate 	int		rc;
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	if (!need_nns_only(ctx, prefix_ctx, status)) {
328*7c478bd9Sstevel@tonic-gate 		if (list_ctx(ctx, entries_p, status) != 0) {
329*7c478bd9Sstevel@tonic-gate 			return (-1);
330*7c478bd9Sstevel@tonic-gate 		}
331*7c478bd9Sstevel@tonic-gate 		if (!need_ctx_and_nns(ctx, status)) {
332*7c478bd9Sstevel@tonic-gate 			return (0);
333*7c478bd9Sstevel@tonic-gate 		}
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 	nns_ctx = lookup_ctx(ctx, slash_cname, FALSE, status);
336*7c478bd9Sstevel@tonic-gate 	if (nns_ctx == NULL) {
337*7c478bd9Sstevel@tonic-gate 		return (0);
338*7c478bd9Sstevel@tonic-gate 	}
339*7c478bd9Sstevel@tonic-gate 	rc = list_ctx(nns_ctx, entries_p, status);
340*7c478bd9Sstevel@tonic-gate 	fn_ctx_handle_destroy(nns_ctx);
341*7c478bd9Sstevel@tonic-gate 	return (rc);
342*7c478bd9Sstevel@tonic-gate }
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate /*
346*7c478bd9Sstevel@tonic-gate  * True if ctx has a hierarchical syntax with a non-slash separator
347*7c478bd9Sstevel@tonic-gate  * and prefix_ctx either has the same syntax or does not provide any
348*7c478bd9Sstevel@tonic-gate  * syntax ("..." should be the only example of the latter condition).
349*7c478bd9Sstevel@tonic-gate  */
350*7c478bd9Sstevel@tonic-gate static bool_t
351*7c478bd9Sstevel@tonic-gate need_nns_only(FN_ctx_t *ctx, FN_ctx_t *prefix_ctx, FN_status_t *status)
352*7c478bd9Sstevel@tonic-gate {
353*7c478bd9Sstevel@tonic-gate 	FN_attrset_t	*syn;
354*7c478bd9Sstevel@tonic-gate 	FN_attrset_t	*prefix_syn;
355*7c478bd9Sstevel@tonic-gate 	bool_t		retval;
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	syn = fn_ctx_get_syntax_attrs(ctx, empty_cname, status);
358*7c478bd9Sstevel@tonic-gate 	if (syn == NULL || !non_slash_hierarchy(syn)) {
359*7c478bd9Sstevel@tonic-gate 		fn_attrset_destroy(syn);
360*7c478bd9Sstevel@tonic-gate 		return (FALSE);
361*7c478bd9Sstevel@tonic-gate 	}
362*7c478bd9Sstevel@tonic-gate 	/*
363*7c478bd9Sstevel@tonic-gate 	 * ctx is hierarchical and not slash-separated.  How about prefix_ctx?
364*7c478bd9Sstevel@tonic-gate 	 */
365*7c478bd9Sstevel@tonic-gate 	prefix_syn = fn_ctx_get_syntax_attrs(prefix_ctx, empty_cname, status);
366*7c478bd9Sstevel@tonic-gate 	retval = (prefix_syn == NULL) || syntax_attrs_equal(syn, prefix_syn);
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	fn_attrset_destroy(syn);
369*7c478bd9Sstevel@tonic-gate 	fn_attrset_destroy(prefix_syn);
370*7c478bd9Sstevel@tonic-gate 	return (retval);
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate /*
375*7c478bd9Sstevel@tonic-gate  * True if ctx has a slash-separated hierarchical syntax.
376*7c478bd9Sstevel@tonic-gate  */
377*7c478bd9Sstevel@tonic-gate static bool_t
378*7c478bd9Sstevel@tonic-gate need_ctx_and_nns(FN_ctx_t *ctx, FN_status_t *status)
379*7c478bd9Sstevel@tonic-gate {
380*7c478bd9Sstevel@tonic-gate 	FN_attrset_t	*syn;
381*7c478bd9Sstevel@tonic-gate 	bool_t		retval;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	syn = fn_ctx_get_syntax_attrs(ctx, empty_cname, status);
384*7c478bd9Sstevel@tonic-gate 	if (syn == NULL) {
385*7c478bd9Sstevel@tonic-gate 		return (FALSE);
386*7c478bd9Sstevel@tonic-gate 	}
387*7c478bd9Sstevel@tonic-gate 	retval = slash_hierarchy(syn);
388*7c478bd9Sstevel@tonic-gate 	fn_attrset_destroy(syn);
389*7c478bd9Sstevel@tonic-gate 	return (retval);
390*7c478bd9Sstevel@tonic-gate }
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate static int
394*7c478bd9Sstevel@tonic-gate list_ctx(FN_ctx_t *ctx, struct dir_entry **entries_p, FN_status_t *status)
395*7c478bd9Sstevel@tonic-gate {
396*7c478bd9Sstevel@tonic-gate 	FN_attrset_t		*syntax;
397*7c478bd9Sstevel@tonic-gate 	FN_compound_name_t	*name;
398*7c478bd9Sstevel@tonic-gate 	int			retval;
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	syntax = fn_ctx_get_syntax_attrs(ctx, empty_cname, status);
401*7c478bd9Sstevel@tonic-gate 	if (syntax == NULL) {
402*7c478bd9Sstevel@tonic-gate 		logstat(status, "", "bad syntax attributes");
403*7c478bd9Sstevel@tonic-gate 		return (-1);
404*7c478bd9Sstevel@tonic-gate 	}
405*7c478bd9Sstevel@tonic-gate 	name =
406*7c478bd9Sstevel@tonic-gate 	    fn_compound_name_from_syntax_attrs(syntax, empty_string, status);
407*7c478bd9Sstevel@tonic-gate 	if (name == NULL) {
408*7c478bd9Sstevel@tonic-gate 		logstat(status, "", "could not create compound name");
409*7c478bd9Sstevel@tonic-gate 		fn_attrset_destroy(syntax);
410*7c478bd9Sstevel@tonic-gate 		return (-1);
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate 	if (!non_slash_hierarchy(syntax)) {
413*7c478bd9Sstevel@tonic-gate 		fn_attrset_destroy(syntax);
414*7c478bd9Sstevel@tonic-gate 		syntax = NULL;
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 	retval = list_ctx_aux(ctx, name, syntax, entries_p, status);
417*7c478bd9Sstevel@tonic-gate 	fn_attrset_destroy(syntax);
418*7c478bd9Sstevel@tonic-gate 	fn_compound_name_destroy(name);
419*7c478bd9Sstevel@tonic-gate 	return (retval);
420*7c478bd9Sstevel@tonic-gate }
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate static int
424*7c478bd9Sstevel@tonic-gate list_ctx_aux(FN_ctx_t *ctx, FN_compound_name_t *name,
425*7c478bd9Sstevel@tonic-gate     const FN_attrset_t *syntax, struct dir_entry **entries_p,
426*7c478bd9Sstevel@tonic-gate     FN_status_t *status)
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate 	FN_bindinglist_t	*bindings;
429*7c478bd9Sstevel@tonic-gate 	FN_string_t		*child;
430*7c478bd9Sstevel@tonic-gate 	FN_ref_t		*ref;
431*7c478bd9Sstevel@tonic-gate 	unsigned int		stat;
432*7c478bd9Sstevel@tonic-gate 	int			rc = 0;
433*7c478bd9Sstevel@tonic-gate 	void			*iter;
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	bindings = fn_ctx_list_bindings(ctx, empty_cname, status);
436*7c478bd9Sstevel@tonic-gate 	if (bindings == NULL) {
437*7c478bd9Sstevel@tonic-gate 		return (0);
438*7c478bd9Sstevel@tonic-gate 	}
439*7c478bd9Sstevel@tonic-gate 	while ((child = fn_bindinglist_next(bindings, &ref, status)) != NULL) {
440*7c478bd9Sstevel@tonic-gate 		if (fn_compound_name_append_comp(name, child, &stat) == 0) {
441*7c478bd9Sstevel@tonic-gate 			rc = -1;
442*7c478bd9Sstevel@tonic-gate 			break;
443*7c478bd9Sstevel@tonic-gate 		}
444*7c478bd9Sstevel@tonic-gate 		if (add_name_to_dirlist(name, entries_p) != 0) {
445*7c478bd9Sstevel@tonic-gate 			rc = -1;
446*7c478bd9Sstevel@tonic-gate 			break;
447*7c478bd9Sstevel@tonic-gate 		}
448*7c478bd9Sstevel@tonic-gate 		if (syntax != NULL) {
449*7c478bd9Sstevel@tonic-gate 			/* Traverse hierarchy. */
450*7c478bd9Sstevel@tonic-gate 			ctx = fn_ctx_handle_from_ref(ref, XFN2(0) status);
451*7c478bd9Sstevel@tonic-gate 			if (ctx != NULL) {
452*7c478bd9Sstevel@tonic-gate 				rc = list_ctx_aux(ctx, name, syntax, entries_p,
453*7c478bd9Sstevel@tonic-gate 				    status);
454*7c478bd9Sstevel@tonic-gate 				fn_ctx_handle_destroy(ctx);
455*7c478bd9Sstevel@tonic-gate 				if (rc != 0) {
456*7c478bd9Sstevel@tonic-gate 					break;
457*7c478bd9Sstevel@tonic-gate 				}
458*7c478bd9Sstevel@tonic-gate 			}
459*7c478bd9Sstevel@tonic-gate 		}
460*7c478bd9Sstevel@tonic-gate 		fn_ref_destroy(ref);
461*7c478bd9Sstevel@tonic-gate 		fn_string_destroy(child);
462*7c478bd9Sstevel@tonic-gate 		(void) fn_compound_name_last(name, &iter);
463*7c478bd9Sstevel@tonic-gate 		(void) fn_compound_name_next(name, &iter);
464*7c478bd9Sstevel@tonic-gate 		(void) fn_compound_name_delete_comp(name, &iter);
465*7c478bd9Sstevel@tonic-gate 	}
466*7c478bd9Sstevel@tonic-gate 	fn_string_destroy(child);
467*7c478bd9Sstevel@tonic-gate 	fn_bindinglist_destroy(bindings XFN1(status));
468*7c478bd9Sstevel@tonic-gate 	return (rc);
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate static int
473*7c478bd9Sstevel@tonic-gate add_name_to_dirlist(const FN_compound_name_t *name,
474*7c478bd9Sstevel@tonic-gate     struct dir_entry **entries_p)
475*7c478bd9Sstevel@tonic-gate {
476*7c478bd9Sstevel@tonic-gate 	FN_string_t		*string;
477*7c478bd9Sstevel@tonic-gate 	char			*str;
478*7c478bd9Sstevel@tonic-gate 	unsigned int		stat;
479*7c478bd9Sstevel@tonic-gate 	struct dir_entry	*entry;
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	string = fn_string_from_compound_name(name);
482*7c478bd9Sstevel@tonic-gate 	if (string == NULL) {
483*7c478bd9Sstevel@tonic-gate 		log_mem_failure();
484*7c478bd9Sstevel@tonic-gate 		return (-1);
485*7c478bd9Sstevel@tonic-gate 	}
486*7c478bd9Sstevel@tonic-gate 	str = (char *)fn_string_str(string, &stat);
487*7c478bd9Sstevel@tonic-gate 	if (str != NULL) {
488*7c478bd9Sstevel@tonic-gate 		str = auto_rddir_strdup(str);
489*7c478bd9Sstevel@tonic-gate 	}
490*7c478bd9Sstevel@tonic-gate 	fn_string_destroy(string);
491*7c478bd9Sstevel@tonic-gate 	if (str == NULL) {
492*7c478bd9Sstevel@tonic-gate 		log_mem_failure();
493*7c478bd9Sstevel@tonic-gate 		return (-1);
494*7c478bd9Sstevel@tonic-gate 	}
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer alignment */
497*7c478bd9Sstevel@tonic-gate 	entry = (struct dir_entry *)
498*7c478bd9Sstevel@tonic-gate 		auto_rddir_malloc(sizeof (*entry));
499*7c478bd9Sstevel@tonic-gate 	if (entry == NULL) {
500*7c478bd9Sstevel@tonic-gate 		log_mem_failure();
501*7c478bd9Sstevel@tonic-gate 		free(str);
502*7c478bd9Sstevel@tonic-gate 		return (-1);
503*7c478bd9Sstevel@tonic-gate 	}
504*7c478bd9Sstevel@tonic-gate 	(void) memset((char *)entry, 0, sizeof (*entry));
505*7c478bd9Sstevel@tonic-gate 	entry->name = str;
506*7c478bd9Sstevel@tonic-gate 	entry->next = *entries_p;
507*7c478bd9Sstevel@tonic-gate 	*entries_p = entry;
508*7c478bd9Sstevel@tonic-gate 	return (0);
509*7c478bd9Sstevel@tonic-gate }
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate /*
513*7c478bd9Sstevel@tonic-gate  * Identifiers of syntax attributes for direction and separator.
514*7c478bd9Sstevel@tonic-gate  */
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate static const FN_identifier_t syntax_direction = {
517*7c478bd9Sstevel@tonic-gate 	FN_ID_STRING,
518*7c478bd9Sstevel@tonic-gate 	sizeof ("fn_std_syntax_direction") - 1,
519*7c478bd9Sstevel@tonic-gate 	"fn_std_syntax_direction"
520*7c478bd9Sstevel@tonic-gate };
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate static const FN_identifier_t syntax_separator = {
523*7c478bd9Sstevel@tonic-gate 	FN_ID_STRING,
524*7c478bd9Sstevel@tonic-gate 	sizeof ("fn_std_syntax_separator") - 1,
525*7c478bd9Sstevel@tonic-gate 	"fn_std_syntax_separator"
526*7c478bd9Sstevel@tonic-gate };
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate static bool_t
530*7c478bd9Sstevel@tonic-gate slash_hierarchy(const FN_attrset_t *syntax)
531*7c478bd9Sstevel@tonic-gate {
532*7c478bd9Sstevel@tonic-gate 	const FN_attrvalue_t	*dir = get_attrval(syntax, &syntax_direction);
533*7c478bd9Sstevel@tonic-gate 	const FN_attrvalue_t	*sep = get_attrval(syntax, &syntax_separator);
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	return (dir != NULL &&
536*7c478bd9Sstevel@tonic-gate 	    memcmp("flat", dir->contents, dir->length) != 0 &&
537*7c478bd9Sstevel@tonic-gate 	    sep != NULL &&
538*7c478bd9Sstevel@tonic-gate 	    memcmp("/", sep->contents, sep->length) == 0);
539*7c478bd9Sstevel@tonic-gate }
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate static bool_t
543*7c478bd9Sstevel@tonic-gate non_slash_hierarchy(const FN_attrset_t *syntax)
544*7c478bd9Sstevel@tonic-gate {
545*7c478bd9Sstevel@tonic-gate 	const FN_attrvalue_t	*dir = get_attrval(syntax, &syntax_direction);
546*7c478bd9Sstevel@tonic-gate 	const FN_attrvalue_t	*sep = get_attrval(syntax, &syntax_separator);
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	return (dir != NULL &&
549*7c478bd9Sstevel@tonic-gate 	    memcmp("flat", dir->contents, dir->length) != 0 &&
550*7c478bd9Sstevel@tonic-gate 	    sep != NULL &&
551*7c478bd9Sstevel@tonic-gate 	    memcmp("/", sep->contents, sep->length) != 0);
552*7c478bd9Sstevel@tonic-gate }
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate static bool_t
556*7c478bd9Sstevel@tonic-gate syntax_attrs_equal(const FN_attrset_t *syn1, const FN_attrset_t *syn2)
557*7c478bd9Sstevel@tonic-gate {
558*7c478bd9Sstevel@tonic-gate 	const FN_attribute_t	*attr;
559*7c478bd9Sstevel@tonic-gate 	const FN_attrvalue_t	*val1;
560*7c478bd9Sstevel@tonic-gate 	const FN_attrvalue_t	*val2;
561*7c478bd9Sstevel@tonic-gate 	void			*iter1;
562*7c478bd9Sstevel@tonic-gate 	void			*iter2;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	if (fn_attrset_count(syn1) != fn_attrset_count(syn2)) {
565*7c478bd9Sstevel@tonic-gate 		return (FALSE);
566*7c478bd9Sstevel@tonic-gate 	}
567*7c478bd9Sstevel@tonic-gate 	for (attr = fn_attrset_first(syn1, &iter1);
568*7c478bd9Sstevel@tonic-gate 	    attr != NULL;
569*7c478bd9Sstevel@tonic-gate 	    attr = fn_attrset_next(syn1, &iter1)) {
570*7c478bd9Sstevel@tonic-gate 		val1 = fn_attribute_first(attr, &iter2);
571*7c478bd9Sstevel@tonic-gate 		val2 = get_attrval(syn2, fn_attribute_identifier(attr));
572*7c478bd9Sstevel@tonic-gate 		if ((val1 == NULL && val2 != NULL) ||
573*7c478bd9Sstevel@tonic-gate 		    (val1 != NULL && val2 == NULL)) {
574*7c478bd9Sstevel@tonic-gate 			return (FALSE);
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 		if (val1 != NULL && val2 != NULL) {
577*7c478bd9Sstevel@tonic-gate 			if (val1->length != val2->length ||
578*7c478bd9Sstevel@tonic-gate 			    memcmp(val1->contents, val2->contents,
579*7c478bd9Sstevel@tonic-gate 				    val1->length) != 0) {
580*7c478bd9Sstevel@tonic-gate 				return (FALSE);
581*7c478bd9Sstevel@tonic-gate 			}
582*7c478bd9Sstevel@tonic-gate 		}
583*7c478bd9Sstevel@tonic-gate 	}
584*7c478bd9Sstevel@tonic-gate 	return (TRUE);
585*7c478bd9Sstevel@tonic-gate }
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate static const FN_attrvalue_t *
589*7c478bd9Sstevel@tonic-gate get_attrval(const FN_attrset_t *attrs, const FN_identifier_t *attr_id)
590*7c478bd9Sstevel@tonic-gate {
591*7c478bd9Sstevel@tonic-gate 	const FN_attribute_t	*attr;
592*7c478bd9Sstevel@tonic-gate 	void			*iter;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	attr = fn_attrset_get(attrs, attr_id);
595*7c478bd9Sstevel@tonic-gate 	if (attr != NULL) {
596*7c478bd9Sstevel@tonic-gate 		return (fn_attribute_first(attr, &iter));
597*7c478bd9Sstevel@tonic-gate 	} else {
598*7c478bd9Sstevel@tonic-gate 		return (NULL);
599*7c478bd9Sstevel@tonic-gate 	}
600*7c478bd9Sstevel@tonic-gate }
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate static FN_ctx_t *
604*7c478bd9Sstevel@tonic-gate lookup_ctx(FN_ctx_t *ctx, const FN_composite_name_t *name, bool_t log,
605*7c478bd9Sstevel@tonic-gate     FN_status_t *status)
606*7c478bd9Sstevel@tonic-gate {
607*7c478bd9Sstevel@tonic-gate 	FN_ref_t	*ref;
608*7c478bd9Sstevel@tonic-gate 	char		*msg;
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	ref = fn_ctx_lookup(ctx, name, status);
611*7c478bd9Sstevel@tonic-gate 	if (ref == NULL) {
612*7c478bd9Sstevel@tonic-gate 		ctx = NULL;
613*7c478bd9Sstevel@tonic-gate 		msg = "lookup failed";
614*7c478bd9Sstevel@tonic-gate 	} else {
615*7c478bd9Sstevel@tonic-gate 		ctx = fn_ctx_handle_from_ref(ref, XFN2(0) status);
616*7c478bd9Sstevel@tonic-gate 		fn_ref_destroy(ref);
617*7c478bd9Sstevel@tonic-gate 		if (ctx == NULL) {
618*7c478bd9Sstevel@tonic-gate 			msg = "could not construct context handle";
619*7c478bd9Sstevel@tonic-gate 		}
620*7c478bd9Sstevel@tonic-gate 	}
621*7c478bd9Sstevel@tonic-gate 	if (ctx == NULL && verbose && (log || transient(status))) {
622*7c478bd9Sstevel@tonic-gate 		logstat(status, "", msg);
623*7c478bd9Sstevel@tonic-gate 	}
624*7c478bd9Sstevel@tonic-gate 	return (ctx);
625*7c478bd9Sstevel@tonic-gate }
626