xref: /titanic_52/usr/src/lib/libfstyp/common/libfstyp.c (revision 0e42dee69ed771bf604dd1789fca9d77b5bbe302)
1*0e42dee6Sartem /*
2*0e42dee6Sartem  * CDDL HEADER START
3*0e42dee6Sartem  *
4*0e42dee6Sartem  * The contents of this file are subject to the terms of the
5*0e42dee6Sartem  * Common Development and Distribution License (the "License").
6*0e42dee6Sartem  * You may not use this file except in compliance with the License.
7*0e42dee6Sartem  *
8*0e42dee6Sartem  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*0e42dee6Sartem  * or http://www.opensolaris.org/os/licensing.
10*0e42dee6Sartem  * See the License for the specific language governing permissions
11*0e42dee6Sartem  * and limitations under the License.
12*0e42dee6Sartem  *
13*0e42dee6Sartem  * When distributing Covered Code, include this CDDL HEADER in each
14*0e42dee6Sartem  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*0e42dee6Sartem  * If applicable, add the following below this CDDL HEADER, with the
16*0e42dee6Sartem  * fields enclosed by brackets "[]" replaced with your own identifying
17*0e42dee6Sartem  * information: Portions Copyright [yyyy] [name of copyright owner]
18*0e42dee6Sartem  *
19*0e42dee6Sartem  * CDDL HEADER END
20*0e42dee6Sartem  */
21*0e42dee6Sartem /*
22*0e42dee6Sartem  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*0e42dee6Sartem  * Use is subject to license terms.
24*0e42dee6Sartem  */
25*0e42dee6Sartem 
26*0e42dee6Sartem #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*0e42dee6Sartem 
28*0e42dee6Sartem #include <stdio.h>
29*0e42dee6Sartem #include <stdlib.h>
30*0e42dee6Sartem #include <libintl.h>
31*0e42dee6Sartem #include <errno.h>
32*0e42dee6Sartem #include <strings.h>
33*0e42dee6Sartem #include <unistd.h>
34*0e42dee6Sartem #include <sys/types.h>
35*0e42dee6Sartem #include <sys/stat.h>
36*0e42dee6Sartem #include <sys/param.h>
37*0e42dee6Sartem #include <sys/fstyp.h>
38*0e42dee6Sartem #include <fcntl.h>
39*0e42dee6Sartem #include <errno.h>
40*0e42dee6Sartem #include <dirent.h>
41*0e42dee6Sartem #include <dlfcn.h>
42*0e42dee6Sartem #include <link.h>
43*0e42dee6Sartem #include <libnvpair.h>
44*0e42dee6Sartem #include <libfstyp.h>
45*0e42dee6Sartem #include <libfstyp_module.h>
46*0e42dee6Sartem 
47*0e42dee6Sartem /* default module directory */
48*0e42dee6Sartem const char *default_libfs_dir = "/usr/lib/fs";
49*0e42dee6Sartem 
50*0e42dee6Sartem #define	FSTYP_VERSION	1
51*0e42dee6Sartem 
52*0e42dee6Sartem #ifndef	TEXT_DOMAIN
53*0e42dee6Sartem #define	TEXT_DOMAIN	"SYS_TEST"
54*0e42dee6Sartem #endif
55*0e42dee6Sartem 
56*0e42dee6Sartem typedef struct fstyp_ops {
57*0e42dee6Sartem 	int		(*fstyp_init)(int fd, off64_t offset,
58*0e42dee6Sartem 			fstyp_mod_handle_t *handle);
59*0e42dee6Sartem 	void		(*fstyp_fini)(fstyp_mod_handle_t handle);
60*0e42dee6Sartem 	int		(*fstyp_ident)(fstyp_mod_handle_t handle);
61*0e42dee6Sartem 	int		(*fstyp_get_attr)(fstyp_mod_handle_t handle,
62*0e42dee6Sartem 			nvlist_t **attr);
63*0e42dee6Sartem 	int		(*fstyp_dump)(fstyp_mod_handle_t handle,
64*0e42dee6Sartem 			FILE *fout, FILE *ferr);
65*0e42dee6Sartem } fstyp_ops_t;
66*0e42dee6Sartem 
67*0e42dee6Sartem typedef struct fstyp_module {
68*0e42dee6Sartem 	struct fstyp_module *next;
69*0e42dee6Sartem 	char		fsname[FSTYPSZ + 1];
70*0e42dee6Sartem 	char		*pathname;	/* absolute module pathname */
71*0e42dee6Sartem 	void		*dl_handle;	/* can be NULL if not loaded */
72*0e42dee6Sartem 	fstyp_ops_t	ops;
73*0e42dee6Sartem 	fstyp_mod_handle_t mod_handle;
74*0e42dee6Sartem } fstyp_module_t;
75*0e42dee6Sartem 
76*0e42dee6Sartem struct fstyp_handle {
77*0e42dee6Sartem 	char		*libfs_dir;	/* directory to look for modules */
78*0e42dee6Sartem 	char		*module_dir;	/* specific module directory */
79*0e42dee6Sartem 	fstyp_module_t	*modules;	/* list of modules */
80*0e42dee6Sartem 	fstyp_module_t	*modules_tail;	/* last module in the list */
81*0e42dee6Sartem 	fstyp_module_t	*ident;		/* identified module */
82*0e42dee6Sartem 	int		fd;
83*0e42dee6Sartem 	off64_t		offset;
84*0e42dee6Sartem 	long		name_max;
85*0e42dee6Sartem };
86*0e42dee6Sartem 
87*0e42dee6Sartem #define	NELEM(a)	sizeof (a) / sizeof (*(a))
88*0e42dee6Sartem 
89*0e42dee6Sartem /* local functions */
90*0e42dee6Sartem static int	fstyp_ident_all(struct fstyp_handle *h, const char **ident);
91*0e42dee6Sartem static int	fstyp_ident_one(struct fstyp_handle *h, const char *fsname,
92*0e42dee6Sartem 		const char **ident);
93*0e42dee6Sartem static fstyp_module_t *fstyp_find_module_by_name(struct fstyp_handle *h,
94*0e42dee6Sartem 		const char *fsname);
95*0e42dee6Sartem static int	fstyp_init_module(struct fstyp_handle *h,
96*0e42dee6Sartem 		char *mdir, char *fsname, fstyp_module_t **mpp);
97*0e42dee6Sartem static void	fstyp_fini_module(struct fstyp_handle *h,
98*0e42dee6Sartem 		fstyp_module_t *mp);
99*0e42dee6Sartem static int	fstyp_init_all_modules(struct fstyp_handle *h);
100*0e42dee6Sartem static void	fstyp_fini_all_modules(struct fstyp_handle *h);
101*0e42dee6Sartem static int	fstyp_load_module(struct fstyp_handle *h,
102*0e42dee6Sartem 		fstyp_module_t *mp);
103*0e42dee6Sartem static void	fstyp_unload_module(struct fstyp_handle *h,
104*0e42dee6Sartem 		fstyp_module_t *);
105*0e42dee6Sartem 
106*0e42dee6Sartem /*
107*0e42dee6Sartem  * Locate and initialize all modules.
108*0e42dee6Sartem  * If 'module_dir' is specified, only initialize module from this dir.
109*0e42dee6Sartem  */
110*0e42dee6Sartem int
111*0e42dee6Sartem fstyp_init(int fd, off64_t offset, char *module_dir, fstyp_handle_t *handle)
112*0e42dee6Sartem {
113*0e42dee6Sartem 	struct fstyp_handle *h;
114*0e42dee6Sartem 	int		error;
115*0e42dee6Sartem 
116*0e42dee6Sartem 	if ((h = calloc(1, sizeof (struct fstyp_handle))) == NULL) {
117*0e42dee6Sartem 		return (FSTYP_ERR_NOMEM);
118*0e42dee6Sartem 	}
119*0e42dee6Sartem 	if ((module_dir != NULL) &&
120*0e42dee6Sartem 	    ((h->module_dir = strdup(module_dir)) == NULL)) {
121*0e42dee6Sartem 		free(h);
122*0e42dee6Sartem 		return (FSTYP_ERR_NOMEM);
123*0e42dee6Sartem 	}
124*0e42dee6Sartem 
125*0e42dee6Sartem 	h->fd = fd;
126*0e42dee6Sartem 	h->offset = offset;
127*0e42dee6Sartem 	h->libfs_dir = (char *)default_libfs_dir;
128*0e42dee6Sartem 
129*0e42dee6Sartem 	if ((h->name_max = pathconf(h->libfs_dir, _PC_NAME_MAX)) < 0) {
130*0e42dee6Sartem 		h->name_max = MAXNAMELEN;
131*0e42dee6Sartem 	}
132*0e42dee6Sartem 	h->name_max++;
133*0e42dee6Sartem 
134*0e42dee6Sartem 	if (h->module_dir == NULL) {
135*0e42dee6Sartem 		error = fstyp_init_all_modules(h);
136*0e42dee6Sartem 	} else {
137*0e42dee6Sartem 		error = fstyp_init_module(h, h->module_dir, "", NULL);
138*0e42dee6Sartem 	}
139*0e42dee6Sartem 	if (error != 0) {
140*0e42dee6Sartem 		fstyp_fini(h);
141*0e42dee6Sartem 		return (error);
142*0e42dee6Sartem 	}
143*0e42dee6Sartem 
144*0e42dee6Sartem 	*handle = h;
145*0e42dee6Sartem 	return (0);
146*0e42dee6Sartem }
147*0e42dee6Sartem 
148*0e42dee6Sartem void
149*0e42dee6Sartem fstyp_fini(struct fstyp_handle *h)
150*0e42dee6Sartem {
151*0e42dee6Sartem 	if (h != NULL) {
152*0e42dee6Sartem 		fstyp_fini_all_modules(h);
153*0e42dee6Sartem 		if (h->module_dir != NULL) {
154*0e42dee6Sartem 			free(h->module_dir);
155*0e42dee6Sartem 		}
156*0e42dee6Sartem 		free(h);
157*0e42dee6Sartem 	}
158*0e42dee6Sartem }
159*0e42dee6Sartem 
160*0e42dee6Sartem /*
161*0e42dee6Sartem  * Identify the filesystem, return result in 'ident'.
162*0e42dee6Sartem  * If 'fsname' is specified, only attempt that filesystem.
163*0e42dee6Sartem  */
164*0e42dee6Sartem int
165*0e42dee6Sartem fstyp_ident(struct fstyp_handle *h, const char *fsname, const char **ident)
166*0e42dee6Sartem {
167*0e42dee6Sartem 	if (fsname == NULL) {
168*0e42dee6Sartem 		return (fstyp_ident_all(h, ident));
169*0e42dee6Sartem 	} else {
170*0e42dee6Sartem 		return (fstyp_ident_one(h, fsname, ident));
171*0e42dee6Sartem 	}
172*0e42dee6Sartem }
173*0e42dee6Sartem 
174*0e42dee6Sartem /*
175*0e42dee6Sartem  * use all modules for identification
176*0e42dee6Sartem  */
177*0e42dee6Sartem static int
178*0e42dee6Sartem fstyp_ident_all(struct fstyp_handle *h, const char **ident)
179*0e42dee6Sartem {
180*0e42dee6Sartem 	fstyp_module_t	*mp;
181*0e42dee6Sartem 
182*0e42dee6Sartem 	if (h->ident != NULL) {
183*0e42dee6Sartem 		*ident = &h->ident->fsname[0];
184*0e42dee6Sartem 		return (0);
185*0e42dee6Sartem 	}
186*0e42dee6Sartem 
187*0e42dee6Sartem 	for (mp = h->modules; mp != NULL; mp = mp->next) {
188*0e42dee6Sartem 		if ((fstyp_load_module(h, mp) == 0) &&
189*0e42dee6Sartem 		    (mp->ops.fstyp_ident(mp->mod_handle) == 0)) {
190*0e42dee6Sartem 			if (h->ident != NULL) {
191*0e42dee6Sartem 				h->ident = NULL;
192*0e42dee6Sartem 				*ident = NULL;
193*0e42dee6Sartem 				return (FSTYP_ERR_MULT_MATCH);
194*0e42dee6Sartem 			} else {
195*0e42dee6Sartem 				h->ident = mp;
196*0e42dee6Sartem 				*ident = &mp->fsname[0];
197*0e42dee6Sartem 				return (0);
198*0e42dee6Sartem 			}
199*0e42dee6Sartem 		}
200*0e42dee6Sartem 	}
201*0e42dee6Sartem 	return (FSTYP_ERR_NO_MATCH);
202*0e42dee6Sartem }
203*0e42dee6Sartem 
204*0e42dee6Sartem /*
205*0e42dee6Sartem  * use only the specified module for identification
206*0e42dee6Sartem  */
207*0e42dee6Sartem static int
208*0e42dee6Sartem fstyp_ident_one(struct fstyp_handle *h, const char *fsname, const char **ident)
209*0e42dee6Sartem {
210*0e42dee6Sartem 	fstyp_module_t	*mp;
211*0e42dee6Sartem 	int		error = FSTYP_ERR_NO_MATCH;
212*0e42dee6Sartem 
213*0e42dee6Sartem 	if (h->ident != NULL) {
214*0e42dee6Sartem 		if (strcmp(h->ident->fsname, fsname) == 0) {
215*0e42dee6Sartem 			*ident = (char *)fsname;
216*0e42dee6Sartem 			return (0);
217*0e42dee6Sartem 		} else {
218*0e42dee6Sartem 			return (FSTYP_ERR_NO_MATCH);
219*0e42dee6Sartem 		}
220*0e42dee6Sartem 	}
221*0e42dee6Sartem 
222*0e42dee6Sartem 	if (strlen(fsname) > FSTYPSZ) {
223*0e42dee6Sartem 		return (FSTYP_ERR_NAME_TOO_LONG);
224*0e42dee6Sartem 	}
225*0e42dee6Sartem 	if (h->module_dir == NULL) {
226*0e42dee6Sartem 		mp = fstyp_find_module_by_name(h, fsname);
227*0e42dee6Sartem 	} else {
228*0e42dee6Sartem 		mp = h->modules;
229*0e42dee6Sartem 	}
230*0e42dee6Sartem 	if (mp == NULL) {
231*0e42dee6Sartem 		return (FSTYP_ERR_MOD_NOT_FOUND);
232*0e42dee6Sartem 	}
233*0e42dee6Sartem 
234*0e42dee6Sartem 	if (((error = fstyp_load_module(h, mp)) == 0) &&
235*0e42dee6Sartem 	    ((error = mp->ops.fstyp_ident(mp->mod_handle)) == 0)) {
236*0e42dee6Sartem 		h->ident = mp;
237*0e42dee6Sartem 		*ident = (char *)fsname;
238*0e42dee6Sartem 		return (0);
239*0e42dee6Sartem 	}
240*0e42dee6Sartem 	return (error);
241*0e42dee6Sartem }
242*0e42dee6Sartem 
243*0e42dee6Sartem /*
244*0e42dee6Sartem  * Get the list of fs attributes.
245*0e42dee6Sartem  */
246*0e42dee6Sartem int
247*0e42dee6Sartem fstyp_get_attr(struct fstyp_handle *h, nvlist_t **attr)
248*0e42dee6Sartem {
249*0e42dee6Sartem 	fstyp_module_t	*mp = h->ident;
250*0e42dee6Sartem 
251*0e42dee6Sartem 	if (mp == NULL) {
252*0e42dee6Sartem 		return (FSTYP_ERR_NO_MATCH);
253*0e42dee6Sartem 	}
254*0e42dee6Sartem 
255*0e42dee6Sartem 	return (mp->ops.fstyp_get_attr(mp->mod_handle, attr));
256*0e42dee6Sartem }
257*0e42dee6Sartem 
258*0e42dee6Sartem /*
259*0e42dee6Sartem  * Dump free-form filesystem information.
260*0e42dee6Sartem  */
261*0e42dee6Sartem int
262*0e42dee6Sartem fstyp_dump(struct fstyp_handle *h, FILE *fout, FILE *ferr)
263*0e42dee6Sartem {
264*0e42dee6Sartem 	fstyp_module_t	*mp = h->ident;
265*0e42dee6Sartem 
266*0e42dee6Sartem 	if (mp == NULL) {
267*0e42dee6Sartem 		return (FSTYP_ERR_NO_MATCH);
268*0e42dee6Sartem 	}
269*0e42dee6Sartem 
270*0e42dee6Sartem 	if (mp->ops.fstyp_dump == NULL) {
271*0e42dee6Sartem 		return (FSTYP_ERR_NOP);
272*0e42dee6Sartem 	}
273*0e42dee6Sartem 
274*0e42dee6Sartem 	return (mp->ops.fstyp_dump(mp->mod_handle, fout, ferr));
275*0e42dee6Sartem }
276*0e42dee6Sartem 
277*0e42dee6Sartem /* ARGSUSED */
278*0e42dee6Sartem const char *
279*0e42dee6Sartem fstyp_strerror(struct fstyp_handle *h, int error)
280*0e42dee6Sartem {
281*0e42dee6Sartem 	char *str;
282*0e42dee6Sartem 
283*0e42dee6Sartem 	switch (error) {
284*0e42dee6Sartem 	case FSTYP_ERR_OK:
285*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "success");
286*0e42dee6Sartem 		break;
287*0e42dee6Sartem 	case FSTYP_ERR_NO_MATCH:
288*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "no matches");
289*0e42dee6Sartem 		break;
290*0e42dee6Sartem 	case FSTYP_ERR_MULT_MATCH:
291*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "multiple matches");
292*0e42dee6Sartem 		break;
293*0e42dee6Sartem 	case FSTYP_ERR_HANDLE:
294*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "invalid handle");
295*0e42dee6Sartem 		break;
296*0e42dee6Sartem 	case FSTYP_ERR_OFFSET:
297*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "invalid or unsupported offset");
298*0e42dee6Sartem 		break;
299*0e42dee6Sartem 	case FSTYP_ERR_NO_PARTITION:
300*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "partition not found");
301*0e42dee6Sartem 		break;
302*0e42dee6Sartem 	case FSTYP_ERR_NOP:
303*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "no such operation");
304*0e42dee6Sartem 		break;
305*0e42dee6Sartem 	case FSTYP_ERR_DEV_OPEN:
306*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "cannot open device");
307*0e42dee6Sartem 		break;
308*0e42dee6Sartem 	case FSTYP_ERR_IO:
309*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "i/o error");
310*0e42dee6Sartem 		break;
311*0e42dee6Sartem 	case FSTYP_ERR_NOMEM:
312*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "out of memory");
313*0e42dee6Sartem 		break;
314*0e42dee6Sartem 	case FSTYP_ERR_MOD_NOT_FOUND:
315*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "module not found");
316*0e42dee6Sartem 		break;
317*0e42dee6Sartem 	case FSTYP_ERR_MOD_DIR_OPEN:
318*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "cannot open module directory");
319*0e42dee6Sartem 		break;
320*0e42dee6Sartem 	case FSTYP_ERR_MOD_OPEN:
321*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "cannot open module");
322*0e42dee6Sartem 		break;
323*0e42dee6Sartem 	case FSTYP_ERR_MOD_VERSION:
324*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "invalid module version");
325*0e42dee6Sartem 		break;
326*0e42dee6Sartem 	case FSTYP_ERR_MOD_INVALID:
327*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "invalid module");
328*0e42dee6Sartem 		break;
329*0e42dee6Sartem 	case FSTYP_ERR_NAME_TOO_LONG:
330*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "filesystem name too long");
331*0e42dee6Sartem 		break;
332*0e42dee6Sartem 	default:
333*0e42dee6Sartem 		str = dgettext(TEXT_DOMAIN, "undefined error");
334*0e42dee6Sartem 		break;
335*0e42dee6Sartem 	}
336*0e42dee6Sartem 
337*0e42dee6Sartem 	return (str);
338*0e42dee6Sartem }
339*0e42dee6Sartem 
340*0e42dee6Sartem 
341*0e42dee6Sartem static fstyp_module_t *
342*0e42dee6Sartem fstyp_find_module_by_name(struct fstyp_handle *h, const char *fsname)
343*0e42dee6Sartem {
344*0e42dee6Sartem 	fstyp_module_t	*mp;
345*0e42dee6Sartem 
346*0e42dee6Sartem 	for (mp = h->modules; mp != NULL; mp = mp->next) {
347*0e42dee6Sartem 		if (strcmp(mp->fsname, fsname) == 0) {
348*0e42dee6Sartem 			return (mp);
349*0e42dee6Sartem 		}
350*0e42dee6Sartem 	}
351*0e42dee6Sartem 	return (NULL);
352*0e42dee6Sartem }
353*0e42dee6Sartem 
354*0e42dee6Sartem /*
355*0e42dee6Sartem  * Allocate and initialize module structure. Do not load just yet.
356*0e42dee6Sartem  * A pointer to the existing module is returned, if such is found.
357*0e42dee6Sartem  */
358*0e42dee6Sartem static int
359*0e42dee6Sartem fstyp_init_module(struct fstyp_handle *h, char *mdir, char *fsname,
360*0e42dee6Sartem     fstyp_module_t **mpp)
361*0e42dee6Sartem {
362*0e42dee6Sartem 	char		*pathname;
363*0e42dee6Sartem 	struct stat	sb;
364*0e42dee6Sartem 	fstyp_module_t	*mp;
365*0e42dee6Sartem 
366*0e42dee6Sartem 	/* if it's already inited, just return the pointer */
367*0e42dee6Sartem 	if ((mp = fstyp_find_module_by_name(h, fsname)) != NULL) {
368*0e42dee6Sartem 		if (mpp != NULL) {
369*0e42dee6Sartem 			*mpp = mp;
370*0e42dee6Sartem 		}
371*0e42dee6Sartem 		return (0);
372*0e42dee6Sartem 	}
373*0e42dee6Sartem 
374*0e42dee6Sartem 	/* allocate pathname buffer */
375*0e42dee6Sartem 	if ((pathname = calloc(1, h->name_max)) == NULL) {
376*0e42dee6Sartem 		return (FSTYP_ERR_NOMEM);
377*0e42dee6Sartem 	}
378*0e42dee6Sartem 
379*0e42dee6Sartem 	/* locate module */
380*0e42dee6Sartem 	(void) snprintf(pathname, h->name_max, "%s/fstyp.so.%d", mdir,
381*0e42dee6Sartem 	    FSTYP_VERSION);
382*0e42dee6Sartem 	if (stat(pathname, &sb) < 0) {
383*0e42dee6Sartem 		return (FSTYP_ERR_MOD_NOT_FOUND);
384*0e42dee6Sartem 	}
385*0e42dee6Sartem 
386*0e42dee6Sartem 	if ((mp = calloc(1, sizeof (fstyp_module_t))) == NULL) {
387*0e42dee6Sartem 		free(pathname);
388*0e42dee6Sartem 		return (FSTYP_ERR_NOMEM);
389*0e42dee6Sartem 	}
390*0e42dee6Sartem 
391*0e42dee6Sartem 	mp->pathname = pathname;
392*0e42dee6Sartem 	(void) strlcpy(mp->fsname, fsname, sizeof (mp->fsname));
393*0e42dee6Sartem 
394*0e42dee6Sartem 	/* append to list */
395*0e42dee6Sartem 	if (h->modules_tail == NULL) {
396*0e42dee6Sartem 		h->modules = h->modules_tail = mp;
397*0e42dee6Sartem 	} else {
398*0e42dee6Sartem 		h->modules_tail->next = mp;
399*0e42dee6Sartem 		h->modules_tail = mp;
400*0e42dee6Sartem 	}
401*0e42dee6Sartem 
402*0e42dee6Sartem 	if (mpp != NULL) {
403*0e42dee6Sartem 		*mpp = mp;
404*0e42dee6Sartem 	}
405*0e42dee6Sartem 	return (0);
406*0e42dee6Sartem }
407*0e42dee6Sartem 
408*0e42dee6Sartem /*
409*0e42dee6Sartem  * Free module resources. NOTE: this does not update the module list.
410*0e42dee6Sartem  */
411*0e42dee6Sartem static void
412*0e42dee6Sartem fstyp_fini_module(struct fstyp_handle *h, fstyp_module_t *mp)
413*0e42dee6Sartem {
414*0e42dee6Sartem 	if (h->ident == mp) {
415*0e42dee6Sartem 		h->ident = NULL;
416*0e42dee6Sartem 	}
417*0e42dee6Sartem 	fstyp_unload_module(h, mp);
418*0e42dee6Sartem 	if (mp->pathname != NULL) {
419*0e42dee6Sartem 		free(mp->pathname);
420*0e42dee6Sartem 	}
421*0e42dee6Sartem 	free(mp);
422*0e42dee6Sartem }
423*0e42dee6Sartem 
424*0e42dee6Sartem /*
425*0e42dee6Sartem  * Look for .so's and save them in the list.
426*0e42dee6Sartem  */
427*0e42dee6Sartem static int
428*0e42dee6Sartem fstyp_init_all_modules(struct fstyp_handle *h)
429*0e42dee6Sartem {
430*0e42dee6Sartem 	char		*mdir;
431*0e42dee6Sartem 	DIR		*dirp;
432*0e42dee6Sartem 	struct dirent	*dp_mem, *dp;
433*0e42dee6Sartem 
434*0e42dee6Sartem 	if ((mdir = calloc(1, h->name_max)) == NULL) {
435*0e42dee6Sartem 		return (FSTYP_ERR_NOMEM);
436*0e42dee6Sartem 	}
437*0e42dee6Sartem 	dp = dp_mem = calloc(1, sizeof (struct dirent) + h->name_max + 1);
438*0e42dee6Sartem 	if (dp == NULL) {
439*0e42dee6Sartem 		return (FSTYP_ERR_NOMEM);
440*0e42dee6Sartem 	}
441*0e42dee6Sartem 	if ((dirp = opendir(h->libfs_dir)) == NULL) {
442*0e42dee6Sartem 		free(mdir);
443*0e42dee6Sartem 		free(dp_mem);
444*0e42dee6Sartem 		return (FSTYP_ERR_MOD_DIR_OPEN);
445*0e42dee6Sartem 	}
446*0e42dee6Sartem 
447*0e42dee6Sartem 	while ((readdir_r(dirp, dp, &dp) == 0) && (dp != NULL)) {
448*0e42dee6Sartem 		if (dp->d_name[0] == '.') {
449*0e42dee6Sartem 			continue;
450*0e42dee6Sartem 		}
451*0e42dee6Sartem 		(void) snprintf(mdir, h->name_max,
452*0e42dee6Sartem 		    "%s/%s", h->libfs_dir, dp->d_name);
453*0e42dee6Sartem 		(void) fstyp_init_module(h, mdir, dp->d_name, NULL);
454*0e42dee6Sartem 	}
455*0e42dee6Sartem 
456*0e42dee6Sartem 	free(mdir);
457*0e42dee6Sartem 	free(dp_mem);
458*0e42dee6Sartem 	(void) closedir(dirp);
459*0e42dee6Sartem 	return (0);
460*0e42dee6Sartem }
461*0e42dee6Sartem 
462*0e42dee6Sartem static void
463*0e42dee6Sartem fstyp_fini_all_modules(struct fstyp_handle *h)
464*0e42dee6Sartem {
465*0e42dee6Sartem 	fstyp_module_t	*mp, *mp_next;
466*0e42dee6Sartem 
467*0e42dee6Sartem 	for (mp = h->modules; mp != NULL; mp = mp_next) {
468*0e42dee6Sartem 		mp_next = mp->next;
469*0e42dee6Sartem 		fstyp_fini_module(h, mp);
470*0e42dee6Sartem 	}
471*0e42dee6Sartem 	h->modules = h->modules_tail = h->ident = NULL;
472*0e42dee6Sartem }
473*0e42dee6Sartem 
474*0e42dee6Sartem 
475*0e42dee6Sartem /*
476*0e42dee6Sartem  * Load the .so module.
477*0e42dee6Sartem  */
478*0e42dee6Sartem static int
479*0e42dee6Sartem fstyp_load_module(struct fstyp_handle *h, fstyp_module_t *mp)
480*0e42dee6Sartem {
481*0e42dee6Sartem 	int	error;
482*0e42dee6Sartem 
483*0e42dee6Sartem 	if (mp->dl_handle != NULL) {
484*0e42dee6Sartem 		return (0);
485*0e42dee6Sartem 	}
486*0e42dee6Sartem 
487*0e42dee6Sartem 	if ((mp->dl_handle = dlopen(mp->pathname, RTLD_LAZY)) == NULL) {
488*0e42dee6Sartem 		return (FSTYP_ERR_MOD_OPEN);
489*0e42dee6Sartem 	}
490*0e42dee6Sartem 
491*0e42dee6Sartem 	mp->ops.fstyp_init = (int (*)(int, off64_t, fstyp_mod_handle_t *))
492*0e42dee6Sartem 	    dlsym(mp->dl_handle, "fstyp_mod_init");
493*0e42dee6Sartem 	mp->ops.fstyp_fini = (void (*)(fstyp_mod_handle_t))
494*0e42dee6Sartem 	    dlsym(mp->dl_handle, "fstyp_mod_fini");
495*0e42dee6Sartem 	mp->ops.fstyp_ident = (int (*)(fstyp_mod_handle_t))
496*0e42dee6Sartem 	    dlsym(mp->dl_handle, "fstyp_mod_ident");
497*0e42dee6Sartem 	mp->ops.fstyp_get_attr = (int (*)(fstyp_mod_handle_t, nvlist_t **))
498*0e42dee6Sartem 	    dlsym(mp->dl_handle, "fstyp_mod_get_attr");
499*0e42dee6Sartem 	mp->ops.fstyp_dump = (int (*)(fstyp_mod_handle_t, FILE *, FILE *))
500*0e42dee6Sartem 	    dlsym(mp->dl_handle, "fstyp_mod_dump");
501*0e42dee6Sartem 
502*0e42dee6Sartem 	if (((mp->ops.fstyp_init) == NULL) ||
503*0e42dee6Sartem 	    ((mp->ops.fstyp_fini) == NULL) ||
504*0e42dee6Sartem 	    ((mp->ops.fstyp_ident) == NULL) ||
505*0e42dee6Sartem 	    ((mp->ops.fstyp_get_attr) == NULL)) {
506*0e42dee6Sartem 		fstyp_unload_module(h, mp);
507*0e42dee6Sartem 		return (FSTYP_ERR_MOD_INVALID);
508*0e42dee6Sartem 	}
509*0e42dee6Sartem 
510*0e42dee6Sartem 	error = mp->ops.fstyp_init(h->fd, h->offset, &mp->mod_handle);
511*0e42dee6Sartem 	if (error != 0) {
512*0e42dee6Sartem 		fstyp_unload_module(h, mp);
513*0e42dee6Sartem 		return (error);
514*0e42dee6Sartem 	}
515*0e42dee6Sartem 
516*0e42dee6Sartem 	return (0);
517*0e42dee6Sartem }
518*0e42dee6Sartem 
519*0e42dee6Sartem /*ARGSUSED*/
520*0e42dee6Sartem static void
521*0e42dee6Sartem fstyp_unload_module(struct fstyp_handle *h, fstyp_module_t *mp)
522*0e42dee6Sartem {
523*0e42dee6Sartem 	if (mp->mod_handle != NULL) {
524*0e42dee6Sartem 		mp->ops.fstyp_fini(mp->mod_handle);
525*0e42dee6Sartem 		mp->mod_handle = NULL;
526*0e42dee6Sartem 	}
527*0e42dee6Sartem 	if (mp->dl_handle != NULL) {
528*0e42dee6Sartem 		(void) dlclose(mp->dl_handle);
529*0e42dee6Sartem 		mp->dl_handle = NULL;
530*0e42dee6Sartem 	}
531*0e42dee6Sartem }
532