diff options
author | Gavin Maltby <gavin.maltby@oracle.com> | 2010-07-30 17:04:17 +1000 |
---|---|---|
committer | Gavin Maltby <gavin.maltby@oracle.com> | 2010-07-30 17:04:17 +1000 |
commit | f6e214c7418f43af38bd8c3a557e3d0a1d311cfa (patch) | |
tree | 0f0e4cee5ead68ee30660107f9eccf7cd9e72c2e /usr/src/lib/fm | |
parent | 265a964d7aa43c47170d21d2f01bcf873d7fd79d (diff) | |
download | illumos-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')
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); } |