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
fstyp_init(int fd,off64_t offset,char * module_dir,fstyp_handle_t * handle)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
fstyp_fini(struct fstyp_handle * h)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
fstyp_ident(struct fstyp_handle * h,const char * fsname,const char ** ident)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
fstyp_ident_all(struct fstyp_handle * h,const char ** ident)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
fstyp_ident_one(struct fstyp_handle * h,const char * fsname,const char ** ident)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
fstyp_get_attr(struct fstyp_handle * h,nvlist_t ** attr)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
fstyp_dump(struct fstyp_handle * h,FILE * fout,FILE * ferr)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 *
fstyp_strerror(struct fstyp_handle * h,int error)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 *
fstyp_find_module_by_name(struct fstyp_handle * h,const char * fsname)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
fstyp_init_module(struct fstyp_handle * h,char * mdir,char * fsname,fstyp_module_t ** mpp)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
fstyp_fini_module(struct fstyp_handle * h,fstyp_module_t * mp)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
fstyp_init_all_modules(struct fstyp_handle * h)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
fstyp_fini_all_modules(struct fstyp_handle * h)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
fstyp_load_module(struct fstyp_handle * h,fstyp_module_t * mp)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
fstyp_unload_module(struct fstyp_handle * h,fstyp_module_t * mp)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