summaryrefslogtreecommitdiff
path: root/usr/src/lib/fm
diff options
context:
space:
mode:
authorGavin Maltby <gavin.maltby@oracle.com>2010-07-30 17:04:17 +1000
committerGavin Maltby <gavin.maltby@oracle.com>2010-07-30 17:04:17 +1000
commitf6e214c7418f43af38bd8c3a557e3d0a1d311cfa (patch)
tree0f0e4cee5ead68ee30660107f9eccf7cd9e72c2e /usr/src/lib/fm
parent265a964d7aa43c47170d21d2f01bcf873d7fd79d (diff)
downloadillumos-joyent-f6e214c7418f43af38bd8c3a557e3d0a1d311cfa.tar.gz
PSARC/2009/617 Software Events Notification Parameters CLI
PSARC/2009/618 snmp-notify: SNMP Notification Daemon for Software Events PSARC/2009/619 smtp-notify: Email Notification Daemon for Software Events PSARC/2010/225 fmd for non-global Solaris zones PSARC/2010/226 Solaris Instance UUID PSARC/2010/227 nvlist_nvflag(3NVPAIR) PSARC/2010/228 libfmevent additions PSARC/2010/257 sysevent_evc_setpropnvl and sysevent_evc_getpropnvl PSARC/2010/265 FMRI and FMA Event Stabilty, 'ireport' category 1 event class, and the 'sw' FMRI scheme PSARC/2010/278 FMA/SMF integration: instance state transitions PSARC/2010/279 Modelling panics within FMA PSARC/2010/290 logadm.conf upgrade 6392476 fmdump needs to pretty-print 6393375 userland ereport/ireport event generation interfaces 6445732 Add email notification agent for FMA and software events 6804168 RFE: Allow an efficient means to monitor SMF services status changes 6866661 scf_values_destroy(3SCF) will segfault if is passed NULL 6884709 Add snmp notification agent for FMA and software events 6884712 Add private interface to tap into libfmd_msg macro expansion capabilities 6897919 fmd to run in a non-global zone 6897937 fmd use of non-private doors is not safe 6900081 add a UUID to Solaris kernel image for use in crashdump identification 6914884 model panic events as a defect diagnosis in FMA 6944862 fmd_case_open_uuid, fmd_case_uuisresolved, fmd_nvl_create_defect 6944866 log legacy sysevents in fmd 6944867 enumerate svc scheme in topo 6944868 software-diagnosis and software-response fmd modules 6944870 model SMF maintenance state as a defect diagnosis in FMA 6944876 savecore runs in foreground for systems with zfs root and dedicated dump 6965796 Implement notification parameters for SMF state transitions and FMA events 6968287 SUN-FM-MIB.mib needs to be updated to reflect Oracle information 6972331 logadm.conf upgrade PSARC/2010/290
Diffstat (limited to 'usr/src/lib/fm')
-rw-r--r--usr/src/lib/fm/Makefile2
-rw-r--r--usr/src/lib/fm/libfmd_msg/common/fmd_msg.c186
-rw-r--r--usr/src/lib/fm/libfmd_msg/common/fmd_msg.h7
-rw-r--r--usr/src/lib/fm/libfmd_msg/common/mapfile-vers2
-rw-r--r--usr/src/lib/fm/libfmd_snmp/Makefile5
-rw-r--r--usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h33
-rw-r--r--usr/src/lib/fm/libfmd_snmp/mibs/SUN-FM-MIB.mib24
-rw-r--r--usr/src/lib/fm/libfmd_snmp/mibs/SUN-IREPORT-MIB.mib204
-rw-r--r--usr/src/lib/fm/libfmevent/Makefile5
-rw-r--r--usr/src/lib/fm/libfmevent/Makefile.com11
-rw-r--r--usr/src/lib/fm/libfmevent/amd64/Makefile5
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_channels.h18
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_evaccess.c35
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_impl.h13
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_publish.c536
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_subscribe.c181
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_util.c57
-rw-r--r--usr/src/lib/fm/libfmevent/common/libfmevent.h305
-rw-r--r--usr/src/lib/fm/libfmevent/common/libfmevent_ruleset.h78
-rw-r--r--usr/src/lib/fm/libfmevent/common/mapfile-vers14
-rw-r--r--usr/src/lib/fm/libfmevent/i386/Makefile5
-rw-r--r--usr/src/lib/fm/libfmevent/sparc/Makefile5
-rw-r--r--usr/src/lib/fm/libfmevent/sparcv9/Makefile5
-rw-r--r--usr/src/lib/fm/libfmnotify/Makefile55
-rw-r--r--usr/src/lib/fm/libfmnotify/Makefile.com63
-rw-r--r--usr/src/lib/fm/libfmnotify/amd64/Makefile31
-rw-r--r--usr/src/lib/fm/libfmnotify/common/libfmnotify.c616
-rw-r--r--usr/src/lib/fm/libfmnotify/common/libfmnotify.h109
-rw-r--r--usr/src/lib/fm/libfmnotify/common/llib-lfmnotify27
-rw-r--r--usr/src/lib/fm/libfmnotify/common/mapfile-vers61
-rw-r--r--usr/src/lib/fm/libfmnotify/i386/Makefile32
-rw-r--r--usr/src/lib/fm/libfmnotify/sparc/Makefile31
-rw-r--r--usr/src/lib/fm/libfmnotify/sparcv9/Makefile32
-rw-r--r--usr/src/lib/fm/topo/libtopo/Makefile.com4
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/dev.c5
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/fmd.c9
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc.c5
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/mem.c11
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/mod.c8
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/pkg.c10
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/svc.c305
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/sw.c530
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/sw.h42
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_builtin.c5
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.c67
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.h7
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_node.c6
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_snap.c6
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/zfs.c8
49 files changed, 3661 insertions, 160 deletions
diff --git a/usr/src/lib/fm/Makefile b/usr/src/lib/fm/Makefile
index 31bb3d9ef4..d0bcbfe8c9 100644
--- a/usr/src/lib/fm/Makefile
+++ b/usr/src/lib/fm/Makefile
@@ -35,6 +35,8 @@ common_SUBDIRS = \
libfmd_msg \
libfmd_snmp \
libfmevent \
+ .WAIT \
+ libfmnotify \
topo
sparc_SUBDIRS = \
diff --git a/usr/src/lib/fm/libfmd_msg/common/fmd_msg.c b/usr/src/lib/fm/libfmd_msg/common/fmd_msg.c
index 7bf4f32947..86cf4ddf75 100644
--- a/usr/src/lib/fm/libfmd_msg/common/fmd_msg.c
+++ b/usr/src/lib/fm/libfmd_msg/common/fmd_msg.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -45,6 +44,8 @@
*
* fmd_msg_gettext_nv - format the entire message for the given event
* fmd_msg_gettext_id - format the entire message for the given event code
+ * fmd_msg_gettext_key - format the entire message for the given dict for the
+ * given explicit message key
*
* fmd_msg_getitem_nv - format a single message item for the given event
* fmd_msg_getitem_id - format a single message item for the given event code
@@ -99,6 +100,7 @@
#include <alloca.h>
#include <assert.h>
+#include <netdb.h>
#include <pthread.h>
#include <synch.h>
#include <strings.h>
@@ -106,6 +108,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
#include <sys/sysmacros.h>
#include <fmd_msg.h>
@@ -1130,6 +1133,125 @@ eos:
}
/*
+ * This is a private interface used by the notification daemons to parse tokens
+ * in user-supplied message templates.
+ */
+char *
+fmd_msg_decode_tokens(nvlist_t *nvl, const char *msg, const char *url)
+{
+ fmd_msg_buf_t buf;
+ wchar_t *h, *u, *w, *p, *q;
+
+ char *s, *expr, host[MAXHOSTNAMELEN + 1];
+ size_t elen;
+ int i;
+
+ u = fmd_msg_mbstowcs(url);
+
+ (void) gethostname(host, MAXHOSTNAMELEN + 1);
+ h = fmd_msg_mbstowcs(host);
+
+ if ((w = fmd_msg_mbstowcs(msg)) == NULL)
+ return (NULL);
+
+ /*
+ * Now expand any escape sequences in the string, storing the final
+ * text in 'buf' in wide-character format, and then convert it back
+ * to multi-byte for return. We expand the following sequences:
+ *
+ * %% - literal % character
+ * %h - hostname
+ * %s - base URL for knowledge articles
+ * %<x> - expression x in the current event, if any
+ *
+ * If an invalid sequence is present, it is elided so we can safely
+ * reserve any future characters for other types of expansions.
+ */
+ fmd_msg_buf_init(&buf);
+
+ for (q = w, p = w; (p = wcschr(p, L'%')) != NULL; q = p) {
+ if (p > q)
+ fmd_msg_buf_write(&buf, q, (size_t)(p - q));
+
+ switch (p[1]) {
+ case L'%':
+ fmd_msg_buf_write(&buf, p, 1);
+ p += 2;
+ break;
+
+ case L'h':
+ if (h != NULL)
+ fmd_msg_buf_write(&buf, h, wcslen(h));
+
+ p += 2;
+ break;
+
+ case L's':
+ if (u != NULL)
+ fmd_msg_buf_write(&buf, u, wcslen(u));
+
+ p += 2;
+ break;
+
+ case L'<':
+ q = p + 2;
+ p = wcschr(p + 2, L'>');
+
+ if (p == NULL)
+ goto eos;
+
+ /*
+ * The expression in %< > must be an ASCII string: as
+ * such allocate its length in bytes plus an extra
+ * MB_CUR_MAX for slop if a multi-byte character is in
+ * there, plus another byte for \0. Since we move a
+ * byte at a time, any multi-byte chars will just be
+ * silently overwritten and fail to parse, which is ok.
+ */
+ elen = (size_t)(p - q);
+ expr = malloc(elen + MB_CUR_MAX + 1);
+
+ if (expr == NULL) {
+ buf.fmb_error = ENOMEM;
+ goto eos;
+ }
+
+ for (i = 0; i < elen; i++)
+ (void) wctomb(&expr[i], q[i]);
+
+ expr[i] = '\0';
+
+ if (nvl != NULL)
+ (void) fmd_msg_nv_parse_nvname(&buf, nvl, expr);
+ else
+ fmd_msg_buf_printf(&buf, "%%<%s>", expr);
+
+ free(expr);
+ p++;
+ break;
+
+ case L'\0':
+ goto eos;
+
+ default:
+ p += 2;
+ break;
+ }
+ }
+eos:
+ fmd_msg_buf_write(&buf, q, wcslen(q) + 1);
+
+ free(h);
+ free(u);
+ free(w);
+
+ s = fmd_msg_buf_read(&buf);
+ fmd_msg_buf_fini(&buf);
+
+ return (s);
+}
+
+/*
* This function is the main engine for formatting an entire event message.
* It retrieves the master format string for an event, formats the individual
* items, and then produces the final string composing all of the items. The
@@ -1179,7 +1301,8 @@ fmd_msg_gettext_locked(fmd_msg_hdl_t *h,
if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME,
&tv, &tn) == 0 && tn == 2 && (sec = (time_t)tv[0]) != (time_t)-1 &&
(tmp = localtime_r(&sec, &tm)) != NULL)
- (void) strftime(date, sizeof (date), "%C", tmp);
+ (void) strftime(date, sizeof (date), "%a %b %e %H:%M:%S %Z %Y",
+ tmp);
else
(void) strlcpy(date, FMD_MSG_MISSING, sizeof (date));
@@ -1358,6 +1481,63 @@ fmd_msg_getitem_id(fmd_msg_hdl_t *h,
return (fmd_msg_getitem(h, locale, NULL, code, item));
}
+char *
+fmd_msg_gettext_key(fmd_msg_hdl_t *h,
+ const char *locale, const char *dict, const char *key)
+{
+ char *old_b, *old_c, *p, *s;
+
+ fmd_msg_lock();
+
+ /*
+ * If a non-default text domain binding was requested, save the old
+ * binding perform the re-bind now that fmd_msg_lock() is held.
+ */
+ if (h->fmh_binding != NULL) {
+ p = bindtextdomain(dict, NULL);
+ old_b = alloca(strlen(p) + 1);
+ (void) strcpy(old_b, p);
+ (void) bindtextdomain(dict, h->fmh_binding);
+ }
+
+ /*
+ * Save the current locale string, and if we've been asked to fetch
+ * the text for a different locale, switch locales now under the lock.
+ */
+ p = setlocale(LC_ALL, NULL);
+ old_c = alloca(strlen(p) + 1);
+ (void) strcpy(old_c, p);
+
+ if (locale != NULL)
+ (void) setlocale(LC_ALL, locale);
+
+ /*
+ * First attempt to fetch the string in the current locale. If this
+ * fails and we're in a non-default locale, attempt to fall back to the
+ * C locale and try again. If it still fails then we return NULL and
+ * set errno.
+ */
+ if ((s = dgettext(dict, key)) == key &&
+ (locale != NULL || strcmp(h->fmh_locale, "C") != 0)) {
+ (void) setlocale(LC_ALL, "C");
+ locale = "C"; /* restore locale */
+
+ if ((s = dgettext(dict, key)) == key) {
+ s = NULL;
+ errno = ENOENT;
+ }
+ }
+ if (locale != NULL)
+ (void) setlocale(LC_ALL, old_c);
+
+ if (h->fmh_binding != NULL)
+ (void) bindtextdomain(dict, old_b);
+
+ fmd_msg_unlock();
+
+ return (s);
+}
+
/*
* Common code for fmd_msg_gettext_nv() and fmd_msg_gettext_id(): this function
* handles locking, changing locales and domains, and restoring i18n state.
diff --git a/usr/src/lib/fm/libfmd_msg/common/fmd_msg.h b/usr/src/lib/fm/libfmd_msg/common/fmd_msg.h
index ac480e1c40..ebf25e0ef9 100644
--- a/usr/src/lib/fm/libfmd_msg/common/fmd_msg.h
+++ b/usr/src/lib/fm/libfmd_msg/common/fmd_msg.h
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _FMD_MSG_H
@@ -73,7 +72,9 @@ extern const char *fmd_msg_url_get(fmd_msg_hdl_t *);
extern char *fmd_msg_gettext_nv(fmd_msg_hdl_t *, const char *, nvlist_t *);
extern char *fmd_msg_gettext_id(fmd_msg_hdl_t *, const char *, const char *);
-
+extern char *fmd_msg_gettext_key(fmd_msg_hdl_t *, const char *, const char *,
+ const char *);
+extern char *fmd_msg_decode_tokens(nvlist_t *, const char *, const char *);
extern char *fmd_msg_getitem_nv(fmd_msg_hdl_t *,
const char *, nvlist_t *, fmd_msg_item_t);
diff --git a/usr/src/lib/fm/libfmd_msg/common/mapfile-vers b/usr/src/lib/fm/libfmd_msg/common/mapfile-vers
index 2c36a033be..15680a7f49 100644
--- a/usr/src/lib/fm/libfmd_msg/common/mapfile-vers
+++ b/usr/src/lib/fm/libfmd_msg/common/mapfile-vers
@@ -38,11 +38,13 @@ $mapfile_version 2
SYMBOL_VERSION SUNWprivate {
global:
+ fmd_msg_decode_tokens;
fmd_msg_fini;
fmd_msg_getitem_id;
fmd_msg_getitem_nv;
fmd_msg_gettext_id;
fmd_msg_gettext_nv;
+ fmd_msg_gettext_key;
fmd_msg_init;
fmd_msg_locale_get;
fmd_msg_locale_set;
diff --git a/usr/src/lib/fm/libfmd_snmp/Makefile b/usr/src/lib/fm/libfmd_snmp/Makefile
index 703e0020d9..c73060ee5f 100644
--- a/usr/src/lib/fm/libfmd_snmp/Makefile
+++ b/usr/src/lib/fm/libfmd_snmp/Makefile
@@ -19,8 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
#
#
@@ -33,7 +32,7 @@ HDRDIR = common
SUBDIRS = $(MACH)
$(BUILD64)SUBDIRS += $(MACH64)
-MIBFILES = SUN-FM-MIB.mib
+MIBFILES = SUN-FM-MIB.mib SUN-IREPORT-MIB.mib
ROOTNETSNMPMIBDIR = $(ROOT)/etc/net-snmp/snmp/mibs
ROOTMIBS = $(MIBFILES:%=$(ROOTNETSNMPMIBDIR)/%)
diff --git a/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h b/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h
index 5b15f664f3..b6f3a488a3 100644
--- a/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h
+++ b/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h
@@ -20,14 +20,11 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
-#ifndef _SUNFM_H
-#define _SUNFM_H
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+#ifndef _FMD_SNMP_H
+#define _FMD_SNMP_H
#ifdef __cplusplus
extern "C" {
@@ -35,7 +32,7 @@ extern "C" {
/*
* These values are derived from, and must remain consistent with, the
- * MIB definitions.
+ * MIB definitions in SUN-FM-MIB.
*/
#define MODNAME_STR "sunFM"
#define SUNFM_OID 1, 3, 6, 1, 4, 1, 42, 2, 195, 1
@@ -114,10 +111,30 @@ extern "C" {
#define SNMP_URL_MSG "snmp-url"
+/*
+ * Definitions from SUN-IREPORT-MIB
+ */
+#define SUNIREPORT_OID 1, 3, 6, 1, 4, 1, 42, 2, 197, 1
+
+#define SUNIREPORTNOTIFICATIONENTRY SUNIREPORT_OID, 1
+
+#define SUNIREPORTHOSTNAME_OID SUNIREPORTNOTIFICATIONENTRY, 1
+#define SUNIREPORTMSGID_OID SUNIREPORTNOTIFICATIONENTRY, 2
+#define SUNIREPORTDESCRIPTION_OID SUNIREPORTNOTIFICATIONENTRY, 3
+#define SUNIREPORTTIME_OID SUNIREPORTNOTIFICATIONENTRY, 4
+#define SUNIREPORTSMFFMRI_OID SUNIREPORTNOTIFICATIONENTRY, 5
+#define SUNIREPORTSMFFROMSTATE_OID SUNIREPORTNOTIFICATIONENTRY, 6
+#define SUNIREPORTSMFTOSTATE_OID SUNIREPORTNOTIFICATIONENTRY, 7
+#define SUNIREPORTTRANSITIONREASON_OID SUNIREPORTNOTIFICATIONENTRY, 8
+
+#define SUNIREPORTTRAPS_OID SUNIREPORT_OID, 2, 0
+#define SUNIREPORTTRAP_OID SUNIREPORTTRAPS_OID, 1
+
+
extern int init_sunFM(void);
#ifdef __cplusplus
}
#endif
-#endif /* _SUNFM_H */
+#endif /* _FMD_SNMP_H */
diff --git a/usr/src/lib/fm/libfmd_snmp/mibs/SUN-FM-MIB.mib b/usr/src/lib/fm/libfmd_snmp/mibs/SUN-FM-MIB.mib
index 1ab18a1d74..b093cbc365 100644
--- a/usr/src/lib/fm/libfmd_snmp/mibs/SUN-FM-MIB.mib
+++ b/usr/src/lib/fm/libfmd_snmp/mibs/SUN-FM-MIB.mib
@@ -20,12 +20,9 @@
--
--
--- Copyright 2008 Sun Microsystems, Inc. All rights reserved.
--- Use is subject to license terms.
+-- Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
--
--- ident "%Z%%M% %I% %E% SMI"
-
SUN-FM-MIB DEFINITIONS ::= BEGIN
IMPORTS
@@ -42,21 +39,20 @@ IMPORTS
sunFmMIB MODULE-IDENTITY
LAST-UPDATED "200808040000Z"
- ORGANIZATION "Sun Microsystems, Inc."
- CONTACT-INFO "Sun Microsystems, Inc.
- 4150 Network Circle
- Santa Clara, CA 95054
+ ORGANIZATION "Oracle Corporation"
+ CONTACT-INFO "Oracle Corporation
+ 500 Oracle Parkway
+ Redwood Shores, CA 94065
- 1-800-555-9SUN or
- 1-650-960-1300
+ 1.650.506.7000 or
+ 1.800.392.2999
- http://www.sun.com
+ http://www.oracle.com
or contact your local support representative"
DESCRIPTION
- "Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- Use is subject to license terms.
+ "Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- MIB providing access to Sun Fault Manager information"
+ MIB providing access to Oracle Fault Manager information"
REVISION "200808040000Z"
DESCRIPTION "Version: 1.1"
::= { fm 1 }
diff --git a/usr/src/lib/fm/libfmd_snmp/mibs/SUN-IREPORT-MIB.mib b/usr/src/lib/fm/libfmd_snmp/mibs/SUN-IREPORT-MIB.mib
new file mode 100644
index 0000000000..21523a2744
--- /dev/null
+++ b/usr/src/lib/fm/libfmd_snmp/mibs/SUN-IREPORT-MIB.mib
@@ -0,0 +1,204 @@
+--
+-- CDDL HEADER START
+--
+-- The contents of this file are subject to the terms of the
+-- Common Development and Distribution License (the "License").
+-- You may not use this file except in compliance with the License.
+--
+-- You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+-- or http://www.opensolaris.org/os/licensing.
+-- See the License for the specific language governing permissions
+-- and limitations under the License.
+--
+-- When distributing Covered Code, include this CDDL HEADER in each
+-- file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+-- If applicable, add the following below this CDDL HEADER, with the
+-- fields enclosed by brackets "[]" replaced with your own identifying
+-- information: Portions Copyright [yyyy] [name of copyright owner]
+--
+-- CDDL HEADER END
+--
+
+--
+-- Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+--
+
+SUN-IREPORT-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ products
+ FROM SUN-MIB
+ Gauge32, Unsigned32, OBJECT-TYPE, NOTIFICATION-TYPE, MODULE-IDENTITY
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION, DateAndTime, DisplayString
+ FROM SNMPv2-TC
+ OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF
+ URLString
+ FROM NETWORK-SERVICES-MIB;
+
+sunIreportMIB MODULE-IDENTITY
+ LAST-UPDATED "201007220000Z" -- July 22, 2010
+ ORGANIZATION "Oracle Corporation"
+ CONTACT-INFO "Oracle Corporation
+ 500 Oracle Parkway
+ Redwood Shores, CA 94065
+
+ 1.650.506.7000 or
+ 1.800.392.2999
+
+ http://www.oracle.com
+ or contact your local support representative"
+ DESCRIPTION
+ "Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ MIB providing access to Oracle Solaris Fault Management
+ Informational Report Notifications"
+
+ REVISION "201007220000Z" -- July 22, 2010
+ DESCRIPTION "Version: 1.0"
+ ::= { ireport 1 }
+
+SunIreportSmfFmriString ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents the FMRI of an SMF service"
+ SYNTAX OCTET STRING (SIZE (0..1023))
+
+SunIreportSmfState ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents an SMF service state"
+ SYNTAX INTEGER {
+ offline(0),
+ online(1),
+ degraded(2),
+ disabled(3),
+ maintenance(4),
+ uninitialized(5)
+ }
+
+ireport OBJECT IDENTIFIER ::= { products 197 }
+
+sunIreportNotification OBJECT-TYPE
+ SYNTAX SunIreportNotificationEntry
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Solaris informational event notification"
+ ::= { sunIreportMIB 1 }
+
+SunIreportNotificationEntry ::= SEQUENCE {
+ sunIreportHostname DisplayString,
+ sunIreportMsgid DisplayString,
+ sunIreportDescription DisplayString,
+ sunIreportTime DateAndTime,
+ sunIreportSmfFMRI SunIreportSmfFmriString,
+ sunIreportSmfFromState SunIreportSmfState,
+ sunIreportSmfToState SunIreportSmfState,
+ sunIreportSmfTransitionReason DisplayString
+}
+
+sunIreportHostname OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Hostname of the system on which the event occurred"
+ ::= { sunIreportNotification 1 }
+
+sunIreportMsgid OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Message ID of Knowledge Article associated with this event"
+ ::= { sunIreportNotification 2 }
+
+sunIreportDescription OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Description of the event"
+ ::= { sunIreportNotification 3 }
+
+sunIreportTime OBJECT-TYPE
+ SYNTAX DateAndTime
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Timestamp of the event"
+ ::= { sunIreportNotification 4 }
+
+sunIreportSmfFMRI OBJECT-TYPE
+ SYNTAX SunIreportSmfFmriString
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "FMRI of the SMF service asssociated with this event"
+ ::= { sunIreportNotification 5 }
+
+sunIreportSmfFromState OBJECT-TYPE
+ SYNTAX SunIreportSmfState
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Previous state of the service that transitioned"
+ ::= { sunIreportNotification 6 }
+
+sunIreportSmfToState OBJECT-TYPE
+ SYNTAX SunIreportSmfState
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Final state of the service that transitioned"
+ ::= { sunIreportNotification 7 }
+
+sunIreportSmfTransitionReason OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Reason for the state transition"
+ ::= { sunIreportNotification 8 }
+
+
+--
+-- RFC 3584 requires that the next-to-last sub-ID be zero to allow for
+-- mapping v2/v3 notifications to v1 traps.
+--
+
+sunIreportTraps OBJECT IDENTIFIER ::= { sunIreportMIB 2 0 }
+
+sunIreportTrap NOTIFICATION-TYPE
+ OBJECTS {
+ sunIreportHostname,
+ sunIreportMsgid,
+ sunIreportDescription,
+ sunIreportTime,
+ sunIreportSmfFMRI,
+ sunIreportSmfFromState,
+ sunIreportSmfToState,
+ sunIreportSmfTransitionReason
+ }
+ STATUS current
+ DESCRIPTION
+ "Trap notification that a Solaris informational report has
+ occurred.
+
+ The last four entries in the trap will only be set for SMF
+ service state transition (STN) events. The following values for
+ sunIreportMsgid correspond to an STN event:
+
+ SMF-8000-SR
+ SMF-8000-TC
+ SMF-8000-UQ
+ SMF-8000-VE
+ SMF-8000-WJ
+ SMF-8000-X2"
+
+ ::= { sunIreportTraps 1 }
+
+END
+
diff --git a/usr/src/lib/fm/libfmevent/Makefile b/usr/src/lib/fm/libfmevent/Makefile
index bcbca44b61..f68ff800da 100644
--- a/usr/src/lib/fm/libfmevent/Makefile
+++ b/usr/src/lib/fm/libfmevent/Makefile
@@ -19,14 +19,13 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
include ../../Makefile.lib
include ../Makefile.lib
-FMHDRS = libfmevent.h
+FMHDRS = libfmevent.h libfmevent_ruleset.h
HDRDIR = common
SUBDIRS = $(MACH)
diff --git a/usr/src/lib/fm/libfmevent/Makefile.com b/usr/src/lib/fm/libfmevent/Makefile.com
index ed023a34d7..1301bb5a2a 100644
--- a/usr/src/lib/fm/libfmevent/Makefile.com
+++ b/usr/src/lib/fm/libfmevent/Makefile.com
@@ -19,8 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
LIBRARY = libfmevent.a
@@ -29,7 +28,8 @@ VERS = .1
LIBSRCS = fmev_subscribe.c \
fmev_evaccess.c \
fmev_errstring.c \
- fmev_util.c
+ fmev_util.c \
+ fmev_publish.c
OBJECTS = $(LIBSRCS:%.c=%.o)
@@ -41,12 +41,15 @@ LIBS = $(DYNLIB) $(LINTLIB)
SRCDIR = ../common
+C99MODE = $(C99_ENABLE)
+
CPPFLAGS += -I../common -I.
$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS)
CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS)
-LDLIBS += -lumem -lnvpair -luutil -lsysevent -lc
+$(DYNLIB) := LDLIBS += -lumem -lnvpair -luutil -lsysevent -L$(ROOTLIBDIR) \
+ -ltopo -lc
LINTFLAGS = -msux
LINTFLAGS64 = -msux -m64
diff --git a/usr/src/lib/fm/libfmevent/amd64/Makefile b/usr/src/lib/fm/libfmevent/amd64/Makefile
index e628bce86d..0efa16d7ae 100644
--- a/usr/src/lib/fm/libfmevent/amd64/Makefile
+++ b/usr/src/lib/fm/libfmevent/amd64/Makefile
@@ -19,11 +19,12 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
include ../Makefile.com
include ../../../Makefile.lib.64
+DYNFLAGS += -R/usr/lib/fm/$(MACH64)
+
install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_channels.h b/usr/src/lib/fm/libfmevent/common/fmev_channels.h
index 033e4f52b3..56dea2e5bf 100644
--- a/usr/src/lib/fm/libfmevent/common/fmev_channels.h
+++ b/usr/src/lib/fm/libfmevent/common/fmev_channels.h
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _FMEV_CHANNELS_H
@@ -39,8 +38,23 @@
extern "C" {
#endif
+/*
+ * Channel that fmd forwards protocol events on, feeding the subscription
+ * aspect of libfmevent.
+ */
#define FMD_SNOOP_CHANNEL "com.sun:fm:protocol_snoop"
+/*
+ * Channels on which published events are dispatched towards fmd for
+ * processing into full protocol events.
+ */
+#define FMEV_CHAN_USER_PRIV_HV "com.sun:fm:user_priv_highval"
+#define FMEV_CHAN_USER_PRIV_LV "com.sun:fm:user_priv_lowval"
+#define FMEV_CHAN_USER_NOPRIV_HV "com.sun:fm:user_nopriv_highval"
+#define FMEV_CHAN_USER_NOPRIV_LV "com.sun:fm:user_nopriv_lowval"
+#define FMEV_CHAN_KERNEL_HV "com.sun:fm:kernel_highval"
+#define FMEV_CHAN_KERNEL_LV "com.sun:fm:kernel_lowval"
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c b/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c
index 442cf0bc01..519f4701d3 100644
--- a/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c
+++ b/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -38,9 +37,8 @@
#include "fmev_impl.h"
-#define API_ENTERV1(iep) \
- ((void) fmev_api_enter(fmev_shdl_cmn(((iep)->ei_hdl)), \
- LIBFMEVENT_VERSION_1))
+#define FMEV_API_ENTER(iep, v) \
+ fmev_api_enter(fmev_shdl_cmn(((iep)->ei_hdl)), LIBFMEVENT_VERSION_##v)
typedef struct {
uint32_t ei_magic; /* _FMEVMAGIC */
@@ -137,7 +135,7 @@ fmev_hold(fmev_t ev)
ASSERT(EVENT_VALID(iep));
- API_ENTERV1(iep);
+ (void) FMEV_API_ENTER(iep, 1);
atomic_inc_32(&iep->ei_refcnt);
}
@@ -149,7 +147,7 @@ fmev_rele(fmev_t ev)
ASSERT(EVENT_VALID(iep));
- API_ENTERV1(iep);
+ (void) FMEV_API_ENTER(iep, 1);
if (atomic_dec_32_nv(&iep->ei_refcnt) == 0)
fmev_free(iep);
@@ -163,7 +161,8 @@ fmev_dup(fmev_t ev)
ASSERT(EVENT_VALID(iep));
- API_ENTERV1(iep);
+ if (!FMEV_API_ENTER(iep, 1))
+ return (NULL); /* fmev_errno set */
if (ev == NULL) {
(void) fmev_seterr(FMEVERR_API);
@@ -194,7 +193,8 @@ fmev_attr_list(fmev_t ev)
ASSERT(EVENT_VALID(iep));
- API_ENTERV1(iep);
+ if (!FMEV_API_ENTER(iep, 1))
+ return (NULL); /* fmev_errno set */
if (ev == NULL) {
(void) fmev_seterr(FMEVERR_API);
@@ -215,7 +215,8 @@ fmev_class(fmev_t ev)
ASSERT(EVENT_VALID(iep));
- API_ENTERV1(iep);
+ if (!FMEV_API_ENTER(iep, 1))
+ return (NULL); /* fmev_errno set */
if (ev == NULL) {
(void) fmev_seterr(FMEVERR_API);
@@ -238,7 +239,8 @@ fmev_timespec(fmev_t ev, struct timespec *tp)
uint64_t timetlimit;
ASSERT(EVENT_VALID(iep));
- API_ENTERV1(iep);
+ if (!FMEV_API_ENTER(iep, 1))
+ return (fmev_errno);
#ifdef _LP64
timetlimit = INT64_MAX;
@@ -275,3 +277,14 @@ fmev_localtime(fmev_t ev, struct tm *tm)
seconds = (time_t)fmev_time_sec(ev);
return (localtime_r(&seconds, tm));
}
+
+fmev_shdl_t
+fmev_ev2shdl(fmev_t ev)
+{
+ fmev_impl_t *iep = FMEV2IMPL(ev);
+
+ if (!FMEV_API_ENTER(iep, 2))
+ return (NULL);
+
+ return (iep->ei_hdl);
+}
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_impl.h b/usr/src/lib/fm/libfmevent/common/fmev_impl.h
index 120660a27e..dc9e97cb49 100644
--- a/usr/src/lib/fm/libfmevent/common/fmev_impl.h
+++ b/usr/src/lib/fm/libfmevent/common/fmev_impl.h
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _FMEV_IMPL_H
@@ -44,6 +43,9 @@ extern "C" {
#include <libuutil.h>
#include <libsysevent.h>
#include <fm/libfmevent.h>
+#include <fm/libtopo.h>
+
+#include "fmev_channels.h"
#ifdef DEBUG
#define ASSERT(x) (assert(x))
@@ -59,8 +61,14 @@ struct fmev_hdl_cmn {
void (*hc_free)(void *, size_t);
};
+#define _FMEV_SHMAGIC 0x5368446c /* ShDl */
+
struct fmev_hdl_cmn *fmev_shdl_cmn(fmev_shdl_t);
+extern void *dflt_alloc(size_t);
+extern void *dflt_zalloc(size_t);
+extern void dflt_free(void *, size_t);
+
extern int fmev_api_init(struct fmev_hdl_cmn *);
extern int fmev_api_enter(struct fmev_hdl_cmn *, uint32_t);
extern void fmev_api_freetsd(void);
@@ -68,6 +76,7 @@ extern fmev_err_t fmev_seterr(fmev_err_t);
extern int fmev_shdl_valid(fmev_shdl_t);
extern fmev_t fmev_sysev2fmev(fmev_shdl_t, sysevent_t *sep, char **,
nvlist_t **);
+extern topo_hdl_t *fmev_topohdl(fmev_shdl_t);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_publish.c b/usr/src/lib/fm/libfmevent/common/fmev_publish.c
new file mode 100644
index 0000000000..f3dc01ed11
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/fmev_publish.c
@@ -0,0 +1,536 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * Simple-minded raw event publication from user context. See extensive
+ * comments in libfmevent.h. These interfaces remain Project Private -
+ * they have to evolve before rollout to Public levels.
+ *
+ * Events are dispatched synchronously using the GPEC sysevent mechanism.
+ * The caller context must therefore be one in which a sysevent_evc_publish
+ * (and possibly sysevent_evc_bind if not already bound) is safe. We will
+ * also allocate and manipulate nvlists.
+ *
+ * Since we use GPEC, which has no least privilege awareness, these interfaces
+ * will only work for would-be producers running as root.
+ *
+ * There is no event rate throttling applied, so we rely on producers
+ * to throttle themselves. A future refinement should apply mandatory
+ * but tuneable throttling on a per-producer basis. In this first version
+ * the only throttle is the publication event queue depth - we'll drop
+ * events when the queue is full.
+ *
+ * We can publish over four channels, for privileged/non-privileged and
+ * high/low priority. Since only privileged producers will work now
+ * (see above) we hardcode priv == B_TRUE and so only two channels are
+ * actually used, separating higher and lower value streams from privileged
+ * producers.
+ */
+
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <atomic.h>
+#include <errno.h>
+#include <pthread.h>
+#include <strings.h>
+
+#include "fmev_impl.h"
+
+static struct {
+ const char *name; /* channel name */
+ evchan_t *binding; /* GPEC binding, once bound */
+ const uint32_t flags; /* flags to use in binding */
+} chaninfo[] = {
+ { FMEV_CHAN_USER_NOPRIV_LV, NULL, 0 },
+ { FMEV_CHAN_USER_NOPRIV_HV, NULL, 0 },
+ { FMEV_CHAN_USER_PRIV_LV, NULL, EVCH_HOLD_PEND_INDEF },
+ { FMEV_CHAN_USER_PRIV_HV, NULL, EVCH_HOLD_PEND_INDEF}
+};
+
+#define CHANIDX(priv, pri) (2 * ((priv) != 0) + (pri == FMEV_HIPRI))
+
+#define CHAN_NAME(priv, pri) (chaninfo[CHANIDX(priv, pri)].name)
+#define CHAN_BINDING(priv, pri) (chaninfo[CHANIDX(priv, pri)].binding)
+#define CHAN_FLAGS(priv, pri) (chaninfo[CHANIDX(priv, pri)].flags)
+
+/*
+ * Called after fork in the new child. We clear the cached event
+ * channel bindings which are only valid in the process that created
+ * them.
+ */
+static void
+clear_bindings(void)
+{
+ int i;
+
+ for (i = 0; i < sizeof (chaninfo) / sizeof chaninfo[0]; i++)
+ chaninfo[i].binding = NULL;
+}
+
+#pragma init(_fmev_publish_init)
+
+static void
+_fmev_publish_init(void)
+{
+ (void) pthread_atfork(NULL, NULL, clear_bindings);
+}
+
+static evchan_t *
+bind_channel(boolean_t priv, fmev_pri_t pri)
+{
+ evchan_t **evcpp = &CHAN_BINDING(priv, pri);
+ evchan_t *evc;
+
+ if (*evcpp != NULL)
+ return (*evcpp);
+
+ if (sysevent_evc_bind(CHAN_NAME(priv, pri), &evc,
+ EVCH_CREAT | CHAN_FLAGS(priv, pri)) != 0)
+ return (NULL);
+
+ if (atomic_cas_ptr(evcpp, NULL, evc) != NULL)
+ (void) sysevent_evc_unbind(evc);
+
+ return (*evcpp);
+}
+
+static fmev_err_t
+vrfy_ruleset(const char *ruleset)
+{
+ if (ruleset != NULL &&
+ strnlen(ruleset, FMEV_MAX_RULESET_LEN) == FMEV_MAX_RULESET_LEN)
+ return (FMEVERR_STRING2BIG);
+
+ return (FMEV_OK);
+
+}
+
+static fmev_err_t
+vrfy_class(const char *class)
+{
+ if (class == NULL || *class == '\0')
+ return (FMEVERR_API);
+
+ if (strnlen(class, FMEV_PUB_MAXCLASSLEN) == FMEV_PUB_MAXCLASSLEN)
+ return (FMEVERR_STRING2BIG);
+
+ return (FMEV_OK);
+}
+
+static fmev_err_t
+vrfy_subclass(const char *subclass)
+{
+ if (subclass == NULL || *subclass == '\0')
+ return (FMEVERR_API);
+
+ if (strnlen(subclass, FMEV_PUB_MAXSUBCLASSLEN) ==
+ FMEV_PUB_MAXSUBCLASSLEN)
+ return (FMEVERR_STRING2BIG);
+
+ return (FMEV_OK);
+}
+
+static fmev_err_t
+vrfy_pri(fmev_pri_t pri)
+{
+ return (pri == FMEV_LOPRI || pri == FMEV_HIPRI ?
+ FMEV_OK : FMEVERR_API);
+}
+
+const char *
+fmev_pri_string(fmev_pri_t pri)
+{
+ static const char *pristr[] = { "low", "high" };
+
+ if (vrfy_pri(pri) != FMEV_OK)
+ return (NULL);
+
+ return (pristr[pri - FMEV_LOPRI]);
+}
+
+static fmev_err_t
+vrfy(const char **rulesetp, const char **classp, const char **subclassp,
+ fmev_pri_t *prip)
+{
+ fmev_err_t rc = FMEV_OK;
+
+ if (rulesetp && (rc = vrfy_ruleset(*rulesetp)) != FMEV_OK)
+ return (rc);
+
+ if (classp && (rc = vrfy_class(*classp)) != FMEV_OK ||
+ subclassp && (rc = vrfy_subclass(*subclassp)) != FMEV_OK ||
+ prip && (rc = vrfy_pri(*prip)) != FMEV_OK)
+ return (rc);
+
+ return (FMEV_OK);
+}
+
+uint_t fmev_va2nvl_maxtuples = 100;
+
+fmev_err_t
+va2nvl(nvlist_t **nvlp, va_list ap, uint_t ntuples)
+{
+ nvlist_t *nvl = NULL;
+ uint_t processed = 0;
+ char *name;
+
+ if (ntuples == 0)
+ return (FMEVERR_INTERNAL);
+
+ if ((name = va_arg(ap, char *)) == NULL || name == FMEV_ARG_TERM)
+ return (FMEVERR_VARARGS_MALFORMED);
+
+ if (ntuples > fmev_va2nvl_maxtuples)
+ return (FMEVERR_VARARGS_TOOLONG);
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+ return (FMEVERR_ALLOC);
+
+ while (name != NULL && name != FMEV_ARG_TERM && processed <= ntuples) {
+ data_type_t type;
+ int err, nelem;
+
+ type = va_arg(ap, data_type_t);
+
+ switch (type) {
+ case DATA_TYPE_BYTE:
+ err = nvlist_add_byte(nvl, name,
+ va_arg(ap, uint_t));
+ break;
+ case DATA_TYPE_BYTE_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_byte_array(nvl, name,
+ va_arg(ap, uchar_t *), nelem);
+ break;
+ case DATA_TYPE_BOOLEAN_VALUE:
+ err = nvlist_add_boolean_value(nvl, name,
+ va_arg(ap, boolean_t));
+ break;
+ case DATA_TYPE_BOOLEAN_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_boolean_array(nvl, name,
+ va_arg(ap, boolean_t *), nelem);
+ break;
+ case DATA_TYPE_INT8:
+ err = nvlist_add_int8(nvl, name,
+ va_arg(ap, int));
+ break;
+ case DATA_TYPE_INT8_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_int8_array(nvl, name,
+ va_arg(ap, int8_t *), nelem);
+ break;
+ case DATA_TYPE_UINT8:
+ err = nvlist_add_uint8(nvl, name,
+ va_arg(ap, uint_t));
+ break;
+ case DATA_TYPE_UINT8_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_uint8_array(nvl, name,
+ va_arg(ap, uint8_t *), nelem);
+ break;
+ case DATA_TYPE_INT16:
+ err = nvlist_add_int16(nvl, name,
+ va_arg(ap, int));
+ break;
+ case DATA_TYPE_INT16_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_int16_array(nvl, name,
+ va_arg(ap, int16_t *), nelem);
+ break;
+ case DATA_TYPE_UINT16:
+ err = nvlist_add_uint16(nvl, name,
+ va_arg(ap, uint_t));
+ break;
+ case DATA_TYPE_UINT16_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_uint16_array(nvl, name,
+ va_arg(ap, uint16_t *), nelem);
+ break;
+ case DATA_TYPE_INT32:
+ err = nvlist_add_int32(nvl, name,
+ va_arg(ap, int32_t));
+ break;
+ case DATA_TYPE_INT32_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_int32_array(nvl, name,
+ va_arg(ap, int32_t *), nelem);
+ break;
+ case DATA_TYPE_UINT32:
+ err = nvlist_add_uint32(nvl, name,
+ va_arg(ap, uint32_t));
+ break;
+ case DATA_TYPE_UINT32_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_uint32_array(nvl, name,
+ va_arg(ap, uint32_t *), nelem);
+ break;
+ case DATA_TYPE_INT64:
+ err = nvlist_add_int64(nvl, name,
+ va_arg(ap, int64_t));
+ break;
+ case DATA_TYPE_INT64_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_int64_array(nvl, name,
+ va_arg(ap, int64_t *), nelem);
+ break;
+ case DATA_TYPE_UINT64:
+ err = nvlist_add_uint64(nvl, name,
+ va_arg(ap, uint64_t));
+ break;
+ case DATA_TYPE_UINT64_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_uint64_array(nvl, name,
+ va_arg(ap, uint64_t *), nelem);
+ break;
+ case DATA_TYPE_STRING:
+ err = nvlist_add_string(nvl, name,
+ va_arg(ap, char *));
+ break;
+ case DATA_TYPE_STRING_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_string_array(nvl, name,
+ va_arg(ap, char **), nelem);
+ break;
+ case DATA_TYPE_NVLIST:
+ err = nvlist_add_nvlist(nvl, name,
+ va_arg(ap, nvlist_t *));
+ break;
+ case DATA_TYPE_NVLIST_ARRAY:
+ nelem = va_arg(ap, int);
+ err = nvlist_add_nvlist_array(nvl, name,
+ va_arg(ap, nvlist_t **), nelem);
+ break;
+ case DATA_TYPE_HRTIME:
+ err = nvlist_add_hrtime(nvl, name,
+ va_arg(ap, hrtime_t));
+ break;
+ case DATA_TYPE_DOUBLE:
+ err = nvlist_add_double(nvl, name,
+ va_arg(ap, double));
+ break;
+ default:
+ err = EINVAL;
+ }
+
+ if (err)
+ break; /* terminate on first error */
+
+ processed++;
+ name = va_arg(ap, char *);
+ }
+
+ if (name != FMEV_ARG_TERM || processed != ntuples) {
+ *nvlp = NULL;
+ nvlist_free(nvl);
+ return (FMEVERR_VARARGS_MALFORMED);
+ }
+
+ *nvlp = nvl;
+ return (FMEV_SUCCESS);
+}
+
+static fmev_err_t
+do_publish(const char *file, const char *func, int64_t line,
+ const char *ruleset, const char *class, const char *subclass,
+ fmev_pri_t pri, nvlist_t *nvl, uint_t ntuples, va_list ap)
+{
+ fmev_err_t rc = FMEVERR_INTERNAL;
+ boolean_t priv = B_TRUE;
+ nvlist_t *tmpnvl = NULL;
+ nvlist_t *pub;
+ evchan_t *evc;
+
+ if (nvl) {
+ ASSERT(ntuples == 0);
+
+ /*
+ * Enforce NV_UNIQUE_NAME
+ */
+ if ((nvlist_nvflag(nvl) & NV_UNIQUE_NAME) != NV_UNIQUE_NAME)
+ return (FMEVERR_NVLIST);
+
+ pub = nvl;
+
+ } else if (ntuples != 0) {
+ fmev_err_t err;
+
+ err = va2nvl(&tmpnvl, ap, ntuples);
+ if (err != FMEV_SUCCESS)
+ return (err);
+
+ pub = tmpnvl;
+ } else {
+ /*
+ * Even if the caller has no tuples to publish (just an event
+ * class and subclass), we are going to add some detector
+ * information so we need some nvlist.
+ */
+ if (nvlist_alloc(&tmpnvl, NV_UNIQUE_NAME, 0) != 0)
+ return (FMEVERR_ALLOC);
+
+ pub = tmpnvl;
+ }
+
+ evc = bind_channel(priv, pri);
+
+ if (evc == NULL) {
+ rc = FMEVERR_INTERNAL;
+ goto done;
+ }
+
+
+ /*
+ * Add detector information
+ */
+ if (file && nvlist_add_string(pub, "__fmev_file", file) != 0 ||
+ func && nvlist_add_string(pub, "__fmev_func", func) != 0 ||
+ line != -1 && nvlist_add_int64(pub, "__fmev_line", line) != 0 ||
+ nvlist_add_int32(pub, "__fmev_pid", getpid()) != 0 ||
+ nvlist_add_string(pub, "__fmev_execname", getexecname()) != 0) {
+ rc = FMEVERR_ALLOC;
+ goto done;
+ }
+
+ if (ruleset == NULL)
+ ruleset = FMEV_RULESET_DEFAULT;
+
+ /*
+ * We abuse the GPEC publication arguments as follows:
+ *
+ * GPEC argument Our usage
+ * -------------------- -----------------
+ * const char *class Raw class
+ * const char *subclass Raw subclass
+ * const char *vendor Ruleset name
+ * const char *pub_name Unused
+ * nvlist_t *attr_list Event attributes
+ */
+ rc = (sysevent_evc_publish(evc, class, subclass, ruleset, "",
+ pub, EVCH_NOSLEEP) == 0) ? FMEV_SUCCESS : FMEVERR_TRANSPORT;
+
+done:
+ /* Free a passed in nvlist iff success */
+ if (nvl && rc == FMEV_SUCCESS)
+ nvlist_free(nvl);
+
+ if (tmpnvl)
+ nvlist_free(tmpnvl);
+
+ return (rc);
+}
+
+fmev_err_t
+_i_fmev_publish_nvl(
+ const char *file, const char *func, int64_t line,
+ const char *ruleset, const char *class, const char *subclass,
+ fmev_pri_t pri, nvlist_t *attr)
+{
+ fmev_err_t rc;
+
+ if ((rc = vrfy(&ruleset, &class, &subclass, &pri)) != FMEV_OK)
+ return (rc); /* any attr not freed */
+
+ return (do_publish(file, func, line,
+ ruleset, class, subclass,
+ pri, attr, 0, NULL)); /* any attr freed iff success */
+}
+
+fmev_err_t
+_i_fmev_publish(
+ const char *file, const char *func, int64_t line,
+ const char *ruleset, const char *class, const char *subclass,
+ fmev_pri_t pri,
+ uint_t ntuples, ...)
+{
+ va_list ap;
+ fmev_err_t rc;
+
+ if ((rc = vrfy(&ruleset, &class, &subclass, &pri)) != FMEV_OK)
+ return (rc);
+
+ if (ntuples != 0)
+ va_start(ap, ntuples);
+
+ rc = do_publish(file, func, line,
+ ruleset, class, subclass,
+ pri, NULL, ntuples, ap);
+
+ if (ntuples != 0)
+ va_end(ap);
+
+ return (rc);
+}
+
+
+#pragma weak fmev_publish = _fmev_publish
+#pragma weak fmev_rspublish = _fmev_rspublish
+
+static fmev_err_t
+_fmev_publish(const char *class, const char *subclass, fmev_pri_t pri,
+ uint_t ntuples, ...)
+{
+ fmev_err_t rc;
+ va_list ap;
+
+ if ((rc = vrfy(NULL, &class, &subclass, &pri)) != FMEV_OK)
+ return (rc);
+
+ if (ntuples != 0)
+ va_start(ap, ntuples);
+
+ rc = do_publish(NULL, NULL, -1,
+ FMEV_RULESET_DEFAULT, class, subclass,
+ pri, NULL, ntuples, ap);
+
+ if (ntuples != 0)
+ va_end(ap);
+
+ return (rc);
+}
+
+static fmev_err_t
+_fmev_rspublish(const char *ruleset, const char *class, const char *subclass,
+ fmev_pri_t pri, uint_t ntuples, ...)
+{
+ fmev_err_t rc;
+ va_list ap;
+
+ if ((rc = vrfy(&ruleset, &class, &subclass, &pri)) != FMEV_OK)
+ return (rc);
+
+ if (ntuples != 0)
+ va_start(ap, ntuples);
+
+ rc = do_publish(NULL, NULL, -1,
+ ruleset, class, subclass,
+ pri, NULL, ntuples, ap);
+
+ if (ntuples != 0)
+ va_end(ap);
+
+ return (rc);
+}
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c b/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c
index a1727f9e58..eebdd4e1e2 100644
--- a/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c
+++ b/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -38,13 +37,14 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include <umem.h>
#include <unistd.h>
+#include <fm/libtopo.h>
#include <fm/libfmevent.h>
#include "fmev_impl.h"
-#include "fmev_channels.h"
+
+static topo_hdl_t *g_topohdl;
typedef struct {
struct fmev_hdl_cmn sh_cmn;
@@ -66,8 +66,8 @@ typedef struct {
#define SHDL_FL_SERIALIZE 0x1
-#define API_ENTERV1(hdl) \
- fmev_api_enter(&HDL2IHDL(hdl)->sh_cmn, LIBFMEVENT_VERSION_1)
+#define FMEV_API_ENTER(hdl, v) \
+ fmev_api_enter(&HDL2IHDL(hdl)->sh_cmn, LIBFMEVENT_VERSION_##v)
/*
* For each subscription on a handle we add a node to an avl tree
@@ -115,7 +115,7 @@ fmev_shdlctl_serialize(fmev_shdl_t hdl)
{
fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
- if (!API_ENTERV1(hdl))
+ if (!FMEV_API_ENTER(hdl, 1))
return (fmev_errno);
if (!shdlctl_start(ihdl))
@@ -135,7 +135,7 @@ fmev_shdlctl_thrattr(fmev_shdl_t hdl, pthread_attr_t *attr)
{
fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
- if (!API_ENTERV1(hdl))
+ if (!FMEV_API_ENTER(hdl, 1))
return (fmev_errno);
if (!shdlctl_start(ihdl))
@@ -152,7 +152,7 @@ fmev_shdlctl_sigmask(fmev_shdl_t hdl, sigset_t *set)
{
fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
- if (!API_ENTERV1(hdl))
+ if (!FMEV_API_ENTER(hdl, 1))
return (fmev_errno);
if (!shdlctl_start(ihdl))
@@ -170,7 +170,7 @@ fmev_shdlctl_thrsetup(fmev_shdl_t hdl, door_xcreate_thrsetup_func_t *func,
{
fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
- if (!API_ENTERV1(hdl))
+ if (!FMEV_API_ENTER(hdl, 1))
return (fmev_errno);
if (!shdlctl_start(ihdl))
@@ -188,7 +188,7 @@ fmev_shdlctl_thrcreate(fmev_shdl_t hdl, door_xcreate_server_func_t *func,
{
fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
- if (!API_ENTERV1(hdl))
+ if (!FMEV_API_ENTER(hdl, 1))
return (fmev_errno);
if (!shdlctl_start(ihdl))
@@ -252,7 +252,7 @@ fmev_shdl_subscribe(fmev_shdl_t hdl, const char *pat, fmev_cbfunc_t func,
uint64_t nsid;
int serr;
- if (!API_ENTERV1(hdl))
+ if (!FMEV_API_ENTER(hdl, 1))
return (fmev_errno);
if (pat == NULL || func == NULL)
@@ -354,7 +354,7 @@ fmev_shdl_unsubscribe(fmev_shdl_t hdl, const char *pat)
struct fmev_subinfo si;
int err;
- if (!API_ENTERV1(hdl))
+ if (!FMEV_API_ENTER(hdl, 1))
return (fmev_errno);
if (pat == NULL)
@@ -386,30 +386,13 @@ fmev_shdl_unsubscribe(fmev_shdl_t hdl, const char *pat)
return (fmev_seterr(rv));
}
-static void *
-dflt_alloc(size_t sz)
-{
- return (umem_alloc(sz, UMEM_DEFAULT));
-}
-
-static void *
-dflt_zalloc(size_t sz)
-{
- return (umem_zalloc(sz, UMEM_DEFAULT));
-}
-
-static void
-dflt_free(void *buf, size_t sz)
-{
- umem_free(buf, sz);
-}
-
void *
fmev_shdl_alloc(fmev_shdl_t hdl, size_t sz)
{
fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
- (void) API_ENTERV1(hdl);
+ if (!FMEV_API_ENTER(hdl, 1))
+ return (NULL);
return (ihdl->sh_cmn.hc_alloc(sz));
}
@@ -419,7 +402,8 @@ fmev_shdl_zalloc(fmev_shdl_t hdl, size_t sz)
{
fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
- (void) API_ENTERV1(hdl);
+ if (!FMEV_API_ENTER(hdl, 1))
+ return (NULL);
return (ihdl->sh_cmn.hc_zalloc(sz));
}
@@ -429,11 +413,44 @@ fmev_shdl_free(fmev_shdl_t hdl, void *buf, size_t sz)
{
fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
- (void) API_ENTERV1(hdl);
+ if (!FMEV_API_ENTER(hdl, 1))
+ return;
ihdl->sh_cmn.hc_free(buf, sz);
}
+char *
+fmev_shdl_strdup(fmev_shdl_t hdl, char *src)
+{
+ fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
+ size_t srclen;
+ char *dst;
+
+ if (!FMEV_API_ENTER(hdl, 2))
+ return (NULL);
+
+ srclen = strlen(src);
+
+ if ((dst = ihdl->sh_cmn.hc_alloc(srclen + 1)) == NULL) {
+ (void) fmev_seterr(FMEVERR_ALLOC);
+ return (NULL);
+ }
+
+ (void) strncpy(dst, src, srclen);
+ dst[srclen] = '\0';
+ return (dst);
+}
+
+void
+fmev_shdl_strfree(fmev_shdl_t hdl, char *buf)
+{
+ fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
+
+ (void) FMEV_API_ENTER(hdl, 2);
+
+ ihdl->sh_cmn.hc_free(buf, strlen(buf) + 1);
+}
+
int
fmev_shdl_valid(fmev_shdl_t hdl)
{
@@ -546,11 +563,100 @@ error:
}
fmev_err_t
+fmev_shdl_getauthority(fmev_shdl_t hdl, nvlist_t **nvlp)
+{
+ fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
+ nvlist_t *propnvl;
+ fmev_err_t rc;
+
+ if (!FMEV_API_ENTER(hdl, 2))
+ return (fmev_errno);
+
+ (void) pthread_mutex_lock(&ihdl->sh_lock);
+
+ if (sysevent_evc_getpropnvl(ihdl->sh_binding, &propnvl) != 0) {
+ *nvlp = NULL;
+ (void) pthread_mutex_unlock(&ihdl->sh_lock);
+ return (fmev_seterr(FMEVERR_UNKNOWN));
+ }
+
+ if (propnvl == NULL) {
+ rc = FMEVERR_BUSY; /* Other end has not bound */
+ } else {
+ nvlist_t *auth;
+
+ if (nvlist_lookup_nvlist(propnvl, "fmdauth", &auth) == 0) {
+ rc = (nvlist_dup(auth, nvlp, 0) == 0) ? FMEV_SUCCESS :
+ FMEVERR_ALLOC;
+ } else {
+ rc = FMEVERR_INTERNAL;
+ }
+ nvlist_free(propnvl);
+ }
+
+ (void) pthread_mutex_unlock(&ihdl->sh_lock);
+
+ if (rc != FMEV_SUCCESS) {
+ *nvlp = NULL;
+ (void) fmev_seterr(rc);
+ }
+
+ return (rc);
+}
+
+char *
+fmev_shdl_nvl2str(fmev_shdl_t hdl, nvlist_t *nvl)
+{
+ fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
+ char *fmri, *fmricp;
+ fmev_err_t err;
+ int topoerr;
+
+ if (!FMEV_API_ENTER(hdl, 2))
+ return (NULL);
+
+ if (g_topohdl == NULL) {
+ (void) pthread_mutex_lock(&ihdl->sh_lock);
+ if (g_topohdl == NULL)
+ g_topohdl = topo_open(TOPO_VERSION, NULL, &topoerr);
+ (void) pthread_mutex_unlock(&ihdl->sh_lock);
+
+ if (g_topohdl == NULL) {
+ (void) fmev_seterr(FMEVERR_INTERNAL);
+ return (NULL);
+ }
+ }
+
+ if (topo_fmri_nvl2str(g_topohdl, nvl, &fmri, &topoerr) == 0) {
+ fmricp = fmev_shdl_strdup(hdl, fmri);
+ topo_hdl_strfree(g_topohdl, fmri);
+ return (fmricp); /* fmev_errno set if strdup failed */
+ }
+
+ switch (topoerr) {
+ case ETOPO_FMRI_NOMEM:
+ err = FMEVERR_ALLOC;
+ break;
+
+ case ETOPO_FMRI_MALFORM:
+ case ETOPO_METHOD_NOTSUP:
+ case ETOPO_METHOD_INVAL:
+ default:
+ err = FMEVERR_INVALIDARG;
+ break;
+ }
+
+ (void) fmev_seterr(err);
+ return (NULL);
+}
+
+fmev_err_t
fmev_shdl_fini(fmev_shdl_t hdl)
{
fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
- (void) API_ENTERV1(hdl);
+ if (!FMEV_API_ENTER(hdl, 1))
+ return (fmev_errno);
(void) pthread_mutex_lock(&ihdl->sh_lock);
@@ -594,6 +700,11 @@ fmev_shdl_fini(fmev_shdl_t hdl)
ihdl->sh_cmn.hc_magic = 0;
+ if (g_topohdl) {
+ topo_close(g_topohdl);
+ g_topohdl = NULL;
+ }
+
(void) pthread_mutex_unlock(&ihdl->sh_lock);
(void) pthread_mutex_destroy(&ihdl->sh_lock);
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_util.c b/usr/src/lib/fm/libfmevent/common/fmev_util.c
index 775cc14bf4..7eec8ad0db 100644
--- a/usr/src/lib/fm/libfmevent/common/fmev_util.c
+++ b/usr/src/lib/fm/libfmevent/common/fmev_util.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -58,18 +57,26 @@ fmev_tsd_destructor(void *data)
int
fmev_api_init(struct fmev_hdl_cmn *hc)
{
- if (!fmev_api_enter(NULL, 0))
+ uint32_t v = hc->hc_api_vers;
+ int rc;
+
+ if (!fmev_api_enter((struct fmev_hdl_cmn *)fmev_api_init, 0))
return (0);
- /*
- * We implement only version 1 of the ABI at this point.
- */
- if (hc->hc_api_vers != LIBFMEVENT_VERSION_1) {
+
+ switch (v) {
+ case LIBFMEVENT_VERSION_1:
+ case LIBFMEVENT_VERSION_2:
+ rc = 1;
+ break;
+
+ default:
if (key_inited)
(void) fmev_seterr(FMEVERR_VERSION_MISMATCH);
- return (0);
+ rc = 0;
+ break;
}
- return (1);
+ return (rc);
}
/*
@@ -82,6 +89,7 @@ fmev_api_init(struct fmev_hdl_cmn *hc)
int
fmev_api_enter(struct fmev_hdl_cmn *hc, uint32_t ver_intro)
{
+ uint32_t v;
struct fmev_tsd *tsd;
/* Initialize key on first visit */
@@ -106,13 +114,18 @@ fmev_api_enter(struct fmev_hdl_cmn *hc, uint32_t ver_intro)
tsd->ts_lasterr = 0;
- if (hc == NULL) {
- return (1);
+ if (hc == (struct fmev_hdl_cmn *)fmev_api_init)
+ return (1); /* special case from fmev_api_init only */
+
+ if (hc == NULL || hc->hc_magic != _FMEV_SHMAGIC) {
+ tsd->ts_lasterr = FMEVERR_API;
+ return (0);
}
+ v = hc->hc_api_vers; /* API version opened */
+
/* Enforce version adherence. */
- if (ver_intro > hc->hc_api_vers ||
- hc->hc_api_vers > LIBFMEVENT_VERSION_LATEST ||
+ if (ver_intro > v || v > LIBFMEVENT_VERSION_LATEST ||
ver_intro > LIBFMEVENT_VERSION_LATEST) {
tsd->ts_lasterr = FMEVERR_VERSION_MISMATCH;
return (0);
@@ -178,3 +191,21 @@ __fmev_errno(void)
return ((const fmev_err_t *)&tsd->ts_lasterr);
}
+
+void *
+dflt_alloc(size_t sz)
+{
+ return (umem_alloc(sz, UMEM_DEFAULT));
+}
+
+void *
+dflt_zalloc(size_t sz)
+{
+ return (umem_zalloc(sz, UMEM_DEFAULT));
+}
+
+void
+dflt_free(void *buf, size_t sz)
+{
+ umem_free(buf, sz);
+}
diff --git a/usr/src/lib/fm/libfmevent/common/libfmevent.h b/usr/src/lib/fm/libfmevent/common/libfmevent.h
index 8cc06595bc..8fad3511aa 100644
--- a/usr/src/lib/fm/libfmevent/common/libfmevent.h
+++ b/usr/src/lib/fm/libfmevent/common/libfmevent.h
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _LIBFMEVENT_H
@@ -31,6 +30,7 @@
* FMA event library.
*
* A. Protocol event subscription interfaces (Committed).
+ * B. Raw event publication interfaces (Consolidation Private).
*/
#ifdef __cplusplus
@@ -49,10 +49,43 @@ extern "C" {
* to fmev_shdl_init. Only interfaces introduced in or prior to the
* quoted version will be available. Once introduced an interface
* only ever changes compatibly.
+ *
+ * Introduced in
+ * API Function LIBFMEVENT_VERSION_*
+ * ----------------------- --------------------
+ * fmev_attr_list; 1
+ * fmev_class; 1
+ * fmev_dup; 1
+ * fmev_ev2shdl 2
+ * fmev_hold; 1
+ * fmev_localtime; 1
+ * fmev_rele; 1
+ * fmev_shdl_alloc; 1
+ * fmev_shdl_init; 1
+ * fmev_shdl_fini; 1
+ * fmev_shdl_free; 1
+ * fmev_shdl_getauthority 2
+ * fmev_shdl_nvl2str 2
+ * fmev_shdl_strdup 2
+ * fmev_shdl_strfree 2
+ * fmev_shdl_subscribe; 1
+ * fmev_shdl_unsubscribe; 1
+ * fmev_shdl_zalloc; 1
+ * fmev_shdlctl_serialize; 1
+ * fmev_shdlctl_sigmask; 1
+ * fmev_shdlctl_thrattr; 1
+ * fmev_shdlctl_thrcreate; 1
+ * fmev_shdlctl_thrsetup; 1
+ * fmev_strerror; 1
+ * fmev_timespec; 1
+ * fmev_time_nsec; 1
+ * fmev_time_sec; 1
*/
+
#define LIBFMEVENT_VERSION_1 1
+#define LIBFMEVENT_VERSION_2 2
-#define LIBFMEVENT_VERSION_LATEST LIBFMEVENT_VERSION_1
+#define LIBFMEVENT_VERSION_LATEST LIBFMEVENT_VERSION_2
/*
* Success and error return values. The descriptive comment for each
@@ -75,7 +108,14 @@ typedef enum {
FMEVERR_BADCLASS, /* Bad event class or class pattern */
FMEVERR_NOMATCH, /* No match to criteria provided */
FMEVERR_MAX_SUBSCRIBERS, /* Exceeds maximum subscribers per handle */
- FMEVERR_INVALIDARG /* Argument is invalid */
+ FMEVERR_INVALIDARG, /* Argument is invalid */
+ FMEVERR_STRING2BIG, /* String argument exceeds maximum length */
+ FMEVERR_VARARGS_MALFORMED, /* Varargs list bad or incorrectly terminated */
+ FMEVERR_VARARGS_TOOLONG, /* Varargs list exceeds maximum length */
+ FMEVERR_BADRULESET, /* Ruleset selected for publication is bad */
+ FMEVERR_BADPRI, /* Priority selected for publication is bad */
+ FMEVERR_TRANSPORT, /* Error in underlying event transport implementation */
+ FMEVERR_NVLIST /* nvlist argument is not of type NV_UNIQUE_NAME */
} fmev_err_t;
/*
@@ -209,6 +249,14 @@ extern fmev_err_t fmev_shdl_subscribe(fmev_shdl_t, const char *, fmev_cbfunc_t,
extern fmev_err_t fmev_shdl_unsubscribe(fmev_shdl_t, const char *);
/*
+ * Retrieve an authority nvlist for the fault manager that is forwarding
+ * events to us. This may be NULL if the fault manager has not yet
+ * started up and made the information available. The caller is
+ * responsible for freeing the nvlist returned.
+ */
+extern fmev_err_t fmev_shdl_getauthority(fmev_shdl_t, nvlist_t **);
+
+/*
* Event access. In the common case that the event is processed to
* completion in the context of the event callback you need only
* use fmev_attr_list to access the nvlist of event attributes,
@@ -250,6 +298,23 @@ extern fmev_err_t fmev_shdl_unsubscribe(fmev_shdl_t, const char *);
* past that second. This can fail with FMEVERR_OVERFLOW if the seconds
* value does not fit within a time_t; you can retrieve the 64-bit second
* and nanosecond values with fmev_time_sec and fmev_time_nsec.
+ *
+ * An FMRI in an event payload is typically in nvlist form, i.e
+ * DATA_TYPE_NVLIST. That form is useful for extracting individual
+ * component fields, but that requires knowledge of the FMRI scheme and
+ * Public commitment thereof. FMRIs are typically Private, but in some
+ * cases they can be descriptive such as in listing the ASRU(s) affected
+ * by a fault; so we offer an API member which will blindly render any
+ * FMRI in its string form. Use fmev_shdl_nvl2str to format an nvlist_t
+ * as a string (if it is recognized as an FMRI); the caller is responsible
+ * for freeing the returned string using fmev_shdl_strfree. If
+ * fmev_shdl_nvl2str fails it will return NULL with fmev_errno set -
+ * FMEVERR_INVALIDARG if the nvlist_t does not appear to be a valid/known FMRI,
+ * FMEVERR_ALLOC if an allocation for memory for the string failed.
+ *
+ * fmev_ev2shdl will return the fmev_shdl_t with which a received fmev_t
+ * is associated. It should only be used in an event delivery callback
+ * context and for the event received in that callback.
*/
extern nvlist_t *fmev_attr_list(fmev_t);
@@ -264,6 +329,10 @@ extern void fmev_hold(fmev_t);
extern void fmev_rele(fmev_t);
extern fmev_t fmev_dup(fmev_t);
+extern char *fmev_shdl_nvl2str(fmev_shdl_t, nvlist_t *);
+
+extern fmev_shdl_t fmev_ev2shdl(fmev_t);
+
/*
* The following will allocate and free memory based on the choices made
* at fmev_shdl_init.
@@ -271,6 +340,234 @@ extern fmev_t fmev_dup(fmev_t);
void *fmev_shdl_alloc(fmev_shdl_t, size_t);
void *fmev_shdl_zalloc(fmev_shdl_t, size_t);
void fmev_shdl_free(fmev_shdl_t, void *, size_t);
+extern char *fmev_shdl_strdup(fmev_shdl_t, char *);
+extern void fmev_shdl_strfree(fmev_shdl_t, char *);
+
+/*
+ * Part B - Raw Event Publication
+ * ======
+ *
+ * The following interfaces are private to the Solaris system and are
+ * subject to change at any time without notice. Applications using
+ * these interfaces will fail to run on future releases. The interfaces
+ * should not be used for any purpose until they are publicly documented
+ * for use outside of Sun. These interface are *certain* to change
+ * incompatibly, as the current interface is very much purpose-built for
+ * a limited application.
+ *
+ * The interfaces below allow a process to publish a "raw" event
+ * which will be transmitted to the fault manager and post-processed
+ * into a full FMA protocol event. The post-processing to be applied
+ * is selected by a "ruleset" specified either implicitly or explicitly
+ * at publication. A ruleset will take the raw event (comprising
+ * class, subclass, priority, raw payload) and mark it up into a full
+ * protocol event; it may also augment the payload through looking up
+ * details that would have been costly to compute at publication time.
+ *
+ * In this first implementation event dispatch is synchronous and blocking,
+ * and not guaranteed to be re-entrant. This limits the call sites
+ * at which publication calls can be placed, and also means that careful
+ * thought is required before sprinkling event publication code throughout
+ * common system libraries. The dispatch mechanism amounts to some
+ * nvlist chicanery followed by a sysevent_evc_publish. A future revision
+ * will relax the context from which one may publish, and add more-powerful
+ * publication interfaces.
+ *
+ * Some publication interfaces (those ending in _nvl) accept a preconstructed
+ * nvlist as raw event payload. We require that such an nvlist be of type
+ * NV_UNIQUE_NAME. The publication interfaces all call nvlist_free on any
+ * nvlist that is passed for publication.
+ *
+ * Other publication interfaces allow you to build up the raw event payload
+ * by specifying the members in a varargs list terminated by FMEV_ARG_TERM.
+ * Again we require that payload member names are unique (that is, you cannot
+ * have two members with the same name but different datatype). See
+ * <sys/nvpair.h> for the data_type_t enumeration of types supported - but
+ * note that DATA_TYPE_BOOLEAN is excluded (DATA_TYPE_BOOLEAN_VALUE is
+ * supported). A single-valued (non-array type) member is specified with 3
+ * consecutive varargs as:
+ *
+ * (char *)name, DATA_TYPE_foo, (type)value
+ *
+ * An array-valued member is specified with 4 consecutive varargs as:
+ *
+ * (char *)name, DATA_TYPE_foo_ARRAY, (int)nelem, (type *)arrayptr
+ *
+ * The varargs list that specifies the nvlist must begin with an
+ * integer that specifies the number of members that follow. For example:
+ *
+ * uint32_t mode;
+ * char *clientname;
+ * uint32_t ins[NARGS];
+ *
+ * fmev_publish("class", "subclass", FMEV_LOPRI,
+ * 3,
+ * "mode", DATA_TYPE_UINT32, mode,
+ * "client", DATA_TYPE_STRING, clientname,
+ * "ins", DATA_TYPE_UINT32_ARRAY, sizeof (ins) / sizeof (ins[0]), ins,
+ * FMEV_ARG_TERM);
+ *
+ * The following tables summarize the capabilities of the various
+ * publication interfaces.
+ *
+ * Detector
+ * Interface Ruleset? File/Line Func
+ * ---------------------------- -------- --------- ----
+ * fmev_publish_nvl default Yes No
+ * fmev_publish_nvl (C99) default Yes Yes
+ * fmev_rspublish_nvl chosen Yes No
+ * fmev_rspublish_nvl (C99) chosen Yes Yes
+ * fmev_publish default No No
+ * fmev_publish (C99) default Yes Yes
+ * fmev_rspublish chosen No No
+ * fmev_rspublish (C99) chosen Yes Yes
+ *
+ * Summary: if not using C99 then try to use the _nvl variants as the
+ * varargs variants will not include file, line or function in the
+ * detector.
+ */
+
+/*
+ * In publishing an event you must select a "ruleset" (or accept the
+ * defaults). Rulesets are listed in the following header.
+ */
+#include <fm/libfmevent_ruleset.h>
+
+/*
+ * In publishing an event we can specify a class and subclass (which
+ * in post-processing combine in some way selected by the ruleset to
+ * form a full event protocol class). The maximum class and subclass
+ * string lengths are as follows.
+ */
+#define FMEV_PUB_MAXCLASSLEN 32
+#define FMEV_PUB_MAXSUBCLASSLEN 32
+
+/*
+ * Events are either high-priority (try really hard not to lose) or
+ * low-priority (can drop, throttle etc). Convert a fmev_pri_t to
+ * a string with fmev_pri_string().
+ */
+typedef enum fmev_pri {
+ FMEV_LOPRI = 0x1000,
+ FMEV_HIPRI
+} fmev_pri_t;
+
+extern const char *fmev_pri_string(fmev_pri_t);
+
+/*
+ * The varargs event publication interfaces must terminate the list
+ * of nvpair specifications with FMEV_ARG_TERM. This is to guard
+ * against very easily-made mistakes in those arg lists.
+ */
+#define FMEV_ARG_TERM (void *)0xa4a3a2a1
+
+/*
+ * The following are NOT for direct use.
+ */
+extern fmev_err_t _i_fmev_publish_nvl(
+ const char *, const char *, int64_t,
+ const char *, const char *, const char *,
+ fmev_pri_t, nvlist_t *);
+
+extern fmev_err_t _i_fmev_publish(
+ const char *, const char *, int64_t,
+ const char *, const char *, const char *,
+ fmev_pri_t,
+ uint_t, ...);
+
+/*
+ * Post-processing will always generate a "detector" payload member. In
+ * the case of the _nvl publishing variants the detector information
+ * includes file and line number, and - if your application is compiled
+ * with C99 enabled - function name.
+ */
+#if __STDC_VERSION__ - 0 >= 199901L
+#define _FMEVFUNC __func__
+#else
+#define _FMEVFUNC NULL
+#endif
+
+/*
+ * All these definitions "return" an fmev_err_t.
+ *
+ * In the _nvl variants you pass a preconstructed event payload; otherwise
+ * you include an integer indicating the number of payload
+ * (name, type, value) tuples that follow, then all those tuples, finally
+ * terminated by FMEV_ARG_TERM.
+ *
+ * In the rspublish variants you select a ruleset from
+ * libfmevent_ruleset.h - just use the final suffix (as in
+ * DEFAULT, EREPORT, ISV).
+ *
+ * The primary classification must not be NULL or the empty string.
+ *
+ * arg type Description
+ * ------- --------------- -------------------------------------------
+ * ruleset const char * Ruleset; can be NULL (implies default ruleset)
+ * cl1 const char * Primary classification string
+ * cl2 const char * Secondary classification string
+ * pri fmev_pri_t Priority
+ * nvl nvlist_t * Preconstructed attributes; caller must free
+ * ntuples int Number of tuples before FMEV_ARG_TERM
+ * suffix - See above.
+ */
+
+/*
+ * fmev_publish_nvl - Default ruleset implied; class/subclass, pri and an nvl
+ */
+#define fmev_publish_nvl(cl1, cl2, pri, nvl) \
+ _i_fmev_publish_nvl( \
+ __FILE__, _FMEVFUNC, __LINE__, \
+ FMEV_RULESET_DEFAULT, cl1, cl2, \
+ pri, nvl)
+
+/*
+ * fmev_rspublish_nvl - As fmev_publish_nvl, but with a chosen ruleset.
+ */
+#define fmev_rspublish_nvl(ruleset, cl1, cl2, pri, nvl) \
+ _i_fmev_publish_nvl( \
+ __FILE__, _FMEVFUNC, __LINE__, \
+ ruleset, cl1, cl2, \
+ pri, nvl)
+
+#if __STDC_VERSION__ - 0 >= 199901L && !defined(__lint)
+
+/*
+ * fmev_publish (C99 version) - Default ruleset; class/subclass, pri, nvpairs
+ */
+#define fmev_publish(cl1, cl2, pri, ntuples, ...) \
+ _i_fmev_publish( \
+ __FILE__, __func__, __LINE__, \
+ FMEV_RULESET_DEFAULT, cl1, cl2, \
+ pri, \
+ ntuples, __VA_ARGS__)
+
+
+/*
+ * fmev_rspublish (C99 version) - As fmev_publish, but with a chosen ruleset.
+ */
+#define fmev_rspublish(ruleset, cl1, cl2, pri, ntuples, ...) \
+ _i_fmev_publish( \
+ __FILE__, __func__, __LINE__, \
+ ruleset, cl1, cl2, \
+ pri, \
+ ntuples, __VA_ARGS__)
+
+#else
+
+/*
+ * fmev_publish (pre C99)
+ */
+extern fmev_err_t fmev_publish(const char *, const char *,
+ fmev_pri_t, uint_t, ...);
+
+/*
+ * fmev_rspublish (pre C99)
+ */
+extern fmev_err_t fmev_rspublish(const char *, const char *, const char *,
+ fmev_pri_t, uint_t, ...);
+
+#endif /* __STDC_VERSION__ */
#ifdef __cplusplus
}
diff --git a/usr/src/lib/fm/libfmevent/common/libfmevent_ruleset.h b/usr/src/lib/fm/libfmevent/common/libfmevent_ruleset.h
new file mode 100644
index 0000000000..3fb1fb5769
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/libfmevent_ruleset.h
@@ -0,0 +1,78 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _LIBFMEVENT_RULESET_H
+#define _LIBFMEVENT_RULESET_H
+
+/*
+ * Event Rulesets. A ruleset is selected by a (namespace, subsystem)
+ * combination, which together we call a "ruleset" selection for that
+ * namespace. The strings can be any ascii string not including
+ * control characters or DEL.
+ *
+ * Selection of a ruleset determines how a "raw" event that we publish
+ * using the libfmevent publication interfaces is post-processed into
+ * a full protocol event.
+ *
+ * New rulesets must follow the FMA Event Registry and Portfolio Review
+ * process. At this time only FMEV_RULESET_SMF and FMEV_RULESET_ON_SUNOS
+ * rulesets are adopted by that process - the others listed here are
+ * experimental.
+ */
+
+#define FMEV_MAX_RULESET_LEN 31
+
+#define FMEV_RS_SEPARATOR "\012"
+#define FMEV_MKRS(v, s) FMEV_V_##v FMEV_RS_SEPARATOR s
+
+/*
+ * Namespaces
+ */
+#define FMEV_V_ALL "*"
+#define FMEV_V_SOLARIS_ON "solaris-osnet" /* Solaris ON Consolidation */
+
+/*
+ * Generic and namespace-agnostic rulesets
+ */
+#define FMEV_RULESET_UNREGISTERED FMEV_MKRS(ALL, "unregistered")
+#define FMEV_RULESET_DEFAULT FMEV_RULESET_UNREGISTERED
+#define FMEV_RULESET_SMF FMEV_MKRS(ALL, "smf")
+
+/*
+ * Solaris ON rulesets
+ */
+#define FMEV_RULESET_ON_EREPORT FMEV_MKRS(SOLARIS_ON, "ereport")
+#define FMEV_RULESET_ON_SUNOS FMEV_MKRS(SOLARIS_ON, "sunos")
+#define FMEV_RULESET_ON_PRIVATE FMEV_MKRS(SOLARIS_ON, "private")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFMEVENT_RULESET_H */
diff --git a/usr/src/lib/fm/libfmevent/common/mapfile-vers b/usr/src/lib/fm/libfmevent/common/mapfile-vers
index 732242af37..ced42890c4 100644
--- a/usr/src/lib/fm/libfmevent/common/mapfile-vers
+++ b/usr/src/lib/fm/libfmevent/common/mapfile-vers
@@ -38,6 +38,15 @@
$mapfile_version 2
+SYMBOL_VERSION SUNW_1.2 {
+ global:
+ fmev_ev2shdl;
+ fmev_shdl_getauthority;
+ fmev_shdl_nvl2str;
+ fmev_shdl_strdup;
+ fmev_shdl_strfree;
+} SUNW_1.1;
+
SYMBOL_VERSION SUNW_1.1 {
global:
fmev_attr_list;
@@ -68,6 +77,11 @@ SYMBOL_VERSION SUNW_1.1 {
SYMBOL_VERSION SUNWprivate {
global:
+ fmev_pri_string;
+ fmev_publish { FLAGS = NODYNSORT };
+ fmev_rspublish { FLAGS = NODYNSORT };
+ _i_fmev_publish;
+ _i_fmev_publish_nvl;
__fmev_errno;
local:
*;
diff --git a/usr/src/lib/fm/libfmevent/i386/Makefile b/usr/src/lib/fm/libfmevent/i386/Makefile
index c86be4377c..1b8b367f7c 100644
--- a/usr/src/lib/fm/libfmevent/i386/Makefile
+++ b/usr/src/lib/fm/libfmevent/i386/Makefile
@@ -19,10 +19,11 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
include ../Makefile.com
+DYNFLAGS += -R/usr/lib/fm
+
install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/fm/libfmevent/sparc/Makefile b/usr/src/lib/fm/libfmevent/sparc/Makefile
index c86be4377c..1b8b367f7c 100644
--- a/usr/src/lib/fm/libfmevent/sparc/Makefile
+++ b/usr/src/lib/fm/libfmevent/sparc/Makefile
@@ -19,10 +19,11 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
include ../Makefile.com
+DYNFLAGS += -R/usr/lib/fm
+
install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/fm/libfmevent/sparcv9/Makefile b/usr/src/lib/fm/libfmevent/sparcv9/Makefile
index e628bce86d..0efa16d7ae 100644
--- a/usr/src/lib/fm/libfmevent/sparcv9/Makefile
+++ b/usr/src/lib/fm/libfmevent/sparcv9/Makefile
@@ -19,11 +19,12 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
include ../Makefile.com
include ../../../Makefile.lib.64
+DYNFLAGS += -R/usr/lib/fm/$(MACH64)
+
install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/fm/libfmnotify/Makefile b/usr/src/lib/fm/libfmnotify/Makefile
new file mode 100644
index 0000000000..645e65ace4
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/Makefile
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../../Makefile.lib
+include ../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+test := TARGET = test
+
+.KEEP_STATE:
+
+all clean clobber lint test: $(SUBDIRS)
+
+install: $(SUBDIRS)
+
+install_h:
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
+include ../Makefile.targ
diff --git a/usr/src/lib/fm/libfmnotify/Makefile.com b/usr/src/lib/fm/libfmnotify/Makefile.com
new file mode 100644
index 0000000000..e1ff0e027a
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/Makefile.com
@@ -0,0 +1,63 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+LIBRARY = libfmnotify.a
+VERS = .1
+
+LIBSRCS = libfmnotify.c
+OBJECTS = $(LIBSRCS:%.c=%.o)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+SRCS = $(LIBSRCS:%.c=../common/%.c)
+LIBS = $(DYNLIB) $(LINTLIB)
+
+SRCDIR = ../common
+
+C99MODE = $(C99_ENABLE)
+
+CPPFLAGS += -I../common -I.
+CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS)
+CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS)
+
+$(DYNLIB) := LDLIBS += $(MACH_LDLIBS)
+$(DYNLIB) := LDLIBS += -lnvpair -lc -lfmd_msg -lfmevent -lscf -ldiagcode
+
+LINTFLAGS = -msux
+LINTFLAGS64 = -msux -m64
+
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+$(LINTLIB) := LINTFLAGS = -nsvx
+$(LINTLIB) := LINTFLAGS64 = -nsvx -m64
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: $(LINTLIB) lintcheck
+
+include ../../../Makefile.targ
+include ../../Makefile.targ
diff --git a/usr/src/lib/fm/libfmnotify/amd64/Makefile b/usr/src/lib/fm/libfmnotify/amd64/Makefile
new file mode 100644
index 0000000000..f0d686dced
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+MACH_LDLIBS = -L$(ROOT)/usr/lib/fm/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/fm/$(MACH64)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/fm/libfmnotify/common/libfmnotify.c b/usr/src/lib/fm/libfmnotify/common/libfmnotify.c
new file mode 100644
index 0000000000..cc3ed572fe
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/common/libfmnotify.c
@@ -0,0 +1,616 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <alloca.h>
+
+#include "libfmnotify.h"
+
+/*ARGSUSED*/
+void
+nd_cleanup(nd_hdl_t *nhdl)
+{
+ nd_debug(nhdl, "Cleaning up ...");
+ if (nhdl->nh_evhdl)
+ (void) fmev_shdl_fini(nhdl->nh_evhdl);
+
+ if (nhdl->nh_msghdl)
+ fmd_msg_fini(nhdl->nh_msghdl);
+
+ nhdl->nh_keep_running = B_FALSE;
+ (void) fclose(nhdl->nh_log_fd);
+}
+
+static void
+get_timestamp(char *buf, size_t bufsize)
+{
+ time_t utc_time;
+ struct tm *p_tm;
+
+ (void) time(&utc_time);
+ p_tm = localtime(&utc_time);
+
+ (void) strftime(buf, bufsize, "%b %d %H:%M:%S", p_tm);
+}
+
+/* PRINTFLIKE2 */
+void
+nd_debug(nd_hdl_t *nhdl, const char *format, ...)
+{
+ char timestamp[64];
+ va_list ap;
+
+ if (nhdl->nh_debug) {
+ get_timestamp(timestamp, sizeof (timestamp));
+ (void) fprintf(nhdl->nh_log_fd, "[ %s ", timestamp);
+ va_start(ap, format);
+ (void) vfprintf(nhdl->nh_log_fd, format, ap);
+ va_end(ap);
+ (void) fprintf(nhdl->nh_log_fd, " ]\n");
+ }
+ (void) fflush(nhdl->nh_log_fd);
+}
+
+void
+nd_dump_nvlist(nd_hdl_t *nhdl, nvlist_t *nvl)
+{
+ if (nhdl->nh_debug)
+ nvlist_print(nhdl->nh_log_fd, nvl);
+}
+
+/* PRINTFLIKE2 */
+void
+nd_error(nd_hdl_t *nhdl, const char *format, ...)
+{
+ char timestamp[64];
+ va_list ap;
+
+ get_timestamp(timestamp, sizeof (timestamp));
+ (void) fprintf(nhdl->nh_log_fd, "[ %s ", timestamp);
+ va_start(ap, format);
+ (void) vfprintf(nhdl->nh_log_fd, format, ap);
+ va_end(ap);
+ (void) fprintf(nhdl->nh_log_fd, " ]\n");
+ (void) fflush(nhdl->nh_log_fd);
+}
+
+/* PRINTFLIKE2 */
+void
+nd_abort(nd_hdl_t *nhdl, const char *format, ...)
+{
+ char timestamp[64];
+ va_list ap;
+
+ get_timestamp(timestamp, sizeof (timestamp));
+ (void) fprintf(nhdl->nh_log_fd, "[ %s ", timestamp);
+ va_start(ap, format);
+ (void) vfprintf(nhdl->nh_log_fd, format, ap);
+ va_end(ap);
+ (void) fprintf(nhdl->nh_log_fd, " ]\n");
+ (void) fflush(nhdl->nh_log_fd);
+ nd_cleanup(nhdl);
+}
+
+void
+nd_daemonize(nd_hdl_t *nhdl)
+{
+ pid_t pid;
+
+ if ((pid = fork()) < 0)
+ nd_abort(nhdl, "Failed to fork child (%s)", strerror(errno));
+ else if (pid > 0)
+ exit(0);
+
+ (void) setsid();
+ (void) close(0);
+ (void) close(1);
+ /*
+ * We leave stderr open so we can write debug/err messages to the SMF
+ * service log
+ */
+ nhdl->nh_is_daemon = B_TRUE;
+}
+
+/*
+ * This function returns a pointer to the specified SMF property group for the
+ * specified SMF service. The caller is responsible for freeing the property
+ * group. On failure, the function returns NULL.
+ */
+static scf_propertygroup_t *
+nd_get_pg(nd_hdl_t *nhdl, scf_handle_t *handle, const char *svcname,
+ const char *pgname)
+{
+ scf_scope_t *sc = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL, *ret = NULL;
+
+ sc = scf_scope_create(handle);
+ svc = scf_service_create(handle);
+ pg = scf_pg_create(handle);
+
+ if (sc == NULL || svc == NULL || pg == NULL) {
+ nd_error(nhdl, "Failed to allocate libscf structures");
+ scf_pg_destroy(pg);
+ goto get_pg_done;
+ }
+
+ if (scf_handle_bind(handle) != -1 &&
+ scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, sc) != -1 &&
+ scf_scope_get_service(sc, svcname, svc) != -1 &&
+ scf_service_get_pg(svc, pgname, pg) != -1)
+ ret = pg;
+ else
+ scf_pg_destroy(pg);
+
+get_pg_done:
+ scf_service_destroy(svc);
+ scf_scope_destroy(sc);
+
+ return (ret);
+}
+
+int
+nd_get_astring_prop(nd_hdl_t *nhdl, const char *svcname, const char *pgname,
+ const char *propname, char **val)
+{
+ scf_handle_t *handle = NULL;
+ scf_propertygroup_t *pg;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ char strval[255];
+ int ret = -1;
+
+ if ((handle = scf_handle_create(SCF_VERSION)) == NULL)
+ return (ret);
+
+ if ((pg = nd_get_pg(nhdl, handle, svcname, pgname)) == NULL) {
+ nd_error(nhdl, "Failed to read retrieve %s "
+ "property group for %s", pgname, svcname);
+ goto astring_done;
+ }
+ prop = scf_property_create(handle);
+ value = scf_value_create(handle);
+ if (prop == NULL || value == NULL) {
+ nd_error(nhdl, "Failed to allocate SMF structures");
+ goto astring_done;
+ }
+ if (scf_pg_get_property(pg, propname, prop) == -1 ||
+ scf_property_get_value(prop, value) == -1 ||
+ scf_value_get_astring(value, strval, 255) == -1) {
+ nd_error(nhdl, "Failed to retrieve %s prop (%s)", propname,
+ scf_strerror(scf_error()));
+ goto astring_done;
+ }
+ *val = strdup(strval);
+ ret = 0;
+
+astring_done:
+ scf_value_destroy(value);
+ scf_property_destroy(prop);
+ scf_pg_destroy(pg);
+ scf_handle_destroy(handle);
+
+ return (ret);
+}
+
+int
+nd_get_boolean_prop(nd_hdl_t *nhdl, const char *svcname, const char *pgname,
+ const char *propname, uint8_t *val)
+{
+ scf_handle_t *handle = NULL;
+ scf_propertygroup_t *pg;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ int ret = -1;
+
+ if ((handle = scf_handle_create(SCF_VERSION)) == NULL)
+ return (ret);
+
+ if ((pg = nd_get_pg(nhdl, handle, svcname, pgname)) == NULL) {
+ nd_error(nhdl, "Failed to read retrieve %s "
+ "property group for %s", pgname, svcname);
+ goto bool_done;
+ }
+ prop = scf_property_create(handle);
+ value = scf_value_create(handle);
+ if (prop == NULL || value == NULL) {
+ nd_error(nhdl, "Failed to allocate SMF structures");
+ goto bool_done;
+ }
+ if (scf_pg_get_property(pg, propname, prop) == -1 ||
+ scf_property_get_value(prop, value) == -1 ||
+ scf_value_get_boolean(value, val) == -1) {
+ nd_error(nhdl, "Failed to retrieve %s prop (%s)", propname,
+ scf_strerror(scf_error()));
+ goto bool_done;
+ }
+ ret = 0;
+
+bool_done:
+ scf_value_destroy(value);
+ scf_property_destroy(prop);
+ scf_pg_destroy(pg);
+ scf_handle_destroy(handle);
+
+ return (ret);
+}
+
+char *
+nd_get_event_fmri(nd_hdl_t *nhdl, fmev_t ev)
+{
+ nvlist_t *ev_nvl, *attr_nvl;
+ char *svcname;
+
+ if ((ev_nvl = fmev_attr_list(ev)) == NULL) {
+ nd_error(nhdl, "Failed to lookup event attr nvlist");
+ return (NULL);
+ }
+ if (nvlist_lookup_nvlist(ev_nvl, "attr", &attr_nvl) ||
+ nvlist_lookup_string(attr_nvl, "svc-string", &svcname)) {
+ nd_error(nhdl, "Malformed event 0x%p", (void *)ev_nvl);
+ return (NULL);
+ }
+
+ return (strdup((const char *)svcname));
+}
+
+int
+nd_get_notify_prefs(nd_hdl_t *nhdl, const char *mech, fmev_t ev,
+ nvlist_t ***pref_nvl, uint_t *nprefs)
+{
+ nvlist_t *ev_nvl, *top_nvl, **np_nvlarr, *mech_nvl;
+ int ret = 1;
+ uint_t nelem;
+
+ if ((ev_nvl = fmev_attr_list(ev)) == NULL) {
+ nd_error(nhdl, "Failed to lookup event attr nvlist");
+ return (-1);
+ }
+
+ if ((ret = smf_notify_get_params(&top_nvl, ev_nvl)) != SCF_SUCCESS) {
+ ret = scf_error();
+ if (ret == SCF_ERROR_NOT_FOUND) {
+ nd_debug(nhdl, "No notification preferences specified "
+ "for this event");
+ goto pref_done;
+ } else {
+ nd_error(nhdl, "Error looking up notification "
+ "preferences (%s)", scf_strerror(ret));
+ nd_dump_nvlist(nhdl, top_nvl);
+ goto pref_done;
+ }
+ }
+
+ if (nvlist_lookup_nvlist_array(top_nvl, SCF_NOTIFY_PARAMS, &np_nvlarr,
+ &nelem) != 0) {
+ nd_error(nhdl, "Malformed nvlist");
+ nd_dump_nvlist(nhdl, top_nvl);
+ ret = 1;
+ goto pref_done;
+ }
+ *pref_nvl = malloc(nelem * sizeof (nvlist_t *));
+ *nprefs = 0;
+
+ for (int i = 0; i < nelem; i++) {
+ if (nvlist_lookup_nvlist(np_nvlarr[i], mech, &mech_nvl) == 0) {
+ (void) nvlist_dup(mech_nvl, *pref_nvl + *nprefs, 0);
+ ++*nprefs;
+ }
+ }
+
+ if (*nprefs == 0) {
+ nd_debug(nhdl, "No %s notification preferences specified",
+ mech);
+ free(*pref_nvl);
+ ret = SCF_ERROR_NOT_FOUND;
+ goto pref_done;
+ }
+ ret = 0;
+pref_done:
+ nvlist_free(top_nvl);
+ return (ret);
+}
+
+static int
+nd_seq_search(char *key, char **list, uint_t nelem)
+{
+ for (int i = 0; i < nelem; i++)
+ if (strcmp(key, list[i]) == 0)
+ return (1);
+ return (0);
+}
+
+/*
+ * This function takes a single string list and splits it into
+ * an string array (analogous to PERL split)
+ *
+ * The caller is responsible for freeing the array.
+ */
+int
+nd_split_list(nd_hdl_t *nhdl, char *list, char *delim, char ***arr,
+ uint_t *nelem)
+{
+ char *item, *tmpstr;
+ int i = 1, size = 1;
+
+ tmpstr = strdup(list);
+ item = strtok(tmpstr, delim);
+ while (item && strtok(NULL, delim) != NULL)
+ size++;
+ free(tmpstr);
+
+ if ((*arr = calloc(size, sizeof (char *))) == NULL) {
+ nd_error(nhdl, "Error allocating memory (%s)", strerror(errno));
+ return (-1);
+ }
+ if (size == 1)
+ (*arr)[0] = strdup(list);
+ else {
+ tmpstr = strdup(list);
+ item = strtok(tmpstr, delim);
+ (*arr)[0] = strdup(item);
+ while ((item = strtok(NULL, delim)) != NULL)
+ (*arr)[i++] = strdup(item);
+ free(tmpstr);
+ }
+ *nelem = size;
+ return (0);
+}
+
+/*
+ * This function merges two string arrays into a single array, removing any
+ * duplicates
+ *
+ * The caller is responsible for freeing the merged array.
+ */
+int
+nd_merge_strarray(nd_hdl_t *nhdl, char **arr1, uint_t n1, char **arr2,
+ uint_t n2, char ***buf)
+{
+ char **tmparr;
+ int uniq = -1;
+
+ tmparr = alloca((n1 + n2) * sizeof (char *));
+ bzero(tmparr, (n1 + n2) * sizeof (char *));
+
+ while (++uniq < n1)
+ tmparr[uniq] = strdup(arr1[uniq]);
+
+ for (int j = 0; j < n2; j++)
+ if (!nd_seq_search(arr2[j], tmparr, uniq))
+ tmparr[uniq++] = strdup(arr2[j]);
+
+ if ((*buf = calloc(uniq, sizeof (char *))) == NULL) {
+ nd_error(nhdl, "Error allocating memory (%s)", strerror(errno));
+ for (int j = 0; j < uniq; j++) {
+ if (tmparr[j])
+ free(tmparr[j]);
+ }
+ return (-1);
+ }
+
+ bcopy(tmparr, *buf, uniq * sizeof (char *));
+ return (uniq);
+}
+
+void
+nd_free_strarray(char **arr, uint_t arrsz)
+{
+ for (uint_t i = 0; i < arrsz; i++)
+ free(arr[i]);
+ free(arr);
+}
+
+/*
+ * This function joins all the strings in a string array into a single string
+ * Each element will be delimited by a comma
+ *
+ * The caller is responsible for freeing the joined string.
+ */
+int
+nd_join_strarray(nd_hdl_t *nhdl, char **arr, uint_t arrsz, char **buf)
+{
+ uint_t len = 0;
+ char *jbuf;
+ int i;
+
+ /*
+ * First, figure out how much space we need to allocate to store the
+ * joined string.
+ */
+ for (i = 0; i < arrsz; i++)
+ len += strlen(arr[i]) + 1;
+
+ if ((jbuf = calloc(len, sizeof (char))) == NULL) {
+ nd_error(nhdl, "Error allocating memory (%s)", strerror(errno));
+ return (-1);
+ }
+
+ (void) snprintf(jbuf, len, "%s", arr[0]);
+ for (i = 1; i < arrsz; i++)
+ (void) snprintf(jbuf, len, "%s,%s", jbuf, arr[i]);
+
+ *buf = jbuf;
+ return (0);
+}
+
+void
+nd_free_nvlarray(nvlist_t **arr, uint_t arrsz)
+{
+ for (uint_t i = 0; i < arrsz; i++)
+ nvlist_free(arr[i]);
+ free(arr);
+}
+
+/*
+ * This function takes a dictionary name and event class and then uses
+ * libdiagcode to compute the MSG ID. We need this for looking up messages
+ * for the committed ireport.* events. For FMA list.* events, the MSG ID is
+ * is contained in the event payload.
+ */
+int
+nd_get_diagcode(nd_hdl_t *nhdl, const char *dict, const char *class, char *buf,
+ size_t buflen)
+{
+ fm_dc_handle_t *dhp;
+ size_t dlen;
+ char *dirpath;
+ const char *key[2];
+ int ret = 0;
+
+ dlen = (strlen(nhdl->nh_rootdir) + strlen(ND_DICTDIR) + 2);
+ dirpath = alloca(dlen);
+ (void) snprintf(dirpath, dlen, "%s/%s", nhdl->nh_rootdir, ND_DICTDIR);
+
+ if ((dhp = fm_dc_opendict(FM_DC_VERSION, dirpath, dict)) == NULL) {
+ nd_error(nhdl, "fm_dc_opendict failed for %s/%s",
+ dirpath, dict);
+ return (-1);
+ }
+
+ key[0] = class;
+ key[1] = NULL;
+ if (fm_dc_key2code(dhp, key, buf, buflen) < 0) {
+ nd_error(nhdl, "fm_dc_key2code failed for %s", key[0]);
+ ret = -1;
+ }
+ fm_dc_closedict(dhp);
+ return (ret);
+}
+
+/*
+ * This function takes an event and extracts the bits of the event payload that
+ * are of interest to notification daemons and conveniently tucks them into a
+ * single struct.
+ *
+ * The caller is responsible for freeing ev_info and any contained strings and
+ * nvlists. A convenience function, nd_free_event_info(), is provided for this
+ * purpose.
+ */
+int
+nd_get_event_info(nd_hdl_t *nhdl, const char *class, fmev_t ev,
+ nd_ev_info_t **ev_info)
+{
+ nvlist_t *ev_nvl, *attr_nvl;
+ nd_ev_info_t *evi;
+ char *code, *uuid, *fmri, *from_state, *to_state, *reason;
+
+ if ((evi = calloc(1, sizeof (nd_ev_info_t))) == NULL) {
+ nd_error(nhdl, "Failed to allocate memory");
+ return (-1);
+ }
+
+ /*
+ * Hold event; class and payload will be valid for as long as
+ * we hold the event.
+ */
+ fmev_hold(ev);
+ evi->ei_ev = ev;
+ ev_nvl = fmev_attr_list(ev);
+
+ /*
+ * Lookup the MSGID, event description and severity and KA URL
+ *
+ * For FMA list.* events we just pull it out of the the event nvlist.
+ * For all other events we call a utility function that computes the
+ * diagcode using the dict name and class.
+ */
+ evi->ei_diagcode = calloc(32, sizeof (char));
+ if ((nvlist_lookup_string(ev_nvl, FM_SUSPECT_DIAG_CODE, &code) == 0 &&
+ strcpy(evi->ei_diagcode, code)) ||
+ nd_get_diagcode(nhdl, "SMF", class, evi->ei_diagcode, 32)
+ == 0) {
+ evi->ei_severity = fmd_msg_getitem_id(nhdl->nh_msghdl,
+ NULL, evi->ei_diagcode, FMD_MSG_ITEM_SEVERITY);
+ evi->ei_descr = fmd_msg_getitem_id(nhdl->nh_msghdl,
+ NULL, evi->ei_diagcode, FMD_MSG_ITEM_DESC);
+ evi->ei_url = fmd_msg_getitem_id(nhdl->nh_msghdl,
+ NULL, evi->ei_diagcode, FMD_MSG_ITEM_URL);
+ } else
+ (void) strcpy(evi->ei_diagcode, ND_UNKNOWN);
+
+ if (!evi->ei_severity)
+ evi->ei_severity = strdup(ND_UNKNOWN);
+ if (!evi->ei_descr)
+ evi->ei_descr = strdup(ND_UNKNOWN);
+ if (!evi->ei_url)
+ evi->ei_url = strdup(ND_UNKNOWN);
+
+ evi->ei_payload = ev_nvl;
+ evi->ei_class = fmev_class(ev);
+ if (nvlist_lookup_string(ev_nvl, FM_SUSPECT_UUID, &uuid) == 0)
+ evi->ei_uuid = strdup(uuid);
+ else {
+ nd_error(nhdl, "Malformed event");
+ nd_dump_nvlist(nhdl, evi->ei_payload);
+ nd_free_event_info(evi);
+ return (-1);
+ }
+
+ if (strncmp(class, "ireport.os.smf", 14) == 0) {
+ if ((fmri = nd_get_event_fmri(nhdl, ev)) == NULL) {
+ nd_error(nhdl, "Failed to get fmri from event payload");
+ nd_free_event_info(evi);
+ return (-1);
+ }
+ if (nvlist_lookup_nvlist(evi->ei_payload, "attr", &attr_nvl) ||
+ nvlist_lookup_string(attr_nvl, "from-state", &from_state) ||
+ nvlist_lookup_string(attr_nvl, "to-state", &to_state) ||
+ nvlist_lookup_string(attr_nvl, "reason-long", &reason)) {
+ nd_error(nhdl, "Malformed event");
+ nd_dump_nvlist(nhdl, evi->ei_payload);
+ nd_free_event_info(evi);
+ free(fmri);
+ return (-1);
+ }
+ evi->ei_fmri = fmri;
+ evi->ei_to_state = strdup(to_state);
+ evi->ei_from_state = strdup(from_state);
+ evi->ei_reason = strdup(reason);
+ }
+ *ev_info = evi;
+ return (0);
+}
+
+static void
+condfree(void *buf)
+{
+ if (buf != NULL)
+ free(buf);
+}
+
+void
+nd_free_event_info(nd_ev_info_t *ev_info)
+{
+ condfree(ev_info->ei_severity);
+ condfree(ev_info->ei_descr);
+ condfree(ev_info->ei_diagcode);
+ condfree(ev_info->ei_url);
+ condfree(ev_info->ei_uuid);
+ condfree(ev_info->ei_fmri);
+ condfree(ev_info->ei_from_state);
+ condfree(ev_info->ei_to_state);
+ condfree(ev_info->ei_reason);
+ fmev_rele(ev_info->ei_ev);
+ free(ev_info);
+}
diff --git a/usr/src/lib/fm/libfmnotify/common/libfmnotify.h b/usr/src/lib/fm/libfmnotify/common/libfmnotify.h
new file mode 100644
index 0000000000..839559dd05
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/common/libfmnotify.h
@@ -0,0 +1,109 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+#ifndef _LIBFMNOTIFY_H
+#define _LIBFMNOTIFY_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <alloca.h>
+#include <errno.h>
+#include <libscf.h>
+#include <limits.h>
+#include <strings.h>
+#include <sys/corectl.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fm/diagcode.h>
+#include <fm/fmd_msg.h>
+#include <fm/libfmevent.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ND_DICTDIR "usr/lib/fm/dict"
+#define ND_UNKNOWN "UNKNOWN"
+
+typedef struct nd_hdl {
+ boolean_t nh_debug;
+ boolean_t nh_is_daemon;
+ boolean_t nh_keep_running;
+ /* handle for libfmevent calls */
+ fmev_shdl_t nh_evhdl;
+ /* handle for libfmd_msg calls */
+ fmd_msg_hdl_t *nh_msghdl;
+ FILE *nh_log_fd;
+ char *nh_rootdir;
+ const char *nh_pname;
+} nd_hdl_t;
+
+const char FMNOTIFY_MSG_DOMAIN[] = "FMNOTIFY";
+
+typedef struct nd_ev_info {
+ fmev_t ei_ev;
+ const char *ei_class;
+ char *ei_descr;
+ char *ei_severity;
+ char *ei_diagcode;
+ char *ei_url;
+ char *ei_uuid;
+ char *ei_fmri;
+ char *ei_from_state;
+ char *ei_to_state;
+ char *ei_reason;
+ nvlist_t *ei_payload;
+} nd_ev_info_t;
+
+
+void nd_cleanup(nd_hdl_t *);
+void nd_dump_nvlist(nd_hdl_t *, nvlist_t *);
+void nd_debug(nd_hdl_t *, const char *, ...);
+void nd_error(nd_hdl_t *, const char *, ...);
+void nd_abort(nd_hdl_t *, const char *, ...);
+void nd_daemonize(nd_hdl_t *);
+int nd_get_boolean_prop(nd_hdl_t *, const char *, const char *, const char *,
+ uint8_t *);
+int nd_get_astring_prop(nd_hdl_t *, const char *, const char *, const char *,
+ char **);
+char *nd_get_event_fmri(nd_hdl_t *, fmev_t);
+int nd_get_event_info(nd_hdl_t *, const char *, fmev_t, nd_ev_info_t **);
+int nd_get_notify_prefs(nd_hdl_t *, const char *, fmev_t, nvlist_t ***,
+ uint_t *);
+int nd_split_list(nd_hdl_t *, char *, char *, char ***, uint_t *);
+int nd_join_strarray(nd_hdl_t *, char **, uint_t, char **);
+int nd_merge_strarray(nd_hdl_t *, char **, uint_t, char **, uint_t, char ***);
+void nd_free_event_info(nd_ev_info_t *);
+void nd_free_nvlarray(nvlist_t **, uint_t);
+void nd_free_strarray(char **, uint_t);
+int nd_get_diagcode(nd_hdl_t *, const char *, const char *, char *, size_t);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFMNOTIFY_H */
diff --git a/usr/src/lib/fm/libfmnotify/common/llib-lfmnotify b/usr/src/lib/fm/libfmnotify/common/llib-lfmnotify
new file mode 100644
index 0000000000..230bb3efd8
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/common/llib-lfmnotify
@@ -0,0 +1,27 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
diff --git a/usr/src/lib/fm/libfmnotify/common/mapfile-vers b/usr/src/lib/fm/libfmnotify/common/mapfile-vers
new file mode 100644
index 0000000000..5c6c048d25
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/common/mapfile-vers
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ nd_abort;
+ nd_cleanup;
+ nd_daemonize;
+ nd_debug;
+ nd_dump_nvlist;
+ nd_error;
+ nd_free_event_info;
+ nd_free_nvlarray;
+ nd_free_strarray;
+ nd_get_astring_prop;
+ nd_get_boolean_prop;
+ nd_get_diagcode;
+ nd_get_event_fmri;
+ nd_get_event_info;
+ nd_get_notify_prefs;
+ nd_join_strarray;
+ nd_merge_strarray;
+ nd_split_list;
+ local:
+ *;
+};
diff --git a/usr/src/lib/fm/libfmnotify/i386/Makefile b/usr/src/lib/fm/libfmnotify/i386/Makefile
new file mode 100644
index 0000000000..4e86c1ee6b
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/i386/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
+
+MACH_LDLIBS = -L$(ROOT)/usr/lib/fm
+
+DYNFLAGS += -R/usr/lib/fm
+
diff --git a/usr/src/lib/fm/libfmnotify/sparc/Makefile b/usr/src/lib/fm/libfmnotify/sparc/Makefile
new file mode 100644
index 0000000000..686815ee32
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/sparc/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
+
+MACH_LDLIBS = -L$(ROOT)/usr/lib/fm
+
+DYNFLAGS += -R/usr/lib/fm
diff --git a/usr/src/lib/fm/libfmnotify/sparcv9/Makefile b/usr/src/lib/fm/libfmnotify/sparcv9/Makefile
new file mode 100644
index 0000000000..c8c3d93095
--- /dev/null
+++ b/usr/src/lib/fm/libfmnotify/sparcv9/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+MACH_LDLIBS = -L$(ROOT)/usr/lib/fm/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/fm/$(MACH64)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/fm/topo/libtopo/Makefile.com b/usr/src/lib/fm/topo/libtopo/Makefile.com
index 8d56ce0c0d..4e16288540 100644
--- a/usr/src/lib/fm/topo/libtopo/Makefile.com
+++ b/usr/src/lib/fm/topo/libtopo/Makefile.com
@@ -19,8 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
#
LIBRARY = libtopo.a
@@ -36,6 +35,7 @@ BUILTINSRCS = \
mod.c \
pkg.c \
svc.c \
+ sw.c \
zfs.c
LIBSRCS = \
diff --git a/usr/src/lib/fm/topo/libtopo/common/dev.c b/usr/src/lib/fm/topo/libtopo/common/dev.c
index 00abe9fc1c..b991a03e90 100644
--- a/usr/src/lib/fm/topo/libtopo/common/dev.c
+++ b/usr/src/lib/fm/topo/libtopo/common/dev.c
@@ -114,6 +114,11 @@ static int
dev_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
topo_instance_t min, topo_instance_t max, void *notused1, void *notused2)
{
+ /*
+ * Methods are registered, but there is no enumeration. Should
+ * enumeration be added be sure to cater for global vs non-global
+ * zones.
+ */
(void) topo_method_register(mod, pnode, dev_methods);
return (0);
}
diff --git a/usr/src/lib/fm/topo/libtopo/common/fmd.c b/usr/src/lib/fm/topo/libtopo/common/fmd.c
index 1b8898770e..be48be3e0c 100644
--- a/usr/src/lib/fm/topo/libtopo/common/fmd.c
+++ b/usr/src/lib/fm/topo/libtopo/common/fmd.c
@@ -21,11 +21,9 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
@@ -96,6 +94,11 @@ int
fmd_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min,
topo_instance_t max, void *notused1, void *notused2)
{
+ /*
+ * Methods are registered, but there is no enumeration. Should
+ * enumeration be added be sure to cater for global vs non-global
+ * zones.
+ */
(void) topo_method_register(mod, pnode, fmd_methods);
return (0);
}
diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c
index 2bec088639..352c34c2f6 100644
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c
@@ -32,6 +32,7 @@
#include <alloca.h>
#include <assert.h>
#include <limits.h>
+#include <zone.h>
#include <fm/topo_mod.h>
#include <fm/topo_hc.h>
#include <fm/fmd_fmri.h>
@@ -311,6 +312,7 @@ int
hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min,
topo_instance_t max, void *notused1, void *notused2)
{
+ int isglobal = (getzoneid() == GLOBAL_ZONEID);
nvlist_t *pfmri = NULL;
nvlist_t *nvl;
nvlist_t *auth;
@@ -331,6 +333,9 @@ hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min,
return (topo_mod_seterrno(mod, EINVAL));
}
+ if (!isglobal)
+ return (0);
+
(void) topo_node_resource(pnode, &pfmri, &err);
auth = topo_mod_auth(mod, pnode);
nvl = hc_fmri_create(mod, pfmri, FM_HC_SCHEME_VERSION, name, min,
diff --git a/usr/src/lib/fm/topo/libtopo/common/mem.c b/usr/src/lib/fm/topo/libtopo/common/mem.c
index 502fbf994b..994bed3d24 100644
--- a/usr/src/lib/fm/topo/libtopo/common/mem.c
+++ b/usr/src/lib/fm/topo/libtopo/common/mem.c
@@ -20,18 +20,16 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <ctype.h>
#include <errno.h>
#include <kstat.h>
#include <limits.h>
#include <strings.h>
#include <unistd.h>
+#include <zone.h>
#include <topo_error.h>
#include <fm/topo_mod.h>
#include <sys/fm/protocol.h>
@@ -96,9 +94,10 @@ static int
mem_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
topo_instance_t min, topo_instance_t max, void *notused1, void *notused2)
{
+ int isglobal = (getzoneid() == GLOBAL_ZONEID);
topo_mod_t *nmp;
- if ((nmp = topo_mod_load(mod, PLATFORM_MEM_NAME,
+ if (isglobal && (nmp = topo_mod_load(mod, PLATFORM_MEM_NAME,
PLATFORM_MEM_VERSION)) == NULL) {
if (topo_mod_errno(mod) == ETOPO_MOD_NOENT) {
/*
@@ -114,7 +113,7 @@ mem_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
}
}
- if (topo_mod_enumerate(nmp, pnode, PLATFORM_MEM_NAME, name,
+ if (isglobal && topo_mod_enumerate(nmp, pnode, PLATFORM_MEM_NAME, name,
min, max, NULL) < 0) {
topo_mod_dprintf(mod, "%s failed to enumerate: %s",
PLATFORM_MEM_NAME, topo_mod_errmsg(mod));
diff --git a/usr/src/lib/fm/topo/libtopo/common/mod.c b/usr/src/lib/fm/topo/libtopo/common/mod.c
index 1b26ccf6e6..5a26378acf 100644
--- a/usr/src/lib/fm/topo/libtopo/common/mod.c
+++ b/usr/src/lib/fm/topo/libtopo/common/mod.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <limits.h>
@@ -94,6 +93,11 @@ static int
mod_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
topo_instance_t min, topo_instance_t max, void *notused1, void *notused2)
{
+ /*
+ * Methods are registered, but there is no enumeration. Should
+ * enumeration be added be sure to cater for global vs non-global
+ * zones.
+ */
(void) topo_method_register(mod, pnode, mod_methods);
return (0);
}
diff --git a/usr/src/lib/fm/topo/libtopo/common/pkg.c b/usr/src/lib/fm/topo/libtopo/common/pkg.c
index 4cf1eddda0..7c5f4ade87 100644
--- a/usr/src/lib/fm/topo/libtopo/common/pkg.c
+++ b/usr/src/lib/fm/topo/libtopo/common/pkg.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <limits.h>
@@ -74,7 +73,7 @@ pkg_init(topo_mod_t *mod, topo_version_t version)
{
if (getenv("TOPOPKGDEBUG"))
topo_mod_setdebug(mod);
- topo_mod_dprintf(mod, "initializing mod builtin\n");
+ topo_mod_dprintf(mod, "initializing pkg builtin\n");
if (version != PKG_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
@@ -99,6 +98,11 @@ static int
pkg_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
topo_instance_t min, topo_instance_t max, void *notused1, void *notused2)
{
+ /*
+ * Methods are registered, but there is no enumeration. Should
+ * enumeration be added be sure to cater for global vs non-global
+ * zones.
+ */
(void) topo_method_register(mod, pnode, pkg_methods);
return (0);
}
diff --git a/usr/src/lib/fm/topo/libtopo/common/svc.c b/usr/src/lib/fm/topo/libtopo/common/svc.c
index 61fed24f5e..7e237661f4 100644
--- a/usr/src/lib/fm/topo/libtopo/common/svc.c
+++ b/usr/src/lib/fm/topo/libtopo/common/svc.c
@@ -20,21 +20,20 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* This provides the basic mechanisms (str2nvl and nvl2str) for dealing with
* the service schema. The official version of a svc FMRI has the form:
*
- * svc://[scope@][system-fqn]/service[:instance][@contract-id]
+ * svc://[scope@][system-fqn]/service[:instance][@contract-id]
*
* Where 'service' is a slash-delimited list of names. Of these fields, the
* scope, constract-id, and system-fqn are rarely used, leaving the much more
* common form such as:
*
- * svc:///network/ssh:default
+ * svc:///network/ssh:default
*
* Note that the SMF software typically uses a shorthard form, where the
* authority is elided (svc:/network/ssh:default). As this module deals with
@@ -49,6 +48,7 @@
#include <sys/fm/protocol.h>
#include <topo_method.h>
#include <topo_subr.h>
+#include <topo_prop.h>
#include <alloca.h>
#include <assert.h>
#include <svc.h>
@@ -67,11 +67,13 @@ static int svc_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t,
nvlist_t *, nvlist_t **);
static int svc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t,
nvlist_t *, nvlist_t **);
-static int svc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
- topo_instance_t, void *, void *);
-static void svc_release(topo_mod_t *, tnode_t *);
+static int svc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t,
+ nvlist_t *, nvlist_t **);
static const topo_method_t svc_methods[] = {
+ { TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC,
+ TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL,
+ svc_fmri_prop_get },
{ TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION,
TOPO_STABILITY_INTERNAL, svc_fmri_nvl2str },
{ TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION,
@@ -90,6 +92,10 @@ static const topo_method_t svc_methods[] = {
{ NULL }
};
+static int svc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
+ topo_instance_t, void *, void *);
+static void svc_release(topo_mod_t *, tnode_t *);
+
static const topo_modops_t svc_ops =
{ svc_enum, svc_release };
static const topo_modinfo_t svc_info =
@@ -134,6 +140,9 @@ svc_get_handle(topo_mod_t *mod)
int
svc_init(topo_mod_t *mod, topo_version_t version)
{
+ if (getenv("TOPOSVCDEBUG"))
+ topo_mod_setdebug(mod);
+
if (version != SVC_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
@@ -157,13 +166,160 @@ svc_fini(topo_mod_t *mod)
topo_mod_unregister(mod);
}
+static tnode_t *
+svc_create_node(topo_mod_t *mod, tnode_t *pnode, char *fmristr)
+{
+ nvlist_t *fmri;
+ tnode_t *tn;
+ char *fixed;
+ ssize_t len;
+ int i, j, err;
+
+ /*
+ * the scf_{x}_to_fmri interfaces return short-hand svc-scheme FMRI's
+ * that look like:
+ *
+ * svc:/service[:instance]
+ *
+ * But all our other code assumes a proper svc-scheme FMRI, so we
+ * correct the fmri string before we try to convert it to an nvlist.
+ *
+ * The short-hand version is kept as the label and can be used when
+ * dealing with the SMF libraries and CLI's.
+ */
+ len = strlen(fmristr) + 1;
+ if ((fixed = topo_mod_zalloc(mod, len + 1)) == NULL) {
+ (void) topo_mod_seterrno(mod, EMOD_NOMEM);
+ topo_mod_dprintf(mod, "topo_mod_zalloc() failed: %s",
+ topo_mod_errmsg(mod));
+ return (NULL);
+ }
+ for (i = 0, j = 0; i < len; i++)
+ if (i == 5)
+ fixed[i] = '/';
+ else
+ fixed[i] = fmristr[j++];
+ fixed[i] = '\0';
+
+ if (topo_mod_str2nvl(mod, fixed, &fmri) < 0) {
+ topo_mod_dprintf(mod, "topo_mod_str2nvl() failed: %s",
+ topo_mod_errmsg(mod));
+ topo_mod_free(mod, fixed, len + 1);
+ return (NULL);
+ }
+ topo_mod_free(mod, fixed, len + 1);
+
+ if (topo_node_range_create(mod, pnode, fmristr, 0, 0) < 0) {
+ topo_mod_dprintf(mod, "topo_node_range_create() failed: %s",
+ topo_mod_errmsg(mod));
+ nvlist_free(fmri);
+ return (NULL);
+ }
+ if ((tn = topo_node_bind(mod, pnode, fmristr, 0, fmri)) == NULL) {
+ topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
+ topo_mod_errmsg(mod));
+ nvlist_free(fmri);
+ return (NULL);
+ }
+ nvlist_free(fmri);
+
+ if (topo_node_label_set(tn, fmristr, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set label: %s\n",
+ topo_strerror(err));
+ return (NULL);
+ }
+ (void) topo_method_register(mod, tn, svc_methods);
+
+ return (tn);
+}
+
/*ARGSUSED*/
static int
svc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
topo_instance_t min, topo_instance_t max, void *notused1, void *notused2)
{
+ scf_handle_t *hdl;
+ scf_scope_t *sc = NULL;
+ scf_iter_t *svc_iter = NULL;
+ scf_iter_t *inst_iter = NULL;
+ scf_service_t *svc = NULL;
+ scf_instance_t *inst = NULL;
+ int ret = -1;
+ char *sfmri, *ifmri;
+ ssize_t slen, ilen;
+ tnode_t *svc_node;
+
(void) topo_method_register(mod, pnode, svc_methods);
- return (0);
+
+ if ((hdl = svc_get_handle(mod)) == NULL)
+ goto out;
+
+ if ((sc = scf_scope_create(hdl)) == NULL ||
+ (svc = scf_service_create(hdl)) == NULL ||
+ (inst = scf_instance_create(hdl)) == NULL ||
+ (svc_iter = scf_iter_create(hdl)) == NULL ||
+ (inst_iter = scf_iter_create(hdl)) == NULL)
+ goto out;
+
+ if (scf_handle_get_scope(hdl, SCF_SCOPE_LOCAL, sc) != 0)
+ goto out;
+
+ if (scf_iter_scope_services(svc_iter, sc) != 0)
+ goto out;
+
+ while (scf_iter_next_service(svc_iter, svc) == 1) {
+ if (scf_iter_service_instances(inst_iter, svc) != 0)
+ continue;
+
+ if ((slen = scf_service_to_fmri(svc, NULL, 0)) < 0)
+ continue;
+
+ if ((sfmri = topo_mod_zalloc(mod, slen + 1)) == NULL) {
+ (void) topo_mod_seterrno(mod, EMOD_NOMEM);
+ goto out;
+ }
+ if (scf_service_to_fmri(svc, sfmri, slen + 1) == -1)
+ goto out;
+
+ if ((svc_node = svc_create_node(mod, pnode, sfmri)) == NULL) {
+ topo_mod_free(mod, sfmri, slen + 1);
+ /* topo mod errno set */
+ goto out;
+ }
+
+ while (scf_iter_next_instance(inst_iter, inst) == 1) {
+ if ((ilen = scf_instance_to_fmri(inst, NULL, 0)) < 0)
+ continue;
+
+ if ((ifmri = topo_mod_zalloc(mod, ilen + 1))
+ == NULL) {
+ (void) topo_mod_seterrno(mod, EMOD_NOMEM);
+ topo_mod_free(mod, sfmri, slen + 1);
+ goto out;
+ }
+ if (scf_instance_to_fmri(inst, ifmri, ilen + 1) == -1)
+ goto out;
+
+ if ((svc_node = svc_create_node(mod, svc_node, ifmri))
+ == NULL) {
+ topo_mod_free(mod, sfmri, slen + 1);
+ topo_mod_free(mod, ifmri, ilen + 1);
+ /* topo mod errno set */
+ goto out;
+ }
+ topo_mod_free(mod, ifmri, ilen + 1);
+ }
+ topo_mod_free(mod, sfmri, slen + 1);
+ }
+ ret = 0;
+out:
+ scf_scope_destroy(sc);
+ scf_service_destroy(svc);
+ scf_instance_destroy(inst);
+ scf_iter_destroy(svc_iter);
+ scf_iter_destroy(inst_iter);
+
+ return (ret);
}
static void
@@ -187,6 +343,76 @@ svc_component_valid(const char *str)
return (B_TRUE);
}
+static int
+svc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+ nvlist_t *in, nvlist_t **out)
+{
+ char *svc_name, *svc_inst = NULL;
+ nvlist_t *rsrc, *args;
+ char *pgroup, *pname;
+ tnode_t *svc_node;
+ char *search;
+ size_t len;
+ int err;
+
+ if (version > TOPO_METH_PROP_GET_VERSION)
+ return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
+
+ err = nvlist_lookup_string(in, TOPO_PROP_GROUP, &pgroup);
+ err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME, &pname);
+ err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &rsrc);
+ if (err != 0)
+ return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+
+ /*
+ * Private args to prop method are optional
+ */
+ if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &args)) != 0) {
+ if (err != ENOENT)
+ return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+ else
+ args = NULL;
+ }
+
+ /*
+ * Lookup a topo node named svc:/svc_name[:svc_inst]
+ */
+ if (nvlist_lookup_string(rsrc, FM_FMRI_SVC_NAME, &svc_name) != 0)
+ return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+
+ (void) nvlist_lookup_string(rsrc, FM_FMRI_SVC_INSTANCE, &svc_inst);
+
+ len = 5 + strlen(svc_name) +
+ (svc_inst != NULL ? 1 + strlen(svc_inst) : 0) + 1;
+
+ if ((search = topo_mod_alloc(mod, len)) == NULL)
+ return (topo_mod_seterrno(mod, EMOD_NOMEM));
+
+ (void) snprintf(search, len, "svc:/%s", svc_name);
+ svc_node = topo_node_lookup(node, (const char *)search, 0);
+
+ if (svc_node == NULL) {
+ topo_mod_free(mod, search, len);
+ return (topo_mod_seterrno(mod, EMOD_NODE_NOENT));
+ }
+
+ if (svc_inst != NULL) {
+ (void) snprintf(search, len, "svc:/%s:%s", svc_name, svc_inst);
+ svc_node = topo_node_lookup(svc_node, (const char *)search, 0);
+ if (svc_node == NULL) {
+ topo_mod_free(mod, search, len);
+ return (topo_mod_seterrno(mod, EMOD_NODE_NOENT));
+ }
+ }
+
+ topo_mod_free(mod, search, len);
+
+ err = 0;
+ (void) topo_prop_getprop(svc_node, pgroup, pname, args, out, &err);
+
+ return (err);
+}
+
/*ARGSUSED*/
static int
svc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version,
@@ -417,10 +643,56 @@ nomem:
}
/*
- * This common function is shared by all consumers (present, unusable, and
- * service_state). It returns one of the FMD_SERVICE_STATE_* states, where
- * FMD_SERVICE_STATE_UNKNOWN means that the FMRI is not present.
+ * This common function is shared by all consumers (present, replaced,
+ * service state and unusable).
+ *
+ * svc_get_state succeeds
+ * Case with FMD_SERVICE_STATE_*
+ * ---------------------------- ------------------------
+ * svc name deleted UNKNOWN
+ * svc name not found UNKNOWN
+ * no fmri instance OK
+ * instance deleted UNKNOWN
+ * instance not found UNKNOWN
+ *
+ * If none of the above apply and this is a call from the "present"
+ * or "replaced" method (presence_only == B_TRUE) then
+ * svc_get_state returns FMD_SERVICE_STATE_OK.
+ *
+ * The "present" method maps a svc_get_state return of UNKNOWN to
+ * "not present" and a svc_get_state return of OK to "present".
+ *
+ * The "replaced" methods maps a return of UNKNOWN to FMD_OBJ_STATE_NOT_PRESENT
+ * and OK to FMD_OBJ_STATE_UNKNOWN.
+ *
+ * For the "service state" and "unusable" methods svc_get_state goes on
+ * to return the instance state as below, and the two methods map that
+ * result as in the last two columns of the following table:
+ *
+ * svc_get_state succeeds Service
+ * Instance state with FMD_SERVICE_STATE_* State Unusable
+ * -------------- ------------------------------- --------------- --------
+ * none OK OK
+ * uninitialized OK OK
+ * maintenance UNUSABLE UNUSABLE Yes
+ * offline OK OK
+ * disabled OK OK
+ * online OK OK
+ * degraded DEGRADED DEGRADED
+ * legacy_run OK (XXX can we see this?) OK
+ *
+ * Note that *only* "maintenance" state should map to an unusable service state
+ * or unusable status. That's because a service entering maintenance state
+ * is modelled as a defect fault diagnosis in FMA, but there is no
+ * corresponding isolation action from a response agent since the the service
+ * is already isolated by virtue of being in maintenance state. Any transition
+ * from maintenance state, even to offline, is considered a repair. If on
+ * repair fmd does not see the service usable again then the case hangs
+ * around in the "resolved but not all resources back online" state and
+ * further maintenance events for this service will not show up in fmd state
+ * because case duplicate checking code will find the old case.
*/
+
static int
svc_get_state(topo_mod_t *mod, nvlist_t *fmri, boolean_t presence_only,
int *ret)
@@ -473,10 +745,6 @@ svc_get_state(topo_mod_t *mod, nvlist_t *fmri, boolean_t presence_only,
}
}
- /*
- * If there is no instance, then it is always present, and always
- * usuable.
- */
if (nvlist_lookup_string(fmri, FM_FMRI_SVC_INSTANCE, &instance) != 0) {
*ret = FMD_SERVICE_STATE_OK;
goto out;
@@ -517,12 +785,13 @@ svc_get_state(topo_mod_t *mod, nvlist_t *fmri, boolean_t presence_only,
if (scf_value_get_astring(val, state, len + 1) < 0)
goto error;
- if (strcmp(state, SCF_STATE_STRING_MAINT) == 0)
+ if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
*ret = FMD_SERVICE_STATE_UNUSABLE;
- else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)
+ } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
*ret = FMD_SERVICE_STATE_DEGRADED;
- else
+ } else {
*ret = FMD_SERVICE_STATE_OK;
+ }
goto out;
error:
diff --git a/usr/src/lib/fm/topo/libtopo/common/sw.c b/usr/src/lib/fm/topo/libtopo/common/sw.c
new file mode 100644
index 0000000000..c655627f52
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/common/sw.c
@@ -0,0 +1,530 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <libnvpair.h>
+#include <fm/topo_mod.h>
+
+#include <sys/fm/protocol.h>
+#include <sys/types.h>
+
+#include <topo_method.h>
+#include <topo_subr.h>
+#include <sw.h>
+
+static int sw_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t,
+ nvlist_t *, nvlist_t **);
+static int sw_fmri_create(topo_mod_t *, tnode_t *, topo_version_t,
+ nvlist_t *, nvlist_t **);
+
+static const topo_method_t sw_methods[] = {
+ { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION,
+ TOPO_STABILITY_INTERNAL, sw_fmri_nvl2str },
+ { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION,
+ TOPO_STABILITY_INTERNAL, sw_fmri_create },
+ { NULL }
+};
+
+static int sw_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
+ topo_instance_t, void *, void *);
+static void sw_release(topo_mod_t *, tnode_t *);
+
+static const topo_modops_t sw_ops =
+ { sw_enum, sw_release };
+
+static const topo_modinfo_t sw_info =
+ { "sw", FM_FMRI_SCHEME_SW, SW_VERSION, &sw_ops };
+
+int
+sw_init(topo_mod_t *mod, topo_version_t version)
+{
+ if (getenv("TOPOSWDEBUG"))
+ topo_mod_setdebug(mod);
+ topo_mod_dprintf(mod, "initializing sw builtin\n");
+
+ if (version != SW_VERSION)
+ return (topo_mod_seterrno(mod, EMOD_VER_NEW));
+
+ if (topo_mod_register(mod, &sw_info, TOPO_VERSION) != 0) {
+ topo_mod_dprintf(mod, "failed to register sw_info: "
+ "%s\n", topo_mod_errmsg(mod));
+ return (-1);
+ }
+
+ return (0);
+}
+
+void
+sw_fini(topo_mod_t *mod)
+{
+ topo_mod_unregister(mod);
+}
+
+static int
+sw_get_optl_string(nvlist_t *nvl, char *name, char **dest)
+{
+ if (nvlist_lookup_string(nvl, name, dest) == 0) {
+ return (0);
+ } else {
+ *dest = NULL;
+ return (errno == ENOENT ? 0 : 1);
+ }
+}
+
+static int
+sw_get_optl_int64(nvlist_t *nvl, char *name, int64_t *dest)
+{
+ if (nvlist_lookup_int64(nvl, name, dest) == 0) {
+ return (0);
+ } else {
+ *dest = -1;
+ return (errno == ENOENT ? 0 : 1);
+ }
+}
+
+static int
+sw_get_optl_nvlist(nvlist_t *nvl, char *name, nvlist_t **dest)
+{
+ if (nvlist_lookup_nvlist(nvl, name, dest) == 0) {
+ return (0);
+ } else {
+ *dest = NULL;
+ return (errno == ENOENT ? 0 : 1);
+ }
+}
+
+static int
+sw_add_optl_string(nvlist_t *nvl, char *name, char *val)
+{
+ if (val)
+ return (nvlist_add_string(nvl, name, val) != 0);
+ else
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+sw_fmri_create(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+ nvlist_t *in, nvlist_t **out)
+{
+ nvlist_t *args, *fmri = NULL, *obj = NULL, *site = NULL, *ctxt = NULL;
+ topo_mod_errno_t moderr;
+ int err = 0;
+
+ char *obj_path, *obj_root;
+ nvlist_t *obj_pkg;
+
+ char *site_token, *site_module, *site_file, *site_func;
+ int64_t site_line;
+
+ char *ctxt_origin, *ctxt_execname, *ctxt_zone;
+ int64_t ctxt_pid, ctxt_ctid;
+ char **ctxt_stack;
+ uint_t ctxt_stackdepth;
+
+
+ if (version > TOPO_METH_FMRI_VERSION)
+ return (topo_mod_seterrno(mod, EMOD_VER_NEW));
+
+ if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args) != 0)
+ return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+
+ if (nvlist_lookup_string(args, "obj_path", &obj_path) != 0)
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ err |= sw_get_optl_string(args, "obj_root", &obj_root);
+ err |= sw_get_optl_nvlist(args, "obj-pkg", &obj_pkg);
+
+ err |= sw_get_optl_string(args, "site_token", &site_token);
+ err |= sw_get_optl_string(args, "site_module", &site_module);
+ err |= sw_get_optl_string(args, "site_file", &site_file);
+ err |= sw_get_optl_string(args, "site_func", &site_func);
+ err |= sw_get_optl_int64(args, "site_line", &site_line);
+
+ err |= sw_get_optl_string(args, "ctxt_origin", &ctxt_origin);
+ err |= sw_get_optl_string(args, "ctxt_execname", &ctxt_execname);
+ err |= sw_get_optl_string(args, "ctxt_zone", &ctxt_zone);
+ err |= sw_get_optl_int64(args, "ctxt_pid", &ctxt_pid);
+ err |= sw_get_optl_int64(args, "ctxt_ctid", &ctxt_ctid);
+
+ if (nvlist_lookup_string_array(args, "stack", &ctxt_stack,
+ &ctxt_stackdepth) != 0) {
+ if (errno == ENOENT)
+ ctxt_stack = NULL;
+ else
+ err++;
+ }
+
+ if (err)
+ (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
+
+ if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0 ||
+ topo_mod_nvalloc(mod, &obj, NV_UNIQUE_NAME) != 0) {
+ moderr = EMOD_NOMEM;
+ goto out;
+ }
+
+ /*
+ * Add standard FMRI members 'version' and 'scheme'.
+ */
+ err |= nvlist_add_uint8(fmri, FM_VERSION, FM_SW_SCHEME_VERSION);
+ err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SW);
+
+ /*
+ * Build up the 'object' nvlist.
+ */
+ err |= nvlist_add_string(obj, FM_FMRI_SW_OBJ_PATH, obj_path);
+ err |= sw_add_optl_string(obj, FM_FMRI_SW_OBJ_ROOT, obj_root);
+ if (obj_pkg)
+ err |= nvlist_add_nvlist(obj, FM_FMRI_SW_OBJ_PKG, obj_pkg);
+
+ /*
+ * Add 'object' to the fmri.
+ */
+ if (err == 0)
+ err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_OBJ, obj);
+
+ if (err) {
+ moderr = EMOD_NOMEM;
+ goto out;
+ }
+
+ /*
+ * Do we have anything for a 'site' nvlist?
+ */
+ if (site_token == NULL && site_module == NULL && site_file == NULL &&
+ site_func == NULL && site_line == -1)
+ goto context;
+
+ /*
+ * Allocate and build 'site' nvlist.
+ */
+ if (topo_mod_nvalloc(mod, &site, NV_UNIQUE_NAME) != 0) {
+ moderr = EMOD_NOMEM;
+ goto out;
+ }
+
+ err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_TOKEN, site_token);
+ err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_MODULE, site_module);
+ err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_FILE, site_file);
+ err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_FUNC, site_func);
+ if ((site_token || site_module || site_file || site_func) &&
+ site_line != -1)
+ err |= nvlist_add_int64(site, FM_FMRI_SW_SITE_LINE, site_line);
+
+ /*
+ * Add 'site' to the fmri.
+ */
+ if (err == 0)
+ err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_SITE, site);
+
+ if (err) {
+ moderr = EMOD_NOMEM;
+ goto out;
+ }
+
+context:
+ /*
+ * Do we have anything for a 'context' nvlist?
+ */
+ if (ctxt_origin || ctxt_execname || ctxt_zone ||
+ ctxt_pid != -1 || ctxt_ctid != -1 || ctxt_stack != NULL)
+ goto out;
+
+ /*
+ * Allocate and build 'context' nvlist.
+ */
+ if (topo_mod_nvalloc(mod, &ctxt, NV_UNIQUE_NAME) != 0) {
+ moderr = EMOD_NOMEM;
+ goto out;
+ }
+
+ err |= sw_add_optl_string(ctxt, FM_FMRI_SW_CTXT_ORIGIN, ctxt_origin);
+ err |= sw_add_optl_string(ctxt, FM_FMRI_SW_CTXT_EXECNAME,
+ ctxt_execname);
+ err |= sw_add_optl_string(ctxt, FM_FMRI_SW_CTXT_ZONE, ctxt_zone);
+ if (ctxt_pid != -1)
+ err |= nvlist_add_int64(ctxt, FM_FMRI_SW_CTXT_PID, ctxt_pid);
+ if (ctxt_ctid != -1)
+ err |= nvlist_add_int64(ctxt, FM_FMRI_SW_CTXT_CTID, ctxt_ctid);
+ if (ctxt_stack != NULL)
+ err |= nvlist_add_string_array(ctxt, FM_FMRI_SW_CTXT_STACK,
+ ctxt_stack, ctxt_stackdepth);
+
+ /*
+ * Add 'context' to the fmri.
+ */
+ if (err == 0)
+ err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_CTXT, ctxt);
+
+ moderr = err ? EMOD_NOMEM : 0;
+out:
+ if (moderr == 0)
+ *out = fmri;
+
+ if (moderr != 0 && fmri)
+ nvlist_free(fmri);
+
+ if (obj)
+ nvlist_free(obj);
+
+ if (site)
+ nvlist_free(site);
+
+ if (ctxt)
+ nvlist_free(ctxt);
+
+ return (moderr == 0 ? 0 : topo_mod_seterrno(mod, moderr));
+}
+
+
+/*ARGSUSED*/
+static int
+sw_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
+ topo_instance_t min, topo_instance_t max, void *notused1, void *notused2)
+{
+ (void) topo_method_register(mod, pnode, sw_methods);
+ return (0);
+}
+
+static void
+sw_release(topo_mod_t *mod, tnode_t *node)
+{
+ topo_method_unregister_all(mod, node);
+}
+
+/*
+ * Lookup a string in an nvlist. Possible return values:
+ * if 'required' is B_TRUE:
+ * 1 = found
+ * 0 = not found
+ * if 'required' is B_FALSE:
+ * 1 = found
+ * 0 = not found, but some error other than ENOENT encountered
+ * -1 = not found, with ENOENT
+ *
+ * So 0 is an error condition in both cases.
+ *
+ * In all "not found" cases, *valp is NULLed.
+ */
+static int
+lookup_string(nvlist_t *nvl, char *name, char **valp, boolean_t required)
+{
+ int err;
+
+ err = nvlist_lookup_string(nvl, name, valp);
+
+ /*
+ * A return value of 1 always means "found"
+ */
+ if (err == 0)
+ return (1);
+
+ /*
+ * Failure to lookup for whatever reason NULLs valp
+ */
+ *valp = NULL;
+
+ /*
+ * Return 0 if not found but required, or optional but some error
+ * other than ENOENT was returned.
+ */
+ if (required == B_TRUE || err != ENOENT)
+ return (0);
+
+ /*
+ * Return -1 if not found but was optional (and got ENOENT).
+ */
+ return (-1);
+}
+
+/*ARGSUSED*/
+static int
+sw_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+ nvlist_t *nvl, nvlist_t **out)
+{
+ nvlist_t *object, *site = NULL, *anvl = NULL;
+ char *file, *func, *token;
+ uint8_t scheme_version;
+ char *path, *root;
+ nvlist_t *fmristr;
+ size_t buflen = 0;
+ int linevalid = 0;
+ char *buf = NULL;
+ ssize_t size = 0;
+ char linebuf[32];
+ int64_t line;
+ int pass;
+ int err;
+
+ if (version > TOPO_METH_NVL2STR_VERSION)
+ return (topo_mod_seterrno(mod, EMOD_VER_NEW));
+
+ if (nvlist_lookup_uint8(nvl, FM_VERSION, &scheme_version) != 0 ||
+ scheme_version > FM_SW_SCHEME_VERSION)
+ return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
+
+ /* Get authority, if present */
+ err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl);
+ if (err != 0 && err != ENOENT)
+ return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
+
+ /*
+ * The 'object' nvlist is required. It must include the path,
+ * but the root is optional.
+ */
+ if (nvlist_lookup_nvlist(nvl, FM_FMRI_SW_OBJ, &object) != 0 ||
+ !lookup_string(object, FM_FMRI_SW_OBJ_PATH, &path, B_TRUE) ||
+ !lookup_string(object, FM_FMRI_SW_OBJ_ROOT, &root, B_FALSE))
+ return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
+
+ /* The 'site' nvlist is optional */
+ file = func = token = NULL;
+ linevalid = 0;
+ if ((err = nvlist_lookup_nvlist(nvl, FM_FMRI_SW_SITE, &site)) == 0) {
+ /*
+ * Prefer 'token' to file/func/line
+ */
+ if (lookup_string(site, FM_FMRI_SW_SITE_TOKEN, &token,
+ B_FALSE) <= 0) {
+ /*
+ * If no token then try file, func, line - but
+ * func and line are meaningless without file.
+ */
+ if (lookup_string(site, FM_FMRI_SW_SITE_FILE,
+ &file, B_FALSE) == 1) {
+ (void) lookup_string(site, FM_FMRI_SW_SITE_FUNC,
+ &func, B_FALSE);
+ if (nvlist_lookup_int64(site,
+ FM_FMRI_SW_SITE_LINE, &line) == 0)
+ linevalid = 1;
+ }
+ }
+ } else if (err != ENOENT) {
+ return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
+ }
+
+ /* On the first pass buf is NULL and size and buflen are 0 */
+ pass = 1;
+again:
+ /*
+ * sw://[<authority>]/
+ * [:root=<object.root]
+ * :path=<object.path>
+ * [#<fragment-identifier>]
+ *
+ * <fragment-identifier> is one of
+ *
+ * :token=<site.token>
+ * or
+ * :file=<site.file>[:func=<site.func>][:line=<site.line>]
+ */
+
+ /* sw:// */
+ topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_SW,
+ NULL, "://");
+
+ /* authority, if any */
+ if (anvl != NULL) {
+ nvpair_t *apair;
+ char *aname, *aval;
+
+ for (apair = nvlist_next_nvpair(anvl, NULL);
+ apair != NULL; apair = nvlist_next_nvpair(anvl, apair)) {
+ if (nvpair_type(apair) != DATA_TYPE_STRING ||
+ nvpair_value_string(apair, &aval) != 0)
+ continue;
+ aname = nvpair_name(apair);
+ topo_fmristr_build(&size, buf, buflen, ":", NULL, NULL);
+ topo_fmristr_build(&size, buf, buflen, "=",
+ aname, aval);
+ }
+ }
+
+ /* separating slash */
+ topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
+
+ /* :root=... */
+ if (root) {
+ topo_fmristr_build(&size, buf, buflen, root,
+ ":" FM_FMRI_SW_OBJ_ROOT "=", NULL);
+ }
+
+ /* :path=... */
+ topo_fmristr_build(&size, buf, buflen, path,
+ ":" FM_FMRI_SW_OBJ_PATH "=", NULL);
+
+ if (token) {
+ /* #:token=... */
+ topo_fmristr_build(&size, buf, buflen, token,
+ "#:" FM_FMRI_SW_SITE_TOKEN "=", NULL);
+ } else if (file) {
+ /* #:file=... */
+ topo_fmristr_build(&size, buf, buflen, file,
+ "#:" FM_FMRI_SW_SITE_FILE "=", NULL);
+
+ /* :func=... */
+ if (func) {
+ topo_fmristr_build(&size, buf, buflen, func,
+ ":" FM_FMRI_SW_SITE_FUNC "=", NULL);
+ }
+
+ /* :line=... */
+ if (linevalid) {
+ if (pass == 1)
+ (void) snprintf(linebuf, sizeof (linebuf),
+ "%lld", line);
+
+ topo_fmristr_build(&size, buf, buflen, linebuf,
+ ":" FM_FMRI_SW_SITE_LINE "=", NULL);
+ }
+ }
+
+ if (buf == NULL) {
+ if ((buf = topo_mod_alloc(mod, size + 1)) == NULL)
+ return (topo_mod_seterrno(mod, EMOD_NOMEM));
+
+ buflen = size + 1;
+ size = 0;
+ pass = 2;
+ goto again;
+ }
+
+ /*
+ * Construct the nvlist to return as the result.
+ */
+ if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) {
+ topo_mod_strfree(mod, buf);
+ return (topo_mod_seterrno(mod, EMOD_NOMEM));
+ }
+
+ if (nvlist_add_string(fmristr, "fmri-string", buf) != 0) {
+ topo_mod_strfree(mod, buf);
+ nvlist_free(fmristr);
+ return (topo_mod_seterrno(mod, EMOD_NOMEM));
+ }
+ topo_mod_strfree(mod, buf);
+ *out = fmristr;
+
+ return (0);
+}
diff --git a/usr/src/lib/fm/topo/libtopo/common/sw.h b/usr/src/lib/fm/topo/libtopo/common/sw.h
new file mode 100644
index 0000000000..d66ae5bd23
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/common/sw.h
@@ -0,0 +1,42 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _SW_H
+#define _SW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SW_VERSION 1
+
+extern int sw_init(topo_mod_t *, topo_version_t); /* see sw.c */
+extern void sw_fini(topo_mod_t *); /* see sw.c */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SW_H */
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_builtin.c b/usr/src/lib/fm/topo/libtopo/common/topo_builtin.c
index c3bb83b63c..fe979488bd 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_builtin.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_builtin.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <pthread.h>
@@ -39,6 +38,7 @@
#include <mod.h>
#include <pkg.h>
#include <svc.h>
+#include <sw.h>
#include <zfs.h>
static const struct topo_builtin _topo_builtins[] = {
@@ -48,6 +48,7 @@ static const struct topo_builtin _topo_builtins[] = {
{ "mem", MEM_VERSION, mem_init, mem_fini },
{ "pkg", PKG_VERSION, pkg_init, pkg_fini },
{ "svc", SVC_VERSION, svc_init, svc_fini },
+ { "sw", SW_VERSION, sw_init, sw_fini },
{ "zfs", ZFS_VERSION, zfs_init, zfs_fini },
{ "mod", MOD_VERSION, mod_init, mod_fini },
{ "hc", HC_VERSION, hc_init, hc_fini }, /* hc must go last */
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
index 00d26891e2..295054dc5e 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -560,6 +559,70 @@ topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver)
return (nfp);
}
+#define _SWFMRI_ADD_STRING(nvl, name, val) \
+ ((val) ? (nvlist_add_string(nvl, name, val) != 0) : 0)
+
+nvlist_t *
+topo_mod_swfmri(topo_mod_t *mod, int version,
+ char *obj_path, char *obj_root, nvlist_t *obj_pkg,
+ char *site_token, char *site_module, char *site_file, char *site_func,
+ int64_t site_line, char *ctxt_origin, char *ctxt_execname,
+ int64_t ctxt_pid, char *ctxt_zone, int64_t ctxt_ctid,
+ char **ctxt_stack, uint_t ctxt_stackdepth)
+{
+ nvlist_t *fmri, *args;
+ nvlist_t *nfp = NULL;
+ int err;
+
+ if (version != FM_SW_SCHEME_VERSION)
+ return (set_fmri_err(mod, EMOD_FMRI_VERSION));
+
+ if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
+ return (set_fmri_err(mod, EMOD_FMRI_NVL));
+
+ err = 0;
+ err |= _SWFMRI_ADD_STRING(args, "obj_path", obj_path);
+ err |= _SWFMRI_ADD_STRING(args, "obj_root", obj_root);
+ if (obj_pkg)
+ err |= nvlist_add_nvlist(args, "obj_pkg", obj_pkg);
+
+ err |= _SWFMRI_ADD_STRING(args, "site_token", site_token);
+ err |= _SWFMRI_ADD_STRING(args, "site_module", site_module);
+ err |= _SWFMRI_ADD_STRING(args, "site_file", site_file);
+ err |= _SWFMRI_ADD_STRING(args, "site_func", site_func);
+ if (site_line != -1)
+ err |= nvlist_add_int64(args, "site_line", site_line);
+
+ err |= _SWFMRI_ADD_STRING(args, "ctxt_origin", ctxt_origin);
+ err |= _SWFMRI_ADD_STRING(args, "ctxt_execname", ctxt_execname);
+ if (ctxt_pid != -1)
+ err |= nvlist_add_int64(args, "ctxt_pid", ctxt_pid);
+ err |= _SWFMRI_ADD_STRING(args, "ctxt_zone", ctxt_zone);
+ if (ctxt_ctid != -1)
+ err |= nvlist_add_int64(args, "ctxt_ctid", ctxt_ctid);
+ if (ctxt_stack != NULL && ctxt_stackdepth != 0)
+ err |= nvlist_add_string_array(args, "stack", ctxt_stack,
+ ctxt_stackdepth);
+
+ if (err) {
+ nvlist_free(args);
+ return (set_fmri_err(mod, EMOD_FMRI_NVL));
+ }
+
+ if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_SW,
+ FM_FMRI_SCHEME_SW, 0, args, &err)) == NULL) {
+ nvlist_free(args);
+ return (set_fmri_err(mod, err));
+ }
+
+ nvlist_free(args);
+
+ (void) topo_mod_nvdup(mod, fmri, &nfp);
+ nvlist_free(fmri);
+
+ return (nfp);
+}
+
int
topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
{
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
index dbb5f3c0f0..2a137ad388 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _TOPO_MOD_H
@@ -93,6 +92,10 @@ extern nvlist_t *topo_mod_memfmri(topo_mod_t *, int, uint64_t, uint64_t,
const char *, int);
extern nvlist_t *topo_mod_modfmri(topo_mod_t *, int, const char *);
extern nvlist_t *topo_mod_pkgfmri(topo_mod_t *, int, const char *);
+extern nvlist_t *topo_mod_swfmri(topo_mod_t *, int,
+ char *, char *, nvlist_t *,
+ char *, char *, char *, char *, int64_t,
+ char *, char *, int64_t, char *, int64_t, char **, uint_t);
extern int topo_mod_nvl2str(topo_mod_t *, nvlist_t *, char **);
extern int topo_mod_str2nvl(topo_mod_t *, const char *, nvlist_t **);
extern int topo_prop_setmutable(tnode_t *node, const char *pgname,
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_node.c b/usr/src/lib/fm/topo/libtopo/common/topo_node.c
index ab720c1755..553bc851f0 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_node.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_node.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -390,6 +389,9 @@ topo_node_lookup(tnode_t *pnode, const char *name, topo_instance_t inst)
tnode_t *node;
topo_nodehash_t *nhp;
+ topo_dprintf(pnode->tn_hdl, TOPO_DBG_MODSVC,
+ "topo_node_lookup: looking for '%s' instance %d\n", name, inst);
+
topo_node_lock(pnode);
for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
nhp = topo_list_next(nhp)) {
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c
index 42ad1cd661..638d8c0677 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -78,6 +77,7 @@
#include <sys/systeminfo.h>
#include <sys/utsname.h>
#include <uuid/uuid.h>
+#include <zone.h>
#include <fm/libtopo.h>
#include <sys/fm/protocol.h>
@@ -379,7 +379,7 @@ topo_snap_hold(topo_hdl_t *thp, const char *uuid, int *errp)
/*
* Now walk the tree and invoke any facility enumeration methods
*/
- if (ret != NULL) {
+ if (ret != NULL && getzoneid() == 0) {
if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
fac_walker, (void *)0, errp)) == NULL) {
return (ret);
diff --git a/usr/src/lib/fm/topo/libtopo/common/zfs.c b/usr/src/lib/fm/topo/libtopo/common/zfs.c
index 6c8a456be3..573115efe3 100644
--- a/usr/src/lib/fm/topo/libtopo/common/zfs.c
+++ b/usr/src/lib/fm/topo/libtopo/common/zfs.c
@@ -21,8 +21,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <stdio.h>
@@ -103,6 +102,11 @@ int
zfs_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min,
topo_instance_t max, void *notused1, void *notused2)
{
+ /*
+ * Methods are registered, but there is no enumeration. Should
+ * enumeration be added be sure to cater for global vs non-global
+ * zones.
+ */
(void) topo_method_register(mod, pnode, zfs_methods);
return (0);
}