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