4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
34 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/fstyp.h>
43 #include <libnvpair.h>
45 #include <libfstyp_module.h>
47 /* default module directory */
48 const char *default_libfs_dir
= "/usr/lib/fs";
50 #define FSTYP_VERSION 1
53 #define TEXT_DOMAIN "SYS_TEST"
56 typedef struct fstyp_ops
{
57 int (*fstyp_init
)(int fd
, off64_t offset
,
58 fstyp_mod_handle_t
*handle
);
59 void (*fstyp_fini
)(fstyp_mod_handle_t handle
);
60 int (*fstyp_ident
)(fstyp_mod_handle_t handle
);
61 int (*fstyp_get_attr
)(fstyp_mod_handle_t handle
,
63 int (*fstyp_dump
)(fstyp_mod_handle_t handle
,
64 FILE *fout
, FILE *ferr
);
67 typedef struct fstyp_module
{
68 struct fstyp_module
*next
;
69 char fsname
[FSTYPSZ
+ 1];
70 char *pathname
; /* absolute module pathname */
71 void *dl_handle
; /* can be NULL if not loaded */
73 fstyp_mod_handle_t mod_handle
;
77 char *libfs_dir
; /* directory to look for modules */
78 char *module_dir
; /* specific module directory */
79 fstyp_module_t
*modules
; /* list of modules */
80 fstyp_module_t
*modules_tail
; /* last module in the list */
81 fstyp_module_t
*ident
; /* identified module */
87 #define NELEM(a) sizeof (a) / sizeof (*(a))
90 static int fstyp_ident_all(struct fstyp_handle
*h
, const char **ident
);
91 static int fstyp_ident_one(struct fstyp_handle
*h
, const char *fsname
,
93 static fstyp_module_t
*fstyp_find_module_by_name(struct fstyp_handle
*h
,
95 static int fstyp_init_module(struct fstyp_handle
*h
,
96 char *mdir
, char *fsname
, fstyp_module_t
**mpp
);
97 static void fstyp_fini_module(struct fstyp_handle
*h
,
99 static int fstyp_init_all_modules(struct fstyp_handle
*h
);
100 static void fstyp_fini_all_modules(struct fstyp_handle
*h
);
101 static int fstyp_load_module(struct fstyp_handle
*h
,
103 static void fstyp_unload_module(struct fstyp_handle
*h
,
107 * Locate and initialize all modules.
108 * If 'module_dir' is specified, only initialize module from this dir.
111 fstyp_init(int fd
, off64_t offset
, char *module_dir
, fstyp_handle_t
*handle
)
113 struct fstyp_handle
*h
;
116 if ((h
= calloc(1, sizeof (struct fstyp_handle
))) == NULL
) {
117 return (FSTYP_ERR_NOMEM
);
119 if ((module_dir
!= NULL
) &&
120 ((h
->module_dir
= strdup(module_dir
)) == NULL
)) {
122 return (FSTYP_ERR_NOMEM
);
127 h
->libfs_dir
= (char *)default_libfs_dir
;
129 if ((h
->name_max
= pathconf(h
->libfs_dir
, _PC_NAME_MAX
)) < 0) {
130 h
->name_max
= MAXNAMELEN
;
134 if (h
->module_dir
== NULL
) {
135 error
= fstyp_init_all_modules(h
);
137 error
= fstyp_init_module(h
, h
->module_dir
, "", NULL
);
149 fstyp_fini(struct fstyp_handle
*h
)
152 fstyp_fini_all_modules(h
);
153 if (h
->module_dir
!= NULL
) {
161 * Identify the filesystem, return result in 'ident'.
162 * If 'fsname' is specified, only attempt that filesystem.
165 fstyp_ident(struct fstyp_handle
*h
, const char *fsname
, const char **ident
)
167 if (fsname
== NULL
) {
168 return (fstyp_ident_all(h
, ident
));
170 return (fstyp_ident_one(h
, fsname
, ident
));
175 * use all modules for identification
178 fstyp_ident_all(struct fstyp_handle
*h
, const char **ident
)
182 if (h
->ident
!= NULL
) {
183 *ident
= &h
->ident
->fsname
[0];
187 for (mp
= h
->modules
; mp
!= NULL
; mp
= mp
->next
) {
188 if ((fstyp_load_module(h
, mp
) == 0) &&
189 (mp
->ops
.fstyp_ident(mp
->mod_handle
) == 0)) {
190 if (h
->ident
!= NULL
) {
193 return (FSTYP_ERR_MULT_MATCH
);
196 *ident
= &mp
->fsname
[0];
201 return (FSTYP_ERR_NO_MATCH
);
205 * use only the specified module for identification
208 fstyp_ident_one(struct fstyp_handle
*h
, const char *fsname
, const char **ident
)
211 int error
= FSTYP_ERR_NO_MATCH
;
213 if (h
->ident
!= NULL
) {
214 if (strcmp(h
->ident
->fsname
, fsname
) == 0) {
215 *ident
= (char *)fsname
;
218 return (FSTYP_ERR_NO_MATCH
);
222 if (strlen(fsname
) > FSTYPSZ
) {
223 return (FSTYP_ERR_NAME_TOO_LONG
);
225 if (h
->module_dir
== NULL
) {
226 mp
= fstyp_find_module_by_name(h
, fsname
);
231 return (FSTYP_ERR_MOD_NOT_FOUND
);
234 if (((error
= fstyp_load_module(h
, mp
)) == 0) &&
235 ((error
= mp
->ops
.fstyp_ident(mp
->mod_handle
)) == 0)) {
237 *ident
= (char *)fsname
;
244 * Get the list of fs attributes.
247 fstyp_get_attr(struct fstyp_handle
*h
, nvlist_t
**attr
)
249 fstyp_module_t
*mp
= h
->ident
;
252 return (FSTYP_ERR_NO_MATCH
);
255 return (mp
->ops
.fstyp_get_attr(mp
->mod_handle
, attr
));
259 * Dump free-form filesystem information.
262 fstyp_dump(struct fstyp_handle
*h
, FILE *fout
, FILE *ferr
)
264 fstyp_module_t
*mp
= h
->ident
;
267 return (FSTYP_ERR_NO_MATCH
);
270 if (mp
->ops
.fstyp_dump
== NULL
) {
271 return (FSTYP_ERR_NOP
);
274 return (mp
->ops
.fstyp_dump(mp
->mod_handle
, fout
, ferr
));
279 fstyp_strerror(struct fstyp_handle
*h
, int error
)
285 str
= dgettext(TEXT_DOMAIN
, "success");
287 case FSTYP_ERR_NO_MATCH
:
288 str
= dgettext(TEXT_DOMAIN
, "no matches");
290 case FSTYP_ERR_MULT_MATCH
:
291 str
= dgettext(TEXT_DOMAIN
, "multiple matches");
293 case FSTYP_ERR_HANDLE
:
294 str
= dgettext(TEXT_DOMAIN
, "invalid handle");
296 case FSTYP_ERR_OFFSET
:
297 str
= dgettext(TEXT_DOMAIN
, "invalid or unsupported offset");
299 case FSTYP_ERR_NO_PARTITION
:
300 str
= dgettext(TEXT_DOMAIN
, "partition not found");
303 str
= dgettext(TEXT_DOMAIN
, "no such operation");
305 case FSTYP_ERR_DEV_OPEN
:
306 str
= dgettext(TEXT_DOMAIN
, "cannot open device");
309 str
= dgettext(TEXT_DOMAIN
, "i/o error");
311 case FSTYP_ERR_NOMEM
:
312 str
= dgettext(TEXT_DOMAIN
, "out of memory");
314 case FSTYP_ERR_MOD_NOT_FOUND
:
315 str
= dgettext(TEXT_DOMAIN
, "module not found");
317 case FSTYP_ERR_MOD_DIR_OPEN
:
318 str
= dgettext(TEXT_DOMAIN
, "cannot open module directory");
320 case FSTYP_ERR_MOD_OPEN
:
321 str
= dgettext(TEXT_DOMAIN
, "cannot open module");
323 case FSTYP_ERR_MOD_VERSION
:
324 str
= dgettext(TEXT_DOMAIN
, "invalid module version");
326 case FSTYP_ERR_MOD_INVALID
:
327 str
= dgettext(TEXT_DOMAIN
, "invalid module");
329 case FSTYP_ERR_NAME_TOO_LONG
:
330 str
= dgettext(TEXT_DOMAIN
, "filesystem name too long");
333 str
= dgettext(TEXT_DOMAIN
, "undefined error");
341 static fstyp_module_t
*
342 fstyp_find_module_by_name(struct fstyp_handle
*h
, const char *fsname
)
346 for (mp
= h
->modules
; mp
!= NULL
; mp
= mp
->next
) {
347 if (strcmp(mp
->fsname
, fsname
) == 0) {
355 * Allocate and initialize module structure. Do not load just yet.
356 * A pointer to the existing module is returned, if such is found.
359 fstyp_init_module(struct fstyp_handle
*h
, char *mdir
, char *fsname
,
360 fstyp_module_t
**mpp
)
366 /* if it's already inited, just return the pointer */
367 if ((mp
= fstyp_find_module_by_name(h
, fsname
)) != NULL
) {
374 /* allocate pathname buffer */
375 if ((pathname
= calloc(1, h
->name_max
)) == NULL
) {
376 return (FSTYP_ERR_NOMEM
);
380 (void) snprintf(pathname
, h
->name_max
, "%s/fstyp.so.%d", mdir
,
382 if (stat(pathname
, &sb
) < 0) {
383 return (FSTYP_ERR_MOD_NOT_FOUND
);
386 if ((mp
= calloc(1, sizeof (fstyp_module_t
))) == NULL
) {
388 return (FSTYP_ERR_NOMEM
);
391 mp
->pathname
= pathname
;
392 (void) strlcpy(mp
->fsname
, fsname
, sizeof (mp
->fsname
));
395 if (h
->modules_tail
== NULL
) {
396 h
->modules
= h
->modules_tail
= mp
;
398 h
->modules_tail
->next
= mp
;
399 h
->modules_tail
= mp
;
409 * Free module resources. NOTE: this does not update the module list.
412 fstyp_fini_module(struct fstyp_handle
*h
, fstyp_module_t
*mp
)
414 if (h
->ident
== mp
) {
417 fstyp_unload_module(h
, mp
);
418 if (mp
->pathname
!= NULL
) {
425 * Look for .so's and save them in the list.
428 fstyp_init_all_modules(struct fstyp_handle
*h
)
432 struct dirent
*dp_mem
, *dp
;
434 if ((mdir
= calloc(1, h
->name_max
)) == NULL
) {
435 return (FSTYP_ERR_NOMEM
);
437 dp
= dp_mem
= calloc(1, sizeof (struct dirent
) + h
->name_max
+ 1);
439 return (FSTYP_ERR_NOMEM
);
441 if ((dirp
= opendir(h
->libfs_dir
)) == NULL
) {
444 return (FSTYP_ERR_MOD_DIR_OPEN
);
447 while ((readdir_r(dirp
, dp
, &dp
) == 0) && (dp
!= NULL
)) {
448 if (dp
->d_name
[0] == '.') {
451 (void) snprintf(mdir
, h
->name_max
,
452 "%s/%s", h
->libfs_dir
, dp
->d_name
);
453 (void) fstyp_init_module(h
, mdir
, dp
->d_name
, NULL
);
458 (void) closedir(dirp
);
463 fstyp_fini_all_modules(struct fstyp_handle
*h
)
465 fstyp_module_t
*mp
, *mp_next
;
467 for (mp
= h
->modules
; mp
!= NULL
; mp
= mp_next
) {
469 fstyp_fini_module(h
, mp
);
471 h
->modules
= h
->modules_tail
= h
->ident
= NULL
;
476 * Load the .so module.
479 fstyp_load_module(struct fstyp_handle
*h
, fstyp_module_t
*mp
)
483 if (mp
->dl_handle
!= NULL
) {
487 if ((mp
->dl_handle
= dlopen(mp
->pathname
, RTLD_LAZY
)) == NULL
) {
488 return (FSTYP_ERR_MOD_OPEN
);
491 mp
->ops
.fstyp_init
= (int (*)(int, off64_t
, fstyp_mod_handle_t
*))
492 dlsym(mp
->dl_handle
, "fstyp_mod_init");
493 mp
->ops
.fstyp_fini
= (void (*)(fstyp_mod_handle_t
))
494 dlsym(mp
->dl_handle
, "fstyp_mod_fini");
495 mp
->ops
.fstyp_ident
= (int (*)(fstyp_mod_handle_t
))
496 dlsym(mp
->dl_handle
, "fstyp_mod_ident");
497 mp
->ops
.fstyp_get_attr
= (int (*)(fstyp_mod_handle_t
, nvlist_t
**))
498 dlsym(mp
->dl_handle
, "fstyp_mod_get_attr");
499 mp
->ops
.fstyp_dump
= (int (*)(fstyp_mod_handle_t
, FILE *, FILE *))
500 dlsym(mp
->dl_handle
, "fstyp_mod_dump");
502 if (((mp
->ops
.fstyp_init
) == NULL
) ||
503 ((mp
->ops
.fstyp_fini
) == NULL
) ||
504 ((mp
->ops
.fstyp_ident
) == NULL
) ||
505 ((mp
->ops
.fstyp_get_attr
) == NULL
)) {
506 fstyp_unload_module(h
, mp
);
507 return (FSTYP_ERR_MOD_INVALID
);
510 error
= mp
->ops
.fstyp_init(h
->fd
, h
->offset
, &mp
->mod_handle
);
512 fstyp_unload_module(h
, mp
);
521 fstyp_unload_module(struct fstyp_handle
*h
, fstyp_module_t
*mp
)
523 if (mp
->mod_handle
!= NULL
) {
524 mp
->ops
.fstyp_fini(mp
->mod_handle
);
525 mp
->mod_handle
= NULL
;
527 if (mp
->dl_handle
!= NULL
) {
528 (void) dlclose(mp
->dl_handle
);
529 mp
->dl_handle
= NULL
;