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]
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
29 #include <libnvpair.h>
30 #include <fm/topo_mod.h>
31 #include <sys/fm/protocol.h>
34 #include <sys/types.h>
36 #include <sys/objfs.h>
37 #include <sys/modctl.h>
41 #include <topo_method.h>
42 #include <topo_subr.h>
45 static int mod_enum(topo_mod_t
*, tnode_t
*, const char *, topo_instance_t
,
46 topo_instance_t
, void *, void *);
47 static void mod_release(topo_mod_t
*, tnode_t
*);
48 static int mod_fmri_create_meth(topo_mod_t
*, tnode_t
*, topo_version_t
,
49 nvlist_t
*, nvlist_t
**);
50 static int mod_fmri_nvl2str(topo_mod_t
*, tnode_t
*, topo_version_t
,
51 nvlist_t
*, nvlist_t
**);
53 static const topo_method_t mod_methods
[] = {
54 { TOPO_METH_FMRI
, TOPO_METH_FMRI_DESC
, TOPO_METH_FMRI_VERSION
,
55 TOPO_STABILITY_INTERNAL
, mod_fmri_create_meth
},
56 { TOPO_METH_NVL2STR
, TOPO_METH_NVL2STR_DESC
, TOPO_METH_NVL2STR_VERSION
,
57 TOPO_STABILITY_INTERNAL
, mod_fmri_nvl2str
},
61 static const topo_modops_t mod_modops
=
62 { mod_enum
, mod_release
};
63 static const topo_modinfo_t mod_info
=
64 { "mod", FM_FMRI_SCHEME_MOD
, MOD_VERSION
, &mod_modops
};
67 mod_init(topo_mod_t
*mod
, topo_version_t version
)
69 if (getenv("TOPOMODDEBUG"))
70 topo_mod_setdebug(mod
);
71 topo_mod_dprintf(mod
, "initializing mod builtin\n");
73 if (version
!= MOD_VERSION
)
74 return (topo_mod_seterrno(mod
, EMOD_VER_NEW
));
76 if (topo_mod_register(mod
, &mod_info
, TOPO_VERSION
) != 0) {
77 topo_mod_dprintf(mod
, "failed to register mod_info: "
78 "%s\n", topo_mod_errmsg(mod
));
79 return (-1); /* mod errno already set */
86 mod_fini(topo_mod_t
*mod
)
88 topo_mod_unregister(mod
);
93 mod_enum(topo_mod_t
*mod
, tnode_t
*pnode
, const char *name
,
94 topo_instance_t min
, topo_instance_t max
, void *notused1
, void *notused2
)
97 * Methods are registered, but there is no enumeration. Should
98 * enumeration be added be sure to cater for global vs non-global
101 (void) topo_method_register(mod
, pnode
, mod_methods
);
106 mod_release(topo_mod_t
*mod
, tnode_t
*node
)
108 topo_method_unregister_all(mod
, node
);
112 mod_binary_path_get(topo_mod_t
*mp
, const char *objpath
)
120 if ((fd
= open(objpath
, O_RDONLY
)) < 0) {
121 topo_mod_dprintf(mp
, "unable to open %s\n", objpath
);
125 if (elf_version(EV_CURRENT
) == EV_NONE
) {
126 topo_mod_dprintf(mp
, "Elf version out of whack\n");
129 if ((elf
= elf_begin(fd
, ELF_C_READ
, NULL
)) == NULL
) {
130 topo_mod_dprintf(mp
, "elf_begin failed\n");
133 if ((gelf_getehdr(elf
, &ehdr
)) == NULL
) {
134 topo_mod_dprintf(mp
, "gelf_getehdr failed\n");
137 scn
= elf_getscn(elf
, 0); /* "seek" to start of sections */
138 while ((scn
= elf_nextscn(elf
, scn
)) != NULL
) {
140 if (gelf_getshdr(scn
, &shdr
) == NULL
) {
141 topo_mod_dprintf(mp
, "gelf_getshdr failed\n");
144 if (shdr
.sh_type
!= SHT_PROGBITS
)
146 sh_name
= elf_strptr(elf
,
147 ehdr
.e_shstrndx
, (size_t)shdr
.sh_name
);
148 if (strcmp(sh_name
, ".filename") != 0)
150 if (elf_getdata(scn
, NULL
) == NULL
) {
151 topo_mod_dprintf(mp
, "no filename data");
165 (void) topo_mod_seterrno(mp
, EMOD_METHOD_INVAL
);
170 mod_nvl_data(topo_mod_t
*mp
, nvlist_t
*out
, const char *path
)
176 if (stat64(path
, &s
) < 0) {
178 "No system object file for driver %s", path
);
179 return (topo_mod_seterrno(mp
, EMOD_METHOD_INVAL
));
182 id
= OBJFS_MODID(s
.st_ino
);
183 mi
.mi_id
= mi
.mi_nextid
= id
;
184 mi
.mi_info
= MI_INFO_ONE
| MI_INFO_NOBASE
;
185 if (modctl(MODINFO
, id
, &mi
) < 0) {
186 return (topo_mod_seterrno(mp
, EMOD_METHOD_INVAL
));
188 mi
.mi_name
[MODMAXNAMELEN
- 1] = '\0';
189 mi
.mi_msinfo
[0].msi_linkinfo
[MODMAXNAMELEN
- 1] = '\0';
190 e
= nvlist_add_string(out
, FM_FMRI_SCHEME
, FM_FMRI_SCHEME_MOD
);
191 e
|= nvlist_add_uint8(out
, FM_VERSION
, FM_MOD_SCHEME_VERSION
);
192 e
|= nvlist_add_int32(out
, FM_FMRI_MOD_ID
, id
);
193 e
|= nvlist_add_string(out
, FM_FMRI_MOD_NAME
, mi
.mi_name
);
194 e
|= nvlist_add_string(out
,
195 FM_FMRI_MOD_DESC
, mi
.mi_msinfo
[0].msi_linkinfo
);
197 return (topo_mod_seterrno(mp
, EMOD_FMRI_NVL
));
203 mod_fmri_create(topo_mod_t
*mp
, const char *driver
)
205 nvlist_t
*out
= NULL
;
206 char objpath
[PATH_MAX
];
208 if (topo_mod_nvalloc(mp
, &out
, NV_UNIQUE_NAME
) != 0) {
209 (void) topo_mod_seterrno(mp
, EMOD_FMRI_NVL
);
213 (void) snprintf(objpath
, PATH_MAX
, "%s/%s/object", OBJFS_ROOT
, driver
);
216 * Validate the module object ELF header if possible
218 if (mod_binary_path_get(mp
, objpath
) < 0)
221 if (mod_nvl_data(mp
, out
, objpath
) < 0) {
222 topo_mod_dprintf(mp
, "failed to get modinfo for %s", driver
);
235 mod_fmri_create_meth(topo_mod_t
*mp
, tnode_t
*node
, topo_version_t version
,
236 nvlist_t
*in
, nvlist_t
**out
)
242 if (version
> TOPO_METH_FMRI_VERSION
)
243 return (topo_mod_seterrno(mp
, EMOD_VER_NEW
));
245 if (nvlist_lookup_nvlist(in
, TOPO_METH_FMRI_ARG_NVL
, &args
) != 0 ||
246 nvlist_lookup_string(args
, "DRIVER", &driver
) != 0) {
247 topo_mod_dprintf(mp
, "no DRIVER string in method argument\n");
248 return (topo_mod_seterrno(mp
, EMOD_METHOD_INVAL
));
251 modnvl
= mod_fmri_create(mp
, driver
);
252 if (modnvl
== NULL
) {
254 topo_mod_dprintf(mp
, "failed to create contained mod FMRI\n");
264 fmri_nvl2str(nvlist_t
*nvl
, char *buf
, size_t buflen
)
266 nvlist_t
*anvl
= NULL
;
271 char *modname
= NULL
, *aname
, *aval
;
272 char numbuf
[MAXINTSTR
];
275 if (nvlist_lookup_uint8(nvl
, FM_VERSION
, &version
) != 0 ||
276 version
> FM_MOD_SCHEME_VERSION
)
279 /* Get authority, if present */
280 err
= nvlist_lookup_nvlist(nvl
, FM_FMRI_AUTHORITY
, &anvl
);
281 if (err
!= 0 && err
!= ENOENT
)
285 * For brevity, we only include the module name and id
286 * present in the FMRI in our output string. The FMRI
287 * also has data on the package containing the module.
290 /* There must be a module name */
291 err
= nvlist_lookup_string(nvl
, FM_FMRI_MOD_NAME
, &modname
);
292 if (err
!= 0 || modname
== NULL
)
295 /* There must be a module id */
296 err
= nvlist_lookup_int32(nvl
, FM_FMRI_MOD_ID
, &modid
);
301 topo_fmristr_build(&size
, buf
, buflen
, FM_FMRI_SCHEME_MOD
, NULL
, "://");
303 /* authority, if any */
305 for (apair
= nvlist_next_nvpair(anvl
, NULL
);
306 apair
!= NULL
; apair
= nvlist_next_nvpair(anvl
, apair
)) {
307 if (nvpair_type(apair
) != DATA_TYPE_STRING
||
308 nvpair_value_string(apair
, &aval
) != 0)
310 aname
= nvpair_name(apair
);
311 topo_fmristr_build(&size
, buf
, buflen
, ":", NULL
, NULL
);
312 topo_fmristr_build(&size
, buf
, buflen
, "=",
318 topo_fmristr_build(&size
, buf
, buflen
, modname
,
319 "/" FM_FMRI_MOD_NAME
"=", "/");
321 (void) snprintf(numbuf
, MAXINTSTR
, "%d", modid
);
322 topo_fmristr_build(&size
, buf
, buflen
, numbuf
, FM_FMRI_MOD_ID
"=",
330 mod_fmri_nvl2str(topo_mod_t
*mod
, tnode_t
*node
, topo_version_t version
,
331 nvlist_t
*nvl
, nvlist_t
**out
)
337 if (version
> TOPO_METH_NVL2STR_VERSION
)
338 return (topo_mod_seterrno(mod
, EMOD_VER_NEW
));
340 if ((len
= fmri_nvl2str(nvl
, NULL
, 0)) == 0 ||
341 (name
= topo_mod_alloc(mod
, len
+ 1)) == NULL
||
342 fmri_nvl2str(nvl
, name
, len
+ 1) == 0) {
344 topo_mod_free(mod
, name
, len
+ 1);
345 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
348 if (topo_mod_nvalloc(mod
, &fmristr
, NV_UNIQUE_NAME
) != 0)
349 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
350 if (nvlist_add_string(fmristr
, "fmri-string", name
) != 0) {
351 topo_mod_free(mod
, name
, len
+ 1);
352 nvlist_free(fmristr
);
353 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
355 topo_mod_free(mod
, name
, len
+ 1);