# HG changeset patch # User Gavin Maltby # Date 1280473457 -36000 # Node ID ab9ae749152fd732e20c68c04b1244c910f046c5 # Parent 19d842faf8e4e178c83ce0513a6d55c62bcc4899 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 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/Makefile.lint --- a/usr/src/Makefile.lint Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/Makefile.lint Fri Jul 30 17:04:17 2010 +1000 @@ -263,6 +263,7 @@ cmd/rpcgen \ cmd/rpcsvc/rpc.bootparamd \ cmd/runat \ + cmd/savecore \ cmd/sbdadm \ cmd/sdpadm \ cmd/setpgrp \ @@ -425,6 +426,7 @@ lib/libsrpt \ lib/libstmf \ lib/libsun_ima \ + lib/libsysevent \ lib/libthread \ lib/libtsnet \ lib/libtsol \ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/cmd-inet/usr.lib/inetd/inetd.c --- a/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -342,7 +341,7 @@ scf_instance_t *scf_inst = NULL; scf_error_t sret; int ret; - char *aux = "none"; + restarter_str_t aux = restarter_str_none; /* update the repository/cached internal state */ inst->cur_istate = new_cur_state; @@ -369,12 +368,12 @@ */ if (new_cur_state == IIS_MAINTENANCE) { if (restarter_inst_ractions_from_tty(scf_inst) == 0) - aux = "service_request"; + aux = restarter_str_service_request; else - aux = "administrative_request"; + aux = restarter_str_administrative_request; } - if (strcmp(aux, "service_request") == 0) { + if (aux == restarter_str_service_request) { if (restarter_inst_validate_ractions_aux_fmri( scf_inst) == 0) { if (restarter_inst_set_aux_fmri(scf_inst)) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/dumpadm/Makefile --- a/usr/src/cmd/dumpadm/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/dumpadm/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. # PROG = dumpadm @@ -41,7 +40,7 @@ ROOTMANIFESTDIR = $(ROOTSVCSYSTEM) -LDLIBS += -ldiskmgt -lzfs +LDLIBS += -ldiskmgt -lzfs -luuid .KEEP_STATE: diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/dumpadm/dconf.c --- a/usr/src/cmd/dumpadm/dconf.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/dumpadm/dconf.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -37,6 +36,7 @@ #include #include #include +#include #include "dconf.h" #include "minfree.h" @@ -495,6 +495,24 @@ return (-1); } +int +dconf_write_uuid(dumpconf_t *dcp) +{ + char uuidstr[36 + 1]; + uuid_t uu; + int err; + + uuid_generate(uu); + uuid_unparse(uu, uuidstr); + + err = ioctl(dcp->dc_dump_fd, DIOCSETUUID, uuidstr); + + if (err) + warn(gettext("kernel image uuid write failed")); + + return (err == 0); +} + void dconf_print(dumpconf_t *dcp, FILE *fp) { @@ -533,7 +551,6 @@ (void) fprintf(fp, gettext(" Savecore enabled: %s\n"), (dcp->dc_enable == DC_OFF) ? gettext("no") : gettext("yes")); - (void) fprintf(fp, gettext(" Save compressed: %s\n"), (dcp->dc_csave == DC_UNCOMPRESSED) ? gettext("off") : gettext("on")); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/dumpadm/dconf.h --- a/usr/src/cmd/dumpadm/dconf.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/dumpadm/dconf.h Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _DCONF_H @@ -71,6 +70,7 @@ extern int dconf_write(dumpconf_t *); extern int dconf_update(dumpconf_t *, int); extern void dconf_print(dumpconf_t *, FILE *); +extern int dconf_write_uuid(dumpconf_t *); extern int dconf_str2device(dumpconf_t *, char *); extern int dconf_str2savdir(dumpconf_t *, char *); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/dumpadm/dumpadm.xml --- a/usr/src/cmd/dumpadm/dumpadm.xml Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/dumpadm/dumpadm.xml Fri Jul 30 17:04:17 2010 +1000 @@ -1,15 +1,13 @@ + + + + @@ -28,6 +27,7 @@ #include #include #include +#include #include "dconf.h" #include "minfree.h" @@ -37,7 +37,7 @@ Usage: %s [-nuy] [-c kernel | curproc | all ] [-d dump-device | swap ]\n\ [-m min {k|m|%%} ] [-s savecore-dir] [-r root-dir] [-z on|off]\n"; -static const char OPTS[] = "nuyc:d:m:s:r:z:"; +static const char OPTS[] = "inuyc:d:m:s:r:z:"; static const char PATH_DEVICE[] = "/dev/dump"; static const char PATH_CONFIG[] = "/etc/dumpadm.conf"; @@ -55,6 +55,8 @@ int modified = 0; /* have we modified the dump config? */ char *minfstr = NULL; /* string value of -m argument */ dumpconf_t dc; /* current configuration */ + int chrooted = 0; + int douuid = 0; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); @@ -66,7 +68,7 @@ */ while (optind < argc) { while ((c = getopt(argc, argv, OPTS)) != (int)EOF) { - if (c == 'r' && chroot(optarg) == -1) + if (c == 'r' && ++chrooted && chroot(optarg) == -1) die(gettext("failed to chroot to %s"), optarg); else if (c == 'u') dcmode = DC_OVERRIDE; @@ -120,6 +122,16 @@ modified++; break; + case 'i': + /* undocumented option */ + if (chrooted) { + warn(gettext("-i and -r cannot be " + "used together\n")); + return (E_USAGE); + } + douuid++; + break; + case 'm': minfstr = optarg; break; @@ -156,6 +168,9 @@ } } + if (douuid) + return (dconf_write_uuid(&dc) ? E_SUCCESS : E_ERROR); + if (minfstr != NULL) { if (minfree_compute(dc.dc_savdir, minfstr, &minf) == -1) return (E_USAGE); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/dumpadm/svc-dumpadm --- a/usr/src/cmd/dumpadm/svc-dumpadm Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/dumpadm/svc-dumpadm Fri Jul 30 17:04:17 2010 +1000 @@ -20,12 +20,11 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # -#ident "%Z%%M% %I% %E% SMI" . /lib/svc/share/smf_include.sh +. /lib/svc/share/fs_include.sh # # mksavedir @@ -47,9 +46,33 @@ # an alternate dump device, then the dump is in the primary swap partition, # which was configured as the dump device by the first swapadd early in boot. # Thus before we run dumpadm to configure the dump device, we first run -# savecore to check the swap partition for a dump. +# savecore to check the swap partition for a dump; this is run in the +# foreground to reduce the chances of overwriting the dump. +# +# This does not apply for zfs root systems that use a zvol for dump; +# for such systems the dedicated dump device is appointed during startup +# of the filesystem/usr:default instance before any swap is added. +# Therefore we must check that the dump device is a swap device here - +# if not then we'll run savecore here in the foreground and prevent +# our dependent services coming online until we're done. # -if [ -x /usr/bin/savecore ]; then + +rootiszfs=0 +alreadydedicated=0 + +readmnttab / /dev/null | grep "Dump device:" | \ + grep '(dedicated)' > /dev/null 2>&1; then + alreadydedicated=1 + fi + fi +fi + +if [ -x /usr/bin/savecore -a \ + \( ! $rootiszfs -eq 1 -o $alreadydedicated -eq 0 \) ]; then [ -r /etc/dumpadm.conf ] && . /etc/dumpadm.conf if [ "x$DUMPADM_ENABLE" != xno ] && mksavedir; then @@ -57,8 +80,17 @@ shift $# set -- `/usr/sbin/dumpadm 2>/dev/null | /usr/bin/grep 'device:'` savedev=${3:-none} + else + # + # dumpadm -n is in effect, but we can still run savecore + # to raise an event with initial panic detail extracted + # from the dump header. + # + /usr/bin/savecore -c fi -else +fi + +if [ ! -x /usr/bin/savecore ]; then echo "WARNING: /usr/bin/savecore is missing or not executable" >& 2 fi @@ -82,20 +114,38 @@ fi # +# If the savecore executable is absent then we're done +# +if [ ! -x /usr/bin/savecore ]; then + exit $SMF_EXIT_ERR_CONFIG +fi + +# # Now that dumpadm has reconfigured /dev/dump, we need to run savecore again # because the dump device may have changed. If the earlier savecore had # saved the dump, savecore will just exit immediately. # + +isswap=0 +swapchanged=0 +if /usr/sbin/swap -l 2>/dev/null | grep "^${DUMPADM_DEVICE} " \ + >/dev/null 2>&1; then + isswap=1 + if [ "x$savedev" != "x$DUMPADM_DEVICE" ]; then + swapchanged=1 + fi +fi + if [ "x$DUMPADM_ENABLE" != xno ]; then - if /usr/sbin/swap -l 2>/dev/null | grep "^${DUMPADM_DEVICE} " \ - >/dev/null 2>&1; then + if [ $isswap -eq 1 ]; then # # If the dump device is part of swap, we only need to run # savecore a second time if the device is different from the # swap device on which we initially ran savecore. # - [ "x$savedev" != "x$DUMPADM_DEVICE" ] && \ + if [ $swapchanged -eq 1 ]; then mksavedir && /usr/bin/savecore $DUMPADM_SAVDIR & + fi else # # The dump device couldn't have been dedicated before we @@ -103,6 +153,16 @@ # mksavedir && /usr/bin/savecore $DUMPADM_SAVDIR & fi +else + # + # savecore not enabled. Check whether a valid dump is + # present on the device and raise an event to signal that, + # but avoid sending a duplicate event from the savecore -c + # earlier. + # + if [ $isswap -eq 0 -o $swapchanged -eq 1 ]; then + /usr/bin/savecore -c + fi fi exit $SMF_EXIT_OK diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/Makefile --- a/usr/src/cmd/fm/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -18,11 +18,10 @@ # # CDDL HEADER END # + # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # -#ident "%Z%%M% %I% %E% SMI" SUBDIRS = \ fmd \ @@ -36,7 +35,8 @@ scripts \ modules \ dicts \ - eversholt + eversholt \ + notify include ./Makefile.subdirs diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/dicts/FMD.dict --- a/usr/src/cmd/fm/dicts/FMD.dict Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/dicts/FMD.dict Fri Jul 30 17:04:17 2010 +1000 @@ -1,4 +1,5 @@ # +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # # CDDL HEADER START # @@ -19,12 +20,11 @@ # # CDDL HEADER END # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. + +# DO NOT EDIT -- this file is generated by the Event Registry. # -#ident "%Z%%M% %I% %E% SMI" -FMDICT: name=FMD version=1 maxkey=1 +FMDICT: name=FMD version=1 maxkey=1 dictid=0x464d defect.sunos.fmd.nosub=0 defect.sunos.fmd.nodiagcode=1 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/dicts/FMD.po --- a/usr/src/cmd/fm/dicts/FMD.po Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/dicts/FMD.po Fri Jul 30 17:04:17 2010 +1000 @@ -1,6 +1,5 @@ # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # # CDDL HEADER START # @@ -21,6 +20,7 @@ # # CDDL HEADER END # + # DO NOT EDIT -- this file is generated by the Event Registry. # # @@ -28,9 +28,6 @@ # msgid "syslog-msgs-message-template" msgstr "SUNW-MSG-ID: %s, TYPE: %s, VER: 1, SEVERITY: %s\nEVENT-TIME: %s\nPLATFORM: %s, CSN: %s, HOSTNAME: %s\nSOURCE: %s, REV: %s\nEVENT-ID: %s\nDESC: %s\nAUTO-RESPONSE: %s\nIMPACT: %s\nREC-ACTION: %s\n" -msgid "syslog-msgs-pointer" -msgstr "\n...\nSee fmadm faulty -u for full information.\n" - # # Fault-related messages # @@ -44,7 +41,7 @@ msgid "FMD-8000-0W.severity" msgstr "Minor" msgid "FMD-8000-0W.description" -msgstr "The Solaris Fault Manager received an event % to which no automated diagnosis software is currently subscribed. Refer to %s for more information." +msgstr "The Solaris Fault Manager received an event from a component to which no automated diagnosis software is currently subscribed. Refer to %s for more information." msgid "FMD-8000-0W.response" msgstr "Error reports from the component will be logged for examination by Sun." msgid "FMD-8000-0W.impact" @@ -110,9 +107,9 @@ msgid "FMD-8000-4M.description" msgstr "All faults associated with an event id have been addressed.\n Refer to %s for more information." msgid "FMD-8000-4M.response" -msgstr "Some system components offlined because of the original fault may have been brought back online.\n" +msgstr "Some system components offlined because of the original fault may have been brought back online." msgid "FMD-8000-4M.impact" -msgstr "Performance degradation of the system due to the original fault may have been recovered.\n" +msgstr "Performance degradation of the system due to the original fault may have been recovered." msgid "FMD-8000-4M.action" msgstr "Use fmdump -v -u to identify the repaired components." # @@ -126,11 +123,11 @@ msgid "FMD-8000-58.description" msgstr "Some faults associated with an event id have been addressed.\n Refer to %s for more information." msgid "FMD-8000-58.response" -msgstr "Some system components offlined because of the original fault may have been brought back online.\n" +msgstr "Some system components offlined because of the original fault may have been brought back online." msgid "FMD-8000-58.impact" -msgstr "Performance degradation of the system due to the original fault may have been recovered.\n" +msgstr "Performance degradation of the system due to the original fault may have been recovered." msgid "FMD-8000-58.action" -msgstr "Use fmadm faulty to identify the repaired components, and any suspects that still need to be repaired.\n" +msgstr "Use fmadm faulty to identify the repaired components, and any suspects that still need to be repaired." # # code: FMD-8000-6U # keys: list.resolved @@ -142,8 +139,8 @@ msgid "FMD-8000-6U.description" msgstr "All faults associated with an event id have been addressed.\n Refer to %s for more information." msgid "FMD-8000-6U.response" -msgstr "All system components offlined because of the original fault have been brought back online.\n" +msgstr "All system components offlined because of the original fault have been brought back online." msgid "FMD-8000-6U.impact" -msgstr "Performance degradation of the system due to the original fault has been recovered.\n" +msgstr "Performance degradation of the system due to the original fault has been recovered." msgid "FMD-8000-6U.action" -msgstr "Use fmdump -v -u to identify the repaired components.\n" +msgstr "Use fmdump -v -u to identify the repaired components." diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/dicts/FMNOTIFY.dict --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/dicts/FMNOTIFY.dict Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,25 @@ +# +# +# 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. +# + +FMDICT: name=FMNOTIFY version=1 maxkey=1 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/dicts/FMNOTIFY.po --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/dicts/FMNOTIFY.po Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,63 @@ +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# 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 +# +# +# DO NOT EDIT -- this file is generated by the Event Registry. +# + +# +# default format for subject of emails generated by the smtp-notify agent +# +# params: hostname, code +# +msgid "smtp-notify-subject-template" +msgstr "Solaris Event Notification:%s:%s" + +# +# format for subject of emails generated by the smtp-notify agent +# for SMF service state transition events +# +# params: hostname, fmri, from-state, to-state +# +msgid "smtp-notify-smf-subject-template" +msgstr "%s: %s %s->%s" + +# +# format for subject of emails generated by the smtp-notify agent +# for FMA events +# +# params: hostname, code +# +msgid "smtp-notify-fm-subject-template" +msgstr "Fault Management Event: %s:%s" + +# +# Generic message template for raw software events +# +msgid "ireport-msg-template" +msgstr "HOSTNAME: %s\nTIMESTAMP: %s\nCLASS: %s\n" + +# +# default email message template for SMF service state transition events +# +msgid "ireport.os.smf-msg-template" +msgstr "HOSTNAME: %s\nTIMESTAMP: %s\nFMRI: %s\nFROM-STATE: %s\nTO-STATE: %s\nDESCRIPTION: %s\nREASON: %s\n" diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/dicts/Makefile --- a/usr/src/cmd/fm/dicts/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/dicts/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -27,7 +27,9 @@ common_DCNAMES = \ DISK \ FMD \ + FMNOTIFY \ NXGE \ + SMF \ SUNOS \ PCI \ PCIEX \ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/dicts/SMF.dict --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/dicts/SMF.dict Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,60 @@ +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# 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 +# + +# DO NOT EDIT -- this file is generated by the Event Registry. +# + +FMDICT: name=SMF version=1 maxkey=1 dictid=0x534d + +defect.sunos.smf.svc.disabled=0 +defect.sunos.smf.svc.temporarily_disabled=1 +defect.sunos.smf.svc.invalid_restarter=2 +defect.sunos.smf.svc.restarter_absent=3 +defect.sunos.smf.svc.uninitialized=4 +defect.sunos.smf.svc.restarter_dead=5 +defect.sunos.smf.svc.administrative_request=6 +defect.sunos.smf.svc.fault_threshold_reached=7 +defect.sunos.smf.svc.method_fail=8 +defect.sunos.smf.svc.none=9 +defect.sunos.smf.svc.unknown=10 +defect.sunos.smf.svc.starting=11 +defect.sunos.smf.svc.administrative_degraded=12 +defect.sunos.smf.svc.dependency_absent=13 +defect.sunos.smf.svc.dependency_running=14 +defect.sunos.smf.svc.dependency_other=15 +defect.sunos.smf.svc.dependency_cycle=16 +defect.sunos.smf.svc.invalid_dependency=17 +defect.sunos.smf.svc.start_method_fail=18 +defect.sunos.smf.svc.restarting_too_quickly=19 +defect.sunos.smf.db.verify=20 +defect.sunos.smf.svc.bad_repo_state=21 +defect.sunos.smf.svc.transitioning=22 +defect.sunos.smf.info.recovery=23 +defect.sunos.smf.svc.service_request=24 +ireport.os.smf.state-transition.offline=25 +ireport.os.smf.state-transition.online=26 +ireport.os.smf.state-transition.disabled=27 +ireport.os.smf.state-transition.degraded=28 +ireport.os.smf.state-transition.uninitialized=29 +ireport.os.smf.state-transition.maintenance=30 +defect.sunos.smf.svc.maintenance=31 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/dicts/SMF.po --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/dicts/SMF.po Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,537 @@ +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# 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 +# + +# DO NOT EDIT -- this file is generated by the Event Registry. +# +# +# code: SMF-8000-05 +# keys: defect.sunos.smf.svc.disabled +# +msgid "SMF-8000-05.type" +msgstr "XXX" +msgid "SMF-8000-05.severity" +msgstr "XXX" +msgid "SMF-8000-05.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-05.response" +msgstr "XXX" +msgid "SMF-8000-05.impact" +msgstr "XXX" +msgid "SMF-8000-05.action" +msgstr "XXX" +# +# code: SMF-8000-1S +# keys: defect.sunos.smf.svc.temporarily_disabled +# +msgid "SMF-8000-1S.type" +msgstr "XXX" +msgid "SMF-8000-1S.severity" +msgstr "XXX" +msgid "SMF-8000-1S.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-1S.response" +msgstr "XXX" +msgid "SMF-8000-1S.impact" +msgstr "XXX" +msgid "SMF-8000-1S.action" +msgstr "XXX" +# +# code: SMF-8000-2A +# keys: defect.sunos.smf.svc.invalid_restarter +# +msgid "SMF-8000-2A.type" +msgstr "XXX" +msgid "SMF-8000-2A.severity" +msgstr "XXX" +msgid "SMF-8000-2A.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-2A.response" +msgstr "XXX" +msgid "SMF-8000-2A.impact" +msgstr "XXX" +msgid "SMF-8000-2A.action" +msgstr "XXX" +# +# code: SMF-8000-3P +# keys: defect.sunos.smf.svc.restarter_absent +# +msgid "SMF-8000-3P.type" +msgstr "XXX" +msgid "SMF-8000-3P.severity" +msgstr "XXX" +msgid "SMF-8000-3P.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-3P.response" +msgstr "XXX" +msgid "SMF-8000-3P.impact" +msgstr "XXX" +msgid "SMF-8000-3P.action" +msgstr "XXX" +# +# code: SMF-8000-4D +# keys: defect.sunos.smf.svc.uninitialized +# +msgid "SMF-8000-4D.type" +msgstr "XXX" +msgid "SMF-8000-4D.severity" +msgstr "XXX" +msgid "SMF-8000-4D.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-4D.response" +msgstr "XXX" +msgid "SMF-8000-4D.impact" +msgstr "XXX" +msgid "SMF-8000-4D.action" +msgstr "XXX" +# +# code: SMF-8000-5H +# keys: defect.sunos.smf.svc.restarter_dead +# +msgid "SMF-8000-5H.type" +msgstr "XXX" +msgid "SMF-8000-5H.severity" +msgstr "XXX" +msgid "SMF-8000-5H.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-5H.response" +msgstr "XXX" +msgid "SMF-8000-5H.impact" +msgstr "XXX" +msgid "SMF-8000-5H.action" +msgstr "XXX" +# +# code: SMF-8000-63 +# keys: defect.sunos.smf.svc.administrative_request +# +msgid "SMF-8000-63.type" +msgstr "XXX" +msgid "SMF-8000-63.severity" +msgstr "XXX" +msgid "SMF-8000-63.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-63.response" +msgstr "XXX" +msgid "SMF-8000-63.impact" +msgstr "XXX" +msgid "SMF-8000-63.action" +msgstr "XXX" +# +# code: SMF-8000-7Y +# keys: defect.sunos.smf.svc.fault_threshold_reached +# +msgid "SMF-8000-7Y.type" +msgstr "XXX" +msgid "SMF-8000-7Y.severity" +msgstr "XXX" +msgid "SMF-8000-7Y.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-7Y.response" +msgstr "XXX" +msgid "SMF-8000-7Y.impact" +msgstr "XXX" +msgid "SMF-8000-7Y.action" +msgstr "XXX" +# +# code: SMF-8000-8Q +# keys: defect.sunos.smf.svc.method_fail +# +msgid "SMF-8000-8Q.type" +msgstr "XXX" +msgid "SMF-8000-8Q.severity" +msgstr "XXX" +msgid "SMF-8000-8Q.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-8Q.response" +msgstr "XXX" +msgid "SMF-8000-8Q.impact" +msgstr "XXX" +msgid "SMF-8000-8Q.action" +msgstr "XXX" +# +# code: SMF-8000-9C +# keys: defect.sunos.smf.svc.none +# +msgid "SMF-8000-9C.type" +msgstr "XXX" +msgid "SMF-8000-9C.severity" +msgstr "XXX" +msgid "SMF-8000-9C.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-9C.response" +msgstr "XXX" +msgid "SMF-8000-9C.impact" +msgstr "XXX" +msgid "SMF-8000-9C.action" +msgstr "XXX" +# +# code: SMF-8000-AR +# keys: defect.sunos.smf.svc.unknown +# +msgid "SMF-8000-AR.type" +msgstr "XXX" +msgid "SMF-8000-AR.severity" +msgstr "XXX" +msgid "SMF-8000-AR.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-AR.response" +msgstr "XXX" +msgid "SMF-8000-AR.impact" +msgstr "XXX" +msgid "SMF-8000-AR.action" +msgstr "XXX" +# +# code: SMF-8000-C4 +# keys: defect.sunos.smf.svc.starting +# +msgid "SMF-8000-C4.type" +msgstr "XXX" +msgid "SMF-8000-C4.severity" +msgstr "XXX" +msgid "SMF-8000-C4.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-C4.response" +msgstr "XXX" +msgid "SMF-8000-C4.impact" +msgstr "XXX" +msgid "SMF-8000-C4.action" +msgstr "XXX" +# +# code: SMF-8000-DX +# keys: defect.sunos.smf.svc.administrative_degraded +# +msgid "SMF-8000-DX.type" +msgstr "XXX" +msgid "SMF-8000-DX.severity" +msgstr "XXX" +msgid "SMF-8000-DX.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-DX.response" +msgstr "XXX" +msgid "SMF-8000-DX.impact" +msgstr "XXX" +msgid "SMF-8000-DX.action" +msgstr "XXX" +# +# code: SMF-8000-E2 +# keys: defect.sunos.smf.svc.dependency_absent +# +msgid "SMF-8000-E2.type" +msgstr "XXX" +msgid "SMF-8000-E2.severity" +msgstr "XXX" +msgid "SMF-8000-E2.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-E2.response" +msgstr "XXX" +msgid "SMF-8000-E2.impact" +msgstr "XXX" +msgid "SMF-8000-E2.action" +msgstr "XXX" +# +# code: SMF-8000-FJ +# keys: defect.sunos.smf.svc.dependency_running +# +msgid "SMF-8000-FJ.type" +msgstr "XXX" +msgid "SMF-8000-FJ.severity" +msgstr "XXX" +msgid "SMF-8000-FJ.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-FJ.response" +msgstr "XXX" +msgid "SMF-8000-FJ.impact" +msgstr "XXX" +msgid "SMF-8000-FJ.action" +msgstr "XXX" +# +# code: SMF-8000-GE +# keys: defect.sunos.smf.svc.dependency_other +# +msgid "SMF-8000-GE.type" +msgstr "XXX" +msgid "SMF-8000-GE.severity" +msgstr "XXX" +msgid "SMF-8000-GE.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-GE.response" +msgstr "XXX" +msgid "SMF-8000-GE.impact" +msgstr "XXX" +msgid "SMF-8000-GE.action" +msgstr "XXX" +# +# code: SMF-8000-HP +# keys: defect.sunos.smf.svc.dependency_cycle +# +msgid "SMF-8000-HP.type" +msgstr "XXX" +msgid "SMF-8000-HP.severity" +msgstr "XXX" +msgid "SMF-8000-HP.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-HP.response" +msgstr "XXX" +msgid "SMF-8000-HP.impact" +msgstr "XXX" +msgid "SMF-8000-HP.action" +msgstr "XXX" +# +# code: SMF-8000-JA +# keys: defect.sunos.smf.svc.invalid_dependency +# +msgid "SMF-8000-JA.type" +msgstr "XXX" +msgid "SMF-8000-JA.severity" +msgstr "XXX" +msgid "SMF-8000-JA.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-JA.response" +msgstr "XXX" +msgid "SMF-8000-JA.impact" +msgstr "XXX" +msgid "SMF-8000-JA.action" +msgstr "XXX" +# +# code: SMF-8000-KS +# keys: defect.sunos.smf.svc.start_method_fail +# +msgid "SMF-8000-KS.type" +msgstr "XXX" +msgid "SMF-8000-KS.severity" +msgstr "XXX" +msgid "SMF-8000-KS.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-KS.response" +msgstr "XXX" +msgid "SMF-8000-KS.impact" +msgstr "XXX" +msgid "SMF-8000-KS.action" +msgstr "XXX" +# +# code: SMF-8000-L5 +# keys: defect.sunos.smf.svc.restarting_too_quickly +# +msgid "SMF-8000-L5.type" +msgstr "XXX" +msgid "SMF-8000-L5.severity" +msgstr "XXX" +msgid "SMF-8000-L5.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-L5.response" +msgstr "XXX" +msgid "SMF-8000-L5.impact" +msgstr "XXX" +msgid "SMF-8000-L5.action" +msgstr "XXX" +# +# code: SMF-8000-MY +# keys: defect.sunos.smf.db.verify +# +msgid "SMF-8000-MY.type" +msgstr "XXX" +msgid "SMF-8000-MY.severity" +msgstr "XXX" +msgid "SMF-8000-MY.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-MY.response" +msgstr "XXX" +msgid "SMF-8000-MY.impact" +msgstr "XXX" +msgid "SMF-8000-MY.action" +msgstr "XXX" +# +# code: SMF-8000-N3 +# keys: defect.sunos.smf.svc.bad_repo_state +# +msgid "SMF-8000-N3.type" +msgstr "XXX" +msgid "SMF-8000-N3.severity" +msgstr "XXX" +msgid "SMF-8000-N3.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-N3.response" +msgstr "XXX" +msgid "SMF-8000-N3.impact" +msgstr "XXX" +msgid "SMF-8000-N3.action" +msgstr "XXX" +# +# code: SMF-8000-PH +# keys: defect.sunos.smf.svc.transitioning +# +msgid "SMF-8000-PH.type" +msgstr "XXX" +msgid "SMF-8000-PH.severity" +msgstr "XXX" +msgid "SMF-8000-PH.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-PH.response" +msgstr "XXX" +msgid "SMF-8000-PH.impact" +msgstr "XXX" +msgid "SMF-8000-PH.action" +msgstr "XXX" +# +# code: SMF-8000-QD +# keys: defect.sunos.smf.info.recovery +# +msgid "SMF-8000-QD.type" +msgstr "XXX" +msgid "SMF-8000-QD.severity" +msgstr "XXX" +msgid "SMF-8000-QD.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-QD.response" +msgstr "XXX" +msgid "SMF-8000-QD.impact" +msgstr "XXX" +msgid "SMF-8000-QD.action" +msgstr "XXX" +# +# code: SMF-8000-R4 +# keys: defect.sunos.smf.svc.service_request +# +msgid "SMF-8000-R4.type" +msgstr "XXX" +msgid "SMF-8000-R4.severity" +msgstr "XXX" +msgid "SMF-8000-R4.description" +msgstr "XXX Refer to %s for more information." +msgid "SMF-8000-R4.response" +msgstr "XXX" +msgid "SMF-8000-R4.impact" +msgstr "XXX" +msgid "SMF-8000-R4.action" +msgstr "XXX" +# +# code: SMF-8000-SR +# keys: ireport.os.smf.state-transition.offline +# +msgid "SMF-8000-SR.type" +msgstr "XXX" +msgid "SMF-8000-SR.severity" +msgstr "minor" +msgid "SMF-8000-SR.description" +msgstr "The indicated service has transitioned to the offline state\n Refer to %s for more information." +msgid "SMF-8000-SR.response" +msgstr "XXX" +msgid "SMF-8000-SR.impact" +msgstr "Functionality provided by the offline service is unavailable." +msgid "SMF-8000-SR.action" +msgstr "XXX" +# +# code: SMF-8000-TC +# keys: ireport.os.smf.state-transition.online +# +msgid "SMF-8000-TC.type" +msgstr "XXX" +msgid "SMF-8000-TC.severity" +msgstr "minor" +msgid "SMF-8000-TC.description" +msgstr "The indicated service has transitioned to the online state\n Refer to %s for more information." +msgid "SMF-8000-TC.response" +msgstr "XXX" +msgid "SMF-8000-TC.impact" +msgstr "Functionality provided by the service is now available." +msgid "SMF-8000-TC.action" +msgstr "XXX" +# +# code: SMF-8000-UQ +# keys: ireport.os.smf.state-transition.disabled +# +msgid "SMF-8000-UQ.type" +msgstr "XXX" +msgid "SMF-8000-UQ.severity" +msgstr "minor" +msgid "SMF-8000-UQ.description" +msgstr "The indicated service has transitioned to the disabled state\n Refer to %s for more information." +msgid "SMF-8000-UQ.response" +msgstr "XXX" +msgid "SMF-8000-UQ.impact" +msgstr "Functionality provided by the service is unavailable." +msgid "SMF-8000-UQ.action" +msgstr "XXX" +# +# code: SMF-8000-VE +# keys: ireport.os.smf.state-transition.degraded +# +msgid "SMF-8000-VE.type" +msgstr "XXX" +msgid "SMF-8000-VE.severity" +msgstr "minor" +msgid "SMF-8000-VE.description" +msgstr "The indicated service has transitioned to the degraded state\n Refer to %s for more information." +msgid "SMF-8000-VE.response" +msgstr "XXX" +msgid "SMF-8000-VE.impact" +msgstr "Some functionality provided by the service may be unavailable." +msgid "SMF-8000-VE.action" +msgstr "XXX" +# +# code: SMF-8000-WJ +# keys: ireport.os.smf.state-transition.uninitialized +# +msgid "SMF-8000-WJ.type" +msgstr "XXX" +msgid "SMF-8000-WJ.severity" +msgstr "minor" +msgid "SMF-8000-WJ.description" +msgstr "The indicated service has transitioned to the uninitialized state\n Refer to %s for more information." +msgid "SMF-8000-WJ.response" +msgstr "XXX" +msgid "SMF-8000-WJ.impact" +msgstr "Functionality provided by the service is unavailable." +msgid "SMF-8000-WJ.action" +msgstr "XXX" +# +# code: SMF-8000-X2 +# keys: ireport.os.smf.state-transition.maintenance +# +msgid "SMF-8000-X2.type" +msgstr "XXX" +msgid "SMF-8000-X2.severity" +msgstr "major" +msgid "SMF-8000-X2.description" +msgstr "The indicated service has transitioned to the maintenance state\n Refer to %s for more information." +msgid "SMF-8000-X2.response" +msgstr "XXX" +msgid "SMF-8000-X2.impact" +msgstr "Functionality provided by the service is unavailable." +msgid "SMF-8000-X2.action" +msgstr "XXX" +# +# code: SMF-8000-YX +# keys: defect.sunos.smf.svc.maintenance +# +msgid "SMF-8000-YX.type" +msgstr "defect" +msgid "SMF-8000-YX.severity" +msgstr "major" +msgid "SMF-8000-YX.description" +msgstr "A service failed - %.\n Refer to %s for more information." +msgid "SMF-8000-YX.response" +msgstr "The service has been placed into the maintenance state." +msgid "SMF-8000-YX.impact" +msgstr "% is unavailable." +msgid "SMF-8000-YX.action" +msgstr "Run 'svcs -xv %' to determine the generic reason why the service failed, the location of any logfiles, and a list of other services impacted." diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/dicts/SUNOS.dict --- a/usr/src/cmd/fm/dicts/SUNOS.dict Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/dicts/SUNOS.dict Fri Jul 30 17:04:17 2010 +1000 @@ -1,6 +1,5 @@ # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # # CDDL HEADER START # @@ -21,6 +20,7 @@ # # CDDL HEADER END # + # DO NOT EDIT -- this file is generated by the Event Registry. # @@ -44,3 +44,4 @@ defect.sunos.eft.undiag.limit=15 defect.sunos.eft.undiag.unknown=16 defect.sunos.eft.unexpected_telemetry fault.sunos.eft.unexpected_telemetry=17 +defect.sunos.kernel.panic=18 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/dicts/SUNOS.po --- a/usr/src/cmd/fm/dicts/SUNOS.po Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/dicts/SUNOS.po Fri Jul 30 17:04:17 2010 +1000 @@ -1,6 +1,5 @@ # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # # CDDL HEADER START # @@ -21,6 +20,7 @@ # # CDDL HEADER END # + # DO NOT EDIT -- this file is generated by the Event Registry. # # @@ -194,11 +194,11 @@ msgid "SUNOS-8000-AK.description" msgstr "Solaris OS could not automatically adjust\n/boot/grub/menu.lst\nto the new boot architecture\n Refer to %s for more information." msgid "SUNOS-8000-AK.response" -msgstr "No automated response.\n" +msgstr "No automated response." msgid "SUNOS-8000-AK.impact" -msgstr "Future reboots could fail until this problem is corrected.\n" +msgstr "Future reboots could fail until this problem is corrected." msgid "SUNOS-8000-AK.action" -msgstr "Examine /boot/grub/menu.lst and revise as\ndescribed in Details.\n" +msgstr "Examine /boot/grub/menu.lst and revise as\ndescribed in Details." # # code: SUNOS-8000-CF # keys: ereport.sunos.boot.upgrade.menu_lst_bfu @@ -210,11 +210,11 @@ msgid "SUNOS-8000-CF.description" msgstr "Solaris OS could not automatically adjust\n/boot/grub/menu.lst\nto the new boot architecture\n Refer to %s for more information." msgid "SUNOS-8000-CF.response" -msgstr "No automated response.\n" +msgstr "No automated response." msgid "SUNOS-8000-CF.impact" -msgstr "Future reboots could fail until this problem is corrected.\n" +msgstr "Future reboots could fail until this problem is corrected." msgid "SUNOS-8000-CF.action" -msgstr "Examine /boot/grub/menu.lst and revise as\ndescribed in Details.\n" +msgstr "Examine /boot/grub/menu.lst and revise as\ndescribed in Details." # # code: SUNOS-8000-DM # keys: defect.sunos.smf.svc.maintenance @@ -304,10 +304,26 @@ msgid "SUNOS-8000-J0.severity" msgstr "Major" msgid "SUNOS-8000-J0.description" -msgstr "The diagnosis engine encountered telemetry from the listed devices for which it was unable to perform a diagnosis - %.\n Refer to %s for more information." +msgstr "The diagnosis engine encountered telemetry from the listed devices for which it was unable to perform a diagnosis - %.\n Refer to %s for more information. Refer to %s for more information." msgid "SUNOS-8000-J0.response" msgstr "Error reports have been logged for examination by Sun.\n" msgid "SUNOS-8000-J0.impact" msgstr "Automated diagnosis and response for these events will not occur.\n" msgid "SUNOS-8000-J0.action" msgstr "Ensure that the latest Solaris Kernel and Predictive Self-Healing (PSH) patches are installed.\n" +# +# code: SUNOS-8000-KL +# keys: defect.sunos.kernel.panic +# +msgid "SUNOS-8000-KL.type" +msgstr "Defect" +msgid "SUNOS-8000-KL.severity" +msgstr "Major" +msgid "SUNOS-8000-KL.description" +msgstr "The system has rebooted after a kernel panic. Refer to %s for more information." +msgid "SUNOS-8000-KL.response" +msgstr "The failed system image was dumped to the dump device. If savecore is enabled (see dumpadm(1M)) a copy of the dump will be written to the savecore directory %." +msgid "SUNOS-8000-KL.impact" +msgstr "There may be some performance impact while the panic is copied to the savecore directory. Disk space usage by panics can be substantial." +msgid "SUNOS-8000-KL.action" +msgstr "If savecore is not enabled then please take steps to preserve the crash image.\nUse 'fmdump -Vp -u %' to view more panic detail. Please refer to the knowledge article for additional information." diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/Makefile.fmd --- a/usr/src/cmd/fm/fmd/Makefile.fmd Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/Makefile.fmd Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # .KEEP_STATE: @@ -77,6 +76,11 @@ MAPFILE-DMOD = $(SRC)/cmd/mdb/common/modules/conf/mapfile-extern +LOGADMFILE = $(PROG).logadm.conf +LOGADMDIR = $(ROOT)/etc/logadm.d +LOGADMENT = $(LOGADMDIR)/$(LOGADMFILE) +$(LOGADMENT) := FILEMODE = 444 + ROOTPDIR = $(ROOT)/usr/lib/fm/$(PROG) ROOTVDIR = $(ROOT)/var/fm/$(PROG) ROOTVSUB = $(ROOTVDIR)/ckpt $(ROOTVDIR)/rsrc $(ROOTVDIR)/xprt @@ -139,6 +143,12 @@ all: $(PROG) $(DMOD) install_h +$(LOGADMDIR): + $(INS.dir) + +$(LOGADMDIR)/%.conf: ../common/%.conf + $(INS.file) + $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(CTFMERGE) -L VERSION -o $@ $(OBJS) @@ -234,7 +244,7 @@ install_h: $(ROOTHDIR) $(ROOTHDRS) -install: all install_h $(ROOTPROG) $(ROOTDMOD) \ +install: all install_h $(ROOTPROG) $(ROOTDMOD) $(LOGADMDIR) $(LOGADMENT) \ $(ROOTCDIR) $(ROOTVDIR) $(ROOTVSUB) $(ROOTMANIFEST) check: $(CHKMANIFEST) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd.c --- a/usr/src/cmd/fm/fmd/common/fmd.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -239,6 +238,7 @@ { "client.buflim", &fmd_conf_size, "10m" }, /* client buffer space limit */ { "client.dbout", &fmd_dbout_ops, NULL }, /* client debug output sinks */ { "client.debug", &fmd_conf_bool, NULL }, /* client debug enable */ +{ "client.doorthrlim", &fmd_conf_uint32, "20" }, /* client door thread limit */ { "client.error", &fmd_cerror_ops, "unload" }, /* client error policy */ { "client.memlim", &fmd_conf_size, "10m" }, /* client allocation limit */ { "client.evqlim", &fmd_conf_uint32, "256" }, /* client event queue limit */ @@ -265,6 +265,8 @@ { "log.creator", &fmd_conf_string, "fmd" }, /* exacct log creator string */ { "log.error", &fmd_conf_string, "var/fm/fmd/errlog" }, /* error log path */ { "log.fault", &fmd_conf_string, "var/fm/fmd/fltlog" }, /* fault log path */ +{ "log.info", &fmd_conf_string, "var/fm/fmd/infolog" }, /* info log path */ +{ "log.info_hival", &fmd_conf_string, "var/fm/fmd/infolog_hival" }, /* hi pri */ { "log.minfree", &fmd_conf_size, "2m" }, /* min log fsys free space */ { "log.rsrc", &fmd_conf_string, "var/fm/fmd/rsrc" }, /* asru log dir path */ { "log.tryrotate", &fmd_conf_uint32, "10" }, /* max log rotation attempts */ @@ -425,6 +427,8 @@ (void) pthread_mutex_init(&dp->d_stats_lock, NULL); (void) pthread_mutex_init(&dp->d_topo_lock, NULL); (void) pthread_rwlock_init(&dp->d_log_lock, NULL); + (void) pthread_rwlock_init(&dp->d_hvilog_lock, NULL); + (void) pthread_rwlock_init(&dp->d_ilog_lock, NULL); (void) pthread_mutex_init(&dp->d_fmd_lock, NULL); (void) pthread_cond_init(&dp->d_fmd_cv, NULL); @@ -695,6 +699,14 @@ (void) pthread_rwlock_rdlock(&dp->d_log_lock); fmd_log_update(dp->d_errlog); (void) pthread_rwlock_unlock(&dp->d_log_lock); + + (void) pthread_rwlock_rdlock(&dp->d_hvilog_lock); + fmd_log_update(dp->d_hvilog); + (void) pthread_rwlock_unlock(&dp->d_hvilog_lock); + + (void) pthread_rwlock_rdlock(&dp->d_ilog_lock); + fmd_log_update(dp->d_ilog); + (void) pthread_rwlock_unlock(&dp->d_ilog_lock); } (void) fmd_conf_getprop(dp->d_conf, "gc_interval", &delta); @@ -771,6 +783,9 @@ /* * Custom door server create callback. Any fmd services that use doors will * require those threads to have their fmd-specific TSD initialized, etc. + * Modules should use door_xcreate and derivatives such as + * sysevent_evc_xsubscribe in order to use private doors that + * avoid this global door server function (see fmd_api_module comments). */ static void fmd_door(door_info_t *dip) @@ -896,6 +911,12 @@ (void) fmd_conf_getprop(dp->d_conf, "log.fault", &name); dp->d_fltlog = fmd_log_open(dp->d_rootdir, name, FMD_LOG_FAULT); + (void) fmd_conf_getprop(dp->d_conf, "log.info_hival", &name); + dp->d_hvilog = fmd_log_open(dp->d_rootdir, name, FMD_LOG_INFO); + + (void) fmd_conf_getprop(dp->d_conf, "log.info", &name); + dp->d_ilog = fmd_log_open(dp->d_rootdir, name, FMD_LOG_INFO); + if (dp->d_asrus == NULL || dp->d_errlog == NULL || dp->d_fltlog == NULL) fmd_error(EFMD_EXIT, "failed to initialize log files\n"); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd.h --- a/usr/src/cmd/fm/fmd/common/fmd.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd.h Fri Jul 30 17:04:17 2010 +1000 @@ -20,15 +20,12 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _FMD_H #define _FMD_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include @@ -135,6 +132,13 @@ pthread_rwlock_t d_log_lock; /* log pointer lock (r=use, w=rotate) */ struct fmd_log *d_errlog; /* log file for error events */ struct fmd_log *d_fltlog; /* log file for fault events */ + + pthread_rwlock_t d_hvilog_lock; /* log pointer lock (r=use, w=rotate) */ + struct fmd_log *d_hvilog; /* log file for hi value info events */ + + pthread_rwlock_t d_ilog_lock; /* log pointer lock (r=use, w=rotate) */ + struct fmd_log *d_ilog; /* log file for info events */ + pthread_cond_t d_fmd_cv; /* sync startup with rpc */ pthread_mutex_t d_fmd_lock; /* sync startup with rpc */ } fmd_t; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd.logadm.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/fmd/common/fmd.logadm.conf Fri Jul 30 17:04:17 2010 +1000 @@ -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. +# +# Entries to be added to /etc/logadm.conf by svc:/application/logadm-upgrade +# +/var/fm/fmd/infolog -N -A 2y -S 50m -s 10m -M '/usr/sbin/fmadm -q rotate infolog && mv /var/fm/fmd/infolog.0- $nfile' +/var/fm/fmd/infolog_hival -N -A 2y -S 50m -s 10m -M '/usr/sbin/fmadm -q rotate infolog_hival && mv /var/fm/fmd/infolog_hival.0- $nfile' + diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd.xml --- a/usr/src/cmd/fm/fmd/common/fmd.xml Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd.xml Fri Jul 30 17:04:17 2010 +1000 @@ -1,15 +1,13 @@ - - #include #include +#include #include #include @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -237,10 +238,17 @@ } /* - * If our TSD refers to the root module and is a door server thread, - * then it was created asynchronously at the request of a module but - * is using now the module API as an auxiliary module thread. We reset - * tp->thr_mod to the module handle so it can act as a module thread. + * If our TSD refers to the root module and is a non-private + * door server thread, then it was created asynchronously at the + * request of a module but is using now the module API as an + * auxiliary module thread. We reset tp->thr_mod to the module + * handle so it can act as a module thread. + * + * If more than one module uses non-private doors then the + * "client handle is not valid" check below can fail since + * door server threads for such doors can service *any* + * non-private door. We use non-private door for legacy sysevent + * alone. */ if (tp->thr_mod == fmd.d_rmod && tp->thr_func == &fmd_door_server) tp->thr_mod = (fmd_module_t *)hdl; @@ -368,7 +376,7 @@ * the module thread to which we assigned this client handle. The info * provided for the handle must be valid and have the minimal settings. */ - if (version > FMD_API_VERSION_4) + if (version > FMD_API_VERSION_5) return (fmd_hdl_register_error(mp, EFMD_VER_NEW)); if (version < FMD_API_VERSION_1) @@ -536,6 +544,25 @@ { fmd_thread_t *tp = fmd_idspace_getspecific(ids, id); + /* + * Door service threads are not cancellable (worse - if they're + * waiting in door_return then that is interrupted, but they then spin + * endlessly!). Non-private door service threads are not tracked + * in the module thread idspace so it's only private server threads + * created via fmd_doorthr_create that we'll encounter. In most + * cases the module _fini should have tidied up (e.g., calling + * sysevent_evc_unbind which will cleanup door threads if + * sysevent_evc_xsubscribe was used). One case that does not + * clean up is sysev_fini which explicitly does not unbind the + * channel, so we must skip any remaining door threads here. + */ + if (tp->thr_isdoor) { + fmd_dprintf(FMD_DBG_MOD, "not cancelling %s private door " + "thread %u\n", mp->mod_name, tp->thr_tid); + fmd_thread_destroy(tp, FMD_THREAD_NOJOIN); + return; + } + fmd_dprintf(FMD_DBG_MOD, "cancelling %s auxiliary thread %u\n", mp->mod_name, tp->thr_tid); @@ -1031,11 +1058,44 @@ fmd_case_open(fmd_hdl_t *hdl, void *data) { fmd_module_t *mp = fmd_api_module_lock(hdl); - fmd_case_t *cp = fmd_case_create(mp, data); + fmd_case_t *cp = fmd_case_create(mp, NULL, data); fmd_module_unlock(mp); return (cp); } +fmd_case_t * +fmd_case_open_uuid(fmd_hdl_t *hdl, const char *uuidstr, void *data) +{ + fmd_module_t *mp; + fmd_case_t *cp; + uint_t uuidlen; + uuid_t uuid; + + mp = fmd_api_module_lock(hdl); + + (void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &uuidlen); + + if (uuidstr == NULL) { + fmd_api_error(mp, EFMD_CASE_INVAL, "NULL uuid string\n"); + } else if (strnlen(uuidstr, uuidlen + 1) != uuidlen) { + fmd_api_error(mp, EFMD_CASE_INVAL, "invalid uuid string: '%s' " + "(expected length %d)\n", uuidstr, uuidlen); + } else if (uuid_parse((char *)uuidstr, uuid) == -1) { + fmd_api_error(mp, EFMD_CASE_INVAL, "cannot parse uuid string: " + "'%s'\n", uuidstr); + } + + if ((cp = fmd_case_hash_lookup(fmd.d_cases, uuidstr)) == NULL) { + cp = fmd_case_create(mp, uuidstr, data); + } else { + fmd_case_rele(cp); + cp = NULL; + } + + fmd_module_unlock(mp); + return (cp); /* May be NULL iff case already exists */ +} + void fmd_case_reset(fmd_hdl_t *hdl, fmd_case_t *cp) { @@ -1157,6 +1217,23 @@ fmd_module_unlock(mp); } +int +fmd_case_uuisresolved(fmd_hdl_t *hdl, const char *uuid) +{ + fmd_module_t *mp = fmd_api_module_lock(hdl); + fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); + fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; + int rv = FMD_B_FALSE; + + if (cip != NULL) { + rv = (cip->ci_state >= FMD_CASE_RESOLVED); + fmd_case_rele(cp); + } + + fmd_module_unlock(mp); + return (rv); +} + static int fmd_case_instate(fmd_hdl_t *hdl, fmd_case_t *cp, uint_t state) { @@ -1760,6 +1837,65 @@ fmd_module_unlock(mp); } +/*ARGSUSED3*/ +int +fmd_doorthr_create(door_info_t *dip, void *(*crf)(void *), void *crarg, + void *cookie) +{ + fmd_thread_t *old_tp, *new_tp; + fmd_module_t *mp; + pthread_t tid; + + /* + * We're called either during initial door_xcreate or during + * a depletion callback. In both cases the current thread + * is already setup so we can retrieve the fmd_thread_t. + * If not then we panic. The new thread will be associated with + * the same module as the old. + * + * If dip == NULL we're being called as part of the + * sysevent_bind_subscriber hack - see comments there. + */ + if ((old_tp = pthread_getspecific(fmd.d_key)) == NULL) + fmd_panic("fmd_doorthr_create from unrecognized thread\n"); + + mp = old_tp->thr_mod; + (void) fmd_api_module_lock((fmd_hdl_t *)mp); + + if (dip && mp->mod_stats->ms_doorthrtotal.fmds_value.ui32 >= + mp->mod_stats->ms_doorthrlimit.fmds_value.ui32) { + fmd_module_unlock(mp); + (void) fmd_dprintf(FMD_DBG_XPRT, "door server %s for %p " + "not attemped - at max\n", + dip->di_attributes & DOOR_DEPLETION_CB ? + "depletion callback" : "startup", (void *)dip); + return (0); + } + + if ((new_tp = fmd_doorthread_create(mp, (fmd_thread_f *)crf, + crarg)) != NULL) { + tid = new_tp->thr_tid; + mp->mod_stats->ms_doorthrtotal.fmds_value.ui32++; + (void) fmd_idspace_xalloc(mp->mod_threads, tid, new_tp); + } + + fmd_module_unlock(mp); + + if (dip) { + fmd_dprintf(FMD_DBG_XPRT, "door server startup for %p %s\n", + (void *)dip, new_tp ? "successful" : "failed"); + } + + return (new_tp ? 1 : -1); +} + +/*ARGSUSED*/ +void +fmd_doorthr_setup(void *cookie) +{ + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); +} + id_t fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta) { @@ -1816,16 +1952,19 @@ fmd_eventq_cancel(mp->mod_queue, FMD_EVT_TIMEOUT, (void *)id); } -nvlist_t * -fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, - uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc) +static nvlist_t * +fmd_nvl_create_suspect(fmd_hdl_t *hdl, const char *class, + uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc, + const char *pfx, boolean_t chkpfx) { fmd_module_t *mp; nvlist_t *nvl; mp = fmd_api_module_lock(hdl); - if (class == NULL || class[0] == '\0') - fmd_api_error(mp, EFMD_NVL_INVAL, "invalid fault class\n"); + if (class == NULL || class[0] == '\0' || + chkpfx == B_TRUE && strncmp(class, pfx, strlen(pfx)) != 0) + fmd_api_error(mp, EFMD_NVL_INVAL, "invalid %s class: '%s'\n", + pfx, class ? class : "(empty)"); nvl = fmd_protocol_fault(class, certainty, asru, fru, rsrc, NULL); @@ -1834,6 +1973,57 @@ return (nvl); } +nvlist_t * +fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, + uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc) +{ + /* + * We can't enforce that callers only specifiy classes matching + * fault.* since there are already a number of modules that + * use fmd_nvl_create_fault to create a defect event. Since + * fmd_nvl_create_{fault,defect} are equivalent, for now anyway, + * no harm is done. So call fmd_nvl_create_suspect with last + * argument B_FALSE. + */ + return (fmd_nvl_create_suspect(hdl, class, certainty, asru, + fru, rsrc, FM_FAULT_CLASS ".", B_FALSE)); +} + +nvlist_t * +fmd_nvl_create_defect(fmd_hdl_t *hdl, const char *class, + uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc) +{ + return (fmd_nvl_create_suspect(hdl, class, certainty, asru, + fru, rsrc, FM_DEFECT_CLASS ".", B_TRUE)); +} + +const nvlist_t * +fmd_hdl_fmauth(fmd_hdl_t *hdl) +{ + fmd_module_t *mp = fmd_api_module_lock(hdl); + const nvlist_t *auth; + + auth = (const nvlist_t *)fmd.d_rmod->mod_fmri; + + fmd_module_unlock(mp); + + return (auth); +} + +const nvlist_t * +fmd_hdl_modauth(fmd_hdl_t *hdl) +{ + fmd_module_t *mp = fmd_api_module_lock(hdl); + const nvlist_t *auth; + + auth = (const nvlist_t *)mp->mod_fmri; + + fmd_module_unlock(mp); + + return (auth); +} + + int fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern) { diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_api.h --- a/usr/src/cmd/fm/fmd/common/fmd_api.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_api.h Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _FMD_API_H @@ -30,6 +29,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -49,8 +49,9 @@ #define FMD_API_VERSION_2 2 #define FMD_API_VERSION_3 3 #define FMD_API_VERSION_4 4 +#define FMD_API_VERSION_5 5 -#define FMD_API_VERSION FMD_API_VERSION_4 +#define FMD_API_VERSION FMD_API_VERSION_5 typedef struct fmd_hdl fmd_hdl_t; typedef struct fmd_event fmd_event_t; @@ -168,6 +169,7 @@ extern void fmd_stat_setstr(fmd_hdl_t *, fmd_stat_t *, const char *); extern fmd_case_t *fmd_case_open(fmd_hdl_t *, void *); +extern fmd_case_t *fmd_case_open_uuid(fmd_hdl_t *, const char *, void *); extern void fmd_case_reset(fmd_hdl_t *, fmd_case_t *); extern void fmd_case_solve(fmd_hdl_t *, fmd_case_t *); extern void fmd_case_close(fmd_hdl_t *, fmd_case_t *); @@ -176,6 +178,7 @@ extern fmd_case_t *fmd_case_uulookup(fmd_hdl_t *, const char *); extern void fmd_case_uuclose(fmd_hdl_t *, const char *); extern int fmd_case_uuclosed(fmd_hdl_t *, const char *); +extern int fmd_case_uuisresolved(fmd_hdl_t *, const char *); extern void fmd_case_uuresolved(fmd_hdl_t *, const char *); extern int fmd_case_solved(fmd_hdl_t *, fmd_case_t *); @@ -215,12 +218,20 @@ extern void fmd_thr_signal(fmd_hdl_t *, pthread_t); extern void fmd_thr_checkpoint(fmd_hdl_t *); +extern door_xcreate_server_func_t fmd_doorthr_create; +extern door_xcreate_thrsetup_func_t fmd_doorthr_setup; + extern id_t fmd_timer_install(fmd_hdl_t *, void *, fmd_event_t *, hrtime_t); extern void fmd_timer_remove(fmd_hdl_t *, id_t); +extern nvlist_t *fmd_nvl_create_defect(fmd_hdl_t *, + const char *, uint8_t, nvlist_t *, nvlist_t *, nvlist_t *); extern nvlist_t *fmd_nvl_create_fault(fmd_hdl_t *, const char *, uint8_t, nvlist_t *, nvlist_t *, nvlist_t *); +extern const nvlist_t *fmd_hdl_fmauth(fmd_hdl_t *); +extern const nvlist_t *fmd_hdl_modauth(fmd_hdl_t *); + extern int fmd_nvl_class_match(fmd_hdl_t *, nvlist_t *, const char *); extern int fmd_nvl_fmri_expand(fmd_hdl_t *, nvlist_t *); extern int fmd_nvl_fmri_present(fmd_hdl_t *, nvlist_t *); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_api.map --- a/usr/src/cmd/fm/fmd/common/fmd_api.map Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_api.map Fri Jul 30 17:04:17 2010 +1000 @@ -39,6 +39,7 @@ fmd_case_getspecific { TYPE = function; FLAGS = extern }; fmd_case_next { TYPE = function; FLAGS = extern }; fmd_case_open { TYPE = function; FLAGS = extern }; + fmd_case_open_uuid { TYPE = function; FLAGS = extern }; fmd_case_prev { TYPE = function; FLAGS = extern }; fmd_case_reset { TYPE = function; FLAGS = extern }; fmd_case_setprincipal { TYPE = function; FLAGS = extern }; @@ -48,9 +49,13 @@ fmd_case_uuclose { TYPE = function; FLAGS = extern }; fmd_case_uuclosed { TYPE = function; FLAGS = extern }; fmd_case_uuid { TYPE = function; FLAGS = extern }; + fmd_case_uuisresolved { TYPE = function; FLAGS = extern }; fmd_case_uulookup { TYPE = function; FLAGS = extern }; fmd_case_uuresolved { TYPE = function; FLAGS = extern }; + fmd_doorthr_create { TYPE = function; FLAGS = extern }; + fmd_doorthr_setup { TYPE = function; FLAGS = extern }; + fmd_event_local { TYPE = function; FLAGS = extern }; fmd_event_ena_create { TYPE = function; FLAGS = extern }; @@ -59,7 +64,9 @@ fmd_hdl_debug { TYPE = function; FLAGS = extern }; fmd_hdl_error { TYPE = function; FLAGS = extern }; fmd_hdl_free { TYPE = function; FLAGS = extern }; + fmd_hdl_fmauth { TYPE = function; FLAGS = extern }; fmd_hdl_getspecific { TYPE = function; FLAGS = extern }; + fmd_hdl_modauth { TYPE = function; FLAGS = extern }; fmd_hdl_opendict { TYPE = function; FLAGS = extern }; fmd_hdl_register { TYPE = function; FLAGS = extern }; fmd_hdl_setspecific { TYPE = function; FLAGS = extern }; @@ -77,6 +84,7 @@ fmd_nvl_alloc { TYPE = function; FLAGS = extern }; fmd_nvl_class_match { TYPE = function; FLAGS = extern }; + fmd_nvl_create_defect { TYPE = function; FLAGS = extern }; fmd_nvl_create_fault { TYPE = function; FLAGS = extern }; fmd_nvl_dup { TYPE = function; FLAGS = extern }; fmd_nvl_fmri_expand { TYPE = function; FLAGS = extern }; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_builtin.c --- a/usr/src/cmd/fm/fmd/common/fmd_builtin.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_builtin.c Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -21,23 +20,22 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include #include #include #include +#include static const struct fmd_builtin _fmd_builtins[] = { - { "fmd-self-diagnosis", self_init, self_fini }, - { "sysevent-transport", sysev_init, sysev_fini }, - { NULL, NULL, NULL } + { "fmd-self-diagnosis", self_init, self_fini, FMD_BUILTIN_ALLCTXT }, + { "sysevent-transport", sysev_init, sysev_fini, + FMD_BUILTIN_CTXT_GLOBALZONE }, + { NULL, NULL, NULL, 0 } }; static int @@ -106,9 +104,16 @@ fmd_builtin_loadall(fmd_modhash_t *mhp) { const fmd_builtin_t *bp; + uint32_t ctxt = 0; int err = 0; + ctxt |= (getzoneid() == GLOBAL_ZONEID) ? FMD_BUILTIN_CTXT_GLOBALZONE : + FMD_BUILTIN_CTXT_NONGLOBALZONE; + for (bp = _fmd_builtins; bp->bltin_name != NULL; bp++) { + if (!(ctxt & bp->bltin_ctxts)) + continue; + if (fmd_modhash_load(mhp, bp->bltin_name, &fmd_bltin_ops) == NULL) err = -1; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_builtin.h --- a/usr/src/cmd/fm/fmd/common/fmd_builtin.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_builtin.h Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -21,15 +20,12 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _FMD_BUILTIN_H #define _FMD_BUILTIN_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -50,8 +46,15 @@ const char *bltin_name; void (*bltin_init)(fmd_hdl_t *); void (*bltin_fini)(fmd_hdl_t *); + int bltin_ctxts; } fmd_builtin_t; +#define FMD_BUILTIN_CTXT_GLOBALZONE 0x1 +#define FMD_BUILTIN_CTXT_NONGLOBALZONE 0x2 + +#define FMD_BUILTIN_ALLCTXT \ + (FMD_BUILTIN_CTXT_GLOBALZONE | FMD_BUILTIN_CTXT_NONGLOBALZONE) + extern int fmd_builtin_loadall(fmd_modhash_t *); extern void self_init(fmd_hdl_t *); /* see fmd_self.c */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_case.c --- a/usr/src/cmd/fm/fmd/common/fmd_case.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_case.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -1247,7 +1246,7 @@ } fmd_case_t * -fmd_case_create(fmd_module_t *mp, void *data) +fmd_case_create(fmd_module_t *mp, const char *uuidstr, void *data) { fmd_case_impl_t *cip = fmd_zalloc(sizeof (fmd_case_impl_t), FMD_SLEEP); fmd_case_impl_t *eip = NULL; @@ -1272,17 +1271,35 @@ (void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &cip->ci_uuidlen); cip->ci_uuid = fmd_zalloc(cip->ci_uuidlen + 1, FMD_SLEEP); - /* - * We expect this loop to execute only once, but code it defensively - * against the possibility of libuuid bugs. Keep generating uuids and - * attempting to do a hash insert until we get a unique one. - */ - do { - if (eip != NULL) - fmd_case_rele((fmd_case_t *)eip); - uuid_generate(uuid); - uuid_unparse(uuid, cip->ci_uuid); - } while ((eip = fmd_case_hash_insert(fmd.d_cases, cip)) != cip); + if (uuidstr == NULL) { + /* + * We expect this loop to execute only once, but code it + * defensively against the possibility of libuuid bugs. + * Keep generating uuids and attempting to do a hash insert + * until we get a unique one. + */ + do { + if (eip != NULL) + fmd_case_rele((fmd_case_t *)eip); + uuid_generate(uuid); + uuid_unparse(uuid, cip->ci_uuid); + } while ((eip = fmd_case_hash_insert(fmd.d_cases, cip)) != cip); + } else { + /* + * If a uuid was specified we must succeed with that uuid, + * or return NULL indicating a case with that uuid already + * exists. + */ + (void) strncpy(cip->ci_uuid, uuidstr, cip->ci_uuidlen + 1); + if (fmd_case_hash_insert(fmd.d_cases, cip) != cip) { + fmd_free(cip->ci_uuid, cip->ci_uuidlen + 1); + (void) fmd_buf_hash_destroy(&cip->ci_bufs); + fmd_module_rele(mp); + pthread_mutex_destroy(&cip->ci_lock); + fmd_free(cip, sizeof (*cip)); + return (NULL); + } + } ASSERT(fmd_module_locked(mp)); fmd_list_append(&mp->mod_cases, cip); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_case.h --- a/usr/src/cmd/fm/fmd/common/fmd_case.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_case.h Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _FMD_CASE_H @@ -121,7 +120,7 @@ extern void fmd_case_hash_apply(fmd_case_hash_t *, void (*)(fmd_case_t *, void *), void *); -extern fmd_case_t *fmd_case_create(struct fmd_module *, void *); +extern fmd_case_t *fmd_case_create(struct fmd_module *, const char *, void *); extern fmd_case_t *fmd_case_recreate(struct fmd_module *, struct fmd_xprt *, uint_t, const char *, const char *); extern void fmd_case_destroy(fmd_case_t *, int); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_log.h --- a/usr/src/cmd/fm/fmd/common/fmd_log.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_log.h Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _FMD_LOG_H #define _FMD_LOG_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -71,6 +67,7 @@ #define FMD_LOG_FAULT "fault" /* tag for fault log files */ #define FMD_LOG_ASRU "asru" /* tag for asru log files */ #define FMD_LOG_XPRT "xprt" /* tag for transport log files */ +#define FMD_LOG_INFO "info" /* tag for info event log files */ extern fmd_log_t *fmd_log_tryopen(const char *, const char *, const char *); extern fmd_log_t *fmd_log_open(const char *, const char *, const char *); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_main.c --- a/usr/src/cmd/fm/fmd/common/fmd_main.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_main.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -37,6 +36,7 @@ #include #include #include +#include #include #include @@ -78,6 +78,7 @@ static int daemonize_init(void) { + const char *gzp1, *gzp2, *gzp3, *gzp4, *gzp5; int status, pfds[2]; sigset_t set, oset; struct rlimit rlim; @@ -111,14 +112,50 @@ * Reset all of our privilege sets to the minimum set of required * privileges. We continue to run as root so that files we create * such as logs and checkpoints are secured in the /var filesystem. + * + * In a non-global zone some of the privileges we retain in a + * global zone are only optionally assigned to the zone, while others + * are prohibited: + * + * PRIV_PROC_PRIOCNTL (optional in a non-global zone): + * There are no calls to priocntl(2) in fmd or plugins. + * + * PRIV_SYS_CONFIG (prohibited in a non-global zone): + * Required, I think, for sysevent_post_event and/or + * other legacy sysevent activity. Legacy sysevent is not + * supported in a non-global zone. + * + * PRIV_SYS_DEVICES (prohibited in a non-global zone): + * Needed in the global zone for ioctls on various drivers + * such as memory-controller drivers. + * + * PRIV_SYS_RES_CONFIG (prohibited in a non-global zone): + * Require for p_online(2) calls to offline cpus. + * + * PRIV_SYS_NET_CONFIG (prohibited in a non-global zone): + * Required for ipsec in etm (which also requires + * PRIV_NET_PRIVADDR). + * + * We do without those privileges in a non-global zone. It's + * possible that there are other privs we could drop since + * hardware-related plugins are not present. */ + if (getzoneid() == GLOBAL_ZONEID) { + gzp1 = PRIV_PROC_PRIOCNTL; + gzp2 = PRIV_SYS_CONFIG; + gzp3 = PRIV_SYS_DEVICES; + gzp4 = PRIV_SYS_RES_CONFIG; + gzp5 = PRIV_SYS_NET_CONFIG; + } else { + gzp1 = gzp2 = gzp3 = gzp4 = gzp5 = NULL; + } + if (__init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS, 0, 0, /* run as uid 0 and gid 0 */ PRIV_FILE_DAC_EXECUTE, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_WRITE, PRIV_FILE_OWNER, PRIV_PROC_OWNER, - PRIV_PROC_PRIOCNTL, PRIV_SYS_ADMIN, PRIV_SYS_CONFIG, - PRIV_SYS_DEVICES, PRIV_SYS_RES_CONFIG, PRIV_NET_PRIVADDR, - PRIV_SYS_NET_CONFIG, NULL) != 0) + PRIV_SYS_ADMIN, PRIV_NET_PRIVADDR, + gzp1, gzp2, gzp3, gzp4, gzp5, NULL) != 0) fmd_error(EFMD_EXIT, "additional privileges required to run\n"); /* diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_mdb.c --- a/usr/src/cmd/fm/fmd/common/fmd_mdb.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_mdb.c Fri Jul 30 17:04:17 2010 +1000 @@ -483,6 +483,10 @@ DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv); (void) fmd_stat((uintptr_t)&mod_stats->ms_thrlimit, DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv); + (void) fmd_stat((uintptr_t)&mod_stats->ms_doorthrtotal, + DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv); + (void) fmd_stat((uintptr_t)&mod_stats->ms_doorthrlimit, + DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv); (void) fmd_stat((uintptr_t)&mod_stats->ms_caseopen, DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv); (void) fmd_stat((uintptr_t)&mod_stats->ms_casesolved, @@ -877,6 +881,9 @@ case FMD_CASE_REPAIRED: (void) strcpy(name, "RPAIR"); break; + case FMD_CASE_RESOLVED: + (void) strcpy(name, "RSLVD"); + break; default: (void) mdb_snprintf(name, sizeof (name), "%u", ci.ci_state); } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_module.c --- a/usr/src/cmd/fm/fmd/common/fmd_module.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_module.c Fri Jul 30 17:04:17 2010 +1000 @@ -79,6 +79,8 @@ { "fmd.buflimit", FMD_TYPE_SIZE, "limit on total buffer space" }, { "fmd.thrtotal", FMD_TYPE_UINT32, "total number of auxiliary threads" }, { "fmd.thrlimit", FMD_TYPE_UINT32, "limit on number of auxiliary threads" }, +{ "fmd.doorthrtotal", FMD_TYPE_UINT32, "total number of door server threads" }, +{ "fmd.doorthrlimit", FMD_TYPE_UINT32, "limit on door server threads" }, { "fmd.caseopen", FMD_TYPE_UINT64, "cases currently open by module" }, { "fmd.casesolved", FMD_TYPE_UINT64, "total cases solved by module" }, { "fmd.caseclosed", FMD_TYPE_UINT64, "total cases closed by module" }, @@ -247,6 +249,9 @@ (void) fmd_conf_getprop(fmd.d_conf, "client.thrlim", &mp->mod_stats->ms_thrlimit.fmds_value.ui32); + (void) fmd_conf_getprop(fmd.d_conf, "client.doorthrlim", + &mp->mod_stats->ms_doorthrlimit.fmds_value.ui32); + (void) fmd_conf_getprop(fmd.d_conf, "client.xprtlim", &mp->mod_stats->ms_xprtlimit.fmds_value.ui32); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_module.h --- a/usr/src/cmd/fm/fmd/common/fmd_module.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_module.h Fri Jul 30 17:04:17 2010 +1000 @@ -20,15 +20,12 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _FMD_MODULE_H #define _FMD_MODULE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -84,6 +81,8 @@ fmd_stat_t ms_buflimit; /* limit on space consumed by buffers */ fmd_stat_t ms_thrtotal; /* total number of auxiliary threads */ fmd_stat_t ms_thrlimit; /* limit on auxiliary threads */ + fmd_stat_t ms_doorthrtotal; /* total number of doorserver threads */ + fmd_stat_t ms_doorthrlimit; /* limit on doorserver threads */ fmd_stat_t ms_caseopen; /* cases currently open */ fmd_stat_t ms_casesolved; /* total cases solved by module */ fmd_stat_t ms_caseclosed; /* total cases closed by module */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_rpc.c --- a/usr/src/cmd/fm/fmd/common/fmd_rpc.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_rpc.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include @@ -236,7 +233,7 @@ /* * Utillity function to fetch the XPRT's ucred and determine if we should deny * the request. For now, we implement a simple policy of rejecting any caller - * who does not have the PRIV_SYS_CONFIG bit in their Effective privilege set, + * who does not have the PRIV_SYS_ADMIN bit in their Effective privilege set, * unless the caller is loading a module, which requires all privileges. */ int @@ -265,5 +262,5 @@ if (rqp->rq_proc == FMD_ADM_MODLOAD) return (!priv_isfullset(psp)); #endif - return (!priv_ismember(psp, PRIV_SYS_CONFIG)); + return (!priv_ismember(psp, PRIV_SYS_ADMIN)); } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_rpc_adm.c --- a/usr/src/cmd/fm/fmd/common/fmd_rpc_adm.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_rpc_adm.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -722,6 +721,7 @@ { fmd_log_t **lpp, *old, *new; int try = 1, trylimit = 1; + pthread_rwlock_t *lockp; hrtime_t nsec = 0; timespec_t tv; @@ -731,11 +731,19 @@ return (TRUE); } - if (strcmp(name, "errlog") == 0) + if (strcmp(name, "errlog") == 0) { lpp = &fmd.d_errlog; - else if (strcmp(name, "fltlog") == 0) + lockp = &fmd.d_log_lock; + } else if (strcmp(name, "fltlog") == 0) { lpp = &fmd.d_fltlog; - else { + lockp = &fmd.d_log_lock; + } else if (strcmp(name, "infolog") == 0) { + lpp = &fmd.d_ilog; + lockp = &fmd.d_ilog_lock; + } else if (strcmp(name, "infolog_hival") == 0) { + lpp = &fmd.d_hvilog; + lockp = &fmd.d_hvilog_lock; + } else { *rvp = FMD_ADM_ERR_ROTSRCH; return (TRUE); } @@ -755,7 +763,7 @@ if (try > 1) (void) nanosleep(&tv, NULL); /* wait for checkpoints */ - (void) pthread_rwlock_wrlock(&fmd.d_log_lock); + (void) pthread_rwlock_wrlock(lockp); old = *lpp; if ((new = fmd_log_rotate(old)) != NULL) { @@ -763,7 +771,7 @@ *lpp = new; } - (void) pthread_rwlock_unlock(&fmd.d_log_lock); + (void) pthread_rwlock_unlock(lockp); } while (new == NULL && errno == EFMD_LOG_ROTBUSY && try++ < trylimit); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_self.c --- a/usr/src/cmd/fm/fmd/common/fmd_self.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_self.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -158,6 +157,10 @@ if (self_case_lookup(hdl, SC_CLASS, class) != NULL) return; /* case is already open against this class */ + if (strncmp(class, FM_IREPORT_CLASS ".", + sizeof (FM_IREPORT_CLASS)) == 0) + return; /* no subscriber required for ireport.* */ + cp = fmd_case_open(hdl, self_case_create(hdl, SC_CLASS, class)); fmd_case_add_ereport(hdl, cp, ep); self_stats.nosub.fmds_value.ui64++; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_sysevent.c --- a/usr/src/cmd/fm/fmd/common/fmd_sysevent.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_sysevent.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -41,6 +40,7 @@ #include #include #include +#include #undef MUTEX_HELD #undef RW_READ_HELD @@ -87,6 +87,8 @@ static int sysev_replay_wait = 1; static int sysev_exiting; +static sysevent_subattr_t *subattr; + /* * Entry point for legacy sysevents. This function is responsible for two * things: passing off interesting events to the DR handler, and converting @@ -100,7 +102,6 @@ char *fullclass; size_t len; nvlist_t *attr, *nvl; - fmd_event_t *e; hrtime_t hrt; /* notify the DR subsystem of the event */ @@ -128,15 +129,12 @@ (void) nvlist_add_uint8(nvl, FM_VERSION, FM_RSRC_VERSION); /* - * Dispatch the event. Ideally, we'd like to use the same transport - * interface as sysev_recv(), but because the legacy sysevent mechanism - * puts in a thread outside fmd's control, using the module APIs is - * impossible. + * Dispatch the event. Because we have used sysevent_bind_xhandle + * the delivery thread is blessed as a proper fmd thread so + * we may use regular fmd api calls. */ sysevent_get_time(sep, &hrt); - (void) nvlist_lookup_string(nvl, FM_CLASS, &fullclass); - e = fmd_event_create(FMD_EVT_PROTOCOL, hrt, nvl, fullclass); - fmd_dispq_dispatch(fmd.d_disp, e, fullclass); + fmd_xprt_post(sysev_hdl, sysev_xprt, nvl, hrt); } /* @@ -444,6 +442,10 @@ uint_t flags; const char *subclasses[] = { EC_SUB_ALL }; + /* This builtin is for the global zone only */ + if (getzoneid() != GLOBAL_ZONEID) + return; + if (fmd_hdl_register(hdl, FMD_API_VERSION, &sysev_info) != 0) return; /* invalid property settings */ @@ -482,15 +484,22 @@ else flags = EVCH_SUB_DUMP; - errno = sysevent_evc_subscribe(sysev_evc, - sysev_sid, sysev_class, sysev_recv, sysev_xprt, flags); + if ((subattr = sysevent_subattr_alloc()) == NULL) + fmd_hdl_abort(hdl, "failed to allocate subscription " + "attributes"); + + sysevent_subattr_thrcreate(subattr, fmd_doorthr_create, NULL); + sysevent_subattr_thrsetup(subattr, fmd_doorthr_setup, NULL); + + errno = sysevent_evc_xsubscribe(sysev_evc, + sysev_sid, sysev_class, sysev_recv, sysev_xprt, flags, subattr); if (errno != 0) { if (errno == EEXIST) { fmd_hdl_abort(hdl, "another fault management daemon is " "active on transport channel %s\n", sysev_channel); } else { - fmd_hdl_abort(hdl, "failed to subscribe to %s on " + fmd_hdl_abort(hdl, "failed to xsubscribe to %s on " "transport channel %s", sysev_class, sysev_channel); } } @@ -512,7 +521,7 @@ return; if ((fmd.d_sysev_hdl = - sysevent_bind_handle(sysev_legacy)) == NULL) + sysevent_bind_xhandle(sysev_legacy, subattr)) == NULL) fmd_hdl_abort(hdl, "failed to bind to legacy sysevent channel"); if (sysevent_subscribe_event(fmd.d_sysev_hdl, EC_ALL, @@ -540,6 +549,11 @@ if (fmd.d_sysev_hdl != NULL) sysevent_unbind_handle(fmd.d_sysev_hdl); + if (subattr != NULL) { + sysevent_subattr_free(subattr); + subattr = NULL; + } + if (sysev_xprt != NULL) { /* * Wait callback returns before destroy the transport. diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_thread.c --- a/usr/src/cmd/fm/fmd/common/fmd_thread.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_thread.c Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include @@ -47,6 +43,7 @@ tp->thr_trdata = fmd_trace_create(); tp->thr_trfunc = (fmd_tracebuf_f *)fmd.d_thr_trace; tp->thr_errdepth = 0; + tp->thr_isdoor = 0; (void) pthread_mutex_lock(&fmd.d_thr_lock); fmd_list_append(&fmd.d_thr_list, tp); @@ -63,15 +60,18 @@ if (pthread_setspecific(fmd.d_key, tp) != 0) fmd_panic("failed to initialize thread key to %p", arg); - (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + if (!tp->thr_isdoor) { + (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + } tp->thr_func(tp->thr_arg); return (NULL); } -fmd_thread_t * -fmd_thread_create(fmd_module_t *mp, fmd_thread_f *func, void *arg) +static fmd_thread_t * +fmd_thread_create_cmn(fmd_module_t *mp, fmd_thread_f *func, void *arg, + int isdoor) { fmd_thread_t *tp = fmd_alloc(sizeof (fmd_thread_t), FMD_SLEEP); sigset_t oset, nset; @@ -83,10 +83,12 @@ tp->thr_trdata = fmd_trace_create(); tp->thr_trfunc = (fmd_tracebuf_f *)fmd.d_thr_trace; tp->thr_errdepth = 0; + tp->thr_isdoor = isdoor; (void) sigfillset(&nset); (void) sigdelset(&nset, SIGABRT); /* always unblocked for fmd_panic() */ - (void) sigdelset(&nset, fmd.d_thr_sig); /* for fmd_thr_signal() */ + if (!isdoor) + (void) sigdelset(&nset, fmd.d_thr_sig); /* fmd_thr_signal() */ (void) pthread_sigmask(SIG_SETMASK, &nset, &oset); err = pthread_create(&tp->thr_tid, NULL, fmd_thread_start, tp); @@ -104,6 +106,18 @@ return (tp); } +fmd_thread_t * +fmd_thread_create(fmd_module_t *mp, fmd_thread_f *func, void *arg) +{ + return (fmd_thread_create_cmn(mp, func, arg, 0)); +} + +fmd_thread_t * +fmd_doorthread_create(fmd_module_t *mp, fmd_thread_f *func, void *arg) +{ + return (fmd_thread_create_cmn(mp, func, arg, 1)); +} + void fmd_thread_destroy(fmd_thread_t *tp, int flag) { diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_thread.h --- a/usr/src/cmd/fm/fmd/common/fmd_thread.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_thread.h Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _FMD_THREAD_H #define _FMD_THREAD_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -49,11 +45,14 @@ fmd_tracebuf_t *thr_trdata; /* thread trace buffer */ fmd_tracebuf_f *thr_trfunc; /* thread trace function */ uint_t thr_errdepth; /* fmd_verror() nesting depth */ + int thr_isdoor; /* a private door server thread */ } fmd_thread_t; extern fmd_thread_t *fmd_thread_xcreate(struct fmd_module *, pthread_t); extern fmd_thread_t *fmd_thread_create(struct fmd_module *, fmd_thread_f *, void *); +extern fmd_thread_t *fmd_doorthread_create(struct fmd_module *, + fmd_thread_f *, void *); #define FMD_THREAD_NOJOIN 0 /* do not attempt to join with thread */ #define FMD_THREAD_JOIN 1 /* wait for and join with thread */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmd/common/fmd_xprt.c --- a/usr/src/cmd/fm/fmd/common/fmd_xprt.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmd/common/fmd_xprt.c Fri Jul 30 17:04:17 2010 +1000 @@ -1099,7 +1099,7 @@ boolean_t injected; fmd_module_lock(xip->xi_queue->eq_mod); - cp = fmd_case_create(xip->xi_queue->eq_mod, NULL); + cp = fmd_case_create(xip->xi_queue->eq_mod, NULL, NULL); if (cp == NULL) { fmd_module_unlock(xip->xi_queue->eq_mod); return; @@ -1457,7 +1457,7 @@ fmd_event_t *e; char *class, *uuid; - boolean_t isproto, isereport; + boolean_t isproto, isereport, isireport, ishvireport, issysevent; uint64_t *tod; uint8_t ttl; @@ -1505,13 +1505,30 @@ fmd_dprintf(FMD_DBG_XPRT, "xprt %u %s %s\n", xip->xi_id, ((logonly == FMD_B_TRUE) ? "logging" : "posting"), class); - isereport = (strncmp(class, FM_EREPORT_CLASS, - sizeof (FM_EREPORT_CLASS - 1)) == 0) ? FMD_B_TRUE : FMD_B_FALSE; + isereport = (strncmp(class, FM_EREPORT_CLASS ".", + sizeof (FM_EREPORT_CLASS)) == 0) ? FMD_B_TRUE : FMD_B_FALSE; + + isireport = (strncmp(class, FM_IREPORT_CLASS ".", + sizeof (FM_IREPORT_CLASS)) == 0) ? FMD_B_TRUE : FMD_B_FALSE; + + issysevent = (strncmp(class, SYSEVENT_RSRC_CLASS, + sizeof (SYSEVENT_RSRC_CLASS) - 1)) == 0 ? FMD_B_TRUE : FMD_B_FALSE; + + if (isireport) { + char *pri; + + if (nvlist_lookup_string(nvl, FM_IREPORT_PRIORITY, &pri) == 0 && + strncmp(pri, "high", 5) == 0) { + ishvireport = 1; + } else { + ishvireport = 0; + } + } /* * The logonly flag should only be set for ereports. */ - if ((logonly == FMD_B_TRUE) && (isereport == FMD_B_FALSE)) { + if (logonly == FMD_B_TRUE && isereport == FMD_B_FALSE) { fmd_error(EFMD_XPRT_INVAL, "discarding nvlist %p: " "logonly flag is not valid for class %s", (void *)nvl, class); @@ -1605,13 +1622,30 @@ } /* - * Record the event in the errlog if it is an ereport. This code will + * Record ereports and ireports in the log. This code will * be replaced later with a per-transport intent log instead. */ - if (isereport == FMD_B_TRUE) { - (void) pthread_rwlock_rdlock(&dp->d_log_lock); - fmd_log_append(dp->d_errlog, e, NULL); - (void) pthread_rwlock_unlock(&dp->d_log_lock); + if (isereport == FMD_B_TRUE || isireport == FMD_B_TRUE || + issysevent == B_TRUE) { + pthread_rwlock_t *lockp; + fmd_log_t *lp; + + if (isereport == FMD_B_TRUE) { + lp = fmd.d_errlog; + lockp = &fmd.d_log_lock; + } else { + if (ishvireport || issysevent) { + lp = fmd.d_hvilog; + lockp = &fmd.d_hvilog_lock; + } else { + lp = fmd.d_ilog; + lockp = &fmd.d_ilog_lock; + } + } + + (void) pthread_rwlock_rdlock(lockp); + fmd_log_append(lp, e, NULL); + (void) pthread_rwlock_unlock(lockp); } /* diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmdump/Makefile.com --- a/usr/src/cmd/fm/fmdump/Makefile.com Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmdump/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -19,14 +19,13 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # .KEEP_STATE: .SUFFIXES: -SRCS += fmdump.c asru.c error.c fault.c scheme.c +SRCS += fmdump.c nvlrender.c asru.c error.c fault.c scheme.c info.c OBJS = $(SRCS:%.c=%.o) LINTFILES = $(SRCS:%.c=%.ln) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmdump/common/asru.c --- a/usr/src/cmd/fm/fmdump/common/asru.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmdump/common/asru.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -71,7 +70,8 @@ /*ARGSUSED*/ static int -asru_verb2(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +asru_verb23_cmn(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp, + nvlist_prtctl_t pctl) { char *uuid = "-"; boolean_t f = 0, u = 0; @@ -95,12 +95,39 @@ fmdump_printf(fp, "%-20s.%9.9llu %-36s %s\n", fmdump_year(buf, sizeof (buf), rp), rp->rec_nsec, uuid, state + 1); - nvlist_print(fp, rp->rec_nvl); + if (pctl) + nvlist_prt(rp->rec_nvl, pctl); + else + nvlist_print(fp, rp->rec_nvl); + fmdump_printf(fp, "\n"); return (0); } +static int +asru_verb2(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + return (asru_verb23_cmn(lp, rp, fp, NULL)); +} + +static int +asru_pretty(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + nvlist_prtctl_t pctl; + int rc; + + if ((pctl = nvlist_prtctl_alloc()) != NULL) { + nvlist_prtctl_setdest(pctl, fp); + nvlist_prtctlop_nvlist(pctl, fmdump_render_nvlist, NULL); + } + + rc = asru_verb23_cmn(lp, rp, fp, pctl); + + nvlist_prtctl_free(pctl); + return (rc); +} + const fmdump_ops_t fmdump_asru_ops = { "asru", { { @@ -113,6 +140,9 @@ "TIME UUID STATE", (fmd_log_rec_f *)asru_verb2 }, { +"TIME UUID STATE", +(fmd_log_rec_f *)asru_pretty +}, { NULL, NULL } } }; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmdump/common/error.c --- a/usr/src/cmd/fm/fmdump/common/error.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmdump/common/error.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -56,18 +55,46 @@ /*ARGSUSED*/ static int -err_verb2(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +err_verb23_cmn(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp, + nvlist_prtctl_t pctl) { char buf[32]; fmdump_printf(fp, "%-20s.%9.9llu %s\n", fmdump_year(buf, sizeof (buf), rp), rp->rec_nsec, rp->rec_class); - nvlist_print(fp, rp->rec_nvl); + if (pctl) + nvlist_prt(rp->rec_nvl, pctl); + else + nvlist_print(fp, rp->rec_nvl); + fmdump_printf(fp, "\n"); return (0); } +static int +err_verb2(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + return (err_verb23_cmn(lp, rp, fp, NULL)); +} + +static int +err_pretty(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + nvlist_prtctl_t pctl; + int rc; + + if ((pctl = nvlist_prtctl_alloc()) != NULL) { + nvlist_prtctl_setdest(pctl, fp); + nvlist_prtctlop_nvlist(pctl, fmdump_render_nvlist, NULL); + } + + rc = err_verb23_cmn(lp, rp, fp, pctl); + + nvlist_prtctl_free(pctl); + return (rc); +} + const fmdump_ops_t fmdump_err_ops = { "error", { { @@ -80,6 +107,9 @@ "TIME CLASS", (fmd_log_rec_f *)err_verb2 }, { +"TIME CLASS", +(fmd_log_rec_f *)err_pretty +}, { NULL, NULL } } }; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmdump/common/fault.c --- a/usr/src/cmd/fm/fmdump/common/fault.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmdump/common/fault.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -34,22 +33,32 @@ char buf[32], str[32]; char *class = NULL, *uuid = "-", *code = "-"; + static const struct { + const char *class; + const char *tag; + } tags[] = { + { FM_LIST_SUSPECT_CLASS, "Diagnosed" }, + { FM_LIST_REPAIRED_CLASS, "Repaired" }, + { FM_LIST_RESOLVED_CLASS, "Resolved" }, + { FM_LIST_UPDATED_CLASS, "Updated" }, + { FM_LIST_ISOLATED_CLASS, "Isolated" }, + }; + (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_UUID, &uuid); (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_DIAG_CODE, &code); (void) nvlist_lookup_string(rp->rec_nvl, FM_CLASS, &class); - if (class != NULL && strcmp(class, FM_LIST_REPAIRED_CLASS) == 0) { - (void) snprintf(str, sizeof (str), "%s %s", code, "Repaired"); - code = str; - } - if (class != NULL && strcmp(class, FM_LIST_RESOLVED_CLASS) == 0) { - (void) snprintf(str, sizeof (str), "%s %s", code, "Resolved"); - code = str; - } + if (class != NULL) { + int i; - if (class != NULL && strcmp(class, FM_LIST_UPDATED_CLASS) == 0) { - (void) snprintf(str, sizeof (str), "%s %s", code, "Updated"); - code = str; + for (i = 0; i < sizeof (tags) / sizeof (tags[0]); i++) { + if (strcmp(class, tags[i].class) == 0) { + (void) snprintf(str, sizeof (str), "%s %s", + code, tags[i].tag); + code = str; + break; + } + } } fmdump_printf(fp, "%-20s %-32s %s\n", @@ -138,7 +147,8 @@ } static int -flt_verb2(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +flt_verb23_cmn(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp, + nvlist_prtctl_t pctl) { const struct fmdump_fmt *efp = &fmdump_err_ops.do_formats[FMDUMP_VERB1]; const struct fmdump_fmt *ffp = &fmdump_flt_ops.do_formats[FMDUMP_VERB2]; @@ -176,12 +186,39 @@ } fmdump_printf(fp, "\n"); - nvlist_print(fp, rp->rec_nvl); + if (pctl) + nvlist_prt(rp->rec_nvl, pctl); + else + nvlist_print(fp, rp->rec_nvl); fmdump_printf(fp, "\n"); return (0); } +static int +flt_verb2(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + return (flt_verb23_cmn(lp, rp, fp, NULL)); +} + + +static int +flt_pretty(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + nvlist_prtctl_t pctl; + int rc; + + if ((pctl = nvlist_prtctl_alloc()) != NULL) { + nvlist_prtctl_setdest(pctl, fp); + nvlist_prtctlop_nvlist(pctl, fmdump_render_nvlist, NULL); + } + + rc = flt_verb23_cmn(lp, rp, fp, pctl); + + nvlist_prtctl_free(pctl); + return (rc); +} + /* * There is a lack of uniformity in how the various entries in our diagnosis * are terminated. Some end with one newline, others with two. This makes the @@ -230,16 +267,22 @@ const fmdump_ops_t fmdump_flt_ops = { "fault", { { -"TIME UUID SUNW-MSG-ID", +"TIME UUID SUNW-MSG-ID " + "EVENT", (fmd_log_rec_f *)flt_short }, { -"TIME UUID SUNW-MSG-ID", +"TIME UUID SUNW-MSG-ID " + "EVENT", (fmd_log_rec_f *)flt_verb1 }, { "TIME UUID" " SUNW-MSG-ID", (fmd_log_rec_f *)flt_verb2 }, { +"TIME UUID" +" SUNW-MSG-ID", +(fmd_log_rec_f *)flt_pretty +}, { NULL, (fmd_log_rec_f *)flt_msg } } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmdump/common/fmdump.c --- a/usr/src/cmd/fm/fmdump/common/fmdump.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmdump/common/fmdump.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -35,6 +34,7 @@ #include #include #include +#include #include @@ -93,6 +93,46 @@ va_end(ap); } +static void +fmdump_exit(int err, int exitcode, const char *format, va_list ap) +{ + (void) fprintf(stderr, "%s: ", g_pname); + + (void) vfprintf(stderr, format, ap); + + if (strchr(format, '\n') == NULL) + (void) fprintf(stderr, ": %s\n", strerror(err)); + + exit(exitcode); +} + +/*PRINTFLIKE1*/ +static void +fmdump_fatal(const char *format, ...) +{ + int err = errno; + + va_list ap; + + va_start(ap, format); + fmdump_exit(err, FMDUMP_EXIT_FATAL, format, ap); + va_end(ap); +} + +/*PRINTFLIKE1*/ +static void +fmdump_usage(const char *format, ...) +{ + + int err = errno; + + va_list ap; + + va_start(ap, format); + fmdump_exit(err, FMDUMP_EXIT_USAGE, format, ap); + va_end(ap); +} + char * fmdump_date(char *buf, size_t len, const fmd_log_record_t *rp) { @@ -134,27 +174,36 @@ return (buf); } +/* BEGIN CSTYLED */ +static const char *synopsis = +"Usage: %s [[-e | -i | -I] | -A ] [-f] [-mvVp] [-c class] [-R root]\n" + "\t [-t time ][-T time] [-u uuid] [-n name[.name]*[=value]] " + "[file]...\n " + "Log selection: [-e | -i | -I] or one [file]; default is the fault log\n" + "\t-e display error log content\n" + "\t-i display infolog content\n" + "\t-I display the high-value-infolog content\n" + "\t-R set root directory for pathname expansions\n " + "Command behaviour:\n" + "\t-A Aggregate specified [file]s or, if no [file], all known logs\n" + "\t-f follow growth of log file by waiting for additional data\n " + "Output options:\n" + "\t-m display human-readable messages (only for fault logs)\n" + "\t-v set verbose mode: display additional event detail\n" + "\t-V set very verbose mode: display complete event contents\n" + "\t-p Used with -V: apply some output prettification\n " + "Selection filters:\n" + "\t-c select events that match the specified class\n" + "\t-t select events that occurred after the specified time\n" + "\t-T select events that occurred before the specified time\n" + "\t-u select events that match the specified diagnosis uuid\n" + "\t-n select events containing named nvpair (with matching value)\n"; +/* END CSTYLED */ + static int usage(FILE *fp) { - (void) fprintf(fp, "Usage: %s [-efmvV] [-c class] [-R root] [-t time] " - "[-T time] [-u uuid]\n\t\t[-n name[.name]*[=value]] [file]\n", - g_pname); - - (void) fprintf(fp, - "\t-c select events that match the specified class\n" - "\t-e display error log content instead of fault log content\n" - "\t-f follow growth of log file by waiting for additional data\n" - "\t-m display human-readable messages for the fault log\n" - "\t-R set root directory for pathname expansions\n" - "\t-t select events that occurred after the specified time\n" - "\t-T select events that occurred before the specified time\n" - "\t-u select events that match the specified uuid\n" - "\t-n select events containing named nvpair " - "(with matching value)\n" - "\t-v set verbose mode: display additional event detail\n" - "\t-V set very verbose mode: display complete event contents\n"); - + (void) fprintf(fp, synopsis, g_pname); return (FMDUMP_EXIT_USAGE); } @@ -204,17 +253,11 @@ struct tm tm; char *p; - if (tvp == NULL) { - (void) fprintf(stderr, "%s: failed to allocate memory: %s\n", - g_pname, strerror(errno)); - exit(FMDUMP_EXIT_FATAL); - } + if (tvp == NULL) + fmdump_fatal("failed to allocate memory"); - if (gettimeofday(&tod, NULL) != 0) { - (void) fprintf(stderr, "%s: failed to get tod: %s\n", - g_pname, strerror(errno)); - exit(FMDUMP_EXIT_FATAL); - } + if (gettimeofday(&tod, NULL) != 0) + fmdump_fatal("failed to get tod"); /* * First try a variety of strptime() calls. If these all fail, we'll @@ -257,11 +300,8 @@ errno = 0; nsec = strtol(arg, (char **)&p, 10); - if (errno != 0 || nsec == 0 || p == arg || *p == '\0') { - (void) fprintf(stderr, "%s: illegal time " - "format -- %s\n", g_pname, arg); - exit(FMDUMP_EXIT_USAGE); - } + if (errno != 0 || nsec == 0 || p == arg || *p == '\0') + fmdump_usage("illegal time format -- %s\n", arg); for (i = 0; suffix[i].name != NULL; i++) { if (strcasecmp(suffix[i].name, p) == 0) { @@ -270,20 +310,15 @@ } } - if (suffix[i].name == NULL) { - (void) fprintf(stderr, "%s: illegal time " - "format -- %s\n", g_pname, arg); - exit(FMDUMP_EXIT_USAGE); - } + if (suffix[i].name == NULL) + fmdump_usage("illegal time format -- %s\n", arg); tvp->tv_sec = nsec / NANOSEC; tvp->tv_usec = (nsec % NANOSEC) / (NANOSEC / MICROSEC); - if (tvp->tv_sec > tod.tv_sec) { - (void) fprintf(stderr, "%s: time delta precedes " - "UTC time origin -- %s\n", g_pname, arg); - exit(FMDUMP_EXIT_USAGE); - } + if (tvp->tv_sec > tod.tv_sec) + fmdump_usage("time delta precedes UTC time origin " + "-- %s\n", arg); tvp->tv_sec = tod.tv_sec - tvp->tv_sec; @@ -316,11 +351,8 @@ tvp->tv_sec = mktime(&tm); tvp->tv_usec = 0; - if (tvp->tv_sec == -1L && errno != 0) { - (void) fprintf(stderr, "%s: failed to compose " - "time %s: %s\n", g_pname, arg, strerror(errno)); - exit(FMDUMP_EXIT_ERROR); - } + if (tvp->tv_sec == -1L && errno != 0) + fmdump_fatal("failed to compose time %s", arg); /* * If our mktime() set tm_isdst, adjust the result for DST by @@ -335,17 +367,13 @@ tvp->tv_usec = (suseconds_t)(strtod(arg, &p) * (double)MICROSEC); - if (errno != 0 || p == arg || *p != '\0') { - (void) fprintf(stderr, "%s: illegal time " - "suffix -- .%s\n", g_pname, arg); - exit(FMDUMP_EXIT_USAGE); - } + if (errno != 0 || p == arg || *p != '\0') + fmdump_usage("illegal time suffix -- .%s\n", + arg); } } else { - (void) fprintf(stderr, "%s: unexpected suffix after " - "time %s -- %s\n", g_pname, arg, p); - exit(FMDUMP_EXIT_USAGE); + fmdump_usage("unexpected suffix after time %s -- %s\n", arg, p); } return (tvp); @@ -404,29 +432,23 @@ while (isspace(*value)) value++; - if ((value_regex = malloc(sizeof (regex_t))) == NULL) { - (void) fprintf(stderr, "%s: failed to allocate memory: " - "%s\n", g_pname, strerror(errno)); - exit(FMDUMP_EXIT_FATAL); - } + if ((value_regex = malloc(sizeof (regex_t))) == NULL) + fmdump_fatal("failed to allocate memory"); /* compile regular expression for possible string match */ if ((rv = regcomp(value_regex, value, REG_NOSUB|REG_NEWLINE)) != 0) { (void) regerror(rv, value_regex, errstr, sizeof (errstr)); - (void) fprintf(stderr, "unexpected regular expression " - "in %s: %s\n", value, errstr); free(value_regex); - exit(FMDUMP_EXIT_USAGE); + fmdump_usage("unexpected regular expression in " + "%s: %s\n", value, errstr); } } - if ((argt = malloc(sizeof (fmd_log_filter_nvarg_t))) == NULL) { - (void) fprintf(stderr, "%s: failed to allocate memory: %s\n", - g_pname, strerror(errno)); - exit(FMDUMP_EXIT_FATAL); - } + if ((argt = malloc(sizeof (fmd_log_filter_nvarg_t))) == NULL) + fmdump_fatal("failed to allocate memory"); + argt->nvarg_name = namevalue; /* now just name */ argt->nvarg_value = value; argt->nvarg_value_regex = value_regex; @@ -441,14 +463,26 @@ int log_filter_silent(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) { + int opt_A = (arg != NULL); boolean_t msg; + char *class; + + /* + * If -A was used then apply this filter only to events of list class + */ + if (opt_A) { + if (nvlist_lookup_string(rp->rec_nvl, FM_CLASS, &class) != 0 || + strncmp(class, FM_LIST_EVENT ".", + sizeof (FM_LIST_EVENT)) != 0) + return (1); + } return (nvlist_lookup_boolean_value(rp->rec_nvl, FM_SUSPECT_MESSAGE, &msg) != 0 || msg != 0); } struct loglink { - char *path; + char *path; long suffix; struct loglink *next; }; @@ -463,11 +497,8 @@ newp = malloc(sizeof (struct loglink)); len = strlen(dirname) + strlen(logname) + 2; str = malloc(len); - if (newp == NULL || str == NULL) { - (void) fprintf(stderr, "%s: failed to allocate memory: %s\n", - g_pname, strerror(errno)); - exit(FMDUMP_EXIT_FATAL); - } + if (newp == NULL || str == NULL) + fmdump_fatal("failed to allocate memory"); (void) snprintf(str, len, "%s/%s", dirname, logname); newp->path = str; @@ -498,8 +529,8 @@ len = strlen(logname); if ((dirp = opendir(dirname)) == NULL) { - (void) fprintf(stderr, "%s: failed to opendir `%s': %s\n", - g_pname, dirname, strerror(errno)); + fmdump_warn("failed to opendir `%s'", dirname); + g_errs++; return (NULL); } @@ -533,13 +564,607 @@ return (head); } +/* + * Aggregate log files. If ifiles is not NULL then one or more files + * were listed on the command line, and we will merge just those files. + * Otherwise we will merge all known log file types, and include the + * rotated logs for each type (you can suppress the inclusion of + * some logtypes through use of FMDUMP_AGGREGATE_IGNORE in the process + * environment, setting it to a comma-separated list of log labels and/or + * log filenames to ignore). + * + * We will not attempt to perform a chronological sort across all log records + * of all files. Indeed, we won't even sort individual log files - + * we will not re-order events differently to how they appeared in their + * original log file. This is because log files are already inherently + * ordered by the order in which fmd receives and processes events. + * So we determine the output order by comparing the "next" record + * off the top of each log file. + * + * We will construct a number of log record source "pipelines". As above, + * the next record to render in the overall output is that from the + * pipeline with the oldest event. + * + * For the case that input logfiles were listed on the command line, each + * pipeline will process exactly one of those logfiles. Distinct pipelines + * may process logfiles of the same "type" - eg if two "error" logs and + * one "fault" logs are specified then there'll be two pipelines producing + * events from "error" logs. + * + * If we are merging all known log types then we will construct exactly + * one pipeline for each known log type - one for error, one for fault, etc. + * Each pipeline will process first the rotated logs of that type and then + * move on to the current log of that type. + * + * The output from all pipelines flows into a serializer which selects + * the next record once all pipelines have asserted their output state. + * The output state of a pipeline is one of: + * + * - record available: the next record from this pipeline is available + * for comparison and consumption + * + * - done: this pipeline will produce no more records + * + * - polling: this pipeline is polling for new records and will + * make them available as output if/when any are observed + * + * - processing: output state will be updated shortly + * + * A pipeline iterates over each file queued to it using fmd_log_xiter. + * We do this in a separate thread for each pipeline. The callback on + * each iteration must update the serializer to let it know that + * a new record is available. In the serializer thread we decide whether + * we have all records expected have arrived and it is time to choose + * the next output record. + */ + +/* + * A pipeline descriptor. The pl_cv condition variable is used together + * with pl_lock for initial synchronisation, and thereafter with the + * lock for the serializer for pausing and continuing this pipeline. + */ +struct fmdump_pipeline { + pthread_mutex_t pl_lock; /* used only in pipeline startup */ + int pl_started; /* sync with main thread on startup */ + pthread_t pl_thr; /* our processing thread */ + pthread_cond_t pl_cv; /* see above */ + struct loglink *pl_rotated; /* rotated logs to process first */ + char *pl_logpath; /* target path to process */ + char *pl_processing; /* path currently being processed */ + struct fmdump_srlzer *pl_srlzer; /* link to serializer */ + int pl_srlzeridx; /* serializer index for this pipeline */ + const fmdump_ops_t *pl_ops; /* ops for the log type we're given */ + int pl_fmt; /* FMDUMP_{SHORT,VERB1,VERB2,PRETTY} */ + boolean_t pl_follow; /* go into poll mode at log end */ + fmdump_arg_t pl_arg; /* arguments */ +}; + +enum fmdump_pipestate { + FMDUMP_PIPE_PROCESSING = 0x1000, + FMDUMP_PIPE_RECORDAVAIL, + FMDUMP_PIPE_POLLING, + FMDUMP_PIPE_DONE +}; + +/* + * Each pipeline has an associated output slot in the serializer. This + * must be updated with the serializer locked. After update evaluate + * whether there are enough slots decided that we should select a + * record to output. + */ +struct fmdump_srlzer_slot { + enum fmdump_pipestate ss_state; + uint64_t ss_sec; + uint64_t ss_nsec; +}; + +/* + * All pipelines are linked to a single serializer. The serializer + * structure must be updated under the ds_lock; this mutex is also + * paired with the pl_cv of individual pipelines (one mutex, many condvars) + * in pausing and continuing individual pipelines. + */ +struct fmdump_srlzer { + struct fmdump_pipeline *ds_pipearr; /* pipeline array */ + pthread_mutex_t ds_lock; /* see above */ + uint32_t ds_pipecnt; /* number of pipelines */ + uint32_t ds_pollcnt; /* pipelines in poll mode */ + uint32_t ds_nrecordavail; /* pipelines with a record */ + uint32_t ds_ndone; /* completed pipelines */ + struct fmdump_srlzer_slot *ds_slot; /* slot array */ +}; + +/* + * All known log types. When aggregation is requested an no file list + * is provided we will process the logs identified here (if lt_enabled + * is true and not over-ridden by environment settings). We also + * use this in determining the appropriate ops structure for each distinct + * label. + */ +static struct fmdump_logtype { + const char *lt_label; /* label from log header */ + boolean_t lt_enabled; /* include in merge? */ + const char *lt_logname; /* var/fm/fmd/%s */ + const fmdump_ops_t *lt_ops; +} logtypes[] = { + { + "error", + B_TRUE, + "errlog", + &fmdump_err_ops + }, + { + "fault", + B_TRUE, + "fltlog", + &fmdump_flt_ops + }, + { + "info", + B_TRUE, + "infolog", + &fmdump_info_ops + }, + { + "info", + B_TRUE, + "infolog_hival", + &fmdump_info_ops + }, + { + "asru", + B_FALSE, /* not included unless in file list */ + NULL, + &fmdump_asru_ops /* but we need ops when it is */ + } +}; + +/* + * Disable logtypes per environment setting. Does not apply when a list + * of logs is provided on the command line. + */ +static void +do_disables(void) +{ + char *env = getenv("FMDUMP_AGGREGATE_IGNORE"); + char *dup, *start, *tofree; + int i; + + if (env == NULL) + return; + + tofree = dup = strdup(env); + + while (dup != NULL) { + start = strsep(&dup, ","); + for (i = 0; i < sizeof (logtypes) / sizeof (logtypes[0]); i++) { + if (logtypes[i].lt_logname == NULL) + continue; + + if (strcmp(start, logtypes[i].lt_label) == 0 || + strcmp(start, logtypes[i].lt_logname) == 0) { + logtypes[i].lt_enabled = B_FALSE; + } + } + } + + free(tofree); +} + +static void +srlzer_enter(struct fmdump_pipeline *pl) +{ + struct fmdump_srlzer *srlzer = pl->pl_srlzer; + + (void) pthread_mutex_lock(&srlzer->ds_lock); +} + +static void +srlzer_exit(struct fmdump_pipeline *pl) +{ + struct fmdump_srlzer *srlzer = pl->pl_srlzer; + + ASSERT(MUTEX_HELD(&srlzer->ds_lock)); + (void) pthread_mutex_unlock(&srlzer->ds_lock); +} + +static struct fmdump_pipeline * +srlzer_choose(struct fmdump_srlzer *srlzer) +{ + struct fmdump_srlzer_slot *slot, *oldest; + int oldestidx = -1; + int first = 1; + int i; + + ASSERT(MUTEX_HELD(&srlzer->ds_lock)); + + for (i = 0, slot = &srlzer->ds_slot[0]; i < srlzer->ds_pipecnt; + i++, slot++) { + if (slot->ss_state != FMDUMP_PIPE_RECORDAVAIL) + continue; + + if (first) { + oldest = slot; + oldestidx = i; + first = 0; + continue; + } + + if (slot->ss_sec < oldest->ss_sec || + slot->ss_sec == oldest->ss_sec && + slot->ss_nsec < oldest->ss_nsec) { + oldest = slot; + oldestidx = i; + } + } + + return (oldestidx >= 0 ? &srlzer->ds_pipearr[oldestidx] : NULL); +} + +static void +pipeline_stall(struct fmdump_pipeline *pl) +{ + struct fmdump_srlzer *srlzer = pl->pl_srlzer; + + ASSERT(MUTEX_HELD(&srlzer->ds_lock)); + (void) pthread_cond_wait(&pl->pl_cv, &srlzer->ds_lock); +} + +static void +pipeline_continue(struct fmdump_pipeline *pl) +{ + struct fmdump_srlzer *srlzer = pl->pl_srlzer; + + ASSERT(MUTEX_HELD(&srlzer->ds_lock)); + (void) pthread_cond_signal(&srlzer->ds_pipearr[pl->pl_srlzeridx].pl_cv); +} + +/* + * Called on each pipeline record iteration to make a new record + * available for input to the serializer. Returns 0 to indicate that + * the caller must stall the pipeline, or 1 to indicate that the + * caller should go ahead and render their record. If this record + * addition fills the serializer then choose a pipeline that must + * render output. + */ +static int +pipeline_output(struct fmdump_pipeline *pl, const fmd_log_record_t *rp) +{ + struct fmdump_srlzer *srlzer = pl->pl_srlzer; + struct fmdump_srlzer_slot *slot; + struct fmdump_pipeline *wpl; + int thisidx = pl->pl_srlzeridx; + + ASSERT(MUTEX_HELD(&srlzer->ds_lock)); + + slot = &srlzer->ds_slot[thisidx]; + slot->ss_state = FMDUMP_PIPE_RECORDAVAIL; + slot->ss_sec = rp->rec_sec; + slot->ss_nsec = rp->rec_nsec; + srlzer->ds_nrecordavail++; + + /* + * Once all pipelines are polling we just render in arrival order. + */ + if (srlzer->ds_pollcnt == srlzer->ds_pipecnt) + return (1); + + /* + * If not all pipelines have asserted an output yet then the + * caller must block. + */ + if (srlzer->ds_nrecordavail + srlzer->ds_ndone + + srlzer->ds_pollcnt < srlzer->ds_pipecnt) + return (0); + + /* + * Right so it's time to turn the crank by choosing which of the + * filled line of slots should produce output. If it is the slot + * for our caller then return their index to them, otherwise return + * -1 to the caller to make them block and cv_signal the winner. + */ + wpl = srlzer_choose(srlzer); + ASSERT(wpl != NULL); + + if (wpl == pl) + return (1); + + /* Wake the oldest, and return 0 to put the caller to sleep */ + pipeline_continue(wpl); + + return (0); +} + +static void +pipeline_mark_consumed(struct fmdump_pipeline *pl) +{ + struct fmdump_srlzer *srlzer = pl->pl_srlzer; + + ASSERT(MUTEX_HELD(&srlzer->ds_lock)); + srlzer->ds_slot[pl->pl_srlzeridx].ss_state = FMDUMP_PIPE_PROCESSING; + srlzer->ds_nrecordavail--; +} + +static void +pipeline_done(struct fmdump_pipeline *pl) +{ + struct fmdump_srlzer *srlzer = pl->pl_srlzer; + struct fmdump_pipeline *wpl; + + srlzer_enter(pl); + + srlzer->ds_slot[pl->pl_srlzeridx].ss_state = FMDUMP_PIPE_DONE; + srlzer->ds_ndone++; + wpl = srlzer_choose(srlzer); + if (wpl != NULL) + pipeline_continue(wpl); + + srlzer_exit(pl); +} + +static void +pipeline_pollmode(struct fmdump_pipeline *pl) +{ + struct fmdump_srlzer *srlzer = pl->pl_srlzer; + struct fmdump_pipeline *wpl; + + if (srlzer->ds_slot[pl->pl_srlzeridx].ss_state == FMDUMP_PIPE_POLLING) + return; + + srlzer_enter(pl); + + srlzer->ds_slot[pl->pl_srlzeridx].ss_state = FMDUMP_PIPE_POLLING; + if (++srlzer->ds_pollcnt + srlzer->ds_nrecordavail == + srlzer->ds_pipecnt && (wpl = srlzer_choose(srlzer)) != NULL) + pipeline_continue(wpl); + + srlzer_exit(pl); +} + +static int +pipeline_err(fmd_log_t *lp, void *arg) +{ + struct fmdump_pipeline *pl = (struct fmdump_pipeline *)arg; + + fmdump_warn("skipping record in %s: %s\n", pl->pl_processing, + fmd_log_errmsg(lp, fmd_log_errno(lp))); + g_errs++; + + return (0); +} + +static int +pipeline_cb(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) +{ + struct fmdump_pipeline *pl = (struct fmdump_pipeline *)arg; + int rc; + + fmd_log_rec_f *func = pl->pl_arg.da_fmt->do_func; + + srlzer_enter(pl); + + if (!pipeline_output(pl, rp)) + pipeline_stall(pl); + + rc = func(lp, rp, pl->pl_arg.da_fp); + pipeline_mark_consumed(pl); + + srlzer_exit(pl); + + return (rc); +} + +static void +pipeline_process(struct fmdump_pipeline *pl, char *logpath, boolean_t follow) +{ + fmd_log_header_t log; + fmd_log_t *lp; + int err; + int i; + + pl->pl_processing = logpath; + + if ((lp = fmd_log_open(FMD_LOG_VERSION, logpath, &err)) == NULL) { + fmdump_warn("failed to open %s: %s\n", + logpath, fmd_log_errmsg(NULL, err)); + g_errs++; + return; + } + + fmd_log_header(lp, &log); + for (i = 0; i < sizeof (logtypes) / sizeof (logtypes[0]); i++) { + if (strcmp(log.log_label, logtypes[i].lt_label) == 0) { + pl->pl_ops = logtypes[i].lt_ops; + pl->pl_arg.da_fmt = + &pl->pl_ops->do_formats[pl->pl_fmt]; + break; + } + } + + if (pl->pl_ops == NULL) { + fmdump_warn("unknown log type %s for %s\n", + log.log_label, logpath); + g_errs++; + return; + } + + do { + if (fmd_log_xiter(lp, FMD_LOG_XITER_REFS, pl->pl_arg.da_fc, + pl->pl_arg.da_fv, pipeline_cb, pipeline_err, (void *)pl, + NULL) != 0) { + fmdump_warn("failed to dump %s: %s\n", + logpath, fmd_log_errmsg(lp, fmd_log_errno(lp))); + g_errs++; + fmd_log_close(lp); + return; + } + + if (follow) { + pipeline_pollmode(pl); + (void) sleep(1); + } + + } while (follow); + + fmd_log_close(lp); +} + +static void * +pipeline_thr(void *arg) +{ + struct fmdump_pipeline *pl = (struct fmdump_pipeline *)arg; + struct loglink *ll; + + (void) pthread_mutex_lock(&pl->pl_lock); + pl->pl_started = 1; + (void) pthread_mutex_unlock(&pl->pl_lock); + (void) pthread_cond_signal(&pl->pl_cv); + + for (ll = pl->pl_rotated; ll != NULL; ll = ll->next) + pipeline_process(pl, ll->path, B_FALSE); + + pipeline_process(pl, pl->pl_logpath, pl->pl_follow); + pipeline_done(pl); + + return (NULL); +} + + +static int +aggregate(char **ifiles, int n_ifiles, int opt_f, + fmd_log_filter_t *fv, uint_t fc, + int opt_v, int opt_V, int opt_p) +{ + struct fmdump_pipeline *pipeline, *pl; + struct fmdump_srlzer srlzer; + uint32_t npipe; + int fmt; + int i; + + if (ifiles != NULL) { + npipe = n_ifiles; + pipeline = calloc(npipe, sizeof (struct fmdump_pipeline)); + if (!pipeline) + fmdump_fatal("failed to allocate memory"); + + for (i = 0; i < n_ifiles; i++) + pipeline[i].pl_logpath = ifiles[i]; + } else { + pipeline = calloc(sizeof (logtypes) / sizeof (logtypes[0]), + sizeof (struct fmdump_pipeline)); + if (!pipeline) + fmdump_fatal("failed to allocate memory"); + + do_disables(); + + npipe = 0; + for (i = 0; i < sizeof (logtypes) / sizeof (logtypes[0]); i++) { + struct fmdump_logtype *ltp = &logtypes[i]; + char *logpath; + + if (ltp->lt_enabled == B_FALSE) + continue; + + if ((logpath = malloc(PATH_MAX)) == NULL) + fmdump_fatal("failed to allocate memory"); + + (void) snprintf(logpath, PATH_MAX, + "%s/var/fm/fmd/%s", + g_root ? g_root : "", ltp->lt_logname); + + pipeline[npipe].pl_rotated = + get_rotated_logs(logpath); + + pipeline[npipe++].pl_logpath = logpath; + } + } + + if (opt_V) + fmt = opt_p ? FMDUMP_PRETTY : FMDUMP_VERB2; + else if (opt_v) + fmt = FMDUMP_VERB1; + else + fmt = FMDUMP_SHORT; + + bzero(&srlzer, sizeof (srlzer)); + srlzer.ds_pipearr = pipeline; + srlzer.ds_pipecnt = npipe; + srlzer.ds_slot = calloc(npipe, sizeof (struct fmdump_srlzer_slot)); + if (!srlzer.ds_slot) + fmdump_fatal("failed to allocate memory"); + (void) pthread_mutex_init(&srlzer.ds_lock, NULL); + + for (i = 0, pl = &pipeline[0]; i < npipe; i++, pl++) { + (void) pthread_mutex_init(&pl->pl_lock, NULL); + (void) pthread_cond_init(&pl->pl_cv, NULL); + srlzer.ds_slot[i].ss_state = FMDUMP_PIPE_PROCESSING; + pl->pl_srlzer = &srlzer; + pl->pl_srlzeridx = i; + pl->pl_follow = opt_f ? B_TRUE : B_FALSE; + pl->pl_fmt = fmt; + pl->pl_arg.da_fv = fv; + pl->pl_arg.da_fc = fc; + pl->pl_arg.da_fp = stdout; + + (void) pthread_mutex_lock(&pl->pl_lock); + + if (pthread_create(&pl->pl_thr, NULL, + pipeline_thr, (void *)pl) != 0) + fmdump_fatal("pthread_create for pipeline %d failed", + i); + } + + for (i = 0, pl = &pipeline[0]; i < npipe; i++, pl++) { + while (!pl->pl_started) + (void) pthread_cond_wait(&pl->pl_cv, &pl->pl_lock); + + (void) pthread_mutex_unlock(&pl->pl_lock); + } + + for (i = 0, pl = &pipeline[0]; i < npipe; i++, pl++) + (void) pthread_join(pl->pl_thr, NULL); + + if (ifiles == NULL) { + for (i = 0; i < npipe; i++) + free(pipeline[i].pl_logpath); + } + + free(srlzer.ds_slot); + + free(pipeline); + + return (FMDUMP_EXIT_SUCCESS); +} + +static void +cleanup(char **ifiles, int n_ifiles) +{ + int i; + + if (ifiles == NULL) + return; + + for (i = 0; i < n_ifiles; i++) { + if (ifiles[i] != NULL) { + free(ifiles[i]); + ifiles[i] = NULL; + } + } + + free(ifiles); +} + int main(int argc, char *argv[]) { - int opt_a = 0, opt_e = 0, opt_f = 0, opt_H = 0, opt_m = 0; + int opt_a = 0, opt_e = 0, opt_f = 0, opt_H = 0, opt_m = 0, opt_p = 0; int opt_u = 0, opt_v = 0, opt_V = 0; - - char ifile[PATH_MAX] = ""; + int opt_i = 0, opt_I = 0; + int opt_A = 0; + char **ifiles = NULL; + char *ifile = NULL; + int n_ifiles; + int ifileidx = 0; int iflags = 0; fmdump_arg_t arg; @@ -568,8 +1193,11 @@ while (optind < argc) { while ((c = - getopt(argc, argv, "ac:efHmn:O:R:t:T:u:vV")) != EOF) { + getopt(argc, argv, "Aac:efHiImn:O:pR:t:T:u:vV")) != EOF) { switch (c) { + case 'A': + opt_A++; + break; case 'a': opt_a++; break; @@ -579,6 +1207,8 @@ allfv[allfc++] = errfv[errfc++]; break; case 'e': + if (opt_i) + return (usage(stderr)); opt_e++; break; case 'f': @@ -587,6 +1217,16 @@ case 'H': opt_H++; break; + case 'i': + if (opt_e || opt_I) + return (usage(stderr)); + opt_i++; + break; + case 'I': + if (opt_e || opt_i) + return (usage(stderr)); + opt_I++; + break; case 'm': opt_m++; break; @@ -594,6 +1234,9 @@ off = strtoull(optarg, NULL, 16); iflags |= FMD_LOG_XITER_OFFS; break; + case 'p': + opt_p++; + break; case 'R': g_root = optarg; break; @@ -631,21 +1274,79 @@ } } + if (opt_A && (opt_e || opt_i || opt_I || opt_m || opt_u)) + fmdump_usage("-A excludes all of " + "-e, -i, -I, -m and -u\n"); + if (optind < argc) { - if (*ifile != '\0') { - (void) fprintf(stderr, "%s: illegal " - "argument -- %s\n", g_pname, argv[optind]); - return (FMDUMP_EXIT_USAGE); - } else { - (void) strlcpy(ifile, - argv[optind++], sizeof (ifile)); + char *dest; + + if (ifiles == NULL) { + n_ifiles = argc - optind; + ifiles = calloc(n_ifiles, sizeof (char *)); + if (ifiles == NULL) { + fmdump_fatal( + "failed to allocate memory for " + "%d input file%s", n_ifiles, + n_ifiles > 1 ? "s" : ""); + } } + + if (ifileidx > 0 && !opt_A) + fmdump_usage("illegal argument -- %s\n", + argv[optind]); + + if ((dest = malloc(PATH_MAX)) == NULL) + fmdump_fatal("failed to allocate memory"); + + (void) strlcpy(dest, argv[optind++], PATH_MAX); + ifiles[ifileidx++] = dest; } } + if (opt_A) { + int rc; + + if (!opt_a) { + fltfv[fltfc].filt_func = log_filter_silent; + fltfv[fltfc].filt_arg = (void *)1; + allfv[allfc++] = fltfv[fltfc++]; + } + + rc = aggregate(ifiles, n_ifiles, opt_f, + allfv, allfc, + opt_v, opt_V, opt_p); + + cleanup(ifiles, n_ifiles); + return (rc); + } else { + if (ifiles == NULL) { + if ((ifile = calloc(1, PATH_MAX)) == NULL) + fmdump_fatal("failed to allocate memory"); + } else { + ifile = ifiles[0]; + } + } + + if (*ifile == '\0') { - (void) snprintf(ifile, sizeof (ifile), "%s/var/fm/fmd/%slog", - g_root ? g_root : "", opt_e && !opt_u ? "err" : "flt"); + const char *pfx, *sfx; + + if (opt_u || (!opt_e && !opt_i && !opt_I)) { + pfx = "flt"; + sfx = ""; + } else { + if (opt_e) { + pfx = "err"; + sfx = ""; + } else { + pfx = "info"; + sfx = opt_I ? "_hival" : ""; + } + } + + (void) snprintf(ifile, PATH_MAX, "%s/var/fm/fmd/%slog%s", + g_root ? g_root : "", pfx, sfx); /* * logadm may rotate the logs. When no input file is specified, * we try to dump all the rotated logs as well in the right @@ -654,21 +1355,16 @@ if (!opt_H && off == 0) rotated_logs = get_rotated_logs(ifile); } else if (g_root != NULL) { - (void) fprintf(stderr, "%s: -R option is not appropriate " - "when file operand is present\n", g_pname); - return (FMDUMP_EXIT_USAGE); + fmdump_usage("-R option is not appropriate " + "when file operand is present\n"); } - if ((g_msg = fmd_msg_init(g_root, FMD_MSG_VERSION)) == NULL) { - (void) fprintf(stderr, "%s: failed to initialize " - "libfmd_msg: %s\n", g_pname, strerror(errno)); - return (FMDUMP_EXIT_FATAL); - } + if ((g_msg = fmd_msg_init(g_root, FMD_MSG_VERSION)) == NULL) + fmdump_fatal("failed to initialize libfmd_msg"); if ((lp = fmd_log_open(FMD_LOG_VERSION, ifile, &err)) == NULL) { - (void) fprintf(stderr, "%s: failed to open %s: %s\n", - g_pname, ifile, fmd_log_errmsg(NULL, err)); - return (FMDUMP_EXIT_FATAL); + fmdump_fatal("failed to open %s: %s\n", ifile, + fmd_log_errmsg(NULL, err)); } if (opt_H) { @@ -687,9 +1383,8 @@ } if (off != 0 && fmd_log_seek(lp, off) != 0) { - (void) fprintf(stderr, "%s: failed to seek %s: %s\n", - g_pname, ifile, fmd_log_errmsg(lp, fmd_log_errno(lp))); - return (FMDUMP_EXIT_FATAL); + fmdump_fatal("failed to seek %s: %s\n", ifile, + fmd_log_errmsg(lp, fmd_log_errno(lp))); } if (opt_e && opt_u) @@ -698,6 +1393,8 @@ ops = &fmdump_flt_ops; else if (strcmp(fmd_log_label(lp), fmdump_asru_ops.do_label) == 0) ops = &fmdump_asru_ops; + else if (strcmp(fmd_log_label(lp), fmdump_info_ops.do_label) == 0) + ops = &fmdump_info_ops; else ops = &fmdump_err_ops; @@ -708,7 +1405,8 @@ } if (opt_V) { - arg.da_fmt = &ops->do_formats[FMDUMP_VERB2]; + arg.da_fmt = + &ops->do_formats[opt_p ? FMDUMP_PRETTY : FMDUMP_VERB2]; iflags |= FMD_LOG_XITER_REFS; } else if (opt_v) { arg.da_fmt = &ops->do_formats[FMDUMP_VERB1]; @@ -718,9 +1416,8 @@ arg.da_fmt = &ops->do_formats[FMDUMP_SHORT]; if (opt_m && arg.da_fmt->do_func == NULL) { - (void) fprintf(stderr, "%s: -m mode is not supported for " - "log of type %s: %s\n", g_pname, fmd_log_label(lp), ifile); - return (FMDUMP_EXIT_USAGE); + fmdump_usage("-m mode is not supported for " + "log of type %s: %s\n", fmd_log_label(lp), ifile); } arg.da_fv = errfv; @@ -759,8 +1456,8 @@ if ((rlp = fmd_log_open(FMD_LOG_VERSION, llp->path, &err)) == NULL) { - (void) fprintf(stderr, "%s: failed to open %s: %s\n", - g_pname, llp->path, fmd_log_errmsg(NULL, err)); + fmdump_warn("failed to open %s: %s\n", + llp->path, fmd_log_errmsg(NULL, err)); g_errs++; continue; } @@ -768,8 +1465,7 @@ recs = 0; if (fmd_log_xiter(rlp, iflags, filtc, filtv, func, error, farg, &recs) != 0) { - (void) fprintf(stderr, - "%s: failed to dump %s: %s\n", g_pname, llp->path, + fmdump_warn("failed to dump %s: %s\n", llp->path, fmd_log_errmsg(rlp, fmd_log_errno(rlp))); g_errs++; } @@ -782,8 +1478,7 @@ recs = 0; if (fmd_log_xiter(lp, iflags, filtc, filtv, func, error, farg, &recs) != 0) { - (void) fprintf(stderr, - "%s: failed to dump %s: %s\n", g_pname, ifile, + fmdump_warn("failed to dump %s: %s\n", ifile, fmd_log_errmsg(lp, fmd_log_errno(lp))); g_errs++; } @@ -795,7 +1490,7 @@ } while (opt_f); if (!opt_f && g_recs == 0 && isatty(STDOUT_FILENO)) - (void) fprintf(stderr, "%s: %s is empty\n", g_pname, ifile); + fmdump_warn("%s is empty\n", ifile); if (g_thp != NULL) topo_close(g_thp); @@ -803,5 +1498,10 @@ fmd_log_close(lp); fmd_msg_fini(g_msg); + if (ifiles == NULL) + free(ifile); + else + cleanup(ifiles, n_ifiles); + return (g_errs ? FMDUMP_EXIT_ERROR : FMDUMP_EXIT_SUCCESS); } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmdump/common/fmdump.h --- a/usr/src/cmd/fm/fmdump/common/fmdump.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmdump/common/fmdump.h Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _FMDUMP_H @@ -30,8 +29,10 @@ extern "C" { #endif +#include #include #include +#include #include #include @@ -40,10 +41,17 @@ #include #include +#ifdef DEBUG +#define ASSERT(x) (assert(x)) +#else +#define ASSERT(x) +#endif + enum { FMDUMP_SHORT, FMDUMP_VERB1, FMDUMP_VERB2, + FMDUMP_PRETTY, FMDUMP_MSG, FMDUMP_NFMTS }; @@ -72,6 +80,7 @@ extern const fmdump_ops_t fmdump_err_ops; extern const fmdump_ops_t fmdump_flt_ops; extern const fmdump_ops_t fmdump_asru_ops; +extern const fmdump_ops_t fmdump_info_ops; extern const char *g_pname; extern ulong_t g_errs; @@ -89,6 +98,9 @@ extern char *fmdump_year(char *, size_t, const fmd_log_record_t *); extern char *fmdump_nvl2str(nvlist_t *nvl); +extern int fmdump_render_nvlist(nvlist_prtctl_t, void *, nvlist_t *, + const char *, nvlist_t *); + #ifdef __cplusplus } #endif diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmdump/common/info.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/fmdump/common/info.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,118 @@ +/* + * 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 +#include +#include + +/*ARGSUSED*/ +static int +info_short(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + char buf[32]; + + fmdump_printf(fp, "%-20s %-32s\n", + fmdump_date(buf, sizeof (buf), rp), rp->rec_class); + + return (0); +} + +/*ARGSUSED*/ +static int +info_verb1(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + char *uuid = "(absent)"; + char buf[32]; + + (void) nvlist_lookup_string(rp->rec_nvl, FM_IREPORT_UUID, &uuid); + + fmdump_printf(fp, "%-20s %-36s %s\n", + fmdump_date(buf, sizeof (buf), rp), uuid, rp->rec_class); + + return (0); +} + +/*ARGSUSED*/ +static int +info_verb23_cmn(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp, + nvlist_prtctl_t pctl) +{ + char buf[32]; + char *uuid = "(absent)"; + + (void) nvlist_lookup_string(rp->rec_nvl, FM_IREPORT_UUID, &uuid); + + fmdump_printf(fp, "%-20s.%9.9llu %s\n", + fmdump_year(buf, sizeof (buf), rp), rp->rec_nsec, uuid); + + if (pctl) + nvlist_prt(rp->rec_nvl, pctl); + else + nvlist_print(fp, rp->rec_nvl); + + fmdump_printf(fp, "\n"); + return (0); +} + +static int +info_verb2(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + return (info_verb23_cmn(lp, rp, fp, NULL)); +} + +static int +info_pretty(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) +{ + nvlist_prtctl_t pctl; + int rc; + + if ((pctl = nvlist_prtctl_alloc()) != NULL) { + nvlist_prtctl_setdest(pctl, fp); + nvlist_prtctlop_nvlist(pctl, fmdump_render_nvlist, NULL); + } + + rc = info_verb23_cmn(lp, rp, fp, pctl); + + nvlist_prtctl_free(pctl); + return (rc); +} + +const fmdump_ops_t fmdump_info_ops = { +"info", { +{ +"TIME CLASS", +(fmd_log_rec_f *)info_short +}, { +"TIME UUID CLASS", +(fmd_log_rec_f *)info_verb1 +}, { +"TIME UUID", +(fmd_log_rec_f *)info_verb2 +}, { +"TIME UUID", +(fmd_log_rec_f *)info_pretty +}, { +NULL, NULL +} } +}; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmdump/common/nvlrender.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/fmdump/common/nvlrender.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,74 @@ +/* + * 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. + */ + +/* + * Rendering functions for nvlist_prt that are of use to all types + * of log. + */ + +#include +#include +#include + +extern topo_hdl_t *fmd_fmri_topo_hold(int); + +/* + * Can be appointed to be called for dumping all nvlist members of + * an nvlist we ask to print with nvlist_prt. Return 0 if the + * nvlist is not recognized as an fmri, and default formatting + * will be applied; otherwise format as an fmri string and return 1. + */ + +/*ARGSUSED*/ +int +fmdump_render_nvlist(nvlist_prtctl_t pctl, void *private, nvlist_t *nvl, + const char *name, nvlist_t *fmri) +{ + topo_hdl_t *thp = fmd_fmri_topo_hold(TOPO_VERSION); + FILE *fp = nvlist_prtctl_getdest(pctl); + char *class, *fmristr = NULL; + uint8_t version; + int err; + + if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &class) != 0 || + nvlist_lookup_uint8(fmri, FM_VERSION, &version) != 0) + return (0); + + /* + * Instead of hardcoding known FMRI classes here we'll try + * topo_fmri_nvl2str which should fail gracefully for invalid + * schemes (ie an nvlist that just happens to have the expected + * class and version members but that isn't an FMRI). + */ + if (topo_fmri_nvl2str(thp, fmri, &fmristr, &err) != 0 || + fmristr == NULL) + return (0); + + nvlist_prtctl_doindent(pctl, 1); + nvlist_prtctl_dofmt(pctl, NVLIST_FMT_MEMBER_NAME, name); + (void) fprintf(fp, "%s", fmristr); + topo_hdl_strfree(thp, fmristr); + + return (1); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/fmtopo/common/fmtopo.c --- a/usr/src/cmd/fm/fmtopo/common/fmtopo.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/fmtopo/common/fmtopo.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -34,6 +33,7 @@ #include #include #include +#include #include #define FMTOPO_EXIT_SUCCESS 0 @@ -960,6 +960,11 @@ topo_walk_t *twp; int flag; + if (getzoneid() != GLOBAL_ZONEID && + strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) { + return (0); + } + if ((twp = topo_walk_init(thp, opt_s, walk_node, NULL, &err)) == NULL) { (void) fprintf(stderr, "%s: failed to walk %s topology:" @@ -1268,8 +1273,11 @@ g_pname, topo_strerror(err)); return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); } else if (err != 0) { - (void) fprintf(stderr, "%s: topology snapshot incomplete\n", - g_pname); + (void) fprintf(stderr, "%s: topology snapshot incomplete%s\n", + g_pname, getzoneid() != GLOBAL_ZONEID && + strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0 ? + " (" FM_FMRI_SCHEME_HC " scheme does not enumerate " + "in a non-global zone)": ""); } if (opt_x) { diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/Makefile.plugin --- a/usr/src/cmd/fm/modules/Makefile.plugin Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/Makefile.plugin Fri Jul 30 17:04:17 2010 +1000 @@ -19,15 +19,13 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # -#ident "%Z%%M% %I% %E% SMI" .KEEP_STATE: .SUFFIXES: -include ../../../../Makefile.cmd +include $(SRC)/cmd/Makefile.cmd MODCLASS = plugins # @@ -40,6 +38,13 @@ CONF = $(MODULE:%=%.conf) # +# We may have sources from directories other than the current, but +# we build all objects in the current directory (not necessarily in the +# directory of its source). +SEDCMDLINE = echo $(OBJS) | sed 's!\.\./[a-z_/]*/!!g' +LINKOBJS = $(SEDCMDLINE:sh) + +# # A module may set DMOD and DMOD_SRCS if it has a mdb proc module. # DMOD, if set, must match PROG above (for mdb autoloading) so it will # be built in a subdirectory. @@ -68,8 +73,8 @@ DMODLINTTGT = $(DMOD:%=lint_dmod) DMODLINTFILES = $(DMOD_SRCS:%.c=%.ln) -APIMAP = ../../../fmd/common/fmd_api.map -FMRIMAP = ../../../fmd/common/fmd_fmri.map +APIMAP = $(SRC)/cmd/fm/fmd/common/fmd_api.map +FMRIMAP = $(SRC)/cmd/fm/fmd/common/fmd_fmri.map CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) $(CC_PICFLAGS) CFLAGS += -G $(XREGSFLAG) @@ -89,8 +94,8 @@ .PARALLEL: $(OBJS) $(LINTFILES) $(DMOD_OBJS) $(DMODLINTFILES) $(PROG): $(OBJS) $(APIMAP) - $(LINK.c) $(OBJS) -o $@ $(LDLIBS) - $(CTFMERGE) -L VERSION -o $@ $(OBJS) + $(LINK.c) $(LINKOBJS) -o $@ $(LDLIBS) + $(CTFMERGE) -L VERSION -o $@ $(LINKOBJS) $(POST_PROCESS_SO) $(DMODPROG): $(DMOD_OBJS) $(MAPFILE-DMOD) @@ -99,17 +104,18 @@ $(POST_PROCESS) %.o: %.c - $(COMPILE.c) $< - $(CTFCONVERT_O) + $(COMPILE.c) $< -o $(@F) + $(CTFCONVERT) $(CTFCVTFLAGS) $(@F) clean: - $(RM) $(OBJS) $(DMOD_OBJS) $(LINTFILES) $(DMODLINTFILES) $(CLEANFILES) + $(RM) $(OBJS) $(DMOD_OBJS) $(LINTFILES) $(DMODLINTFILES) $(CLEANFILES) \ + $(LINKOBJS) clobber: clean $(RM) $(PROG) $(DMODPROG) %.ln: %.c - $(LINT.c) -c $< + $(LINT.c) -dirout=$(@D) -c $< lint_prog: $(LINTFILES) $(LINT) $(LINTFLAGS) $(LINTFILES) $(LDLIBS) @@ -132,4 +138,4 @@ install: $(ROOTPROG) $(ROOTCONF) $(ROOTDMOD) -include ../../Makefile.rootdirs +include $(SRC)/cmd/fm/modules/Makefile.rootdirs diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/Makefile --- a/usr/src/cmd/fm/modules/common/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -19,9 +19,9 @@ # CDDL HEADER END # # +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # -#Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. -# + SUBDIRS = cpumem-retire \ disk-monitor \ disk-transport \ @@ -33,7 +33,7 @@ ip-transport \ sensor-transport \ ses-log-transport \ - snmp-trapgen \ + sw-diag-response \ sp-monitor \ syslog-msgs \ zfs-diagnosis \ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/eversholt/eft.c --- a/usr/src/cmd/fm/modules/common/eversholt/eft.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/eversholt/eft.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,10 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ +#include #include #include #include @@ -213,7 +213,7 @@ { char *ename = (char *)lhs; - out(O_DEBUG, "allow silent discard_if_config_unknown: \"%s\"", ename); + out(O_VERB, "allow silent discard_if_config_unknown: \"%s\"", ename); } extern struct stats *Filecount; @@ -248,7 +248,7 @@ static void doopendict(const char *lhs, void *rhs, void *arg) { - out(O_DEBUG, "opendict: \"%s\"", lhs); + out(O_VERB, "opendict: \"%s\"", lhs); fmd_hdl_opendict(Hdl, lhs); } @@ -340,7 +340,7 @@ fme_istat_load(hdl); fme_serd_load(hdl); - out(O_DEBUG, "reconstituting any existing fmes"); + out(O_VERB, "reconstituting any existing fmes"); while ((casep = fmd_case_next(hdl, casep)) != NULL) { fme_restart(hdl, casep); } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/eversholt/fme.c --- a/usr/src/cmd/fm/modules/common/eversholt/fme.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/eversholt/fme.c Fri Jul 30 17:04:17 2010 +1000 @@ -2779,14 +2779,14 @@ ipath_print(O_DEBUG|O_NONL, rp->suspect->enode->u.event.ename->u.name.s, rp->suspect->ipp); - out(O_DEBUG, " has no FITrate (using 1)"); + out(O_VERB, " has no FITrate (using 1)"); fr = 1; } else if (fr == 0) { out(O_DEBUG|O_NONL, "event "); ipath_print(O_DEBUG|O_NONL, rp->suspect->enode->u.event.ename->u.name.s, rp->suspect->ipp); - out(O_DEBUG, " has zero FITrate (using 1)"); + out(O_VERB, " has zero FITrate (using 1)"); fr = 1; } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/eversholt/platform.c --- a/usr/src/cmd/fm/modules/common/eversholt/platform.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/eversholt/platform.c Fri Jul 30 17:04:17 2010 +1000 @@ -867,7 +867,7 @@ fnlen = strlen(fnstr); for (i = 0; dirname[i] != NULL; i++) { - out(O_DEBUG, "Looking for %s files in %s", fnstr, dirname[i]); + out(O_VERB, "Looking for %s files in %s", fnstr, dirname[i]); if ((dirp = opendir(dirname[i])) == NULL) { out(O_DEBUG|O_SYS, "platform_get_files: opendir failed for %s", @@ -886,7 +886,7 @@ if (lut_lookup(foundnames, (void *)snm, NULL) != NULL) { - out(O_DEBUG, + out(O_VERB, "platform_get_files: " "skipping repeated name " "%s/%s", @@ -910,7 +910,7 @@ totlen = strlen(dirname[i]) + 1; totlen += strlen(dp->d_name) + 1; files[nfiles] = MALLOC(totlen); - out(O_DEBUG, "File %d: \"%s/%s\"", nfiles, + out(O_VERB, "File %d: \"%s/%s\"", nfiles, dirname[i], dp->d_name); (void) snprintf(files[nfiles++], totlen, "%s/%s", dirname[i], dp->d_name); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/Makefile --- a/usr/src/cmd/fm/modules/common/ext-event-transport/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -19,16 +19,22 @@ # 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. # MODULE = ext-event-transport CLASS = common -SRCS = fmevt_main.c fmevt_outbound.c +SRCS = fmevt_main.c \ + fmevt_outbound.c \ + fmevt_inbound.c \ + fmevt_inbound_default.c \ + fmevt_inbound_on.c \ + fmevt_inbound_smf.c \ + fmevt_inbound_sunos.c include ../../Makefile.plugin CFLAGS += $(INCS) LINTFLAGS += $(INCS) -LDLIBS += -lsysevent +LDLIBS += -L$(ROOTLIB)/fm -lsysevent -lfmevent -ltopo -luuid -lscf -lc +LDFLAGS += -R/usr/lib/fm diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/ext-event-transport.conf --- a/usr/src/cmd/fm/modules/common/ext-event-transport/ext-event-transport.conf Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/ext-event-transport.conf Fri Jul 30 17:04:17 2010 +1000 @@ -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. # # @@ -48,5 +47,4 @@ # Changing this list may lead to breakage and/or excessive event forwarding. # subscribe list.* -subscribe swevent.* - +subscribe ireport.* diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/fmevt.h --- a/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 _FMEVT_H @@ -35,10 +34,10 @@ extern "C" { #endif -#include +#include #include #include -#include +#include #include "../../../../../lib/fm/libfmevent/common/fmev_channels.h" @@ -48,8 +47,90 @@ extern void fmevt_init_outbound(fmd_hdl_t *); extern void fmevt_fini_outbound(fmd_hdl_t *); +extern void fmevt_init_inbound(fmd_hdl_t *); +extern void fmevt_fini_inbound(fmd_hdl_t *); + extern void fmevt_recv(fmd_hdl_t *, fmd_event_t *, nvlist_t *, const char *); + +/* + * Post-processing + */ + +/* + * Structure passed to a post-processing functions with details of the + * raw event. + */ +struct fmevt_ppargs { + const char *pp_rawclass; /* class from event publication */ + const char *pp_rawsubclass; /* subclass from event publication */ + hrtime_t pp_hrt; /* hrtime of event publication */ + int pp_user; /* userland or kernel source? */ + int pp_priv; /* privileged? */ + fmev_pri_t pp_pri; /* published priority */ + char pp_uuidstr[36 + 1]; /* uuid we'll use for first event */ +}; + +/* + * The maximum length that a protocol event class name generated + * in post-processing can be. + */ +#define FMEVT_MAX_CLASS 64 + +/* + * A post-processing function may derive up to this number of separate + * protocol events for each raw event. + */ +#define FMEVT_FANOUT_MAX 5 + +/* + * Post-processing function type. The function receives raw event + * details in the struct fmevt_ppargs. It must prepare up to + * FMEVT_FANOUT_MAX protocol events (usually just one event) + * based on the raw event, and return the number of events + * to be posted. The array of class pointers must have that + * number of non-NULL entries. You may return 0 to ditch an event; + * in this case the caller will not perform an frees so you must + * tidy up. + * + * The array of string pointers has the first member pointed to + * some storage of size FMEV_MAX_CLASS into which the post-processing + * function must render the protocol event classname. If fanning + * out into more than one event then the post-processing function + * must allocate additional buffers (using fmd_hdl_alloc) and return + * pointers to these in the array of string pointers (but do not change + * the first element); buffers allocated and returned in this way will + * be freed by the caller as it iterates over the protocol events to + * post them. Similarly the function must prepare an attributes + * nvlist for each event; it can return the raw attributes or it + * can fmd_nvl_alloc or fmd_nvl_dup and return those (to be freed + * by the caller). + * + * Events will be generated based on the results as follows: + * + * event[i] = + * + * timestamp = as supplied by incoming event and in pp_hrt + * class = class_array[i]; entry 0 is allocated, fmd_hdl_alloc others + * detector = generated detector as passed to function + * uuid = generated UUID, or that supplied by raw event + * attr = nvlist_array[i], can be absent; may return raw attributes + * + */ +typedef uint_t fmevt_pp_func_t( + char *[FMEVT_FANOUT_MAX], /* event class(es) */ + nvlist_t *[FMEVT_FANOUT_MAX], /* event attributes */ + const char *, /* ruleset */ + const nvlist_t *, /* detector */ + nvlist_t *, /* raw attributes */ + const struct fmevt_ppargs *); /* more raw event info */ + +extern fmevt_pp_func_t fmevt_pp_on_ereport; +extern fmevt_pp_func_t fmevt_pp_smf; +extern fmevt_pp_func_t fmevt_pp_on_sunos; +extern fmevt_pp_func_t fmevt_pp_on_private; +extern fmevt_pp_func_t fmevt_pp_unregistered; + #ifdef __cplusplus } #endif diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,658 @@ +/* + * 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. + */ + +/* + * Receive (on GPEC channels) raw events published by a few select producers + * using the private libfmevent publication interfaces, and massage those + * raw events into full protocol events. Each raw event selects a "ruleset" + * by which to perform the transformation into a protocol event. + * + * Only publication from userland running privileged is supported; two + * channels are used - one for high-value and one for low-value events. + * There is some planning in the implementation below for kernel hi and low + * value channels, and for non-privileged userland low and hi value channels. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fmevt.h" + +static struct fmevt_inbound_stats { + fmd_stat_t raw_callbacks; + fmd_stat_t raw_noattrlist; + fmd_stat_t raw_nodetector; + fmd_stat_t pp_bad_ruleset; + fmd_stat_t pp_explicitdrop; + fmd_stat_t pp_fallthrurule; + fmd_stat_t pp_fanoutmax; + fmd_stat_t pp_intldrop; + fmd_stat_t pp_badclass; + fmd_stat_t pp_nvlallocfail; + fmd_stat_t pp_nvlbuildfail; + fmd_stat_t pp_badreturn; + fmd_stat_t xprt_posted; +} inbound_stats = { + { "raw_callbacks", FMD_TYPE_UINT64, + "total raw event callbacks from producers" }, + { "raw_noattrlist", FMD_TYPE_UINT64, + "missing attribute list" }, + { "raw_nodetector", FMD_TYPE_UINT64, + "unable to add detector" }, + { "pp_bad_ruleset", FMD_TYPE_UINT64, + "post-process bad ruleset" }, + { "pp_explicitdrop", FMD_TYPE_UINT64, + "ruleset drops event with NULL func" }, + { "pp_fanoutmax", FMD_TYPE_UINT64, + "post-processing produced too many events" }, + { "pp_intldrop", FMD_TYPE_UINT64, + "post-processing requested event drop" }, + { "pp_badclass", FMD_TYPE_UINT64, + "post-processing produced invalid event class" }, + { "pp_nvlallocfail", FMD_TYPE_UINT64, + "fmd_nvl_alloc failed" }, + { "pp_nvlbuildfail", FMD_TYPE_UINT64, + "nvlist_add_foo failed in building event" }, + { "pp_badreturn", FMD_TYPE_UINT64, + "inconsistent number of events returned" }, + { "xprt_posted", FMD_TYPE_UINT64, + "protocol events posted with fmd_xprt_post" }, +}; + +static int isglobalzone; +static char zonename[ZONENAME_MAX]; + +#define BUMPSTAT(stat) inbound_stats.stat.fmds_value.ui64++ + +#define CBF_USER 0x1U +#define CBF_PRIV 0x2U +#define CBF_LV 0x4U +#define CBF_HV 0x8U +#define CBF_ALL (CBF_USER | CBF_PRIV | CBF_LV | CBF_HV) + +static struct fmevt_chaninfo { + const char *ci_propname; /* property to get channel name */ + evchan_t *ci_binding; /* GPEC binding for this channel */ + char ci_sid[MAX_SUBID_LEN]; /* subscriber id */ + uint32_t ci_cbarg; /* callback cookie */ + uint32_t ci_sflags; /* subscription flags to use */ +} chaninfo[] = { + { "user_priv_highval_channel", NULL, { 0 }, + CBF_USER | CBF_PRIV | CBF_HV, EVCH_SUB_KEEP }, + { "user_priv_lowval_channel", NULL, { 0 }, + CBF_USER | CBF_PRIV | CBF_LV, EVCH_SUB_KEEP }, +}; + +static pthread_cond_t fmevt_cv = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t fmevt_lock = PTHREAD_MUTEX_INITIALIZER; +static int fmevt_exiting; + +static fmd_xprt_t *fmevt_xprt; +static uint32_t fmevt_xprt_refcnt; +static sysevent_subattr_t *subattr; + +/* + * Rulesets we recognize and who handles them. Additions and changes + * must follow the Portfolio Review process. At ths time only + * the FMEV_RULESET_ON_SUNOS and FMEVT_RULESET_SMF rulesets are + * formally recognized by that process - the others here are experimental. + */ +static struct fmevt_rs { + char *rs_pat; + fmevt_pp_func_t *rs_ppfunc; + char *rs_namespace; + char *rs_subsys; +} rulelist[] = { + { FMEV_RULESET_SMF, fmevt_pp_smf }, + { FMEV_RULESET_ON_EREPORT, fmevt_pp_on_ereport }, + { FMEV_RULESET_ON_SUNOS, fmevt_pp_on_sunos }, + { FMEV_RULESET_ON_PRIVATE, fmevt_pp_on_private }, + { FMEV_RULESET_UNREGISTERED, fmevt_pp_unregistered } +}; + +/* + * Take a ruleset specification string and separate it into namespace + * and subsystem components. + */ +static int +fmevt_rs_burst(fmd_hdl_t *hdl, char *ruleset, char **nsp, char **subsysp, + boolean_t alloc) +{ + char *ns, *s; + size_t len; + + if (ruleset == NULL || *ruleset == '\0' || + strnlen(ruleset, FMEV_MAX_RULESET_LEN) == FMEV_MAX_RULESET_LEN) + return (0); + + if (alloc == B_FALSE) { + s = ruleset; + ns = strsep(&s, FMEV_RS_SEPARATOR); + + if (s == NULL || s == ns + 1) + return (0); + } else { + if ((s = strstr(ruleset, FMEV_RS_SEPARATOR)) == NULL || + s == ruleset + strlen(ruleset) - 1) + return (0); + + len = s - ruleset; + + ns = fmd_hdl_alloc(hdl, len + 1, FMD_SLEEP); + (void) strncpy(ns, ruleset, len); + ns[len] = '\0'; + + s++; + } + + if (nsp) + *nsp = ns; /* caller must free if alloc == B_TRUE */ + + if (subsysp) + *subsysp = s; /* always within original ruleset string */ + + return (1); +} + +static int +fmevt_rs_init(fmd_hdl_t *hdl) +{ + int i; + + for (i = 0; i < sizeof (rulelist) / sizeof (rulelist[0]); i++) { + struct fmevt_rs *rsp = &rulelist[i]; + + if (!fmevt_rs_burst(hdl, rsp->rs_pat, &rsp->rs_namespace, + &rsp->rs_subsys, B_TRUE)) + return (0); + } + + return (1); +} + +/* + * Construct a "sw" scheme detector FMRI. + * + * We make no use of priv or pri. + */ +/*ARGSUSED3*/ +static nvlist_t * +fmevt_detector(nvlist_t *attr, char *ruleset, int user, int priv, + fmev_pri_t pri) +{ + char buf[FMEV_MAX_RULESET_LEN + 1]; + char *ns, *subsys; + nvlist_t *obj, *dtcr, *site, *ctxt; + char *execname = NULL; + int32_t i32; + int64_t i64; + int err = 0; + char *str; + + (void) strncpy(buf, ruleset, sizeof (buf)); + if (!fmevt_rs_burst(NULL, buf, &ns, &subsys, B_FALSE)) + return (NULL); + + obj = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP); + dtcr = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP); + site = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP); + ctxt = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP); + + if (obj == NULL || dtcr == NULL || site == NULL || ctxt == NULL) { + err++; + goto done; + } + + /* + * Build up 'object' nvlist. + */ + if (nvlist_lookup_string(attr, "__fmev_execname", &execname) == 0) + err += nvlist_add_string(obj, FM_FMRI_SW_OBJ_PATH, execname); + + /* + * Build up 'site' nvlist. We should have source file and line + * number and, if the producer was compiled with C99, function name. + */ + if (nvlist_lookup_string(attr, "__fmev_file", &str) == 0) { + err += nvlist_add_string(site, FM_FMRI_SW_SITE_FILE, str); + (void) nvlist_remove(attr, "__fmev_file", DATA_TYPE_STRING); + } + + if (nvlist_lookup_string(attr, "__fmev_func", &str) == 0) { + err += nvlist_add_string(site, FM_FMRI_SW_SITE_FUNC, str); + (void) nvlist_remove(attr, "__fmev_func", DATA_TYPE_STRING); + } + + if (nvlist_lookup_int64(attr, "__fmev_line", &i64) == 0) { + err += nvlist_add_int64(site, FM_FMRI_SW_SITE_LINE, i64); + (void) nvlist_remove(attr, "__fmev_line", DATA_TYPE_INT64); + } + + /* + * Build up 'context' nvlist. We do not include contract id at + * this time. + */ + + err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_ORIGIN, + user ? "userland" : "kernel"); + + if (execname) { + err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_EXECNAME, + execname); + (void) nvlist_remove(attr, "__fmev_execname", DATA_TYPE_STRING); + } + + if (nvlist_lookup_int32(attr, "__fmev_pid", &i32) == 0) { + err += nvlist_add_int32(ctxt, FM_FMRI_SW_CTXT_PID, i32); + (void) nvlist_remove(attr, "__fmev_pid", DATA_TYPE_INT32); + } + + if (!isglobalzone) + err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_ZONE, zonename); + + /* Put it all together */ + + err += nvlist_add_uint8(dtcr, FM_VERSION, SW_SCHEME_VERSION0); + err += nvlist_add_string(dtcr, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SW); + err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_OBJ, obj); + err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_SITE, site); + err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_CTXT, ctxt); + +done: + if (obj != NULL) + nvlist_free(obj); + if (site != NULL) + nvlist_free(site); + if (ctxt != NULL) + nvlist_free(ctxt); + + if (err == 0) { + return (dtcr); + } else { + nvlist_free(dtcr); + return (NULL); + } +} + +static int +class_ok(char *class) +{ + static const char *approved[] = { + FM_IREPORT_CLASS ".", + FM_EREPORT_CLASS "." + }; + + int i; + + for (i = 0; i < sizeof (approved) / sizeof (approved[0]); i++) { + if (strncmp(class, approved[i], strlen(approved[i])) == 0) + return (1); + } + + return (0); +} + +static void +fmevt_postprocess(char *ruleset, nvlist_t *dtcr, nvlist_t *rawattr, + struct fmevt_ppargs *eap) +{ + uint_t expected = 0, processed = 0; + char rs2burst[FMEV_MAX_RULESET_LEN + 1]; + char *class[FMEVT_FANOUT_MAX]; + nvlist_t *attr[FMEVT_FANOUT_MAX]; + fmevt_pp_func_t *dispf = NULL; + char buf[FMEV_MAX_CLASS]; + char *ns, *subsys; + int i, found = 0; + uuid_t uu; + + (void) strncpy(rs2burst, ruleset, sizeof (rs2burst)); + if (!fmevt_rs_burst(NULL, rs2burst, &ns, &subsys, B_FALSE)) { + BUMPSTAT(pp_bad_ruleset); + return; + } + + /* + * Lookup a matching rule in our table. + */ + for (i = 0; i < sizeof (rulelist) / sizeof (rulelist[0]); i++) { + struct fmevt_rs *rsp = &rulelist[i]; + + if (*ns != '*' && *rsp->rs_namespace != '*' && + strcmp(ns, rsp->rs_namespace) != 0) + continue; + + if (*subsys != '*' && *rsp->rs_subsys != '*' && + strcmp(subsys, rsp->rs_subsys) != 0) + continue; + + dispf = rsp->rs_ppfunc; + found = 1; + break; + + } + + /* + * If a ruleset matches but specifies a NULL function then + * it's electing to drop the event. If no rule was matched + * then default to unregistered processing. + */ + if (dispf == NULL) { + if (found) { + BUMPSTAT(pp_explicitdrop); + return; + } else { + BUMPSTAT(pp_fallthrurule); + dispf = fmevt_pp_unregistered; + } + } + + /* + * Clear the arrays in which class strings and attribute + * nvlists can be returned. Pass a pointer to our stack buffer + * that the callee can use for the first event class (for others + * it must fmd_hdl_alloc and we'll free below). We will free + * and nvlists that are returned. + */ + bzero(class, sizeof (class)); + bzero(attr, sizeof (attr)); + class[0] = buf; + + /* + * Generate an event UUID which will be used for the first + * event generated by post-processing; if post-processing + * fans out into more than one event the additional events + * can reference this uuid (but we don't generate their + * UUIDs until later). + */ + uuid_generate(uu); + uuid_unparse(uu, eap->pp_uuidstr); + + /* + * Call selected post-processing function. See block comment + * in fmevt.h for a description of this process. + */ + expected = (*dispf)(class, attr, ruleset, + (const nvlist_t *)dtcr, rawattr, + (const struct fmevt_ppargs *)eap); + + if (expected > FMEVT_FANOUT_MAX) { + BUMPSTAT(pp_fanoutmax); + return; /* without freeing class and nvl - could leak */ + } else if (expected == 0) { + BUMPSTAT(pp_intldrop); + return; + } + + /* + * Post as many events as the callback completed. + */ + for (i = 0; i < FMEVT_FANOUT_MAX; i++) { + char uuidstr[36 + 1]; + char *uuidstrp; + nvlist_t *nvl; + int err = 0; + + if (class[i] == NULL) + continue; + + if (!class_ok(class[i])) { + BUMPSTAT(pp_badclass); + continue; + } + + if (processed++ == 0) { + uuidstrp = eap->pp_uuidstr; + } else { + uuid_generate(uu); + uuid_unparse(uu, uuidstr); + uuidstrp = uuidstr; + } + + if ((nvl = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP)) == NULL) { + BUMPSTAT(pp_nvlallocfail); + continue; + } + + err += nvlist_add_uint8(nvl, FM_VERSION, 0); + err += nvlist_add_string(nvl, FM_CLASS, (const char *)class[i]); + err += nvlist_add_string(nvl, FM_IREPORT_UUID, uuidstrp); + err += nvlist_add_nvlist(nvl, FM_IREPORT_DETECTOR, dtcr); + err += nvlist_add_string(nvl, FM_IREPORT_PRIORITY, + fmev_pri_string(eap->pp_pri) ? + fmev_pri_string(eap->pp_pri) : "?"); + + if (attr[i] != NULL) + err += nvlist_add_nvlist(nvl, FM_IREPORT_ATTRIBUTES, + attr[i]); + + /* + * If we post the event into fmd_xport_post then the + * transport code is responsible for freeing the nvl we + * posted. + */ + if (err == 0) { + fmd_xprt_post(fmevt_hdl, fmevt_xprt, nvl, + eap->pp_hrt); + } else { + BUMPSTAT(pp_nvlbuildfail); + nvlist_free(nvl); + } + } + + if (processed != expected) + BUMPSTAT(pp_badreturn); + + for (i = 0; i < FMEVT_FANOUT_MAX; i++) { + /* + * We provided storage for class[0] but any + * additional events have allocated a string. + */ + if (i > 0 && class[i] != NULL) + fmd_hdl_strfree(fmevt_hdl, class[i]); + + /* + * Free all attribute lists passed in if they are not + * just a pointer to the raw attributes + */ + if (attr[i] != NULL && attr[i] != rawattr) + nvlist_free(attr[i]); + } +} + +static int +fmevt_cb(sysevent_t *sep, void *arg) +{ + char *ruleset = NULL, *rawclass, *rawsubclass; + uint32_t cbarg = (uint32_t)arg; + nvlist_t *rawattr = NULL; + struct fmevt_ppargs ea; + nvlist_t *dtcr; + int user, priv; + fmev_pri_t pri; + + BUMPSTAT(raw_callbacks); + + if (cbarg & ~CBF_ALL) + fmd_hdl_abort(fmevt_hdl, "event receipt callback with " + "invalid flags\n"); + + user = (cbarg & CBF_USER) != 0; + priv = (cbarg & CBF_PRIV) != 0; + pri = (cbarg & CBF_HV ? FMEV_HIPRI : FMEV_LOPRI); + + (void) pthread_mutex_lock(&fmevt_lock); + + if (fmevt_exiting) { + while (fmevt_xprt_refcnt > 0) + (void) pthread_cond_wait(&fmevt_cv, &fmevt_lock); + (void) pthread_mutex_unlock(&fmevt_lock); + return (0); /* discard event */ + } + + fmevt_xprt_refcnt++; + (void) pthread_mutex_unlock(&fmevt_lock); + + ruleset = sysevent_get_vendor_name(sep); /* must free */ + rawclass = sysevent_get_class_name(sep); /* valid with sep */ + rawsubclass = sysevent_get_subclass_name(sep); /* valid with sep */ + + if (sysevent_get_attr_list(sep, &rawattr) != 0) { + BUMPSTAT(raw_noattrlist); + goto done; + } + + if ((dtcr = fmevt_detector(rawattr, ruleset, user, priv, + pri)) == NULL) { + BUMPSTAT(raw_nodetector); + goto done; + } + + ea.pp_rawclass = rawclass; + ea.pp_rawsubclass = rawsubclass; + sysevent_get_time(sep, &ea.pp_hrt); + ea.pp_user = user; + ea.pp_priv = priv; + ea.pp_pri = pri; + + fmevt_postprocess(ruleset, dtcr, rawattr, &ea); + nvlist_free(dtcr); +done: + (void) pthread_mutex_lock(&fmevt_lock); + + if (--fmevt_xprt_refcnt == 0 && fmevt_exiting) + (void) pthread_cond_broadcast(&fmevt_cv); + + (void) pthread_mutex_unlock(&fmevt_lock); + + if (ruleset) + free(ruleset); + + if (rawattr) + nvlist_free(rawattr); + + return (0); /* in all cases consider the event delivered */ +} + +void +fmevt_init_inbound(fmd_hdl_t *hdl) +{ + char *sidpfx; + zoneid_t zoneid; + int i; + + if (!fmevt_rs_init(hdl)) + fmd_hdl_abort(hdl, "error in fmevt_rs_init\n"); + + (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (inbound_stats) / + sizeof (fmd_stat_t), (fmd_stat_t *)&inbound_stats); + + zoneid = getzoneid(); + isglobalzone = (zoneid == GLOBAL_ZONEID); + if (getzonenamebyid(zoneid, zonename, sizeof (zonename)) == -1) + fmd_hdl_abort(hdl, "getzonenamebyid failed"); + + if ((subattr = sysevent_subattr_alloc()) == NULL) + fmd_hdl_abort(hdl, "failed to allocate subscription " + "attributes: %s"); + + sysevent_subattr_thrcreate(subattr, fmd_doorthr_create, NULL); + sysevent_subattr_thrsetup(subattr, fmd_doorthr_setup, NULL); + + sidpfx = fmd_prop_get_string(hdl, "sidprefix"); + fmevt_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL); + + for (i = 0; i < sizeof (chaninfo) / sizeof (chaninfo[0]); i++) { + struct fmevt_chaninfo *cip = &chaninfo[i]; + char *channel = fmd_prop_get_string(hdl, cip->ci_propname); + int err; + + if (sysevent_evc_bind(channel, &cip->ci_binding, + EVCH_CREAT | EVCH_HOLD_PEND_INDEF) != 0) + fmd_hdl_abort(hdl, "failed to bind GPEC channel for " + "channel %s", channel); + + (void) snprintf(cip->ci_sid, sizeof (cip->ci_sid), + "%s_%c%c%c", sidpfx, + cip->ci_cbarg & CBF_USER ? 'u' : 'k', + cip->ci_cbarg & CBF_PRIV ? 'p' : 'n', + cip->ci_cbarg & CBF_HV ? 'h' : 'l'); + + err = sysevent_evc_xsubscribe(cip->ci_binding, cip->ci_sid, + EC_ALL, fmevt_cb, (void *)cip->ci_cbarg, + cip->ci_sflags, subattr); + + if (err == EEXIST) + fmd_hdl_abort(hdl, "another fmd is active on " + "channel %s\n", channel); + else if (err != 0) + fmd_hdl_abort(hdl, "failed to subscribe to channel %s", + channel); + + fmd_prop_free_string(hdl, channel); + } + + fmd_prop_free_string(hdl, sidpfx); +} + +void +fmevt_fini_inbound(fmd_hdl_t *hdl) +{ + int i; + + for (i = 0; i < sizeof (chaninfo) / sizeof (chaninfo[0]); i++) { + struct fmevt_chaninfo *cip = &chaninfo[i]; + + if (cip->ci_binding) { + (void) sysevent_evc_unsubscribe(cip->ci_binding, + cip->ci_sid); + (void) sysevent_evc_unbind(cip->ci_binding); + cip->ci_binding = NULL; + } + } + + if (subattr) { + sysevent_subattr_free(subattr); + subattr = NULL; + } + + if (fmevt_xprt) { + /* drain before destruction */ + (void) pthread_mutex_lock(&fmevt_lock); + fmevt_exiting = 1; + while (fmevt_xprt_refcnt > 0) + (void) pthread_cond_wait(&fmevt_cv, &fmevt_lock); + (void) pthread_mutex_unlock(&fmevt_lock); + + fmd_xprt_close(hdl, fmevt_xprt); + } + +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound_default.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound_default.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,52 @@ +/* + * 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 "fmevt.h" + +/* + * Post-processing according to the FMEV_RULESET_UNREGISTERED ruleset. + * + * Generate a class of ireport.unregistered.. + * with attributes just those of the raw event. If either the raw + * class or subclass is NULL or empty then drop the event. + */ +/*ARGSUSED*/ +uint_t +fmevt_pp_unregistered(char *classes[FMEVT_FANOUT_MAX], + nvlist_t *attr[FMEVT_FANOUT_MAX], const char *ruleset, + const nvlist_t *detector, nvlist_t *rawattr, + const struct fmevt_ppargs *eap) +{ + if (eap->pp_rawclass == NULL || eap->pp_rawsubclass == NULL) + return (0); + + if (snprintf(classes[0], FMEVT_MAX_CLASS, "%s.%s.%s.%s", + FM_IREPORT_CLASS, "unregistered", + eap->pp_rawclass, eap->pp_rawsubclass) >= FMEVT_MAX_CLASS - 1) + return (0); + + attr[0] = rawattr; + return (1); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound_on.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound_on.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,76 @@ +/* + * 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 "fmevt.h" + +/* + * Post-processing according to the FMEV_RULESET_ON_EREPORT ruleset. + * Produce a single event of class ereport... + * If either the raw class or subclass is NULL, drop the event. + * The event will have the raw attributes. + */ +/*ARGSUSED*/ +uint_t +fmevt_pp_on_ereport(char *classes[FMEVT_FANOUT_MAX], + nvlist_t *attr[FMEVT_FANOUT_MAX], const char *ruleset, + const nvlist_t *detector, nvlist_t *rawattr, + const struct fmevt_ppargs *eap) +{ + if (eap->pp_rawclass == NULL || eap->pp_rawsubclass == NULL) + return (0); + + if (snprintf(classes[0], FMEVT_MAX_CLASS, "%s.%s.%s", FM_EREPORT_CLASS, + eap->pp_rawclass, eap->pp_rawsubclass) >= FMEVT_MAX_CLASS - 1) + return (0); + + attr[0] = rawattr; + return (1); +} + +/* + * Post-processing according to the FMEV_RULESET_ON_PRIVATE ruleset. + * Produce a single event of class + * ireport.private.solaris-osnet... + * If either the raw class or subclass is NULL, drop the event. + * The event will have the raw attributes. + */ +/*ARGSUSED*/ +uint_t +fmevt_pp_on_private(char *classes[FMEVT_FANOUT_MAX], + nvlist_t *attr[FMEVT_FANOUT_MAX], const char *ruleset, + const nvlist_t *detector, nvlist_t *rawattr, + const struct fmevt_ppargs *eap) +{ + if (eap->pp_rawclass == NULL || eap->pp_rawsubclass == NULL) + return (0); + + if (snprintf(classes[0], FMEVT_MAX_CLASS, "%s.%s.%s.%s", + FM_IREPORT_CLASS, "private.solaris-osnet", + eap->pp_rawclass, eap->pp_rawsubclass) >= FMEVT_MAX_CLASS - 1) + return (0); + + attr[0] = rawattr; + return (1); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound_smf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound_smf.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,194 @@ +/* + * 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 +#include +#include +#include +#include + +#include "fmevt.h" + +/* + * Post-processing according to the FMEV_RULESET_SMF ruleset. + * + * Raw event we expect: + * + * ========================================================================== + * Class: "state-transition" + * Subclasses: The new state, one of SCF_STATE_STRING_* from libscf.h + * Attr: + * Name DATA_TYPE_* Description + * ------------ --------------- --------------------------------------------- + * fmri STRING svc:/... (svc scheme shorthand version) + * transition INT32 (old_state << 16) | new_state + * reason-version UINT32 reason-short namespace version + * reason-short STRING Short/keyword reason for transition + * reason-long STRING Long-winded reason for the transition + * ========================================================================== + * + * Protocol event components we return: + * + * ========================================================================== + * Class: ireport.os.smf.state-transition. + * Attr: + * Name DATA_TYPE_* Description + * ------------ --------------- ---------------------------------------- + * svc NVLIST "svc" scheme FMRI of affected service instance + * svc-string STRING SMF FMRI in short string form svc:/foo/bar + * from-state STRING Previous state; SCF_STATE_STRING_* + * to-state STRING New state; SCF_STATE_STRING_* + * reason-version UINT32 reason-short namespace version + * reason-short STRING Short/keyword reason for transition + * reason-long STRING Long-winded reason for the transition + * ========================================================================== + */ + +/* + * svc.startd generates events using the FMRI shorthand (svc:/foo/bar) + * instead of the standard form (svc:///foo/bar). This function converts to + * the standard representation. The caller must free the allocated string. + */ +static char * +shortfmri_to_fmristr(fmd_hdl_t *hdl, const char *shortfmristr) +{ + size_t len; + char *fmristr; + + if (strncmp(shortfmristr, "svc:/", 5) != 0) + return (NULL); + + len = strlen(shortfmristr) + 3; + fmristr = fmd_hdl_alloc(hdl, len, FMD_SLEEP); + (void) snprintf(fmristr, len, "svc:///%s", shortfmristr + 5); + + return (fmristr); +} + +/* + * Convert a shorthand svc FMRI into a full svc FMRI nvlist + */ +static nvlist_t * +shortfmri_to_fmri(fmd_hdl_t *hdl, const char *shortfmristr) +{ + nvlist_t *ret, *fmri; + topo_hdl_t *thp; + char *fmristr; + int err; + + if ((fmristr = shortfmri_to_fmristr(hdl, shortfmristr)) == NULL) + return (NULL); + + thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION); + + if (topo_fmri_str2nvl(thp, fmristr, &fmri, &err) != 0) { + fmd_hdl_error(hdl, "failed to convert '%s' to nvlist\n", + fmristr); + fmd_hdl_strfree(hdl, fmristr); + fmd_hdl_topo_rele(hdl, thp); + return (NULL); + } + + fmd_hdl_strfree(hdl, fmristr); + + if ((ret = fmd_nvl_dup(hdl, fmri, FMD_SLEEP)) == NULL) { + fmd_hdl_error(hdl, "failed to dup fmri\n"); + nvlist_free(fmri); + fmd_hdl_topo_rele(hdl, thp); + return (NULL); + } + + nvlist_free(fmri); + fmd_hdl_topo_rele(hdl, thp); + + return (ret); +} + +/*ARGSUSED*/ +uint_t +fmevt_pp_smf(char *classes[FMEVT_FANOUT_MAX], + nvlist_t *attr[FMEVT_FANOUT_MAX], const char *ruleset, + const nvlist_t *detector, nvlist_t *rawattr, + const struct fmevt_ppargs *eap) +{ + int32_t transition, from, to; + const char *fromstr, *tostr; + char *svcname, *rsn, *rsnl; + nvlist_t *myattr; + nvlist_t *fmri; + uint32_t ver; + + if (!fmd_prop_get_int32(fmevt_hdl, "inbound_postprocess_smf")) + return (0); + + if (rawattr == NULL || + strcmp(eap->pp_rawclass, "state-transition") != 0 || + nvlist_lookup_string(rawattr, "fmri", &svcname) != 0 || + nvlist_lookup_int32(rawattr, "transition", &transition) != 0 || + nvlist_lookup_string(rawattr, "reason-short", &rsn) != 0 || + nvlist_lookup_string(rawattr, "reason-long", &rsnl) != 0 || + nvlist_lookup_uint32(rawattr, "reason-version", &ver) != 0) + return (0); + + from = transition >> 16; + to = transition & 0xffff; + + fromstr = smf_state_to_string(from); + tostr = smf_state_to_string(to); + + if (fromstr == NULL || tostr == NULL) + return (0); + + if (strcmp(eap->pp_rawsubclass, tostr) != 0) + return (0); + + if ((fmri = shortfmri_to_fmri(fmevt_hdl, svcname)) == NULL) + return (0); + + if (snprintf(classes[0], FMEVT_MAX_CLASS, "%s.%s.%s.%s", + FM_IREPORT_CLASS, "os.smf", eap->pp_rawclass, + eap->pp_rawsubclass) >= FMEVT_MAX_CLASS - 1) + return (0); + + if ((myattr = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP)) == NULL) + return (0); + + if (nvlist_add_nvlist(myattr, "svc", fmri) != 0 || + nvlist_add_string(myattr, "svc-string", svcname) != 0 || + nvlist_add_string(myattr, "from-state", fromstr) != 0 || + nvlist_add_string(myattr, "to-state", tostr) != 0 || + nvlist_add_uint32(myattr, "reason-version", ver) != 0 || + nvlist_add_string(myattr, "reason-short", rsn) != 0 || + nvlist_add_string(myattr, "reason-long", rsnl) != 0) { + nvlist_free(fmri); + nvlist_free(myattr); + return (0); + } + + attr[0] = myattr; + nvlist_free(fmri); + + return (1); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound_sunos.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_inbound_sunos.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,88 @@ +/* + * 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 +#include "fmevt.h" + +/* + * Support for the FMEV_RULESET_ON_SUNOS ruleset. + */ + +/* + * Panic events. + */ + +/*ARGSUSED*/ +static int +pp_sunos_panic(char *classes[FMEVT_FANOUT_MAX], + nvlist_t *attr[FMEVT_FANOUT_MAX], const char *ruleset, + const nvlist_t *detector, nvlist_t *rawattr, + const struct fmevt_ppargs *eap) + +{ + nvlist_t *myattr; + time_t panictime32; + int64_t panictime; + char buf[128]; + struct tm ts; + + if (strcmp(eap->pp_rawsubclass, "dump_pending_on_device") != 0 && + strcmp(eap->pp_rawsubclass, "savecore_failure") != 0 && + strcmp(eap->pp_rawsubclass, "dump_available") != 0) + return (0); + + if (snprintf(classes[0], FMEVT_MAX_CLASS, "%s.%s.%s", FM_IREPORT_CLASS, + "os.sunos.panic", eap->pp_rawsubclass) >= FMEVT_MAX_CLASS - 1) + return (0); + + if (nvlist_lookup_int64(rawattr, "crashtime", &panictime) != 0) + return (0); + + panictime32 = (time_t)panictime; + + myattr = fmd_nvl_dup(fmevt_hdl, rawattr, FMD_SLEEP); + + if (localtime_r(&panictime32, &ts) != NULL && + strftime(buf, sizeof (buf), "%c %Z", &ts) != 0) + (void) nvlist_add_string(myattr, "panic-time", buf); + + attr[0] = myattr; + return (1); +} + + +/*ARGSUSED*/ +uint_t +fmevt_pp_on_sunos(char *classes[FMEVT_FANOUT_MAX], + nvlist_t *attr[FMEVT_FANOUT_MAX], const char *ruleset, + const nvlist_t *detector, nvlist_t *rawattr, + const struct fmevt_ppargs *eap) +{ + if (strcmp(eap->pp_rawclass, "panic") == 0) + return (pp_sunos_panic(classes, attr, ruleset, + detector, rawattr, eap)); + + return (0); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_main.c --- a/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_main.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_main.c Fri Jul 30 17:04:17 2010 +1000 @@ -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. */ #include @@ -32,6 +31,12 @@ { "protocol_forward_disable", FMD_TYPE_BOOL, "false" }, { "outbound_channel", FMD_TYPE_STRING, FMD_SNOOP_CHANNEL }, { "outbound_channel_depth", FMD_TYPE_INT32, "256" }, + { "user_priv_highval_channel", FMD_TYPE_STRING, + FMEV_CHAN_USER_PRIV_HV }, + { "user_priv_lowval_channel", FMD_TYPE_STRING, + FMEV_CHAN_USER_PRIV_LV }, + { "sidprefix", FMD_TYPE_STRING, "fmd" }, + { "inbound_postprocess_smf", FMD_TYPE_BOOL, "true" }, { NULL, 0, NULL }, }; @@ -46,9 +51,11 @@ }; static const fmd_hdl_info_t fmd_info = { - "External FM event transport", "0.1", &fmd_ops, fmevt_props + "External FM event transport", "0.2", &fmd_ops, fmevt_props }; +fmd_hdl_t *fmevt_hdl; + void _fmd_init(fmd_hdl_t *hdl) { @@ -60,11 +67,15 @@ if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) return; + fmevt_hdl = hdl; + fmevt_init_outbound(hdl); + fmevt_init_inbound(hdl); } void _fmd_fini(fmd_hdl_t *hdl) { fmevt_fini_outbound(hdl); + fmevt_fini_inbound(hdl); } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_outbound.c --- a/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_outbound.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_outbound.c Fri Jul 30 17:04:17 2010 +1000 @@ -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. */ #include @@ -38,7 +37,7 @@ static struct fmevt_outbound_stats { fmd_stat_t recv_calls; fmd_stat_t recv_list; - fmd_stat_t recv_swevent; + fmd_stat_t recv_ireport; fmd_stat_t recv_other; fmd_stat_t fwd_success; fmd_stat_t fwd_failure; @@ -47,8 +46,8 @@ "total events received for forwarding" }, { "outbound_cat1class_list", FMD_TYPE_UINT64, "events received matching list.*" }, - { "outbound_cat1class_swevent", FMD_TYPE_UINT64, - "events received matching swevent.*" }, + { "outbound_cat1class_ireport", FMD_TYPE_UINT64, + "events received matching ireport.*" }, { "outbound_cat1class_other", FMD_TYPE_UINT64, "events of other classes" }, { "outbound_fwd_success", FMD_TYPE_UINT64, @@ -60,7 +59,7 @@ #define BUMPSTAT(stat) outbound_stats.stat.fmds_value.ui64++ /* - * In the .conf file we subscribe to list.* and swevent.* event classes. + * In the .conf file we subscribe to list.* and ireport.* event classes. * Any additions to that set could cause some unexpected behaviour. * For example adding fault.foo won't work (since we don't publish * faults directly but only within a list.suspect) but we will get @@ -74,8 +73,8 @@ if (strncmp(class, "list.", 5) == 0) BUMPSTAT(recv_list); - else if (strncmp(class, "swevent.", 8) == 0) - BUMPSTAT(recv_swevent); + else if (strncmp(class, "ireport.", 8) == 0) + BUMPSTAT(recv_ireport); else BUMPSTAT(recv_other); @@ -93,6 +92,7 @@ { int32_t channel_depth; char *channel_name; + nvlist_t *nvl; if (fmd_prop_get_int32(hdl, "protocol_forward_disable") == B_TRUE) { fmd_hdl_debug(hdl, "protocol forwarding disabled " @@ -122,8 +122,14 @@ fmd_hdl_abort(hdl, "Unable to set depth of channel %s to %d", channel_name, channel_depth); } + fmd_prop_free_string(hdl, channel_name); - fmd_prop_free_string(hdl, channel_name); + nvl = fmd_nvl_alloc(hdl, FMD_SLEEP); + (void) nvlist_add_nvlist(nvl, "fmdauth", + (nvlist_t *)fmd_hdl_fmauth(hdl)); + (void) sysevent_evc_setpropnvl(fmevt_outbound_chan, nvl); + nvlist_free(nvl); + } /*ARGSUSED*/ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sensor-transport/sensor_transport.c --- a/usr/src/cmd/fm/modules/common/sensor-transport/sensor_transport.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/sensor-transport/sensor_transport.c Fri Jul 30 17:04:17 2010 +1000 @@ -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. */ #include @@ -71,6 +70,9 @@ { "repairs", FMD_TYPE_UINT64, "auto repairs" } }; +static int st_check_component_complaints; +static int have_complained; + static int st_check_component(topo_hdl_t *thp, tnode_t *node, void *arg) { @@ -117,9 +119,12 @@ if (topo_method_invoke(node, TOPO_METH_SENSOR_FAILURE, TOPO_METH_SENSOR_FAILURE_VERSION, NULL, &nvl, &err) != 0) { if (err == ETOPO_METHOD_NOTSUP) { - fmd_hdl_debug(hdl, "Method %s not supported on %s=%d", - TOPO_METH_SENSOR_FAILURE, name, - topo_node_instance(node)); + st_check_component_complaints++; + if (!have_complained) { + fmd_hdl_debug(hdl, "Method %s not supported " + "on %s=%d", TOPO_METH_SENSOR_FAILURE, name, + topo_node_instance(node)); + } nvlist_free(rsrc); return (0); } @@ -271,6 +276,8 @@ return (0); } +int st_timeout_verbose = 0; + /*ARGSUSED*/ static void st_timeout(fmd_hdl_t *hdl, id_t id, void *data) @@ -281,7 +288,8 @@ topo_walk_t *twp; int err; - fmd_hdl_debug(hdl, "timeout: checking topology"); + if (st_timeout_verbose) + fmd_hdl_debug(hdl, "timeout: checking topology"); stp = fmd_hdl_getspecific(hdl); thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION); @@ -295,6 +303,9 @@ return; } + if (st_check_component_complaints) + have_complained++; + /* * Initialize values in our internal FRU list for this iteration of * sensor reads. Keep track of whether the FRU was faulted in the diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/snmp-trapgen/Makefile --- a/usr/src/cmd/fm/modules/common/snmp-trapgen/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -# -# 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 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# - -MODULE = snmp-trapgen -CLASS = common -SRCS = snmp.c -NETSNMPCONFS = fmd-trapgen.conf - -ROOTNETSNMPDIR = $(ROOT)/etc/net-snmp/snmp -ROOTNETSNMPCONFS = $(NETSNMPCONFS:%=$(ROOTNETSNMPDIR)/%) - -include ../../Makefile.plugin - -SNMPLIBS = -lnetsnmp -lnetsnmpagent -lfmd_msg -lint := SNMPLIBS = - -LDFLAGS += -L$(ROOT)/usr/lib/fm -R/usr/lib/fm -LINTFLAGS += -L$(ROOT)/usr/lib/fm -LDLIBS += $(SNMPLIBS) -lfmd_msg - -$(ROOTNETSNMPCONFS) := FILEMODE = 0600 - -$(ROOTNETSNMPDIR)/%: % - $(INS.file) - -install: $(ROOTNETSNMPCONFS) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/snmp-trapgen/fmd-trapgen.conf --- a/usr/src/cmd/fm/modules/common/snmp-trapgen/fmd-trapgen.conf Thu Jul 29 22:45:58 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -# -# 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 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# - -# -# Supplemental configuration for the snmp-trapgen FMA module. Normal -# configuration of this module should be made via trap sink directives -# in /etc/net-snmp/snmp/snmpd.conf, not in this file. See snmpd(4) and -# snmp_config(4). -# diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/snmp-trapgen/snmp-trapgen.conf --- a/usr/src/cmd/fm/modules/common/snmp-trapgen/snmp-trapgen.conf Thu Jul 29 22:45:58 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -# -# snmp-trapgen agent properties: -# diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/snmp-trapgen/snmp.c --- a/usr/src/cmd/fm/modules/common/snmp-trapgen/snmp.c Thu Jul 29 22:45:58 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,286 +0,0 @@ -/* - * 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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct stats { - fmd_stat_t bad_vers; - fmd_stat_t bad_code; - fmd_stat_t bad_uuid; - fmd_stat_t no_trap; -} snmp_stats = { - { "bad_vers", FMD_TYPE_UINT64, "event version is missing or invalid" }, - { "bad_code", FMD_TYPE_UINT64, "failed to compute url for code" }, - { "bad_uuid", FMD_TYPE_UINT64, "event uuid is too long to send" }, - { "no_trap", FMD_TYPE_UINT64, "trap generation suppressed" } -}; - -static fmd_msg_hdl_t *snmp_msghdl; /* handle for libfmd_msg */ -static int snmp_trapall; /* set to trap on all faults */ - -static const char SNMP_SUPPCONF[] = "fmd-trapgen"; - -/*ARGSUSED*/ -static void -send_trap(fmd_hdl_t *hdl, const char *uuid, const char *code, const char *url) -{ - static const oid sunFmProblemTrap_oid[] = { SUNFMPROBLEMTRAP_OID }; - const size_t sunFmProblemTrap_len = OID_LENGTH(sunFmProblemTrap_oid); - - static const oid sunFmProblemUUID_oid[] = - { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_UUID }; - static const oid sunFmProblemCode_oid[] = - { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_CODE }; - static const oid sunFmProblemURL_oid[] = - { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_URL }; - - const size_t sunFmProblem_base_len = OID_LENGTH(sunFmProblemUUID_oid); - - size_t uuid_len = strlen(uuid); - size_t var_len = sunFmProblem_base_len + 1 + uuid_len; - oid var_name[MAX_OID_LEN]; - int i; - - netsnmp_variable_list *notification_vars = NULL; - - /* - * The format of our trap varbinds' oids is as follows: - * - * +-----------------------+---+--------+----------+------+ - * | SUNFMPROBLEMTABLE_OID | 1 | column | uuid_len | uuid | - * +-----------------------+---+--------+----------+------+ - * \---- index ----/ - * - * A common mistake here is to send the trap with varbinds that - * do not contain the index. All the indices are the same, and - * all the oids are the same length, so the only thing we need to - * do for each varbind is set the table and column parts of the - * variable name. - */ - - if (var_len > MAX_OID_LEN) { - snmp_stats.bad_uuid.fmds_value.ui64++; - return; - } - - var_name[sunFmProblem_base_len] = (oid)uuid_len; - for (i = 0; i < uuid_len; i++) - var_name[i + sunFmProblem_base_len + 1] = (oid)uuid[i]; - - /* - * Ordinarily, we would need to add the OID of the trap itself - * to the head of the variable list; this is required by SNMP v2. - * However, send_enterprise_trap_vars does this for us as a part - * of converting between v1 and v2 traps, so we skip directly to - * the objects we're sending. - */ - - (void) memcpy(var_name, sunFmProblemUUID_oid, - sunFmProblem_base_len * sizeof (oid)); - (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len, - ASN_OCTET_STR, (uchar_t *)uuid, strlen(uuid)); - (void) memcpy(var_name, sunFmProblemCode_oid, - sunFmProblem_base_len * sizeof (oid)); - (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len, - ASN_OCTET_STR, (uchar_t *)code, strlen(code)); - (void) memcpy(var_name, sunFmProblemURL_oid, - sunFmProblem_base_len * sizeof (oid)); - (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len, - ASN_OCTET_STR, (uchar_t *)url, strlen(url)); - - /* - * This function is capable of sending both v1 and v2/v3 traps. - * Which is sent to a specific destination is determined by the - * configuration file(s). - */ - send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC, - sunFmProblemTrap_oid[sunFmProblemTrap_len - 1], - (oid *)sunFmProblemTrap_oid, sunFmProblemTrap_len - 2, - notification_vars); - - snmp_free_varbind(notification_vars); -} - -/*ARGSUSED*/ -static void -snmp_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) -{ - char *uuid, *code, *url; - boolean_t domsg; - uint8_t version; - - if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || - version > FM_SUSPECT_VERSION) { - fmd_hdl_debug(hdl, "invalid event version: %u\n", version); - snmp_stats.bad_vers.fmds_value.ui64++; - return; - } - - if (!snmp_trapall && nvlist_lookup_boolean_value(nvl, - FM_SUSPECT_MESSAGE, &domsg) == 0 && !domsg) { - fmd_hdl_debug(hdl, "%s requested no trap\n", class); - snmp_stats.no_trap.fmds_value.ui64++; - return; - } - - (void) nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid); - (void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &code); - - url = fmd_msg_getitem_nv(snmp_msghdl, NULL, nvl, FMD_MSG_ITEM_URL); - - if (url != NULL) { - send_trap(hdl, uuid, code, url); - free(url); - } else { - fmd_hdl_debug(hdl, "failed to format url for %s", uuid); - snmp_stats.bad_code.fmds_value.ui64++; - } -} - -static int -init_sma(void) -{ - int err; - - /* - * The only place we could possibly log is syslog, but the - * full agent doesn't normally log there. It would be confusing - * if this agent did so; therefore we disable logging entirely. - */ - snmp_disable_log(); - - /* - * Net-SNMP has a provision for reading an arbitrary number of - * configuration files. A configuration file is read if it has - * had any handlers registered for it, or if it's the value in - * of NETSNMP_DS_LIB_APPTYPE. Our objective here is to read - * both snmpd.conf and fmd-trapgen.conf. - */ - if ((err = netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, - NETSNMP_DS_AGENT_ROLE, 0 /* MASTER_AGENT */)) != SNMPERR_SUCCESS) - return (err); - - init_agent_read_config("snmpd"); - if ((err = netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, - NETSNMP_DS_LIB_APPTYPE, SNMP_SUPPCONF)) != SNMPERR_SUCCESS) - return (err); - if (register_app_config_handler("trapsink", snmpd_parse_config_trapsink, - snmpd_free_trapsinks, "host [community] [port]") == NULL) - return (SNMPERR_MALLOC); - if (register_app_config_handler("trap2sink", - snmpd_parse_config_trap2sink, NULL, "host [community] [port]") == - NULL) - return (SNMPERR_MALLOC); - if (register_app_config_handler("trapsess", snmpd_parse_config_trapsess, - NULL, "[snmpcmdargs] host") == NULL) - return (SNMPERR_MALLOC); - - init_traps(); - init_snmp(SNMP_SUPPCONF); - - return (SNMPERR_SUCCESS); -} - -static const fmd_prop_t fmd_props[] = { - { "url", FMD_TYPE_STRING, "http://sun.com/msg/" }, - { "trap_all", FMD_TYPE_BOOL, "false" }, - { NULL, 0, NULL } -}; - -static const fmd_hdl_ops_t fmd_ops = { - snmp_recv, /* fmdo_recv */ - NULL, /* fmdo_timeout */ - NULL, /* fmdo_close */ - NULL, /* fmdo_stats */ - NULL, /* fmdo_gc */ -}; - -static const fmd_hdl_info_t fmd_info = { - "SNMP Trap Generation Agent", "1.0", &fmd_ops, fmd_props -}; - -void -_fmd_init(fmd_hdl_t *hdl) -{ - char *rootdir, *urlbase; - - if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) - return; /* invalid data in configuration file */ - - (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (snmp_stats) / - sizeof (fmd_stat_t), (fmd_stat_t *)&snmp_stats); - - if (init_sma() != SNMPERR_SUCCESS) - fmd_hdl_abort(hdl, "snmp-trapgen agent initialization failed"); - - rootdir = fmd_prop_get_string(hdl, "fmd.rootdir"); - snmp_msghdl = fmd_msg_init(rootdir, FMD_MSG_VERSION); - fmd_prop_free_string(hdl, rootdir); - - if (snmp_msghdl == NULL) - fmd_hdl_abort(hdl, "failed to initialize libfmd_msg"); - - urlbase = fmd_prop_get_string(hdl, "url"); - (void) fmd_msg_url_set(snmp_msghdl, urlbase); - fmd_prop_free_string(hdl, urlbase); - - snmp_trapall = fmd_prop_get_int32(hdl, "trap_all"); - fmd_hdl_subscribe(hdl, FM_LIST_SUSPECT_CLASS); - fmd_hdl_subscribe(hdl, FM_LIST_REPAIRED_CLASS); - fmd_hdl_subscribe(hdl, FM_LIST_RESOLVED_CLASS); -} - -/*ARGSUSED*/ -void -_fmd_fini(fmd_hdl_t *hdl) -{ - fmd_msg_fini(snmp_msghdl); - - /* - * snmp_shutdown, which we would normally use here, calls free_slots, - * a callback that is supposed to tear down the pkcs11 state; however, - * it abuses C_Finalize, causing fmd to drop core on shutdown. Avoid - * this by shutting down the library piecemeal. - */ - snmp_store(SNMP_SUPPCONF); - snmp_alarm_unregister_all(); - (void) snmp_close_sessions(); - shutdown_mib(); - unregister_all_config_handlers(); - netsnmp_ds_shutdown(); -} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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. +# + +SUBDIRS = software-diagnosis software-response + +include ../../../Makefile.subdirs diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/Makefile.com --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -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. +# + +CMN_SRCS = common/sw_main_cmn.c + +SMF_CMN_SRCS = subsidiary/smf/smf_util.c +SMF_DE_SRCS = subsidiary/smf/smf_diag.c $(SMF_CMN_SRCS) +SMF_RP_SRCS = subsidiary/smf/smf_response.c $(SMF_CMN_SRCS) + +PANIC_DE_SRCS = subsidiary/panic/panic_diag.c diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/common/sw.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/common/sw.h Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,255 @@ +/* + * 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 + +#include +#include +#include +#include +#include + +/* + * We have two real fmd modules - software-diagnosis and software-response. + * Each hosts a number of subsidiary diagnosis engines and response agents, + * although these are not fmd modules as such (the intention is to avoid + * a proliferation of small C diagnosis and response modules). + * + * Subsidiary "modules" are not loaded as normal fmd modules are. Instead + * each of the real modules software-diagnosis and software-response includes + * an array listing the subsidiaries it hosts, and when the real module + * is loaded by fmd it iterates over this list to "load" subsidiaries by + * calling their nominated init function. + */ + +/* Maximum number of subsidiary "modules" */ +#define SW_SUB_MAX 10 + +/* Maximum number of supported timers across all subsidiaries */ +#define SW_TIMER_MAX 20 + +/* + * A subsidiary must perform fmd_hdl_subscribe calls for all events of + * interest to it. These are typically performed during its init + * function. All subscription callbacks funnel through the shared + * fmdo_recv entry point; that function walks through the dispatch list + * for each subsidiary and performs a callback for the first matching entry of + * each subsidiary. The init entry point for each subsidiary + * returns a pointer to an array of struct sw_disp applicable for that + * entity. + * + * Note that the framework does *not* perform any fmd_hdl_subscribe calls + * on behalf of the subsidiary - the swd_classpat member below is used + * in routing events, not in establishing subscriptions for them. A + * subsidiary can subscribe to say "ireport.foo.a" and "ireport.foo.b" + * but could elect to nominate a common handler for those via a single + * struct sw_disp with swd_classpat of "ireport.foo.*". + */ +typedef void sw_dispfunc_t(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, void *); + +struct sw_disp { + const char *swd_classpat; /* event classes to callback for */ + sw_dispfunc_t *swd_func; /* callback function */ + void *swd_arg; /* opaque argument to callback */ +}; + +/* + * A diagnosis or response subsidiary must provide a struct sw_subinfo with + * all its pertinent information; a pointer to this structure must be + * included in the array of struct sw_subinfo pointers in each of + * software-diagnosis and software-response. + * + * swsub_name + * This should be chosen to be unique to this subsidiary; + * by convention it should also be the name prefix used in any fmd + * buffers the subsidiary creates. + * + * swsub_casetype + * A diagnosis subsidiary solves cases using swde_case_* below, and it + * must specify in swsub_casetype the type of case it solves. A response + * subsidiary must specify SW_CASE_NONE here. A subsidiary may only solve + * at most one type of case, and no two subsidiaries must solve the same + * case type. We use the case type to associate a subsidiary owner of + * the fmd case that is really owned by the host module. + * + * swsub_init + * The initialization function for this subsidiary, akin to the + * _fmd_init in a traditional fmd module. This must not be NULL. + * + * When the host diagnosis/response module initializes the _fmd_init + * entry point will call the swsub_init function for each subsidiary + * in turn. The fmd handle has already been registered and timers are + * available for installation (see below); the swsub_init function must + * return a pointer to a NULL-terminated array of struct sw_disp + * describing the event dispatch preferences for that module, and fill + * an integer we pass with the number of entries in that array (including + * the terminating NULL entry). The swsub_init function also receives + * a subsidiary-unique id_t assigned by the framework that it should + * keep a note of for use in timer installation (see below); this id + * should not be persisted to checkpoint data. + * + * swsub_fini + * When the host module _fmd_fini is called it will call this function + * for each subsidiary. A subsidiary can specify NULL here. + * + * swsub_timeout + * This is the timeout function to call for expired timers installed by + * this subsidiary. See sw_timer_{install,remove} below. May be + * NULL if no timers are used by this subsidiary. + * + * swsub_case_close + * This function is called when a case "owned" by a subsidiary + * is the subject of an fmdo_close callback. Can be NULL, and + * must be NULL for a subsidiary with case type SW_CASE_NONE (such + * as a response subsidiary). + * + * swsub_case_verify + * This is called during _fmd_init of the host module. The host module + * iterates over all cases that it owns and calls the verify function + * for the real owner which may choose to close cases if they no longer + * apply. Can be NULL, and must be NULL for a subsidiary with case + * type SW_CASE_NONE. + */ + +/* + * sw_casetype values are persisted to checkpoints - do not change values. + */ +enum sw_casetype { + SW_CASE_NONE = 0x0ca5e000, + SW_CASE_SMF, + SW_CASE_PANIC +}; + +/* + * Returns for swsub_init. The swsub_fini entry point will only be + * called for subsidiaries that returned SW_SUB_INIT_SUCCESS on init. + */ +#define SW_SUB_INIT_SUCCESS 0 +#define SW_SUB_INIT_FAIL_VOLUNTARY 1 /* chose not to init */ +#define SW_SUB_INIT_FAIL_ERROR 2 /* error prevented init */ + +typedef void swsub_case_close_func_t(fmd_hdl_t *, fmd_case_t *); +typedef int sw_case_vrfy_func_t(fmd_hdl_t *, fmd_case_t *); + +struct sw_subinfo { + const char *swsub_name; + enum sw_casetype swsub_casetype; + int (*swsub_init)(fmd_hdl_t *, id_t, const struct sw_disp **, int *); + void (*swsub_fini)(fmd_hdl_t *); + void (*swsub_timeout)(fmd_hdl_t *, id_t, void *); + swsub_case_close_func_t *swsub_case_close; + sw_case_vrfy_func_t *swsub_case_verify; +}; + +/* + * List sw_subinfo for each subsidiary diagnosis and response "module" here + */ +extern const struct sw_subinfo smf_diag_info; +extern const struct sw_subinfo smf_response_info; +extern const struct sw_subinfo panic_diag_info; + +/* + * Timers - as per the fmd module API but with an additional id_t argument + * specifying the unique id of the subsidiary installing the timer (provided + * to the subsidiary in its swsub_init call). + */ +extern id_t sw_timer_install(fmd_hdl_t *, id_t, void *, fmd_event_t *, + hrtime_t); +extern void sw_timer_remove(fmd_hdl_t *, id_t, id_t); + +/* + * The software-diagnosis subsidiaries can open and solve cases; to do so + * they must use the following wrappers to the usual fmd module API case + * management functions. We need this so that a subsidiary can iterate + * over *its* cases (fmd_case_next would iterate over those of other + * subsidiaries), receive in the subsidiary a callback when a case it opened + * is closed, etc. The subsidiary can use other fmd module API members + * for case management, such as fmd_case_add_ereport. + * + * Each subsidiary opens cases of its own unique type, identified by + * the sw_casetype enumeration. The values used in this enumeration + * must never change - they are written to checkpoint state. + * + * swde_case_open + * Opens a new case of the correct subsidiary type for the given + * subsidiary id. If a uuid string is provided then open a case + * with that uuid using fmd_case_open_uuid, allowing case uuid + * to match some relevant uuid that was received in one of the + * events that has led us to open this case. + * + * If the subsidiarywishes to associate some persistent + * case data with the new case thenit can fmd_hdl_alloc and complete a + * suitably-packed serialization structure and include a pointer to it + * in the call to sw_case_open together with the structure size and + * structure version. The framework will create a new fmd buffer (named + * for you, based on the case type) and write the structure out to disk; + * when the module or fmd is restarted this structure is restored from + * disk for you and reassociated with the case - use swde_case_data to + * retrieve a pointer to it. + * + * swde_case_first, swde_case_next + * A subsidiary DE can iterate over its cases using swde_case_first and + * swde_case_next. For swde_case_first quote the subsidiary id; + * for swde_case_next quote the last case returned. + * + * swde_case_data + * Returns a pointer to the previously-serialized case data, and fills + * a uint32_t with the version of that serialized data. + * + * swde_case_data_write + * Whenever a subsidiary modifies its persistent data structure + * it must call swde_case_data_write to indicate that the associated + * fmd buffer is dirty and needs to be rewritten. + * + * swde_case_data_upgrade + * If the subsidiary ever revs its persistent structure it needs to call + * swde_case_data_upgrade to register the new version and structure size, + * and write the structure out to a reallocated fmd buffer; the old + * case data structure (if any) will be freed. A subsidiary may use + * this interface to migrate old persistence structures restored from + * checkpoint - swde_case_data will return a version number below the + * current. + */ + +extern fmd_case_t *swde_case_open(fmd_hdl_t *, id_t, char *, uint32_t, + void *, size_t); +extern fmd_case_t *swde_case_first(fmd_hdl_t *, id_t); +extern fmd_case_t *swde_case_next(fmd_hdl_t *, fmd_case_t *); +extern void *swde_case_data(fmd_hdl_t *, fmd_case_t *, uint32_t *); +extern void swde_case_data_write(fmd_hdl_t *, fmd_case_t *); +extern void swde_case_data_upgrade(fmd_hdl_t *, fmd_case_t *, uint32_t, + void *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _SW_H */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/common/sw_impl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/common/sw_impl.h Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,101 @@ +/* + * 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_IMPL_H +#define _SW_IMPL_H + +#include "sw.h" + +/* + * The common code between software-response and software-diagnosis + * needs somewhere to track the subsidaries that have "registered", + * their dispatch tables etc. In the _fmd_init of each module we + * call the shared sw_fmd_init code, and there we allocate a + * struct sw_modspecific and assign this as the fmd fodule-specific + * data with fmd_hdl_setspecific. + */ +struct sw_modspecific { + int swms_dispcnt; + const struct sw_subinfo *(*swms_subinfo)[SW_SUB_MAX]; + const struct sw_disp *(*swms_disptbl)[SW_SUB_MAX]; + pthread_mutex_t swms_timerlock; + struct { + int swt_state; /* slot in use? */ + id_t swt_timerid; /* fmd_timer_install result */ + id_t swt_ownerid; /* subsidiary owner id */ + } swms_timers[SW_TIMER_MAX]; +}; + +#define SW_TMR_INUSE 1 +#define SW_TMR_RMVD 0 +#define SW_TMR_UNTOUCHED -1 + +extern swsub_case_close_func_t *sw_sub_case_close_func(fmd_hdl_t *, + enum sw_casetype); +extern sw_case_vrfy_func_t *sw_sub_case_vrfy_func(fmd_hdl_t *, + enum sw_casetype); + +/* + * Software DE fmdo_close entry point. + */ +extern void swde_close(fmd_hdl_t *, fmd_case_t *); + +/* + * Shared functions for software-diagnosis and software-response fmd + * module implementation using shared code. Subsidiaries do not need + * to call these functions. + * + * sw_fmd_init is called from _fmd_init of the two modules, to do most of + * the real work of initializing the subsidiaries etc. + * + * sw_fmd_fini is called from _fmd_fini and calls the swsub_fini + * function of each subsidiary after uninstalling all timers. + * + * sw_recv is the fmdo_recv entry point; it checks the event against + * the dispatch table of each subsidiary and dispatches the first + * match for each module. + * + * sw_timeout is the fmdo_timeout entry point; it looks up the unique id_t + * of the subsidiary that installed the timer (via sw_timer_install in which + * the id is quoted) and calls the swsub_timeout function for that subsidiary. + * + * swde_case_init and swde_case_fini initialize and finalize the + * software-diagnosis case-tracking infrastructure; swde_case_init + * is responsible for unserializing case state. + * + * sw_id_to_casetype take a subsidiary id and returns the case type it + * registered with. + */ +extern int sw_fmd_init(fmd_hdl_t *, const fmd_hdl_info_t *, + const struct sw_subinfo *(*)[SW_SUB_MAX]); +extern void sw_fmd_fini(fmd_hdl_t *); +extern void sw_recv(fmd_hdl_t *, fmd_event_t *, nvlist_t *, const char *); +extern void sw_timeout(fmd_hdl_t *, id_t, void *); +extern void swde_case_init(fmd_hdl_t *); +extern void swde_case_fini(fmd_hdl_t *); + +enum sw_casetype sw_id_to_casetype(fmd_hdl_t *, id_t); + +#endif /* _SW_IMPL_H */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/common/sw_main_cmn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/common/sw_main_cmn.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,474 @@ +/* + * 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. + */ + +/* + * Code shared by software-diagnosis and software-response modules. + * The fmd module linkage info for the two modules lives in swde_main.c + * (for software-diagnosis) and swrp_main.c (for software-response). + */ + +#include "../common/sw_impl.h" + +/* + * Each subsidiary that is hosted is assigned a unique subsidiary id. These + * macros convert between the id of a subsidiary and the index used in keeping + * track of subsidiaries. Outside of this file these ids should remain + * opaque. + */ +#define ID2IDX(id) ((int)((id) & 0xff0000) >> 16) +#define IDX2ID(i) ((id_t)((i) << 16) | 0x1d000000) + +#define SUBIDVALID(msinfo, id) (((int)(id) & 0xff00ffff) == 0x1d000000 && \ + ID2IDX(id) < (msinfo)->swms_dispcnt) + +static struct { + fmd_stat_t sw_recv_total; + fmd_stat_t sw_recv_match; + fmd_stat_t sw_recv_callback; +} sw_stats = { + { "sw_recv_total", FMD_TYPE_UINT64, + "total events received" }, + { "sw_recv_match", FMD_TYPE_UINT64, + "events matching some subsidiary" }, + { "sw_recv_callback", FMD_TYPE_UINT64, + "callbacks to all subsidiaries" }, +}; + +#define BUMPSTAT(stat) sw_stats.stat.fmds_value.ui64++ +#define BUMPSTATN(stat, n) sw_stats.stat.fmds_value.ui64 += (n) + +/* + * ========================== Event Receipt ================================= + * + * The fmdo_recv entry point. See which sub de/response agents have a + * matching subscription and callback for the first match from each. + * The sub de/response agents should dispatch *all* their subscriptions + * via their registered dispatch table, including things like list.repaired. + */ +void +sw_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) +{ + struct sw_modspecific *msinfo; + int calls = 0; + int mod; + + BUMPSTAT(sw_recv_total); + + msinfo = (struct sw_modspecific *)fmd_hdl_getspecific(hdl); + + /* + * For each sub module that has a matching class pattern call the + * registered callback for that sub DE. Only one match per sub module + * is allowed (the first match in its table, others are not checked). + */ + for (mod = 0; mod < msinfo->swms_dispcnt; mod++) { + const struct sw_disp *dp; + sw_dispfunc_t *dispf = NULL; + + for (dp = (*msinfo->swms_disptbl)[mod]; + dp != NULL && dp->swd_classpat != NULL; dp++) { + if (fmd_nvl_class_match(hdl, nvl, dp->swd_classpat)) { + dispf = dp->swd_func; + break; + } + } + if (dispf != NULL) { + calls++; + (*dispf)(hdl, ep, nvl, class, dp->swd_arg); + } + } + + BUMPSTAT(sw_recv_match); + if (calls) + BUMPSTATN(sw_recv_callback, calls); +} + +/* + * ========================== Timers ======================================== + * + * A subsidiary can install a timer; it must pass an additional argument + * identifying itself so that we can hand off to the appropriate + * swsub_timeout function in the fmdo_timeout entry point when the timer fires. + */ +id_t +sw_timer_install(fmd_hdl_t *hdl, id_t who, void *arg, fmd_event_t *ep, + hrtime_t hrt) +{ + struct sw_modspecific *msinfo; + const struct sw_subinfo **subinfo; + const struct sw_subinfo *sip; + int slot, chosen = -1; + id_t timerid; + + msinfo = (struct sw_modspecific *)fmd_hdl_getspecific(hdl); + if (!SUBIDVALID(msinfo, who)) + fmd_hdl_abort(hdl, "sw_timer_install: invalid subid %d\n", who); + + subinfo = *msinfo->swms_subinfo; + sip = subinfo[ID2IDX(who)]; + + if (sip-> swsub_timeout == NULL) + fmd_hdl_abort(hdl, "sw_timer_install: no swsub_timeout\n"); + + /* + * Look for a slot. Module entry points are single-threaded + * in nature, but if someone installs a timer from a door + * service function we're contended. + */ + (void) pthread_mutex_lock(&msinfo->swms_timerlock); + for (slot = 0; slot < SW_TIMER_MAX; slot++) { + if (msinfo->swms_timers[slot].swt_state != SW_TMR_INUSE) { + chosen = slot; + break; + } + } + + if (chosen == -1) + fmd_hdl_abort(hdl, "timer slots exhausted\n"); + + msinfo->swms_timers[chosen].swt_state = SW_TMR_INUSE; + msinfo->swms_timers[chosen].swt_ownerid = who; + msinfo->swms_timers[chosen].swt_timerid = timerid = + fmd_timer_install(hdl, arg, ep, hrt); + + (void) pthread_mutex_unlock(&msinfo->swms_timerlock); + + return (timerid); +} + +/* + * Look for a timer installed by a given subsidiary matching timerid. + */ +static int +subtimer_find(struct sw_modspecific *msinfo, id_t who, id_t timerid) +{ + int slot; + + for (slot = 0; slot < SW_TIMER_MAX; slot++) { + if (msinfo->swms_timers[slot].swt_state == SW_TMR_INUSE && + (who == -1 || + msinfo->swms_timers[slot].swt_ownerid == who) && + msinfo->swms_timers[slot].swt_timerid == timerid) + return (slot); + } + + return (-1); +} + +void +sw_timer_remove(fmd_hdl_t *hdl, id_t who, id_t timerid) +{ + struct sw_modspecific *msinfo; + const struct sw_subinfo **subinfo; + const struct sw_subinfo *sip; + int slot; + + msinfo = (struct sw_modspecific *)fmd_hdl_getspecific(hdl); + if (!SUBIDVALID(msinfo, who)) + fmd_hdl_abort(hdl, "sw_timer_remove: invalid subid\n"); + + subinfo = *msinfo->swms_subinfo; + sip = subinfo[ID2IDX(who)]; + + (void) pthread_mutex_lock(&msinfo->swms_timerlock); + if ((slot = subtimer_find(msinfo, who, timerid)) == -1) + fmd_hdl_abort(hdl, "sw_timer_remove: timerid %d not found " + "for %s\n", timerid, sip->swsub_name); + fmd_timer_remove(hdl, timerid); + msinfo->swms_timers[slot].swt_state = SW_TMR_RMVD; + (void) pthread_mutex_unlock(&msinfo->swms_timerlock); +} + +/* + * The fmdo_timeout entry point. + */ +void +sw_timeout(fmd_hdl_t *hdl, id_t timerid, void *arg) +{ + struct sw_modspecific *msinfo; + const struct sw_subinfo **subinfo; + const struct sw_subinfo *sip; + id_t owner; + int slot; + + msinfo = (struct sw_modspecific *)fmd_hdl_getspecific(hdl); + + (void) pthread_mutex_lock(&msinfo->swms_timerlock); + if ((slot = subtimer_find(msinfo, -1, timerid)) == -1) + fmd_hdl_abort(hdl, "sw_timeout: timerid %d not found\n"); + (void) pthread_mutex_unlock(&msinfo->swms_timerlock); + + owner = msinfo->swms_timers[slot].swt_ownerid; + if (!SUBIDVALID(msinfo, owner)) + fmd_hdl_abort(hdl, "sw_timeout: invalid subid\n"); + + subinfo = *msinfo->swms_subinfo; + sip = subinfo[ID2IDX(owner)]; + + sip->swsub_timeout(hdl, timerid, arg); +} + +/* + * ========================== sw_subinfo access ============================= + */ + +enum sw_casetype +sw_id_to_casetype(fmd_hdl_t *hdl, id_t who) +{ + struct sw_modspecific *msinfo; + const struct sw_subinfo **subinfo; + const struct sw_subinfo *sip; + + msinfo = (struct sw_modspecific *)fmd_hdl_getspecific(hdl); + if (!SUBIDVALID(msinfo, who)) + fmd_hdl_abort(hdl, "sw_id_to_casetype: invalid subid %d\n", + who); + + subinfo = *msinfo->swms_subinfo; + sip = subinfo[ID2IDX(who)]; + + if ((sip->swsub_casetype & SW_CASE_NONE) != SW_CASE_NONE) + fmd_hdl_abort(hdl, "sw_id_to_casetype: bad case type %d " + "for %s\n", sip->swsub_casetype, sip->swsub_name); + + return (sip->swsub_casetype); +} + +/* + * Given a case type lookup the struct sw_subinfo for the subsidiary + * that opens cases of that type. + */ +static const struct sw_subinfo * +sw_subinfo_bycase(fmd_hdl_t *hdl, enum sw_casetype type) +{ + struct sw_modspecific *msinfo; + const struct sw_subinfo **subinfo; + const struct sw_subinfo *sip; + int i; + + msinfo = (struct sw_modspecific *)fmd_hdl_getspecific(hdl); + + subinfo = *msinfo->swms_subinfo; + for (i = 0; i < SW_SUB_MAX; i++) { + sip = subinfo[i]; + if (sip->swsub_casetype == type) + return (sip); + } + + return (NULL); +} + +/* + * Find the case close function for the given case type; can be NULL. + */ +swsub_case_close_func_t * +sw_sub_case_close_func(fmd_hdl_t *hdl, enum sw_casetype type) +{ + const struct sw_subinfo *sip; + + if ((sip = sw_subinfo_bycase(hdl, type)) == NULL) + fmd_hdl_abort(hdl, "sw_sub_case_close_func: case type " + "%d not found\n", type); + + return (sip->swsub_case_close); +} + +/* + * Find the case verify function for the given case type; can be NULL. + */ +sw_case_vrfy_func_t * +sw_sub_case_vrfy_func(fmd_hdl_t *hdl, enum sw_casetype type) +{ + const struct sw_subinfo *sip; + + if ((sip = sw_subinfo_bycase(hdl, type)) == NULL) + fmd_hdl_abort(hdl, "sw_sub_case_vrfy_func: case type " + "%d not found\n", type); + + return (sip->swsub_case_verify); +} + +/* + * ========================== Initialization ================================ + * + * The two modules - software-diagnosis and software-response - call + * sw_fmd_init from their _fmd_init entry points. + */ + +static void +sw_add_callbacks(fmd_hdl_t *hdl, const char *who, + const struct sw_disp *dp, int nelem, struct sw_modspecific *msinfo) +{ + int i; + + (*msinfo->swms_disptbl)[msinfo->swms_dispcnt++] = dp; + + if (dp == NULL) + return; /* subsidiary failed init */ + + /* check that the nelem'th entry is the NULL termination */ + if (dp[nelem - 1].swd_classpat != NULL || + dp[nelem - 1].swd_func != NULL || dp[nelem - 1].swd_arg != NULL) + fmd_hdl_abort(hdl, "subsidiary %s dispatch table not NULL-" + "terminated\n", who); + + /* now validate the entries; we allow NULL handlers */ + for (i = 0; i < nelem - 1; i++) { + if (dp[i].swd_classpat == NULL) + fmd_hdl_abort(hdl, "subsidiary %s dispatch table entry " + "%d has a NULL pattern or function\n", who, i); + } + +} + +int +sw_fmd_init(fmd_hdl_t *hdl, const fmd_hdl_info_t *hdlinfo, + const struct sw_subinfo *(*subsid)[SW_SUB_MAX]) +{ + struct sw_modspecific *msinfo; + int i; + + if (fmd_hdl_register(hdl, FMD_API_VERSION, hdlinfo) != 0) + return (0); + + if (fmd_prop_get_int32(hdl, "enable") != B_TRUE) { + fmd_hdl_debug(hdl, "%s disabled though .conf file setting\n", + hdlinfo->fmdi_desc); + fmd_hdl_unregister(hdl); + return (0); + } + + msinfo = fmd_hdl_zalloc(hdl, sizeof (*msinfo), FMD_SLEEP); + + msinfo->swms_subinfo = subsid; + msinfo->swms_disptbl = fmd_hdl_zalloc(hdl, + SW_SUB_MAX * sizeof (struct sw_disp *), FMD_SLEEP); + + (void) pthread_mutex_init(&msinfo->swms_timerlock, NULL); + + for (i = 0; i < SW_TIMER_MAX; i++) + msinfo->swms_timers[i].swt_state = SW_TMR_UNTOUCHED; + + fmd_hdl_setspecific(hdl, (void *)msinfo); + + (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (sw_stats) / + sizeof (fmd_stat_t), (fmd_stat_t *)&sw_stats); + + /* + * Initialize subsidiaries. Each must make any subscription + * requests it needs and return a pointer to a NULL-terminated + * callback dispatch table and an indication of the number of + * entries in that table including the NULL termination entry. + */ + for (i = 0; i < SW_SUB_MAX; i++) { + const struct sw_subinfo *sip = (*subsid)[i]; + const struct sw_disp *dp; + char dbgbuf[80]; + int nelem = -1; + int initrslt; + + if (!sip || sip->swsub_name == NULL) + break; + + initrslt = (*sip->swsub_init)(hdl, IDX2ID(i), &dp, &nelem); + + (void) snprintf(dbgbuf, sizeof (dbgbuf), + "subsidiary %d (id 0x%lx) '%s'", + i, IDX2ID(i), sip->swsub_name); + + switch (initrslt) { + case SW_SUB_INIT_SUCCESS: + if (dp == NULL || nelem < 1) + fmd_hdl_abort(hdl, "%s returned dispatch " + "table 0x%p and nelem %d\n", + dbgbuf, dp, nelem); + + fmd_hdl_debug(hdl, "%s initialized\n", dbgbuf); + sw_add_callbacks(hdl, sip->swsub_name, dp, nelem, + msinfo); + break; + + case SW_SUB_INIT_FAIL_VOLUNTARY: + fmd_hdl_debug(hdl, "%s chose not to initialize\n", + dbgbuf); + sw_add_callbacks(hdl, sip->swsub_name, NULL, -1, + msinfo); + break; + + case SW_SUB_INIT_FAIL_ERROR: + fmd_hdl_debug(hdl, "%s failed to initialize " + "because of an error\n", dbgbuf); + sw_add_callbacks(hdl, sip->swsub_name, NULL, -1, + msinfo); + break; + + default: + fmd_hdl_abort(hdl, "%s returned out-of-range result " + "%d\n", dbgbuf, initrslt); + break; + } + } + + return (1); +} + +void +sw_fmd_fini(fmd_hdl_t *hdl) +{ + const struct sw_subinfo **subinfo; + struct sw_modspecific *msinfo; + int i; + + msinfo = (struct sw_modspecific *)fmd_hdl_getspecific(hdl); + subinfo = *msinfo->swms_subinfo; + + (void) pthread_mutex_lock(&msinfo->swms_timerlock); + for (i = 0; i < SW_TIMER_MAX; i++) { + if (msinfo->swms_timers[i].swt_state != SW_TMR_INUSE) + continue; + + fmd_timer_remove(hdl, msinfo->swms_timers[i].swt_timerid); + msinfo->swms_timers[i].swt_state = SW_TMR_RMVD; + } + (void) pthread_mutex_unlock(&msinfo->swms_timerlock); + + (void) pthread_mutex_destroy(&msinfo->swms_timerlock); + + for (i = 0; i < msinfo->swms_dispcnt; i++) { + const struct sw_subinfo *sip = subinfo[i]; + + if ((*msinfo->swms_disptbl)[i] == NULL) + continue; /* swsub_init did not succeed */ + + if (sip->swsub_fini != NULL) + (*sip->swsub_fini)(hdl); + } + + fmd_hdl_free(hdl, msinfo->swms_disptbl, + SW_SUB_MAX * sizeof (struct sw_disp *)); + + fmd_hdl_setspecific(hdl, NULL); + fmd_hdl_free(hdl, msinfo, sizeof (*msinfo)); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/software-diagnosis/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/software-diagnosis/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,51 @@ +# +# 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. +# + +MODULE = software-diagnosis +CLASS = common + +include ../Makefile.com + +# +# Sources for the primary software-diagnosis module +# +SWDE_SRCS = swde_main.c swde_case.c + +# +# Sources for subsidiary diagnosis "modules" that we host. These should +# be listed in ../Makefile.com +# +SUBDE_SRCS = $(SMF_DE_SRCS) $(PANIC_DE_SRCS) + +# +# All sources for softtware-diagnosis +# +SRCS = $(SWDE_SRCS) $(CMN_SRCS:%=../%) $(SUBDE_SRCS:%=../%) + +include ../../../Makefile.plugin + +CFLAGS += $(INCS) +LINTFLAGS += $(INCS) +LDLIBS += -L$(ROOTLIB)/fm -ltopo -luutil -luuid -lkstat +LDFLAGS += -R/usr/lib/fm diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/software-diagnosis/software-diagnosis.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/software-diagnosis/software-diagnosis.conf Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,36 @@ +# +# 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. +# + +# +# Configuration for the software-diagnosis diagnosis engine. +# + +# +# Dictionaries in use by software-diagnosis. The SMF dictionary *must* +# be listed before the SUNOS dictionary so that the smf maintenance +# defect is found in SMF instead of SUNOS. +# + +dictionary SMF +dictionary SUNOS diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/software-diagnosis/swde_case.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/software-diagnosis/swde_case.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,368 @@ +/* + * 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 +#include + +#include "../common/sw_impl.h" + +/* + * We maintain a single list of all active cases across all + * subsidary diagnosis "modules". We also offer some serialization + * services to them. + * + * To open a new case a subsidiary engine should use swde_case_open + * indicating the subsidiary id (from which we lookup the enum sw_casetype) + * and, optionally, a pointer to a structure for serialization and its size. + * + * For each case opened with swde_case_open we maintain an swde_case_t + * structure in-core. Embedded in this is the swde_case_data_t with + * information we need to keep track of and manage this case - it's + * case type, buffer name used for the sub-de-private data (if any) + * and the size of the sub-de-private structure. It is this + * embedded structure which is serialized as the "casedata" buffer, + * while the subsidiary-private structure is serialized into another buffer + * "casedata_". + * + * The subsidiary-private data structure, if any, is required to start + * with a uint32_t recording the data structure version. This + * version is also specified as an argument to swde_case_open, and + * we note it in the "casedata" buffer we write out and require + * a match on restore. + * + * When we unserialize we restore our management structure as well as + * the sub-de-private structure. + * + * Here's how serialization works: + * + * In swde_case_open we create a case data buffer for the case named + * SW_CASE_DATA_BUFNAME. We write the buffer out after filling in the + * structure version and recording the type of case this is, and if there + * is data for the subsidiary then we call swde_subdata to note the + * size and version of that data in the case data buf and then to create + * and write the subdata in a buffer named SW_CASE_DATA_BUFNAME_. + * + * If the subsidiary updates its case data it is required to call + * swde_case_data_write. This just calls fmd_buf_write for the subsidiary + * buffer name. + * + * A subsidiary can retrieve its private data buffer for a case using + * swde_case_data. This also fills a uint32_t with the version of the + * buffer that we have for this subsidiary; if that is an old version + * the subsidiary can cast appropriately and/or upgrade the buffer as + * below. + * + * When the host module is reloaded it calls swde_case_init to iterate + * through all cases we own. For each we call swde_case_unserialize + * which restores our case tracking data and any subsidiary-private + * data that our case data notes. We then call swde_case_verify which + * calls any registered verify function in the subsidiary owner, and if this + * returns 0 the case is closed. + * + * After initial write, we don't usually have to update the + * SW_CASE_DATA_BUFNAME buffer unless the subsidiary changes the size or + * version of its private buffer. To do that the subsidiary must call + * swde_case_data_upgrade. In that function we destroy the old subsidiary + * buffer and, if there is still a subsidiary data structure, create a + * new buffer appropriately sized and call swde_subdata to write it out + * after updating our case structure with new size etc. Finally we write + * out our updated case data structure. + */ + +#define SW_CASE_DATA_BUFNAME "casedata" + +#define SW_CASE_DATA_VERSION_INITIAL 1 +#define SW_CASE_DATA_BUFNAMELEN 18 /* 8 + 1 + 8 + 1 */ +typedef struct swde_case_data { + uint32_t sc_version; /* buffer structure version */ + int32_t sc_type; /* enum sw_casetype */ + uint32_t sc_sub_bufvers; /* version expected in subsidiary */ + char sc_sub_bufname[SW_CASE_DATA_BUFNAMELEN]; /* subsidiary bufname */ + int32_t sc_sub_bufsz; /* subsidiary structure size */ +} swde_case_data_t; + +#define SW_CASE_DATA_VERSION SW_CASE_DATA_VERSION_INITIAL + +/* + * In-core case structure. + */ +typedef struct swde_case { + fmd_case_t *swc_fmdcase; /* fmd case handle */ + swde_case_data_t swc_data; /* case data for serialization */ + void *swc_subdata; /* subsidiary data for serialization */ +} swde_case_t; + +static void +swde_case_associate(fmd_hdl_t *hdl, fmd_case_t *cp, swde_case_t *scp, + void *subdata) +{ + scp->swc_fmdcase = cp; + scp->swc_subdata = subdata; + fmd_case_setspecific(hdl, cp, scp); +} + +static void +swde_case_unserialize(fmd_hdl_t *hdl, fmd_case_t *cp) +{ + swde_case_t *scp; + swde_case_data_t *datap; + void *subdata; + size_t sz; + + scp = fmd_hdl_zalloc(hdl, sizeof (*scp), FMD_SLEEP); + datap = &scp->swc_data; + + fmd_buf_read(hdl, cp, SW_CASE_DATA_BUFNAME, datap, sizeof (*datap)); + + if (datap->sc_version > SW_CASE_DATA_VERSION_INITIAL) { + fmd_hdl_free(hdl, scp, sizeof (*scp)); + return; + } + + if ((sz = datap->sc_sub_bufsz) != 0) { + subdata = fmd_hdl_alloc(hdl, sz, FMD_SLEEP); + fmd_buf_read(hdl, cp, datap->sc_sub_bufname, subdata, sz); + + if (*((uint32_t *)subdata) != datap->sc_sub_bufvers) { + fmd_hdl_abort(hdl, "unserialize: expected subdata " + "version %u but received %u\n", + datap->sc_sub_bufvers, *((uint32_t *)subdata)); + } + } + + swde_case_associate(hdl, cp, scp, subdata); +} + +static void +swde_subdata(fmd_hdl_t *hdl, fmd_case_t *cp, enum sw_casetype type, + swde_case_t *scp, uint32_t subdata_vers, void *subdata, size_t subdata_sz) +{ + swde_case_data_t *datap = &scp->swc_data; + + if (*((uint32_t *)subdata) != subdata_vers) + fmd_hdl_abort(hdl, "swde_subdata: subdata version " + "does not match argument\n"); + + (void) snprintf(datap->sc_sub_bufname, sizeof (datap->sc_sub_bufname), + "%s_%08x", SW_CASE_DATA_BUFNAME, type); + + datap->sc_sub_bufsz = subdata_sz; + datap->sc_sub_bufvers = subdata_vers; + fmd_buf_create(hdl, cp, datap->sc_sub_bufname, subdata_sz); + fmd_buf_write(hdl, cp, datap->sc_sub_bufname, subdata, subdata_sz); +} + +fmd_case_t * +swde_case_open(fmd_hdl_t *hdl, id_t who, char *req_uuid, + uint32_t subdata_vers, void *subdata, size_t subdata_sz) +{ + enum sw_casetype ct = sw_id_to_casetype(hdl, who); + swde_case_data_t *datap; + swde_case_t *scp; + fmd_case_t *cp; + + if (ct == SW_CASE_NONE) + fmd_hdl_abort(hdl, "swde_case_open for type SW_CASE_NONE\n"); + + if (subdata != NULL && subdata_sz <= sizeof (uint32_t) || + subdata_sz != 0 && subdata == NULL) + fmd_hdl_abort(hdl, "swde_case_open: bad subdata\n", ct); + + scp = fmd_hdl_zalloc(hdl, sizeof (*scp), FMD_SLEEP); + datap = &scp->swc_data; + + if (req_uuid == NULL) { + cp = fmd_case_open(hdl, (void *)scp); + } else { + cp = fmd_case_open_uuid(hdl, req_uuid, (void *)scp); + if (cp == NULL) { + fmd_hdl_free(hdl, scp, sizeof (*scp)); + return (NULL); + } + } + + fmd_buf_create(hdl, cp, SW_CASE_DATA_BUFNAME, sizeof (*datap)); + datap->sc_version = SW_CASE_DATA_VERSION_INITIAL; + datap->sc_type = ct; + + if (subdata) + swde_subdata(hdl, cp, ct, scp, subdata_vers, subdata, + subdata_sz); + + fmd_buf_write(hdl, cp, SW_CASE_DATA_BUFNAME, datap, sizeof (*datap)); + swde_case_associate(hdl, cp, scp, subdata); + + return (cp); +} + +/* + * fmdo_close entry point for software-diagnosis + */ +void +swde_close(fmd_hdl_t *hdl, fmd_case_t *cp) +{ + swde_case_t *scp = fmd_case_getspecific(hdl, cp); + swde_case_data_t *datap = &scp->swc_data; + swsub_case_close_func_t *closefunc; + + if ((closefunc = sw_sub_case_close_func(hdl, datap->sc_type)) != NULL) + closefunc(hdl, cp); + + /* + * Now that the sub-de has had a chance to clean up, do some ourselves. + * Note that we free the sub-de-private subdata structure. + */ + + if (scp->swc_subdata) { + fmd_hdl_free(hdl, scp->swc_subdata, datap->sc_sub_bufsz); + fmd_buf_destroy(hdl, cp, datap->sc_sub_bufname); + } + + fmd_buf_destroy(hdl, cp, SW_CASE_DATA_BUFNAME); + + fmd_hdl_free(hdl, scp, sizeof (*scp)); +} + +fmd_case_t * +swde_case_first(fmd_hdl_t *hdl, id_t who) +{ + enum sw_casetype ct = sw_id_to_casetype(hdl, who); + swde_case_t *scp; + fmd_case_t *cp; + + if (ct == SW_CASE_NONE) + fmd_hdl_abort(hdl, "swde_case_first for type SW_CASE_NONE\n"); + + for (cp = fmd_case_next(hdl, NULL); cp; cp = fmd_case_next(hdl, cp)) { + scp = fmd_case_getspecific(hdl, cp); + if (scp->swc_data.sc_type == ct) + break; + } + + return (cp); +} + +fmd_case_t * +swde_case_next(fmd_hdl_t *hdl, fmd_case_t *lastcp) +{ + swde_case_t *scp; + fmd_case_t *cp; + int ct; + + if (lastcp == NULL) + fmd_hdl_abort(hdl, "swde_case_next called for NULL lastcp\n"); + + scp = fmd_case_getspecific(hdl, lastcp); + ct = scp->swc_data.sc_type; + + cp = lastcp; + while ((cp = fmd_case_next(hdl, cp)) != NULL) { + scp = fmd_case_getspecific(hdl, cp); + if (scp->swc_data.sc_type == ct) + break; + } + + return (cp); +} + +void * +swde_case_data(fmd_hdl_t *hdl, fmd_case_t *cp, uint32_t *svp) +{ + swde_case_t *scp = fmd_case_getspecific(hdl, cp); + swde_case_data_t *datap = &scp->swc_data; + + if (svp != NULL && scp->swc_subdata) + *svp = datap->sc_sub_bufvers; + + return (scp->swc_subdata); +} + +void +swde_case_data_write(fmd_hdl_t *hdl, fmd_case_t *cp) +{ + swde_case_t *scp = fmd_case_getspecific(hdl, cp); + swde_case_data_t *datap = &scp->swc_data; + + if (scp->swc_subdata == NULL) + return; + + fmd_buf_write(hdl, cp, scp->swc_data.sc_sub_bufname, + scp->swc_subdata, datap->sc_sub_bufsz); +} + +void +swde_case_data_upgrade(fmd_hdl_t *hdl, fmd_case_t *cp, uint32_t subdata_vers, + void *subdata, size_t subdata_sz) +{ + swde_case_t *scp = fmd_case_getspecific(hdl, cp); + swde_case_data_t *datap = &scp->swc_data; + + if (scp->swc_subdata) { + fmd_buf_destroy(hdl, cp, datap->sc_sub_bufname); + fmd_hdl_free(hdl, scp->swc_subdata, datap->sc_sub_bufsz); + scp->swc_subdata = NULL; + datap->sc_sub_bufsz = 0; + datap->sc_sub_bufname[0] = '\0'; + } + + if (subdata != NULL) { + scp->swc_subdata = subdata; + swde_subdata(hdl, cp, datap->sc_type, scp, subdata_vers, + subdata, subdata_sz); + } + + fmd_buf_write(hdl, scp->swc_fmdcase, SW_CASE_DATA_BUFNAME, + datap, sizeof (*datap)); +} + +static void +swde_case_verify(fmd_hdl_t *hdl, fmd_case_t *cp) +{ + swde_case_t *scp = fmd_case_getspecific(hdl, cp); + swde_case_data_t *datap = &scp->swc_data; + sw_case_vrfy_func_t *vrfy_func; + + if ((vrfy_func = sw_sub_case_vrfy_func(hdl, datap->sc_type)) != NULL) { + if (vrfy_func(hdl, cp) == 0) + fmd_case_close(hdl, cp); + } +} + +void +swde_case_init(fmd_hdl_t *hdl) +{ + fmd_case_t *cp; + + for (cp = fmd_case_next(hdl, NULL); cp; cp = fmd_case_next(hdl, cp)) { + swde_case_unserialize(hdl, cp); + swde_case_verify(hdl, cp); + } +} + +/*ARGSUSED*/ +void +swde_case_fini(fmd_hdl_t *hdl) +{ +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/software-diagnosis/swde_main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/software-diagnosis/swde_main.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,67 @@ +/* + * 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 "../common/sw_impl.h" + +static const fmd_prop_t swde_props[] = { + { "enable", FMD_TYPE_BOOL, "true" }, + { NULL, 0, NULL } +}; + +static const fmd_hdl_ops_t swde_ops = { + sw_recv, /* fmdo_recv - provided by common code */ + sw_timeout, /* fmdo_timeout - provided by common code */ + swde_close, /* fmdo_close */ + NULL, /* fmdo_stats */ + NULL, /* fmdo_gc */ + NULL, /* fmdo_send */ + NULL /* fmdo_topo */ +}; + +const fmd_hdl_info_t swde_info = { + "Software Diagnosis engine", "0.1", &swde_ops, swde_props +}; + +/* + * Subsidiary diagnosis "modules" that we host. + */ +static const struct sw_subinfo *subde[SW_SUB_MAX] = { + &smf_diag_info, + &panic_diag_info +}; + +void +_fmd_init(fmd_hdl_t *hdl) +{ + if (sw_fmd_init(hdl, &swde_info, &subde)) + swde_case_init(hdl); +} + +void +_fmd_fini(fmd_hdl_t *hdl) +{ + swde_case_fini(hdl); + sw_fmd_fini(hdl); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/software-response/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/software-response/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,41 @@ +# +# 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. +# + +MODULE = software-response +CLASS = common + +include ../Makefile.com + +SWRP_SRCS = swrp_main.c + +SUBRP_SRCS = $(SMF_RP_SRCS) + +SRCS = $(SWRP_SRCS) $(CMN_SRCS:%=../%) $(SUBRP_SRCS:%=../%) + +include ../../../Makefile.plugin + +CFLAGS += $(INCS) +LINTFLAGS += $(INCS) +LDLIBS += -L$(ROOTLIB)/fm -ltopo -lscf +LDFLAGS += -R/usr/lib/fm diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/software-response/software-response.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/software-response/software-response.conf Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,29 @@ +# +# 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. +# + +# +# Configuration for the software-diagnosis diagnosis engine. +# + +subscribe list.repaired diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/software-response/swrp_main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/software-response/swrp_main.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,64 @@ +/* + * 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 "../common/sw_impl.h" + +static const fmd_prop_t swrp_props[] = { + { "enable", FMD_TYPE_BOOL, "true" }, + { NULL, 0, NULL } +}; + +static const fmd_hdl_ops_t swrp_ops = { + sw_recv, /* fmdo_recv - provided by common code */ + sw_timeout, /* fmdo_timeout */ + NULL, /* fmdo_close */ + NULL, /* fmdo_stats */ + NULL, /* fmdo_gc */ + NULL, /* fmdo_send */ + NULL /* fmdo_topo */ +}; + +const fmd_hdl_info_t swrp_info = { + "Software Response Agent", "0.1", &swrp_ops, swrp_props +}; + +/* + * Subsidiary response "modules" that we host. + */ +static const struct sw_subinfo *subrp[SW_SUB_MAX] = { + &smf_response_info, +}; + +void +_fmd_init(fmd_hdl_t *hdl) +{ + (void) sw_fmd_init(hdl, &swrp_info, &subrp); +} + +void +_fmd_fini(fmd_hdl_t *hdl) +{ + sw_fmd_fini(hdl); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/panic/panic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/panic/panic.h Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,45 @@ +/* + * 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 _PANIC_H +#define _PANIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SW_SUNOS_PANIC_DETECTED "ireport.os.sunos.panic.dump_pending_on_device" +#define SW_SUNOS_PANIC_FAILURE "ireport.os.sunos.panic.savecore_failure" +#define SW_SUNOS_PANIC_AVAIL "ireport.os.sunos.panic.dump_available" + +#define SW_SUNOS_PANIC_DEFECT "defect.sunos.kernel.panic" + +extern char *sw_panic_fmri2str(fmd_hdl_t *, nvlist_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _PANIC_H */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/panic/panic_diag.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/panic/panic_diag.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,591 @@ +/* + * 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. + */ + +/* + * Panic software-diagnosis subsidiary + * + * We model a system panic as a defect diagnosis in FMA. When a system + * panicks, savecore publishes events which we subscribe to here. + * + * Our driving events are all raised by savecore, run either from + * startup of the dumpadm service or interactively at the command line. + * The following describes the logic for the handling of these events. + * + * On reboot after panic we will run savecore as part of the dumpadm + * service startup; we run savecore even if savecore is otherwise + * disabled (ie dumpadm -n in effect) - we run savecore -c to check for + * a valid dump and raise the initial event. + * + * If savecore (or savecore -c) observes a valid dump pending on the + * device, it raises a "dump_pending_on_device" event provided this + * was not an FMA-initiated panic (for those we will replay ereports + * from the dump device as usual and make a diagnosis from those; we do + * not need to open a case for the panic). We subscribe to the + * "dump_pending_on_device" event and use that to open a case; we + * open a case requesting the same case uuid as the panic dump image + * has for the OS instance uuid - if that fails because of a duplicate + * uuid then we have already opened a case for this panic so no need + * to open another. + * + * Included in the "dump_pending_on_device" event is an indication of + * whether or not dumpadm is enabled. If not (dumpadm -n in effect) + * then we do not expect any further events regarding this panic + * until such time as the admin runs savecore manually (if ever). + * So in this case we solve the case immediately after open. If/when + * subsequent events arrive when savecore is run manually, we will toss + * them. + * + * If dumpadm is enabled then savecore, run from dumpadm service startup, + * will attempt to process the dump - either to copy it off the dump + * device (if saving compressed) or to uncompress it off the dump device. + * If this succeeds savecore raises a "dump_available" event which + * includes information on the directory it was saved in, the instance + * number, image uuid, compressed form or not, and whether the dump + * was complete (as per the dumphdr). If the savecore fails for + * some reason then it exits and raises a "savecore_failure" event. + * These two events are raised even for FMA-initiated panics. + * + * We subscribe to both the "dump_available" and "savecore_failed" events, + * and in the handling thereof we will close the case opened earlier (if + * this is not an FMA-initiated panic). On receipt of the initial + * "dump_available" event we also arm a timer for +10 minutes if + * dumpadm is enabled - if no "dump_available" or "savecore_failed" arrives + * in that time we will solve the case on timeout. + * + * When the timer fires we check whether the initial event for each panic + * case was received more than 30 minutes ago; if it was we solve the case + * with what we have. If we're still within the waiting period we rearm + * for a further 10 minutes. The timer is shared by all cases that we + * create, which is why the fire interval is shorter than the maximum time + * we are prepared to wait. + */ + +#include +#include +#include +#include + +#include "../../common/sw.h" +#include "panic.h" + +#define MAX_STRING_LEN 160 + +static id_t myid; + +static id_t mytimerid; + +/* + * Our serialization structure type. + */ +#define SWDE_PANIC_CASEDATA_VERS 1 + +typedef struct swde_panic_casedata { + uint32_t scd_vers; /* must be first member */ + uint64_t scd_receive_time; /* when we first knew of this panic */ + size_t scd_nvlbufsz; /* size of following buffer */ + /* packed attr nvlist follows */ +} swde_panic_casedata_t; + +static struct { + fmd_stat_t swde_panic_diagnosed; + fmd_stat_t swde_panic_badclass; + fmd_stat_t swde_panic_noattr; + fmd_stat_t swde_panic_unexpected_fm_panic; + fmd_stat_t swde_panic_badattr; + fmd_stat_t swde_panic_badfmri; + fmd_stat_t swde_panic_noinstance; + fmd_stat_t swde_panic_nouuid; + fmd_stat_t swde_panic_dupuuid; + fmd_stat_t swde_panic_nocase; + fmd_stat_t swde_panic_notime; + fmd_stat_t swde_panic_nopanicstr; + fmd_stat_t swde_panic_nodumpdir; + fmd_stat_t swde_panic_nostack; + fmd_stat_t swde_panic_incomplete; + fmd_stat_t swde_panic_failed; + fmd_stat_t swde_panic_basecasedata; + fmd_stat_t swde_panic_failsrlz; +} swde_panic_stats = { + { "swde_panic_diagnosed", FMD_TYPE_UINT64, + "panic defects published" }, + { "swde_panic_badclass", FMD_TYPE_UINT64, + "incorrect event class received" }, + { "swde_panic_noattr", FMD_TYPE_UINT64, + "malformed event - missing attr nvlist" }, + { "swde_panic_unexpected_fm_panic", FMD_TYPE_UINT64, + "dump available for an fm_panic()" }, + { "swde_panic_badattr", FMD_TYPE_UINT64, + "malformed event - invalid attr list" }, + { "swde_panic_badfmri", FMD_TYPE_UINT64, + "malformed event - fmri2str fails" }, + { "swde_panic_noinstance", FMD_TYPE_UINT64, + "malformed event - no instance number" }, + { "swde_panic_nouuid", FMD_TYPE_UINT64, + "malformed event - missing uuid" }, + { "swde_panic_dupuuid", FMD_TYPE_UINT64, + "duplicate events received" }, + { "swde_panic_nocase", FMD_TYPE_UINT64, + "case missing for uuid" }, + { "swde_panic_notime", FMD_TYPE_UINT64, + "missing crash dump time" }, + { "swde_panic_nopanicstr", FMD_TYPE_UINT64, + "missing panic string" }, + { "swde_panic_nodumpdir", FMD_TYPE_UINT64, + "missing crashdump save directory" }, + { "swde_panic_nostack", FMD_TYPE_UINT64, + "missing panic stack" }, + { "swde_panic_incomplete", FMD_TYPE_UINT64, + "missing panic incomplete" }, + { "swde_panic_failed", FMD_TYPE_UINT64, + "missing panic failed" }, + { "swde_panic_badcasedata", FMD_TYPE_UINT64, + "bad case data during timeout" }, + { "swde_panic_failsrlz", FMD_TYPE_UINT64, + "failures to serialize case data" }, +}; + +#define BUMPSTAT(stat) swde_panic_stats.stat.fmds_value.ui64++ + +static nvlist_t * +panic_sw_fmri(fmd_hdl_t *hdl, char *object) +{ + nvlist_t *fmri; + nvlist_t *sw_obj; + int err = 0; + + fmri = fmd_nvl_alloc(hdl, FMD_SLEEP); + err |= nvlist_add_uint8(fmri, FM_VERSION, FM_SW_SCHEME_VERSION); + err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SW); + + sw_obj = fmd_nvl_alloc(hdl, FMD_SLEEP); + err |= nvlist_add_string(sw_obj, FM_FMRI_SW_OBJ_PATH, object); + err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_OBJ, sw_obj); + if (sw_obj) + nvlist_free(sw_obj); + if (!err) + return (fmri); + else + return (0); +} + +static const char *dumpfiles[2] = { "unix.%lld", "vmcore.%lld" }; +static const char *dumpfiles_comp[2] = { "vmdump.%lld", NULL}; + +static void +swde_panic_solve(fmd_hdl_t *hdl, fmd_case_t *cp, + nvlist_t *attr, fmd_event_t *ep, boolean_t savecore_success) +{ + char *dumpdir, *path, *uuid; + nvlist_t *defect, *rsrc; + nvpair_t *nvp; + int i; + + /* + * Attribute members to include in event-specific defect + * payload. Some attributes will not be present for some + * cases - e.g., if we timed out and solved the case without + * a "dump_available" report. + */ + const char *toadd[] = { + "os-instance-uuid", /* same as case uuid */ + "panicstr", /* for initial classification work */ + "panicstack", /* for initial classification work */ + "crashtime", /* in epoch time */ + "panic-time", /* Formatted crash time */ + }; + + if (ep != NULL) + fmd_case_add_ereport(hdl, cp, ep); + /* + * As a temporary solution we create and fmri in the sw scheme + * in panic_sw_fmri. This should become a generic fmri constructor + * + * We need to user a resource FMRI which will have a sufficiently + * unique string representation such that fmd will not see + * repeated panic diagnoses (all using the same defect class) + * as duplicates and discard later cases. We can't actually diagnose + * the panic to anything specific (e.g., a path to a module and + * function/line etc therein). We could pick on a generic + * representative such as /kernel/genunix but that could lead + * to misunderstanding. So we choose a path based on + * and the OS instance UUID - "/.". + * There's no file at that path (*) but no matter. We can't use + * /vmdump.N or similar because if savecore is disabled + * or failed we don't have any file or instance number. + * + * (*) Some day it would seem tidier to keep all files to do + * with a single crash (unix/vmcore/vmdump, analysis output etc) + * in a distinct directory, and /. seems like a good + * choice. For compatability we'd symlink into it. So that is + * another reason for this choice - some day it may exist! + */ + (void) nvlist_lookup_string(attr, "dumpdir", &dumpdir); + (void) nvlist_lookup_string(attr, "os-instance-uuid", &uuid); + path = alloca(strlen(dumpdir) + 1 + 1 + 36 + 1); + /* LINTED: E_SEC_SPRINTF_UNBOUNDED_COPY */ + (void) sprintf(path, "%s/.%s", dumpdir, uuid); + rsrc = panic_sw_fmri(hdl, path); + + defect = fmd_nvl_create_defect(hdl, SW_SUNOS_PANIC_DEFECT, + 100, rsrc, NULL, rsrc); + nvlist_free(rsrc); + + (void) nvlist_add_boolean_value(defect, "savecore-succcess", + savecore_success); + + if (savecore_success) { + boolean_t compressed; + int64_t instance; + const char **pathfmts; + char buf[2][32]; + int files = 0; + char *arr[2]; + int i; + + (void) nvlist_lookup_int64(attr, "instance", &instance); + (void) nvlist_lookup_boolean_value(attr, "compressed", + &compressed); + + pathfmts = compressed ? &dumpfiles_comp[0] : &dumpfiles[0]; + + for (i = 0; i < 2; i++) { + if (pathfmts[i] == NULL) { + arr[i] = NULL; + continue; + } + + (void) snprintf(buf[i], 32, pathfmts[i], instance); + arr[i] = buf[i]; + files++; + } + + (void) nvlist_add_string(defect, "dump-dir", dumpdir); + (void) nvlist_add_string_array(defect, "dump-files", arr, + files); + } else { + char *rsn; + + if (nvlist_lookup_string(attr, "failure-reason", &rsn) == 0) + (void) nvlist_add_string(defect, "failure-reason", rsn); + } + + /* + * Not all attributes will necessarily be available - eg if + * dumpadm was not enabled there'll be no instance and dumpdir. + */ + for (i = 0; i < sizeof (toadd) / sizeof (toadd[0]); i++) { + if (nvlist_lookup_nvpair(attr, toadd[i], &nvp) == 0) + (void) nvlist_add_nvpair(defect, nvp); + } + + fmd_case_add_suspect(hdl, cp, defect); + fmd_case_solve(hdl, cp); + + /* + * Close the case. Do no free casedata - framework does that for us + * on closure callback. + */ + fmd_case_close(hdl, cp); + BUMPSTAT(swde_panic_diagnosed); +} + +/*ARGSUSED*/ +static void +swde_panic_timeout(fmd_hdl_t *hdl, id_t timerid, void *data) +{ + fmd_case_t *cp = swde_case_first(hdl, myid); + swde_panic_casedata_t *cdp; + time_t now = time(NULL); + nvlist_t *attr; + int remain = 0; + uint32_t vers; + + while (cp != NULL) { + cdp = swde_case_data(hdl, cp, &vers); + if (vers != SWDE_PANIC_CASEDATA_VERS) + fmd_hdl_abort(hdl, "case data version confused\n"); + + if (now > cdp->scd_receive_time + 30 * 60) { + if (nvlist_unpack((char *)cdp + sizeof (*cdp), + cdp->scd_nvlbufsz, &attr, 0) == 0) { + swde_panic_solve(hdl, cp, attr, NULL, B_FALSE); + nvlist_free(attr); + } else { + BUMPSTAT(swde_panic_basecasedata); + fmd_case_close(hdl, cp); + } + } else { + remain++; + } + + + cp = swde_case_next(hdl, cp); + } + + if (remain) { + mytimerid = sw_timer_install(hdl, myid, NULL, NULL, + 10ULL * NANOSEC * 60); + } +} + +/* + * Our verify entry point is called for each of our open cases during + * module load. We must return 0 for the case to be closed by our caller, + * or 1 to keep it (or if we have already closed it during this call). + */ +static int +swde_panic_vrfy(fmd_hdl_t *hdl, fmd_case_t *cp) +{ + swde_panic_casedata_t *cdp; + time_t now = time(NULL); + nvlist_t *attr; + uint32_t vers; + + cdp = swde_case_data(hdl, cp, &vers); + + if (vers != SWDE_PANIC_CASEDATA_VERS) + return (0); /* case will be closed */ + + if (now > cdp->scd_receive_time + 30 * 60) { + if (nvlist_unpack((char *)cdp + sizeof (*cdp), + cdp->scd_nvlbufsz, &attr, 0) == 0) { + swde_panic_solve(hdl, cp, attr, NULL, B_FALSE); + nvlist_free(attr); + return (1); /* case already closed */ + } else { + return (0); /* close case */ + } + } + + if (mytimerid != 0) + mytimerid = sw_timer_install(hdl, myid, + NULL, NULL, 10ULL * NANOSEC * 60); + + return (1); /* retain case */ +} + +/* + * Handler for ireport.os.sunos.panic.dump_pending_on_device. + * + * A future RFE should try adding a means of avoiding diagnosing repeated + * defects on panic loops, which would just add to the mayhem and potentially + * log lots of calls through ASR. Panics with similar enough panic + * strings and/or stacks should not diagnose to new defects with some + * period of time, for example. + */ + +/*ARGSUSED*/ +void +swde_panic_detected(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + const char *class, void *arg) +{ + boolean_t fm_panic, expect_savecore; + swde_panic_casedata_t *cdp; + nvlist_t *attr; + fmd_case_t *cp; + char *fmribuf; + char *uuid; + size_t sz; + + fmd_hdl_debug(hdl, "swde_panic_detected\n"); + + if (nvlist_lookup_nvlist(nvl, FM_IREPORT_ATTRIBUTES, &attr) != 0) { + BUMPSTAT(swde_panic_noattr); + return; + } + + if (nvlist_lookup_string(attr, "os-instance-uuid", &uuid) != 0) { + BUMPSTAT(swde_panic_nouuid); + return; + } + + fmd_hdl_debug(hdl, "swde_panic_detected: OS instance %s\n", uuid); + + if (nvlist_lookup_boolean_value(attr, "fm-panic", &fm_panic) != 0 || + fm_panic == B_TRUE) { + BUMPSTAT(swde_panic_unexpected_fm_panic); + return; + } + + /* + * Prepare serialization data to be associated with a new + * case. Our serialization data consists of a swde_panic_casedata_t + * structure followed by a packed nvlist of the attributes of + * the initial event. + */ + if (nvlist_size(attr, &sz, NV_ENCODE_NATIVE) != 0) { + BUMPSTAT(swde_panic_failsrlz); + return; + } + + cdp = fmd_hdl_zalloc(hdl, sizeof (*cdp) + sz, FMD_SLEEP); + fmribuf = (char *)cdp + sizeof (*cdp); + cdp->scd_vers = SWDE_PANIC_CASEDATA_VERS; + cdp->scd_receive_time = time(NULL); + cdp->scd_nvlbufsz = sz; + + /* + * Open a case with UUID matching the the panicking kernel, add this + * event to the case. + */ + if ((cp = swde_case_open(hdl, myid, uuid, SWDE_PANIC_CASEDATA_VERS, + cdp, sizeof (*cdp) + sz)) == NULL) { + BUMPSTAT(swde_panic_dupuuid); + fmd_hdl_debug(hdl, "swde_case_open returned NULL - dup?\n"); + fmd_hdl_free(hdl, cdp, sizeof (*cdp) + sz); + return; + } + + fmd_case_setprincipal(hdl, cp, ep); + + if (nvlist_lookup_boolean_value(attr, "will-attempt-savecore", + &expect_savecore) != 0 || expect_savecore == B_FALSE) { + fmd_hdl_debug(hdl, "savecore not being attempted - " + "solve now\n"); + swde_panic_solve(hdl, cp, attr, ep, B_FALSE); + return; + } + + /* + * We expect to see either a "dump_available" or a "savecore_failed" + * event before too long. In case that never shows up, for whatever + * reason, we want to be able to solve the case anyway. + */ + fmd_case_add_ereport(hdl, cp, ep); + (void) nvlist_pack(attr, &fmribuf, &sz, NV_ENCODE_NATIVE, 0); + swde_case_data_write(hdl, cp); + + if (mytimerid == 0) { + mytimerid = sw_timer_install(hdl, myid, NULL, ep, + 10ULL * NANOSEC * 60); + fmd_hdl_debug(hdl, "armed timer\n"); + } else { + fmd_hdl_debug(hdl, "timer already armed\n"); + } +} + +/* + * savecore has now run and saved a crash dump to the filesystem. It is + * either a compressed dump (vmdump.n) or uncompressed {unix.n, vmcore.n} + * Savecore has raised an ireport to say the dump is there. + */ + +/*ARGSUSED*/ +void +swde_panic_savecore_done(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + const char *class, void *arg) +{ + boolean_t savecore_success = (arg != NULL); + boolean_t fm_panic; + nvlist_t *attr; + fmd_case_t *cp; + char *uuid; + + fmd_hdl_debug(hdl, "savecore_done (%s)\n", savecore_success ? + "success" : "fail"); + + if (nvlist_lookup_nvlist(nvl, FM_IREPORT_ATTRIBUTES, &attr) != 0) { + BUMPSTAT(swde_panic_noattr); + return; + } + + if (nvlist_lookup_boolean_value(attr, "fm-panic", &fm_panic) != 0 || + fm_panic == B_TRUE) { + return; /* not expected, but just in case */ + } + + if (nvlist_lookup_string(attr, "os-instance-uuid", &uuid) != 0) { + BUMPSTAT(swde_panic_nouuid); + return; + } + + /* + * Find the case related to the panicking kernel; our cases have + * the same uuid as the crashed OS image. + */ + cp = fmd_case_uulookup(hdl, uuid); + if (!cp) { + /* Unable to find the case. */ + fmd_hdl_debug(hdl, "savecore_done: can't find case for " + "image %s\n", uuid); + BUMPSTAT(swde_panic_nocase); + return; + } + + fmd_hdl_debug(hdl, "savecore_done: solving case %s\n", uuid); + swde_panic_solve(hdl, cp, attr, ep, savecore_success); +} + +const struct sw_disp swde_panic_disp[] = { + { SW_SUNOS_PANIC_DETECTED, swde_panic_detected, NULL }, + { SW_SUNOS_PANIC_AVAIL, swde_panic_savecore_done, (void *)1 }, + { SW_SUNOS_PANIC_FAILURE, swde_panic_savecore_done, NULL }, + /* + * Something has to subscribe to every fault + * or defect diagnosed in fmd. We do that here, but throw it away. + */ + { SW_SUNOS_PANIC_DEFECT, NULL, NULL }, + { NULL, NULL, NULL } +}; + +/*ARGSUSED*/ +int +swde_panic_init(fmd_hdl_t *hdl, id_t id, const struct sw_disp **dpp, + int *nelemp) +{ + myid = id; + + if (getzoneid() != GLOBAL_ZONEID) + return (SW_SUB_INIT_FAIL_VOLUNTARY); + + (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, + sizeof (swde_panic_stats) / sizeof (fmd_stat_t), + (fmd_stat_t *)&swde_panic_stats); + + fmd_hdl_subscribe(hdl, SW_SUNOS_PANIC_DETECTED); + fmd_hdl_subscribe(hdl, SW_SUNOS_PANIC_FAILURE); + fmd_hdl_subscribe(hdl, SW_SUNOS_PANIC_AVAIL); + + *dpp = &swde_panic_disp[0]; + *nelemp = sizeof (swde_panic_disp) / sizeof (swde_panic_disp[0]); + return (SW_SUB_INIT_SUCCESS); +} + +void +swde_panic_fini(fmd_hdl_t *hdl) +{ + if (mytimerid) + sw_timer_remove(hdl, myid, mytimerid); +} + +const struct sw_subinfo panic_diag_info = { + "panic diagnosis", /* swsub_name */ + SW_CASE_PANIC, /* swsub_casetype */ + swde_panic_init, /* swsub_init */ + swde_panic_fini, /* swsub_fini */ + swde_panic_timeout, /* swsub_timeout */ + NULL, /* swsub_case_close */ + swde_panic_vrfy, /* swsub_case_vrfy */ +}; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/smf/smf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/smf/smf.h Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,44 @@ +/* + * 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 _SMF_H +#define _SMF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define TRANCLASS(leaf) "ireport.os.smf.state-transition." leaf + +#define SW_SMF_MAINT_DEFECT "defect.sunos.smf.svc.maintenance" + +extern char *sw_smf_svcfmri2str(fmd_hdl_t *, nvlist_t *); +extern char *sw_smf_svcfmri2shortstr(fmd_hdl_t *, nvlist_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SMF_H */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/smf/smf_diag.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/smf/smf_diag.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,305 @@ +/* + * 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. + */ + +/* + * SMF software-diagnosis subsidiary + * + * We model service instances in maintenance state as a defect diagnosis + * in FMA. When an instance transitions to maintenance state the SMF + * graph engine publishes an event which we subscribe to here, and diagnose + * a corresponding defect. + * + * We always solve a case immediately after opening it. But we leave the + * case close action to the response agent which needs to cache case UUIDs. + * So in the normal case, where software-response is loaded and operational, + * our cases will transition to CLOSED state moments after we solve them. + * But if fmd restarts in the interim or if software-response is not loaded + * then our cases may hang around in SOLVED state for a while, which means + * we could iterate over them on receipt of new events. But we don't - + * we blindly solve a new case for every new maintenance event received, + * and leave it to the fmd duplicate detection and history-based diagnosis + * logic to do the right thing. + * + * Our sibling SMF response subsidiary propogates fmadm-initiated repairs + * into SMF, and svcadm-initiated clears back into FMA. In both cases + * the case is moved on to the RESOLVED state, even if fmd is unable to + * verify that the service is out of maintenance state (i.e., no longer + * isolated). If the service immediately re-enters maintenance state then + * we diagnose a fresh case. The history-based diagnosis changes in fmd + * "do the right thing" and avoid throwing away new cases as duplicates + * of old ones hanging around in the "resolved but not all usable again" + * state. + */ + +#include +#include +#include + +#include "../../common/sw.h" +#include "smf.h" + +static id_t myid; + +static struct { + fmd_stat_t swde_smf_diagnosed; + fmd_stat_t swde_smf_bad_class; + fmd_stat_t swde_smf_no_attr; + fmd_stat_t swde_smf_bad_attr; + fmd_stat_t swde_smf_bad_fmri; + fmd_stat_t swde_smf_no_uuid; + fmd_stat_t swde_smf_no_reason_short; + fmd_stat_t swde_smf_no_reason_long; + fmd_stat_t swde_smf_no_svcname; + fmd_stat_t swde_smf_admin_maint_drop; + fmd_stat_t swde_smf_bad_nvlist_pack; + fmd_stat_t swde_smf_dupuuid; +} swde_smf_stats = { + { "swde_smf_diagnosed", FMD_TYPE_UINT64, + "maintenance state defects published" }, + { "swde_smf_bad_class", FMD_TYPE_UINT64, + "incorrect event class received" }, + { "swde_smf_no_attr", FMD_TYPE_UINT64, + "malformed event - missing attr nvlist" }, + { "swde_smf_bad_attr", FMD_TYPE_UINT64, + "malformed event - invalid attr list" }, + { "swde_smf_bad_fmri", FMD_TYPE_UINT64, + "malformed event - fmri2str fails" }, + { "swde_smf_no_uuid", FMD_TYPE_UINT64, + "malformed event - missing uuid" }, + { "swde_smf_no_reason_short", FMD_TYPE_UINT64, + "SMF transition event had no reason-short" }, + { "swde_smf_no_reason_long", FMD_TYPE_UINT64, + "SMF transition event had no reason-long" }, + { "swde_smf_no_svcname", FMD_TYPE_UINT64, + "SMF transition event had no svc-string" }, + { "swde_smf_admin_maint_drop", FMD_TYPE_UINT64, + "maintenance transitions requested by admin - no diagnosis" }, + { "swde_smf_bad_nvlist_pack", FMD_TYPE_UINT64, + "failed nvlist_size or nvlist_pack" }, + { "swde_smf_dupuuid", FMD_TYPE_UINT64, + "duplicate events received" }, +}; + +#define SWDE_SMF_CASEDATA_VERS 1 + +typedef struct swde_smf_casedata { + uint32_t scd_vers; /* must be first member */ + size_t scd_nvlbufsz; /* size of following buffer */ + /* packed fmri nvlist follows */ +} swde_smf_casedata_t; + +#define BUMPSTAT(stat) swde_smf_stats.stat.fmds_value.ui64++ + +/*ARGSUSED*/ +void +swde_smf_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + const char *class, void *arg) +{ + char *rsn = NULL, *rsnl = NULL, *svcname = NULL; + nvlist_t *attr, *svcfmri, *defect; + swde_smf_casedata_t *cdp; + fmd_case_t *cp; + char *fmribuf; + char *uuid; + size_t sz; + + if (!fmd_nvl_class_match(hdl, nvl, TRANCLASS("maintenance"))) { + BUMPSTAT(swde_smf_bad_class); + return; + } + + if (nvlist_lookup_nvlist(nvl, FM_IREPORT_ATTRIBUTES, &attr) != 0) { + BUMPSTAT(swde_smf_no_attr); + return; + } + + if (nvlist_lookup_string(nvl, FM_IREPORT_UUID, &uuid) != 0) { + BUMPSTAT(swde_smf_no_uuid); + return; + } + + if (nvlist_lookup_nvlist(attr, "svc", &svcfmri) != 0) { + BUMPSTAT(swde_smf_bad_attr); + return; + } + + if (nvlist_lookup_string(attr, "reason-short", &rsn) != 0) { + BUMPSTAT(swde_smf_no_reason_short); + return; + } + + if (nvlist_lookup_string(attr, "reason-long", &rsnl) != 0) { + BUMPSTAT(swde_smf_no_reason_long); + return; + } + + if (nvlist_lookup_string(attr, "svc-string", &svcname) != 0) { + BUMPSTAT(swde_smf_no_svcname); + return; + } + + if (strcmp(rsn, "administrative_request") == 0) { + BUMPSTAT(swde_smf_admin_maint_drop); + return; + } + + /* + * Our case checkpoint data, version 1. + */ + if (nvlist_size(svcfmri, &sz, NV_ENCODE_NATIVE) != 0) { + BUMPSTAT(swde_smf_bad_nvlist_pack); + return; + } + cdp = fmd_hdl_zalloc(hdl, sizeof (*cdp) + sz, FMD_SLEEP); + cdp->scd_vers = SWDE_SMF_CASEDATA_VERS; + fmribuf = (char *)cdp + sizeof (*cdp); + cdp->scd_nvlbufsz = sz; + (void) nvlist_pack(svcfmri, &fmribuf, &sz, NV_ENCODE_NATIVE, 0); + + /* + * Open a case with UUID matching the originating event, and no + * associated serialization data. Create a defect and add it to + * the case, and link the originating event to the case. This + * call will return NULL if a case with the requested UUID already + * exists, which would mean we are processing an event twice so + * we can discard. + */ + if ((cp = swde_case_open(hdl, myid, uuid, SWDE_SMF_CASEDATA_VERS, + (void *)cdp, sizeof (*cdp) + sz)) == NULL) { + BUMPSTAT(swde_smf_dupuuid); + fmd_hdl_free(hdl, cdp, sizeof (*cdp) + sz); + return; + } + + defect = fmd_nvl_create_defect(hdl, SW_SMF_MAINT_DEFECT, + 100, svcfmri, NULL, svcfmri); + if (rsn != NULL) + (void) nvlist_add_string(defect, "reason-short", rsn); + if (rsnl != NULL) + (void) nvlist_add_string(defect, "reason-long", rsnl); + if (svcname != NULL) + (void) nvlist_add_string(defect, "svc-string", svcname); + fmd_case_add_suspect(hdl, cp, defect); + fmd_case_add_ereport(hdl, cp, ep); + + /* + * Now solve the case, and immediately close it. Although the + * resource is already isolated (SMF put it in maintenance state) + * we do not immediately close the case here - our sibling response + * logic will do that after caching the case UUID. + */ + fmd_case_solve(hdl, cp); + BUMPSTAT(swde_smf_diagnosed); +} + +/* + * In the normal course of events we keep in sync with SMF through the + * maintenance enter/clear events it raises. Even if a maintenance + * state is cleared using svcadm while fmd is not running, the event + * will pend and be consumed when fmd does start and we'll close the + * case (in the response agent). + * + * But is is possible for discontinuities to produce some confusion: + * + * - if an instance is in maintenance state (and so shown in svcs -x + * and fmadm faulty output) at the time we clone a new boot + * environment then when we boot the new BE we can be out of + * sync if the instance is cleared when we boot there + * + * - meddling with /var/fm state - eg manual clear of files there, + * or restore of old state + * + * So as an extra guard we have a case verify function which is called + * at fmd restart (module load for software-diagnosis). We must + * return 0 to close the case, non-zero to retain it. + */ +int +swde_smf_vrfy(fmd_hdl_t *hdl, fmd_case_t *cp) +{ + swde_smf_casedata_t *cdp; + nvlist_t *svcfmri; + uint32_t v; + int rv; + + cdp = swde_case_data(hdl, cp, &v); + + if (cdp == NULL || v != 1) + return (0); /* bad or damaged - just close */ + + if (nvlist_unpack((char *)cdp + sizeof (*cdp), + cdp->scd_nvlbufsz, &svcfmri, 0) != 0) + return (0); /* ditto */ + + switch (fmd_nvl_fmri_service_state(hdl, svcfmri)) { + case FMD_SERVICE_STATE_UNUSABLE: + /* + * Keep case iff in maintenance state + */ + rv = 1; + break; + + default: + /* + * Discard the case for all other states - cleared, + * service no longer exists, ... whatever. + */ + rv = 0; + break; + } + + nvlist_free(svcfmri); + return (rv); +} + +const struct sw_disp swde_smf_disp[] = { + { TRANCLASS("maintenance"), swde_smf_recv, NULL }, + { NULL, NULL, NULL } +}; + +/*ARGSUSED*/ +int +swde_smf_init(fmd_hdl_t *hdl, id_t id, const struct sw_disp **dpp, int *nelemp) +{ + myid = id; + + (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (swde_smf_stats) / + sizeof (fmd_stat_t), (fmd_stat_t *)&swde_smf_stats); + + fmd_hdl_subscribe(hdl, TRANCLASS("maintenance")); + + *dpp = &swde_smf_disp[0]; + *nelemp = sizeof (swde_smf_disp) / sizeof (swde_smf_disp[0]); + return (SW_SUB_INIT_SUCCESS); +} + +const struct sw_subinfo smf_diag_info = { + "smf diagnosis", /* swsub_name */ + SW_CASE_SMF, /* swsub_casetype */ + swde_smf_init, /* swsub_init */ + NULL, /* swsub_fini */ + NULL, /* swsub_timeout */ + NULL, /* swsub_case_close */ + swde_smf_vrfy, /* swsub_case_vrfy */ +}; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/smf/smf_response.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/smf/smf_response.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,543 @@ +/* + * 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. + */ + +/* + * SMF software-response subsidiary + */ + +#include +#include +#include +#include +#include + +#include "../../common/sw.h" +#include "smf.h" + +static struct { + fmd_stat_t swrp_smf_repairs; + fmd_stat_t swrp_smf_clears; + fmd_stat_t swrp_smf_closed; + fmd_stat_t swrp_smf_wrongclass; + fmd_stat_t swrp_smf_badlist; + fmd_stat_t swrp_smf_badresource; + fmd_stat_t swrp_smf_badclrevent; + fmd_stat_t swrp_smf_noloop; + fmd_stat_t swrp_smf_suppressed; + fmd_stat_t swrp_smf_cachefull; +} swrp_smf_stats = { + { "swrp_smf_repairs", FMD_TYPE_UINT64, + "repair events received for propogation to SMF" }, + { "swrp_smf_clears", FMD_TYPE_UINT64, + "notifications from SMF of exiting maint state" }, + { "swrp_smf_closed", FMD_TYPE_UINT64, + "cases closed" }, + { "swrp_smf_wrongclass", FMD_TYPE_UINT64, + "unexpected event class received" }, + { "swrp_smf_badlist", FMD_TYPE_UINT64, + "list event with invalid structure" }, + { "swrp_smf_badresource", FMD_TYPE_UINT64, + "list.repaired with smf fault but bad svc fmri" }, + { "swrp_smf_badclrevent", FMD_TYPE_UINT64, + "maint clear event from SMF malformed" }, + { "swrp_smf_noloop", FMD_TYPE_UINT64, + "avoidance of smf->fmd->smf repairs propogations" }, + { "swrp_smf_suppressed", FMD_TYPE_UINT64, + "not propogated to smf because no longer in maint" }, + { "swrp_smf_cachefull", FMD_TYPE_UINT64, + "uuid cache full" }, +}; + +#define BUMPSTAT(stat) swrp_smf_stats.stat.fmds_value.ui64++ + +#define CACHE_NENT_INC 16 +#define CACHE_NENT_MAX 128 + +struct smf_uuid_cache_ent { + char uuid[37]; + char fmristr[90]; + uint8_t mark; +}; + +#define CACHE_VERSION 1 + +struct smf_uuid_cache { + uint32_t version; /* Version */ + uint32_t nentries; /* Real size of array below */ + struct smf_uuid_cache_ent entry[1]; /* Cache entries */ +}; + +static struct smf_uuid_cache *uuid_cache; + +#define UUID_CACHE_BUFNAME "uuid_cache" + +static void +uuid_cache_grow(fmd_hdl_t *hdl) +{ + struct smf_uuid_cache *newcache; + size_t newsz; + uint32_t n; + + n = (uuid_cache == NULL ? 0 : uuid_cache->nentries) + CACHE_NENT_INC; + newsz = sizeof (struct smf_uuid_cache) + (n - 1) * + sizeof (struct smf_uuid_cache_ent); + + newcache = fmd_hdl_zalloc(hdl, newsz, FMD_SLEEP); + newcache->version = CACHE_VERSION; + newcache->nentries = n; + + if (uuid_cache != NULL) { + uint32_t oldn = uuid_cache->nentries; + size_t oldsz = sizeof (struct smf_uuid_cache) + + (oldn - 1) * sizeof (struct smf_uuid_cache_ent); + + bcopy(&uuid_cache->entry[0], &newcache->entry[0], oldsz); + fmd_hdl_free(hdl, uuid_cache, oldsz); + fmd_buf_destroy(hdl, NULL, UUID_CACHE_BUFNAME); + } + + uuid_cache = newcache; + fmd_buf_create(hdl, NULL, UUID_CACHE_BUFNAME, newsz); +} + +static void +uuid_cache_persist(fmd_hdl_t *hdl) +{ + size_t sz = sizeof (struct smf_uuid_cache) + + (uuid_cache->nentries - 1) * sizeof (struct smf_uuid_cache_ent); + + fmd_buf_write(hdl, NULL, UUID_CACHE_BUFNAME, uuid_cache, sz); +} + +/* + * Garbage-collect the uuid cache. Any cases that are already resolved + * we do not need an entry for. If a case is not resolved but the + * service involved in that case is no longer in maintenance state + * then we've lost sync somehow, so repair the asru (which will + * also resolve the case). + */ +static void +uuid_cache_gc(fmd_hdl_t *hdl) +{ + struct smf_uuid_cache_ent *entp; + topo_hdl_t *thp = NULL; + nvlist_t *svcfmri; + char *svcname; + int err, i; + + for (i = 0; i < uuid_cache->nentries; i++) { + entp = &uuid_cache->entry[i]; + + if (entp->uuid[0] == '\0') + continue; + + if (fmd_case_uuisresolved(hdl, entp->uuid)) { + bzero(entp->uuid, sizeof (entp->uuid)); + bzero(entp->fmristr, sizeof (entp->fmristr)); + entp->mark = 0; + } else { + if (thp == NULL) + thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION); + + if (topo_fmri_str2nvl(thp, entp->fmristr, &svcfmri, + &err) != 0) { + fmd_hdl_error(hdl, "str2nvl failed for %s\n", + entp->fmristr); + continue; + } + + if (fmd_nvl_fmri_service_state(hdl, svcfmri) != + FMD_SERVICE_STATE_UNUSABLE) { + svcname = sw_smf_svcfmri2shortstr(hdl, svcfmri); + (void) fmd_repair_asru(hdl, entp->fmristr); + fmd_hdl_strfree(hdl, svcname); + } + + nvlist_free(svcfmri); + } + } + + if (thp) + fmd_hdl_topo_rele(hdl, thp); + + uuid_cache_persist(hdl); +} + +static void +uuid_cache_restore(fmd_hdl_t *hdl) +{ + size_t sz = fmd_buf_size(hdl, NULL, UUID_CACHE_BUFNAME); + + if (sz == 0) + return; + + uuid_cache = fmd_hdl_alloc(hdl, sz, FMD_SLEEP); + fmd_buf_read(hdl, NULL, UUID_CACHE_BUFNAME, uuid_cache, sz); + + /* + * Garbage collect now, not just for tidiness but also to help + * fmd and smf state stay in sync at module startup. + */ + uuid_cache_gc(hdl); +} + +/* + * Add the UUID of an SMF maintenance defect case to our cache and + * record the associated full svc FMRI string for the case. + */ +static void +swrp_smf_cache_add(fmd_hdl_t *hdl, char *uuid, char *fmristr) +{ + struct smf_uuid_cache_ent *entp = NULL; + int gced = 0; + int i; + + if (uuid_cache == NULL) + uuid_cache_grow(hdl); + + /* + * If we somehow already have an entry for this uuid then + * return leaving it undisturbed. + */ + for (i = 0; i < uuid_cache->nentries; i++) { + if (strcmp(uuid, uuid_cache->entry[i].uuid) == 0) + return; + } + +scan: + for (i = 0; i < uuid_cache->nentries; i++) { + if (uuid_cache->entry[i].uuid[0] == '\0') { + entp = &uuid_cache->entry[i]; + break; + } + } + + if (entp == NULL) { + uint32_t oldn = uuid_cache->nentries; + + /* + * Before growing the cache we try again after first + * garbage-collecting the existing cache for any cases + * that are confirmed as resolved. + */ + if (!gced) { + uuid_cache_gc(hdl); + gced = 1; + goto scan; + } + + if (oldn < CACHE_NENT_MAX) { + uuid_cache_grow(hdl); + entp = &uuid_cache->entry[oldn]; + } else { + BUMPSTAT(swrp_smf_cachefull); + return; + } + } + + (void) strncpy(entp->uuid, uuid, sizeof (entp->uuid)); + (void) strncpy(entp->fmristr, fmristr, sizeof (entp->fmristr)); + uuid_cache_persist(hdl); +} + +/* + * Mark cache entry/entries as resolved - if they match in either uuid + * (if not NULL) or fmristr (if not NULL) mark as resolved. Return 1 iff + * an entry that matched on uuid was already marked, otherwise (entry + * matched on either, matched on uuid but not marked, not found). + */ +static int +swrp_smf_cache_mark(fmd_hdl_t *hdl, char *uuid, char *fmristr) +{ + int dirty = 0; + int rv = 0; + int i; + + if (uuid_cache == NULL) + return (0); + + for (i = 0; i < uuid_cache->nentries; i++) { + struct smf_uuid_cache_ent *entp = &uuid_cache->entry[i]; + + if (entp->uuid[0] == '\0') + continue; + + if (uuid && strcmp(uuid, entp->uuid) == 0) { + if (entp->mark) + rv = 1; + entp->mark = 1; + dirty++; + } else if (fmristr && strcmp(fmristr, entp->fmristr) == 0) { + entp->mark = 1; + dirty++; + } + } + + if (dirty) + uuid_cache_persist(hdl); + + return (rv); +} + +/* + * We will receive list events for cases we are not interested in. Test + * that this list has exactly one suspect and that it matches the maintenance + * defect. Return the defect to the caller in the second argument, + * and the defect resource element in the third arg. + */ +static int +suspect_is_maint_defect(fmd_hdl_t *hdl, nvlist_t *nvl, + nvlist_t **defectnvl, nvlist_t **rsrcnvl) +{ + nvlist_t **faults; + uint_t nfaults; + + if (nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, + &faults, &nfaults) != 0) { + BUMPSTAT(swrp_smf_badlist); + return (0); + } + + if (nfaults != 1 || + !fmd_nvl_class_match(hdl, faults[0], SW_SMF_MAINT_DEFECT)) + return (0); + + if (nvlist_lookup_nvlist(faults[0], FM_FAULT_RESOURCE, rsrcnvl) != 0) { + BUMPSTAT(swrp_smf_badlist); + return (0); + } + + *defectnvl = faults[0]; + + return (1); +} + +/* + * Received newly-diagnosed list.suspect events that are for the + * maintenane defect we diagnose. Close the case (the resource was already + * isolated by SMF) after cachng the case UUID. + */ +/*ARGSUSED*/ +static void +swrp_smf_cacheuuid(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + const char *class, void *arg) +{ + nvlist_t *defect, *rsrc; + char *fmristr, *uuid; + + if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) != 0) { + BUMPSTAT(swrp_smf_badlist); + return; + } + + if (!suspect_is_maint_defect(hdl, nvl, &defect, &rsrc)) + return; + + if ((fmristr = sw_smf_svcfmri2str(hdl, rsrc)) == NULL) { + BUMPSTAT(swrp_smf_badlist); + return; + } + + swrp_smf_cache_add(hdl, uuid, fmristr); + fmd_hdl_strfree(hdl, fmristr); + + if (!fmd_case_uuclosed(hdl, uuid)) { + fmd_case_uuclose(hdl, uuid); + BUMPSTAT(swrp_smf_closed); + } +} + +/*ARGSUSED*/ +static void +swrp_smf2fmd(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + const char *class, void *arg) +{ + nvlist_t *attr, *fmri; + char *fromstate; + char *fmristr; + + if (!fmd_nvl_class_match(hdl, nvl, TRANCLASS("*"))) { + BUMPSTAT(swrp_smf_wrongclass); + return; + } + + if (nvlist_lookup_nvlist(nvl, FM_IREPORT_ATTRIBUTES, &attr) != 0 || + nvlist_lookup_string(attr, "from-state", &fromstate) != 0) { + BUMPSTAT(swrp_smf_badclrevent); + return; + } + + /* + * Filter those not describing a transition out of maintenance. + */ + if (strcmp(fromstate, "maintenance") != 0) + return; + + if (nvlist_lookup_nvlist(attr, "svc", &fmri) != 0) { + BUMPSTAT(swrp_smf_badclrevent); + return; + } + + if ((fmristr = sw_smf_svcfmri2str(hdl, fmri)) == NULL) { + BUMPSTAT(swrp_smf_badclrevent); + return; + } + + /* + * Mark any UUID for a case against this service as resolved + * in our cache. When we fmd_repair_asru below fmd will emit + * a list.repaired as a result, and our handling of that event + * must not propogate the repair towards SMF (since the repair + * was initiated via SMF itself and not via fmadm). + */ + (void) swrp_smf_cache_mark(hdl, NULL, fmristr); + + (void) fmd_repair_asru(hdl, fmristr); + fmd_hdl_strfree(hdl, fmristr); + BUMPSTAT(swrp_smf_clears); +} + +/*ARGSUSED*/ +static void +swrp_fmd2smf(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + const char *class, void *arg) +{ + char *fmristr, *shrtfmristr; + nvlist_t *defect, *rsrc; + char *uuid; + int already; + + if (strcmp(class, FM_LIST_REPAIRED_CLASS) != 0) { + BUMPSTAT(swrp_smf_wrongclass); + return; + } + + if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) != 0) { + BUMPSTAT(swrp_smf_badlist); + return; + } + + if (!suspect_is_maint_defect(hdl, nvl, &defect, &rsrc)) + return; + + if ((fmristr = sw_smf_svcfmri2str(hdl, rsrc)) == NULL) { + BUMPSTAT(swrp_smf_badresource); + return; + } + + already = swrp_smf_cache_mark(hdl, uuid, fmristr); + fmd_hdl_strfree(hdl, fmristr); + + /* + * If the cache already had a marked entry for this UUID then + * this is a list.repaired arising from a SMF-initiated maintenance + * clear (propogated with fmd_repair_asru above which then results + * in a list.repaired) and so we should not propogate the repair + * back towards SMF. But do still force the case to RESOLVED state in + * case fmd is unable to confirm the service no longer in maintenance + * state (it may have failed again) so that a new case can be opened. + */ + fmd_case_uuresolved(hdl, uuid); + if (already) { + BUMPSTAT(swrp_smf_noloop); + return; + } + + /* + * Only propogate to SMF if we can see that service still + * in maintenance state. We're not synchronized with SMF + * and this state could change at any time, but if we can + * see it's not in maintenance state then things are obviously + * moving (e.g., external svcadm active) so we don't poke + * at SMF otherwise we confuse things or duplicate operations. + */ + + if (fmd_nvl_fmri_service_state(hdl, rsrc) == + FMD_SERVICE_STATE_UNUSABLE) { + shrtfmristr = sw_smf_svcfmri2shortstr(hdl, rsrc); + + if (shrtfmristr != NULL) { + (void) smf_restore_instance(shrtfmristr); + fmd_hdl_strfree(hdl, shrtfmristr); + BUMPSTAT(swrp_smf_repairs); + } else { + BUMPSTAT(swrp_smf_badresource); + } + } else { + BUMPSTAT(swrp_smf_suppressed); + } +} + +const struct sw_disp swrp_smf_disp[] = { + { TRANCLASS("*"), swrp_smf2fmd, NULL }, + { FM_LIST_SUSPECT_CLASS, swrp_smf_cacheuuid, NULL }, + { FM_LIST_REPAIRED_CLASS, swrp_fmd2smf, NULL }, + { NULL, NULL, NULL } +}; + +/*ARGSUSED*/ +int +swrp_smf_init(fmd_hdl_t *hdl, id_t id, const struct sw_disp **dpp, int *nelemp) +{ + (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (swrp_smf_stats) / + sizeof (fmd_stat_t), (fmd_stat_t *)&swrp_smf_stats); + + uuid_cache_restore(hdl); + + /* + * We need to subscribe to all SMF transition class events because + * we need to look inside the payload to see which events indicate + * a transition out of maintenance state. + */ + fmd_hdl_subscribe(hdl, TRANCLASS("*")); + + /* + * Subscribe to the defect class diagnosed for maintenance events. + * The module will then receive list.suspect events including + * these defects, and in our dispatch table above we list routing + * for list.suspect. + */ + fmd_hdl_subscribe(hdl, SW_SMF_MAINT_DEFECT); + + *dpp = &swrp_smf_disp[0]; + *nelemp = sizeof (swrp_smf_disp) / sizeof (swrp_smf_disp[0]); + return (SW_SUB_INIT_SUCCESS); +} + +/*ARGSUSED*/ +void +swrp_smf_fini(fmd_hdl_t *hdl) +{ +} + +const struct sw_subinfo smf_response_info = { + "smf repair", /* swsub_name */ + SW_CASE_NONE, /* swsub_casetype */ + swrp_smf_init, /* swsub_init */ + swrp_smf_fini, /* swsub_fini */ + NULL, /* swsub_timeout */ + NULL, /* swsub_case_close */ + NULL, /* swsub_case_vrfy */ +}; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/smf/smf_util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/sw-diag-response/subsidiary/smf/smf_util.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,80 @@ +/* + * 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. + */ + +/* + * SMF software diagnosis engine components. + */ + +#include +#include + +#include "../../common/sw.h" +#include "smf.h" + +/* + * Given a "svc' scheme FMRI in nvlist form, produce a string form + * of the FMRI (with no short-hand). + */ +char * +sw_smf_svcfmri2str(fmd_hdl_t *hdl, nvlist_t *fmri) +{ + char *fmristr = NULL; + topo_hdl_t *thp; + char *topostr; + int err; + + thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION); + if (topo_fmri_nvl2str(thp, fmri, &topostr, &err) == 0) { + fmristr = fmd_hdl_strdup(hdl, (const char *)topostr, FMD_SLEEP); + topo_hdl_strfree(thp, topostr); + } + fmd_hdl_topo_rele(hdl, thp); + + return (fmristr); /* caller must fmd_hdl_strfree */ +} + +/* + * Given a "svc" scheme FMRI in nvlist form, produce a short-hand form + * string FMRI "svc:/..." as generally used in SMF cmdline output. + */ +char * +sw_smf_svcfmri2shortstr(fmd_hdl_t *hdl, nvlist_t *fmri) +{ + char *name, *inst, *bufp, *fullname; + size_t len; + + if (nvlist_lookup_string(fmri, FM_FMRI_SVC_NAME, &name) != 0 || + nvlist_lookup_string(fmri, FM_FMRI_SVC_INSTANCE, &inst) != 0) + return (NULL); + + len = strlen(name) + strlen(inst) + 8; + bufp = fmd_hdl_alloc(hdl, len, FMD_SLEEP); + (void) snprintf(bufp, len, "svc:/%s:%s", name, inst); + + fullname = fmd_hdl_strdup(hdl, bufp, FMD_SLEEP); + fmd_hdl_free(hdl, bufp, len); + + return (fullname); /* caller must fmd_hdl_strfree */ +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/syslog-msgs/Makefile --- a/usr/src/cmd/fm/modules/common/syslog-msgs/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/syslog-msgs/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -19,10 +19,8 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # -#ident "%Z%%M% %I% %E% SMI" MODULE = syslog-msgs CLASS = common @@ -32,4 +30,4 @@ LDFLAGS += -L $(ROOT)/usr/lib/fm -R/usr/lib/fm LINTFLAGS += -L$(ROOT)/usr/lib/fm -LDLIBS += -lfmd_msg +LDLIBS += -lfmd_msg -lscf diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/common/syslog-msgs/syslog.c --- a/usr/src/cmd/fm/modules/common/syslog-msgs/syslog.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/common/syslog-msgs/syslog.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,13 +20,13 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include +#include #include #include @@ -175,13 +175,84 @@ } } +static void +free_notify_prefs(fmd_hdl_t *hdl, nvlist_t **prefs, uint_t nprefs) +{ + int i; + + for (i = 0; i < nprefs; i++) { + if (prefs[i]) + nvlist_free(prefs[i]); + } + + fmd_hdl_free(hdl, prefs, sizeof (nvlist_t *) * nprefs); +} + +static int +get_notify_prefs(fmd_hdl_t *hdl, nvlist_t *ev_nvl, nvlist_t ***pref_nvl, + uint_t *nprefs) +{ + nvlist_t *top_nvl, **np_nvlarr, *mech_nvl; + nvlist_t **tmparr; + int ret, i; + uint_t nelem, nslelem; + + if ((ret = smf_notify_get_params(&top_nvl, ev_nvl)) != SCF_SUCCESS) { + ret = scf_error(); + if (ret != SCF_ERROR_NOT_FOUND) { + fmd_hdl_debug(hdl, "Error looking up notification " + "preferences (%s)", scf_strerror(ret)); + return (ret); + } + return (ret); + } + + if (nvlist_lookup_nvlist_array(top_nvl, SCF_NOTIFY_PARAMS, &np_nvlarr, + &nelem) != 0) { + fmd_hdl_debug(hdl, "Malformed preference nvlist\n"); + ret = SCF_ERROR_INVALID_ARGUMENT; + goto pref_done; + } + + tmparr = fmd_hdl_alloc(hdl, nelem * sizeof (nvlist_t *), FMD_SLEEP); + nslelem = 0; + + for (i = 0; i < nelem; i++) { + if (nvlist_lookup_nvlist(np_nvlarr[i], "syslog", &mech_nvl) + == 0) + tmparr[nslelem++] = fmd_nvl_dup(hdl, mech_nvl, + FMD_SLEEP); + } + + if (nslelem != 0) { + size_t sz = nslelem * sizeof (nvlist_t *); + + *pref_nvl = fmd_hdl_zalloc(hdl, sz, FMD_SLEEP); + *nprefs = nslelem; + bcopy(tmparr, *pref_nvl, sz); + ret = 0; + } else { + *pref_nvl = NULL; + *nprefs = 0; + ret = SCF_ERROR_NOT_FOUND; + } + + fmd_hdl_free(hdl, tmparr, nelem * sizeof (nvlist_t *)); +pref_done: + nvlist_free(top_nvl); + return (ret); +} + /*ARGSUSED*/ static void syslog_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) { uint8_t version; - boolean_t domsg; + boolean_t domsg, *active; char *msg; + nvlist_t **prefs; + uint_t nprefs, nelems; + int ret; if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || version > FM_SUSPECT_VERSION) { @@ -197,6 +268,32 @@ return; /* event is not to be messaged */ } + ret = get_notify_prefs(hdl, nvl, &prefs, &nprefs); + if (ret == SCF_ERROR_NOT_FOUND) { + /* + * No syslog notification preferences specified for this type of + * event, so we're done + */ + fmd_hdl_debug(hdl, "No syslog notification preferences " + "configured for class %s\n", class); + syslog_stats.no_msg.fmds_value.ui64++; + return; + } else if (ret != 0 || nvlist_lookup_boolean_array(prefs[0], "active", + &active, &nelems)) { + fmd_hdl_debug(hdl, "Failed to retrieve notification " + "preferences for class %s\n", class); + if (ret == 0) + free_notify_prefs(hdl, prefs, nprefs); + return; + } else if (!active[0]) { + fmd_hdl_debug(hdl, "Syslog notifications disabled for " + "class %s\n", class); + syslog_stats.no_msg.fmds_value.ui64++; + free_notify_prefs(hdl, prefs, nprefs); + return; + } + free_notify_prefs(hdl, prefs, nprefs); + if ((msg = fmd_msg_gettext_nv(syslog_msghdl, NULL, nvl)) == NULL) { fmd_hdl_debug(hdl, "failed to format message"); syslog_stats.bad_code.fmds_value.ui64++; @@ -204,8 +301,10 @@ } syslog_ctl.pri &= LOG_FACMASK; - if (strcmp(class, FM_LIST_RESOLVED_CLASS) == 0 || - strcmp(class, FM_LIST_REPAIRED_CLASS) == 0) + if (strcmp(class, FM_LIST_ISOLATED_CLASS) == 0 || + strcmp(class, FM_LIST_RESOLVED_CLASS) == 0 || + strcmp(class, FM_LIST_REPAIRED_CLASS) == 0 || + strcmp(class, FM_LIST_UPDATED_CLASS) == 0) syslog_ctl.pri |= LOG_NOTICE; else syslog_ctl.pri |= LOG_ERR; @@ -233,7 +332,7 @@ }; static const fmd_hdl_info_t fmd_info = { - "Syslog Messaging Agent", "1.0", &fmd_ops, fmd_props + "Syslog Messaging Agent", "1.1", &fmd_ops, fmd_props }; void @@ -303,9 +402,16 @@ (void) fmd_msg_url_set(syslog_msghdl, urlbase); fmd_prop_free_string(hdl, urlbase); + /* + * We subscribe to all FM events and then consult the notification + * preferences in the serice configuration repo to determine whether + * or not to emit a console message. + */ fmd_hdl_subscribe(hdl, FM_LIST_SUSPECT_CLASS); fmd_hdl_subscribe(hdl, FM_LIST_REPAIRED_CLASS); fmd_hdl_subscribe(hdl, FM_LIST_RESOLVED_CLASS); + fmd_hdl_subscribe(hdl, FM_LIST_ISOLATED_CLASS); + fmd_hdl_subscribe(hdl, FM_LIST_UPDATED_CLASS); } /*ARGSUSED*/ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c --- a/usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,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 @@ -69,6 +68,8 @@ { "eagain", FMD_TYPE_UINT64, "events retried due to low memory" }, }; +static sysevent_subattr_t *subattr; + /* * event_transfer(sysevent_t *ev, void *arg) * takes a sysevent ev, extracts the nvlist of @@ -122,6 +123,8 @@ if (h_event != NULL) { (void) sysevent_evc_unsubscribe(h_event, SUBSCRIBE_ID); (void) sysevent_evc_unbind(h_event); + if (subattr != NULL) + sysevent_subattr_free(subattr); } if (h_fmd != NULL && h_xprt != NULL) @@ -154,8 +157,15 @@ fmd_hdl_unregister(hdl); } - ret = sysevent_evc_subscribe(h_event, SUBSCRIBE_ID, - SUBSCRIBE_FLAGS, event_transfer, NULL, 0); + if ((subattr = sysevent_subattr_alloc()) == NULL) + fmd_hdl_abort(hdl, "failed to allocate subscription " + "attributes: %s"); + + sysevent_subattr_thrcreate(subattr, fmd_doorthr_create, NULL); + sysevent_subattr_thrsetup(subattr, fmd_doorthr_setup, NULL); + + ret = sysevent_evc_xsubscribe(h_event, SUBSCRIBE_ID, + SUBSCRIBE_FLAGS, event_transfer, NULL, 0, subattr); if (ret != 0) { if (ret == EEXIST) { fmd_hdl_unregister(hdl); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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. +# + +SUBDIRS = \ + smtp-notify \ + snmp-notify + +include ./Makefile.subdirs +include ../../Makefile.cmd diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/Makefile.subdirs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/Makefile.subdirs Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,40 @@ +# +# 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. +# + +.KEEP_STATE: + +all := TARGET += all +clean := TARGET += clean +clobber := TARGET += clobber +install := TARGET += install +install_h := TARGET += install_h +lint := TARGET += lint + +all clean clobber install install_h lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/notify-params.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/notify-params.xml Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/smtp-notify/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/smtp-notify/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,28 @@ +# +# 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. +# + +SUBDIRS = $(MACH) + +include ../Makefile.subdirs diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/smtp-notify/Makefile.com --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/smtp-notify/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -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. +# + +.KEEP_STATE: +.SUFFIXES: + +SRCS += smtp-notify.c +OBJS = $(SRCS:%.c=%.o) +LINTFILES = $(SRCS:%.c=%.ln) + +PROG = smtp-notify +HELPER = process_msg_template.sh +ROOTLIBFM = $(ROOT)/usr/lib/fm +ROOTLIBNOTIFY = $(ROOT)/usr/lib/fm/notify +ROOTPROG = $(ROOTLIBNOTIFY)/$(PROG) +ROOTHELPER = $(ROOTLIBNOTIFY)/$(HELPER) + +ROOTMANIFESTDIR = $(ROOTSVCSYSTEM)/fm +ROOTMANIFEST = $(ROOTMANIFESTDIR)/$(PROG).xml +ROOTNOTIFYPARAMS = $(ROOTMANIFESTDIR)/notify-params.xml +$(ROOTMANIFEST) := FILEMODE = 0444 +$(ROOTNOTIFYPARAMS) := FILEMODE = 0444 + +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG +CPPFLAGS += -I. -I../common -I../../../../../lib/fm/libfmnotify/common +C99MODE = $(C99_ENABLE) +CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) +LDLIBS += -L$(ROOT)/usr/lib/fm -lnvpair -lfmevent -lfmd_msg -lfmnotify \ +-lumem +LDFLAGS += -R/usr/lib/fm +LINTFLAGS += -mnu + +.NO_PARALLEL: +.PARALLEL: $(OBJS) $(LINTFILES) + +all: $(PROG) $(HELPER) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(CTFMERGE) -L VERSION -o $@ $(OBJS) + $(POST_PROCESS) + +$(HELPER): ../common/$(HELPER) + $(CP) ../common/$(HELPER) . + +%.o: ../common/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.o: %.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +clean: + $(RM) $(OBJS) $(HELPER) $(LINTFILES) + +clobber: clean + $(RM) $(PROG) + +%.ln: ../common/%.c + $(LINT.c) -c $< + +%.ln: %.c + $(LINT.c) -c $< + +lint: $(LINTFILES) + $(LINT) $(LINTFLAGS) $(LINTFILES) + +$(ROOTLIBNOTIFY): + $(INS.dir) + +$(ROOTLIBNOTIFY)/%: % + $(INS.file) + +$(ROOTMANIFESTDIR): + $(INS.dir) + +$(ROOTMANIFESTDIR)/%.xml: ../common/%.xml + $(INS.file) + +$(ROOTMANIFESTDIR)/notify-params.xml: ../../notify-params.xml + $(INS.file) ../../notify-params.xml + +install_h: + +install: all $(ROOTLIBNOTIFY) $(ROOTPROG) $(ROOTHELPER) $(ROOTMANIFESTDIR) \ +$(ROOTMANIFEST) $(ROOTNOTIFYPARAMS) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/smtp-notify/common/process_msg_template.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/smtp-notify/common/process_msg_template.sh Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,68 @@ +#!/bin/sh + +# +# 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. +# + +# +# This is a simple helper script for smtp-notify which looks for certain +# expansion macros, which we've committed and converts them to valid +# libfmd_msg macros which directly reference event payload members. +# +# This allows us to change event payload names or alter the libfmd_msg +# expansion macro syntax without breaking user-supplied message body +# templates. +# +# We use all-caps for the committed macro names to avoid colliding +# with an actual event payload member name. +# +# Usage: process_msg_template.sh +# + +# +# Verify template exists, is readable and is an ascii text file +# +if [ ! -e $1 ] || [ ! -r $1 ]; then + exit 1 +fi + +/usr/bin/file $1 | grep "ascii text" > /dev/null +if [ $? != 0 ]; then + exit 1 +fi + +tmpfile1=$2; +tmpfile2=`/usr/bin/mktemp -p /var/tmp` + +cat $1 | sed s/\%\/$3/g > $tmpfile1 +cat $tmpfile1 | sed s/\%\/\%\/g > $tmpfile2 +cat $tmpfile2 | sed s/\%\/\%\/g > $tmpfile1 +cat $tmpfile1 | sed s/\%\/$4/g > $tmpfile2 +cat $tmpfile2 | sed s/\%\/svc\:\\/\%\\:\%\/g > $tmpfile1 +cat $tmpfile1 | sed s/\%\/\%\/g > $tmpfile2 +cat $tmpfile2 | sed s/\%\/\%\/g > $tmpfile1 +cat $tmpfile1 | sed s/\%\/\%h/g > $tmpfile2 +cat $tmpfile2 | sed s/\%\/\%s/g > $tmpfile1 +rm -f $tmpfile2 +exit 0 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/smtp-notify/common/smtp-notify.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/smtp-notify/common/smtp-notify.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,906 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libfmnotify.h" + +#define SENDMAIL "/usr/sbin/sendmail" +#define SVCNAME "system/fm/smtp-notify" + +#define XHDR_HOSTNAME "X-FMEV-HOSTNAME" +#define XHDR_CLASS "X-FMEV-CLASS" +#define XHDR_UUID "X-FMEV-UUID" +#define XHDR_MSGID "X-FMEV-CODE" +#define XHDR_SEVERITY "X-FMEV-SEVERITY" +#define XHDR_FMRI "X-FMEV-FMRI" +#define XHDR_FROM_STATE "X-FMEV-FROM-STATE" +#define XHDR_TO_STATE "X-FMEV-TO-STATE" + +/* + * Debug messages can be enabled by setting the debug property to true + * + * # svccfg -s svc:/system/fm/smtp-notify setprop config/debug=true + * + * Debug messages will be spooled to the service log at: + * /var/svc/log/system-fm-smtp-notify:default.log + */ +#define PP_SCRIPT "usr/lib/fm/notify/process_msg_template.sh" + +typedef struct email_pref +{ + int ep_num_recips; + char **ep_recips; + char *ep_reply_to; + char *ep_template_path; + char *ep_template; +} email_pref_t; + +static nd_hdl_t *nhdl; +static char hostname[MAXHOSTNAMELEN + 1]; +static const char optstr[] = "dfR:"; +static const char DEF_SUBJ_TEMPLATE[] = "smtp-notify-subject-template"; +static const char SMF_SUBJ_TEMPLATE[] = "smtp-notify-smf-subject-template"; +static const char FM_SUBJ_TEMPLATE[] = "smtp-notify-fm-subject-template"; +static const char IREPORT_MSG_TEMPLATE[] = "ireport-msg-template"; +static const char SMF_MSG_TEMPLATE[] = "ireport.os.smf-msg-template"; + +static int +usage(const char *pname) +{ + (void) fprintf(stderr, "Usage: %s [-df] [-R ]\n", pname); + + (void) fprintf(stderr, + "\t-d enable debug mode\n" + "\t-f stay in foreground\n" + "\t-R specify alternate root\n"); + + return (1); +} + +/* + * This function simply reads the file specified by "template" into a buffer + * and returns a pointer to that buffer (or NULL on failure). The caller is + * responsible for free'ing the returned buffer. + */ +static char * +read_template(const char *template) +{ + int fd; + struct stat statb; + char *buf; + + if (stat(template, &statb) != 0) { + nd_error(nhdl, "Failed to stat %s (%s)", template, + strerror(errno)); + return (NULL); + } + if ((fd = open(template, O_RDONLY)) < 0) { + nd_error(nhdl, "Failed to open %s (%s)", template, + strerror(errno)); + return (NULL); + } + if ((buf = malloc(statb.st_size + 1)) == NULL) { + nd_error(nhdl, "Failed to allocate %d bytes", statb.st_size); + (void) close(fd); + return (NULL); + } + if (read(fd, buf, statb.st_size) < 0) { + nd_error(nhdl, "Failed to read in template (%s)", + strerror(errno)); + free(buf); + (void) close(fd); + return (NULL); + } + buf[statb.st_size] = '\0'; + (void) close(fd); + return (buf); +} + +/* + * This function runs a user-supplied message body template through a script + * which replaces the "committed" expansion macros with actual libfmd_msg + * expansion macros. + */ +static int +process_template(nd_ev_info_t *ev_info, email_pref_t *eprefs) +{ + char pp_script[PATH_MAX], tmpfile[PATH_MAX], pp_cli[PATH_MAX]; + int ret = -1; + + (void) snprintf(pp_script, sizeof (pp_script), "%s%s", + nhdl->nh_rootdir, PP_SCRIPT); + (void) snprintf(tmpfile, sizeof (tmpfile), "%s%s", + nhdl->nh_rootdir, tmpnam(NULL)); + + /* + * If it's an SMF event, then the diagcode and severity won't be part + * of the event payload and so libfmd_msg won't be able to expand them. + * Therefore we pass the code and severity into the script and let the + * script do the expansion. + */ + /* LINTED: E_SEC_SPRINTF_UNBOUNDED_COPY */ + (void) sprintf(pp_cli, "%s %s %s %s %s", pp_script, + eprefs->ep_template_path, tmpfile, ev_info->ei_diagcode, + ev_info->ei_severity); + + nd_debug(nhdl, "Executing %s", pp_cli); + if (system(pp_cli) != -1) + if ((eprefs->ep_template = read_template(tmpfile)) != NULL) + ret = 0; + + (void) unlink(tmpfile); + return (ret); +} + +/* + * If someone does an "svcadm refresh" on us, then this function gets called, + * which rereads our service configuration. + */ +static void +get_svc_config() +{ + int s = 0; + uint8_t val; + + s = nd_get_boolean_prop(nhdl, SVCNAME, "config", "debug", &val); + nhdl->nh_debug = val; + + s += nd_get_astring_prop(nhdl, SVCNAME, "config", "rootdir", + &(nhdl->nh_rootdir)); + + if (s != 0) + nd_error(nhdl, "Failed to read retrieve service " + "properties\n"); +} + +static void +nd_sighandler(int sig) +{ + if (sig == SIGHUP) + get_svc_config(); + else + nd_cleanup(nhdl); +} + +/* + * This function constructs all the email headers and puts them into the + * "headers" buffer handle. The caller is responsible for free'ing this + * buffer. + */ +static int +build_headers(nd_hdl_t *nhdl, nd_ev_info_t *ev_info, email_pref_t *eprefs, + char **headers) +{ + const char *subj_key; + char *subj_fmt, *subj = NULL; + size_t len; + boolean_t is_smf_event = B_FALSE, is_fm_event = B_FALSE; + + /* + * Fetch and format the email subject. + */ + if (strncmp(ev_info->ei_class, "list.", 5) == 0) { + is_fm_event = B_TRUE; + subj_key = FM_SUBJ_TEMPLATE; + } else if (strncmp(ev_info->ei_class, "ireport.os.smf", 14) == 0) { + is_smf_event = B_TRUE; + subj_key = SMF_SUBJ_TEMPLATE; + } else { + subj_key = DEF_SUBJ_TEMPLATE; + } + + if ((subj_fmt = fmd_msg_gettext_key(nhdl->nh_msghdl, NULL, + FMNOTIFY_MSG_DOMAIN, subj_key)) == NULL) { + nd_error(nhdl, "Failed to contruct subject format"); + return (-1); /* libfmd_msg error */ + } + + if (is_fm_event) { + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + len = snprintf(NULL, 0, subj_fmt, hostname, + ev_info->ei_diagcode); + subj = alloca(len + 1); + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + (void) snprintf(subj, len + 1, subj_fmt, hostname, + ev_info->ei_diagcode); + } else if (is_smf_event) { + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + len = snprintf(NULL, 0, subj_fmt, hostname, ev_info->ei_fmri, + ev_info->ei_from_state, ev_info->ei_to_state); + subj = alloca(len + 1); + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + (void) snprintf(subj, len + 1, subj_fmt, hostname, + ev_info->ei_fmri, ev_info->ei_from_state, + ev_info->ei_to_state); + } else { + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + len = snprintf(NULL, 0, subj_fmt, hostname); + subj = alloca(len + 1); + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + (void) snprintf(subj, len + 1, subj_fmt, hostname); + } + + /* + * Here we add some X-headers to our mail message for use by mail + * filtering agents. We add headers for the following bits of event + * data for all events + * + * hostname + * msg id (diagcode) + * event class + * event severity + * event uuid + * + * For SMF transition events, we'll have the following add'l X-headers + * + * from-state + * to-state + * service fmri + * + * We follow the X-headers with standard Reply-To and Subject headers. + */ + if (is_fm_event) { + len = snprintf(NULL, 0, "%s: %s\n%s: %s\n%s: %s\n%s: %s\n" + "%s: %s\nReply-To: %s\nSubject: %s\n\n", XHDR_HOSTNAME, + hostname, XHDR_CLASS, ev_info->ei_class, XHDR_UUID, + ev_info->ei_uuid, XHDR_MSGID, ev_info->ei_diagcode, + XHDR_SEVERITY, ev_info->ei_severity, eprefs->ep_reply_to, + subj); + + *headers = calloc(len + 1, sizeof (char)); + + (void) snprintf(*headers, len + 1, "%s: %s\n%s: %s\n%s: %s\n" + "%s: %s\n%s: %s\nReply-To: %s\nSubject: %s\n\n", + XHDR_HOSTNAME, hostname, XHDR_CLASS, ev_info->ei_class, + XHDR_UUID, ev_info->ei_uuid, XHDR_MSGID, + ev_info->ei_diagcode, XHDR_SEVERITY, ev_info->ei_severity, + eprefs->ep_reply_to, subj); + } else if (is_smf_event) { + len = snprintf(NULL, 0, "%s: %s\n%s: %s\n%s: %s\n%s: %s\n" + "%s: %s\n%s: %s\n%s: %s\nReply-To: %s\n" + "Subject: %s\n\n", XHDR_HOSTNAME, hostname, XHDR_CLASS, + ev_info->ei_class, XHDR_MSGID, ev_info->ei_diagcode, + XHDR_SEVERITY, ev_info->ei_severity, XHDR_FMRI, + ev_info->ei_fmri, XHDR_FROM_STATE, ev_info->ei_from_state, + XHDR_TO_STATE, ev_info->ei_to_state, eprefs->ep_reply_to, + subj); + + *headers = calloc(len + 1, sizeof (char)); + + (void) snprintf(*headers, len + 1, "%s: %s\n%s: %s\n%s: %s\n" + "%s: %s\n%s: %s\n%s: %s\n%s: %s\nReply-To: %s\n" + "Subject: %s\n\n", XHDR_HOSTNAME, hostname, XHDR_CLASS, + ev_info->ei_class, XHDR_MSGID, ev_info->ei_diagcode, + XHDR_SEVERITY, ev_info->ei_severity, XHDR_FMRI, + ev_info->ei_fmri, XHDR_FROM_STATE, ev_info->ei_from_state, + XHDR_TO_STATE, ev_info->ei_to_state, eprefs->ep_reply_to, + subj); + } else { + len = snprintf(NULL, 0, "%s: %s\n%s: %s\n%s: %s\n%s: %s\n" + "Reply-To: %s\nSubject: %s\n\n", XHDR_HOSTNAME, + hostname, XHDR_CLASS, ev_info->ei_class, XHDR_MSGID, + ev_info->ei_diagcode, XHDR_SEVERITY, ev_info->ei_severity, + eprefs->ep_reply_to, subj); + + *headers = calloc(len + 1, sizeof (char)); + + (void) snprintf(*headers, len + 1, "%s: %s\n%s: %s\n%s: %s\n" + "%s: %s\nReply-To: %s\nSubject: %s\n\n", + XHDR_HOSTNAME, hostname, XHDR_CLASS, ev_info->ei_class, + XHDR_MSGID, ev_info->ei_diagcode, XHDR_SEVERITY, + ev_info->ei_severity, eprefs->ep_reply_to, subj); + } + return (0); +} + +static void +send_email(nd_hdl_t *nhdl, const char *headers, const char *body, + const char *recip) +{ + FILE *mp; + char sm_cli[PATH_MAX]; + + /* + * Open a pipe to sendmail and pump out the email message + */ + (void) snprintf(sm_cli, PATH_MAX, "%s -t %s", SENDMAIL, recip); + + nd_debug(nhdl, "Sending email notification to %s", recip); + if ((mp = popen(sm_cli, "w")) == NULL) { + nd_error(nhdl, "Failed to open pipe to %s (%s)", SENDMAIL, + strerror(errno)); + return; + } + if (fprintf(mp, "%s", headers) < 0) + nd_error(nhdl, "Failed to write to pipe (%s)", strerror(errno)); + + if (fprintf(mp, "%s\n.\n", body) < 0) + nd_error(nhdl, "Failed to write to pipe (%s)", + strerror(errno)); + + (void) pclose(mp); +} + +static void +send_email_template(nd_hdl_t *nhdl, nd_ev_info_t *ev_info, email_pref_t *eprefs) +{ + char *msg, *headers; + + if (build_headers(nhdl, ev_info, eprefs, &headers) != 0) + return; + + /* + * If the user specified a message body template, then we pass it + * through a private interface in libfmd_msg, which will return a string + * with any expansion tokens decoded. + */ + if ((msg = fmd_msg_decode_tokens(ev_info->ei_payload, + eprefs->ep_template, ev_info->ei_url)) == NULL) { + nd_error(nhdl, "Failed to parse msg template"); + free(headers); + return; + } + for (int i = 0; i < eprefs->ep_num_recips; i++) + send_email(nhdl, headers, msg, eprefs->ep_recips[i]); + + free(msg); + free(headers); +} + +static int +get_email_prefs(nd_hdl_t *nhdl, fmev_t ev, email_pref_t **eprefs) +{ + nvlist_t **p_nvl = NULL; + email_pref_t *ep; + uint_t npref, tn1 = 0, tn2 = 0; + char **tmparr1, **tmparr2; + int r, ret = -1; + + r = nd_get_notify_prefs(nhdl, "smtp", ev, &p_nvl, &npref); + if (r == SCF_ERROR_NOT_FOUND) { + /* + * No email notification preferences specified for this type of + * event, so we're done + */ + return (-1); + } else if (r != 0) { + nd_error(nhdl, "Failed to retrieve notification preferences " + "for this event"); + return (-1); + } + + if ((ep = malloc(sizeof (email_pref_t))) == NULL) { + nd_error(nhdl, "Failed to allocate space for email preferences " + "(%s)", strerror(errno)); + goto eprefs_done; + } + (void) memset(ep, 0, sizeof (email_pref_t)); + + /* + * For SMF state transition events, pref_nvl may contain two sets of + * preferences, which will have to be merged. + * + * The "smtp" nvlist can contain up to four members: + * + * "active" - boolean - used to toggle notfications + * "to" - a string array of email recipients + * "reply-to" - a string array containing the reply-to addresses + * - this is optional and defaults to root@localhost + * "msg_template" - the pathname of a user-supplied message body + * template + * + * In the case that we have two sets of preferences, we will merge them + * using the following rules: + * + * "active" will be set to true, if it is true in either set + * + * The "reply-to" and "to" lists will be merged, with duplicate email + * addresses removed. + */ + if (npref == 2) { + boolean_t *act1, *act2; + char **arr1, **arr2, **strarr, **reparr1, **reparr2; + uint_t n1, n2, arrsz, repsz; + + r = nvlist_lookup_boolean_array(p_nvl[0], "active", &act1, &n1); + r += nvlist_lookup_boolean_array(p_nvl[1], "active", &act2, + &n2); + r += nvlist_lookup_string_array(p_nvl[0], "to", &arr1, &n1); + r += nvlist_lookup_string_array(p_nvl[1], "to", &arr2, &n2); + + if (r != 0) { + nd_error(nhdl, "Malformed email notification " + "preferences"); + nd_dump_nvlist(nhdl, p_nvl[0]); + nd_dump_nvlist(nhdl, p_nvl[1]); + goto eprefs_done; + } else if (!act1[0] && !act2[0]) { + nd_debug(nhdl, "Email notification is disabled"); + goto eprefs_done; + } + + if (nd_split_list(nhdl, arr1[0], ",", &tmparr1, &tn1) != 0 || + nd_split_list(nhdl, arr2[0], ",", &tmparr2, &tn2) != 0) { + nd_error(nhdl, "Error parsing \"to\" lists"); + nd_dump_nvlist(nhdl, p_nvl[0]); + nd_dump_nvlist(nhdl, p_nvl[1]); + goto eprefs_done; + } + + if ((ep->ep_num_recips = nd_merge_strarray(nhdl, tmparr1, tn1, + tmparr2, tn2, &ep->ep_recips)) < 0) { + nd_error(nhdl, "Error merging email recipient lists"); + goto eprefs_done; + } + + r = nvlist_lookup_string_array(p_nvl[0], "reply-to", &arr1, + &n1); + r += nvlist_lookup_string_array(p_nvl[1], "reply-to", &arr2, + &n2); + repsz = n1 = n2 = 0; + if (!r && + nd_split_list(nhdl, arr1[0], ",", &reparr1, &n1) != 0 || + nd_split_list(nhdl, arr2[0], ",", &reparr2, &n2) != 0 || + (repsz = nd_merge_strarray(nhdl, tmparr1, n1, tmparr2, n2, + &strarr)) != 0 || + nd_join_strarray(nhdl, strarr, repsz, &ep->ep_reply_to) + != 0) { + + ep->ep_reply_to = strdup("root@localhost"); + } + if (n1) + nd_free_strarray(reparr1, n1); + if (n2) + nd_free_strarray(reparr2, n2); + if (repsz > 0) + nd_free_strarray(strarr, repsz); + + if (nvlist_lookup_string_array(p_nvl[0], "msg_template", + &strarr, &arrsz) == 0) + ep->ep_template_path = strdup(strarr[0]); + } else { + char **strarr, **tmparr; + uint_t arrsz; + boolean_t *active; + + /* + * Both the "active" and "to" notification preferences are + * required, so if we have trouble looking either of these up + * we return an error. We will also return an error if "active" + * is set to false. Returning an error will cause us to not + * send a notification for this event. + */ + r = nvlist_lookup_boolean_array(p_nvl[0], "active", &active, + &arrsz); + r += nvlist_lookup_string_array(p_nvl[0], "to", &strarr, + &arrsz); + + if (r != 0) { + nd_error(nhdl, "Malformed email notification " + "preferences"); + nd_dump_nvlist(nhdl, p_nvl[0]); + goto eprefs_done; + } else if (!active[0]) { + nd_debug(nhdl, "Email notification is disabled"); + goto eprefs_done; + } + + if (nd_split_list(nhdl, strarr[0], ",", &tmparr, &arrsz) + != 0) { + nd_error(nhdl, "Error parsing \"to\" list"); + goto eprefs_done; + } + ep->ep_num_recips = arrsz; + ep->ep_recips = tmparr; + + if (nvlist_lookup_string_array(p_nvl[0], "msg_template", + &strarr, &arrsz) == 0) + ep->ep_template_path = strdup(strarr[0]); + + if (nvlist_lookup_string_array(p_nvl[0], "reply-to", &strarr, + &arrsz) == 0) + ep->ep_reply_to = strdup(strarr[0]); + else + ep->ep_reply_to = strdup("root@localhost"); + } + ret = 0; + *eprefs = ep; +eprefs_done: + if (ret != 0) { + if (ep->ep_recips) + nd_free_strarray(ep->ep_recips, ep->ep_num_recips); + if (ep->ep_reply_to) + free(ep->ep_reply_to); + free(ep); + } + if (tn1) + nd_free_strarray(tmparr1, tn1); + if (tn2) + nd_free_strarray(tmparr2, tn2); + nd_free_nvlarray(p_nvl, npref); + + return (ret); +} + +/*ARGSUSED*/ +static void +irpt_cbfunc(fmev_t ev, const char *class, nvlist_t *nvl, void *arg) +{ + char *body_fmt, *headers = NULL, *body = NULL, tstamp[32]; + struct tm ts; + size_t len; + nd_ev_info_t *ev_info = NULL; + email_pref_t *eprefs; + + nd_debug(nhdl, "Received event of class %s", class); + + if (get_email_prefs(nhdl, ev, &eprefs) < 0) + return; + + if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0) + goto irpt_done; + + /* + * If the user specified a template, then we pass it through a script, + * which post-processes any expansion macros. Then we attempt to read + * it in and then send the message. Otherwise we carry on with the rest + * of this function which will contruct the message body from one of the + * default templates. + */ + if (eprefs->ep_template != NULL) + free(eprefs->ep_template); + + if (eprefs->ep_template_path != NULL && + process_template(ev_info, eprefs) == 0) { + send_email_template(nhdl, ev_info, eprefs); + goto irpt_done; + } + + /* + * Fetch and format the event timestamp + */ + if (fmev_localtime(ev, &ts) == NULL) { + nd_error(nhdl, "Malformed event: failed to retrieve " + "timestamp"); + goto irpt_done; + } + (void) strftime(tstamp, sizeof (tstamp), NULL, &ts); + + /* + * We have two message body templates to choose from. One for SMF + * service transition events and a generic one for any other + * uncommitted ireport. + */ + if (strncmp(class, "ireport.os.smf", 14) == 0) { + /* + * For SMF state transition events we have a standard message + * template that we fill in based on the payload of the event. + */ + if ((body_fmt = fmd_msg_gettext_key(nhdl->nh_msghdl, NULL, + FMNOTIFY_MSG_DOMAIN, SMF_MSG_TEMPLATE)) == NULL) { + nd_error(nhdl, "Failed to format message body"); + goto irpt_done; + } + + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + len = snprintf(NULL, 0, body_fmt, hostname, tstamp, + ev_info->ei_fmri, ev_info->ei_from_state, + ev_info->ei_to_state, ev_info->ei_descr, + ev_info->ei_reason); + body = calloc(len, sizeof (char)); + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + (void) snprintf(body, len, body_fmt, hostname, tstamp, + ev_info->ei_fmri, ev_info->ei_from_state, + ev_info->ei_to_state, ev_info->ei_descr, + ev_info->ei_reason); + } else { + if ((body_fmt = fmd_msg_gettext_key(nhdl->nh_msghdl, NULL, + FMNOTIFY_MSG_DOMAIN, IREPORT_MSG_TEMPLATE)) == NULL) { + nd_error(nhdl, "Failed to format message body"); + goto irpt_done; + } + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + len = snprintf(NULL, 0, body_fmt, hostname, tstamp, class); + body = calloc(len, sizeof (char)); + /* LINTED: E_SEC_PRINTF_VAR_FMT */ + (void) snprintf(body, len, body_fmt, hostname, tstamp, class); + } + + if (build_headers(nhdl, ev_info, eprefs, &headers) != 0) + goto irpt_done; + + /* + * Everything is ready, so now we just iterate through the list of + * recipents, sending an email notification to each one. + */ + for (int i = 0; i < eprefs->ep_num_recips; i++) + send_email(nhdl, headers, body, eprefs->ep_recips[i]); + +irpt_done: + free(headers); + free(body); + if (ev_info) + nd_free_event_info(ev_info); + if (eprefs->ep_recips) + nd_free_strarray(eprefs->ep_recips, eprefs->ep_num_recips); + if (eprefs->ep_reply_to) + free(eprefs->ep_reply_to); + free(eprefs); +} + +/* + * There is a lack of uniformity in how the various entries in our diagnosis + * are terminated. Some end with one newline, others with two. This makes the + * output look a bit ugly. Therefore we postprocess the message before sending + * it, removing consecutive occurences of newlines. + */ +static void +postprocess_msg(char *msg) +{ + int i = 0, j = 0; + char *buf; + + if ((buf = malloc(strlen(msg) + 1)) == NULL) + return; + + buf[j++] = msg[i++]; + for (i = 1; i < strlen(msg); i++) { + if (!(msg[i] == '\n' && msg[i - 1] == '\n')) + buf[j++] = msg[i]; + } + buf[j] = '\0'; + (void) strncpy(msg, buf, j+1); + free(buf); +} + +/*ARGSUSED*/ +static void +listev_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg) +{ + char *body = NULL, *headers = NULL; + nd_ev_info_t *ev_info = NULL; + boolean_t domsg; + email_pref_t *eprefs; + + nd_debug(nhdl, "Received event of class %s", class); + + if (get_email_prefs(nhdl, ev, &eprefs) < 0) + return; + + if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0) + goto listcb_done; + + /* + * If the message payload member is set to 0, then it's an event we + * typically suppress messaging on, so we won't send an email for it. + */ + if (nvlist_lookup_boolean_value(ev_info->ei_payload, FM_SUSPECT_MESSAGE, + &domsg) == 0 && !domsg) { + nd_debug(nhdl, "Messaging suppressed for this event"); + goto listcb_done; + } + + /* + * If the user specified a template, then we pass it through a script, + * which post-processes any expansion macros. Then we attempt to read + * it in and then send the message. Otherwise we carry on with the rest + * of this function which will contruct the message body from one of the + * default templates. + */ + if (eprefs->ep_template != NULL) + free(eprefs->ep_template); + + if (eprefs->ep_template_path != NULL && + process_template(ev_info, eprefs) == 0) { + send_email_template(nhdl, ev_info, eprefs); + goto listcb_done; + } + + /* + * Format the message body + * + * For FMA list.* events we use the same message that the + * syslog-msgs agent would emit as the message body + * + */ + if ((body = fmd_msg_gettext_nv(nhdl->nh_msghdl, NULL, + ev_info->ei_payload)) == NULL) { + nd_error(nhdl, "Failed to format message body"); + nd_dump_nvlist(nhdl, ev_info->ei_payload); + goto listcb_done; + } + postprocess_msg(body); + + if (build_headers(nhdl, ev_info, eprefs, &headers) != 0) + goto listcb_done; + + /* + * Everything is ready, so now we just iterate through the list of + * recipents, sending an email notification to each one. + */ + for (int i = 0; i < eprefs->ep_num_recips; i++) + send_email(nhdl, headers, body, eprefs->ep_recips[i]); + +listcb_done: + free(headers); + free(body); + if (ev_info) + nd_free_event_info(ev_info); + if (eprefs->ep_recips) + nd_free_strarray(eprefs->ep_recips, eprefs->ep_num_recips); + if (eprefs->ep_reply_to) + free(eprefs->ep_reply_to); + free(eprefs); +} + +int +main(int argc, char *argv[]) +{ + struct rlimit rlim; + struct sigaction act; + sigset_t set; + char c; + boolean_t run_fg = B_FALSE; + + if ((nhdl = malloc(sizeof (nd_hdl_t))) == NULL) { + (void) fprintf(stderr, "Failed to allocate space for notifyd " + "handle (%s)", strerror(errno)); + return (1); + } + (void) memset(nhdl, 0, sizeof (nd_hdl_t)); + + nhdl->nh_keep_running = B_TRUE; + nhdl->nh_log_fd = stderr; + nhdl->nh_pname = argv[0]; + + get_svc_config(); + + /* + * In the case where we get started outside of SMF, args passed on the + * command line override SMF property setting + */ + while (optind < argc) { + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'd': + nhdl->nh_debug = B_TRUE; + break; + case 'f': + run_fg = B_TRUE; + break; + case 'R': + nhdl->nh_rootdir = strdup(optarg); + break; + default: + free(nhdl); + return (usage(nhdl->nh_pname)); + } + } + } + + /* + * Set up a signal handler for SIGTERM (and SIGINT if we'll + * be running in the foreground) to ensure sure we get a chance to exit + * in an orderly fashion. We also catch SIGHUP, which will be sent to + * us by SMF if the service is refreshed. + */ + (void) sigfillset(&set); + (void) sigfillset(&act.sa_mask); + act.sa_handler = nd_sighandler; + act.sa_flags = 0; + + (void) sigaction(SIGTERM, &act, NULL); + (void) sigdelset(&set, SIGTERM); + (void) sigaction(SIGHUP, &act, NULL); + (void) sigdelset(&set, SIGHUP); + + if (run_fg) { + (void) sigaction(SIGINT, &act, NULL); + (void) sigdelset(&set, SIGINT); + } else + nd_daemonize(nhdl); + + rlim.rlim_cur = RLIM_INFINITY; + rlim.rlim_max = RLIM_INFINITY; + (void) setrlimit(RLIMIT_CORE, &rlim); + + /* + * We need to be root to initialize our libfmevent handle (because that + * involves reading/writing to /dev/sysevent), so we do this before + * calling __init_daemon_priv. + */ + nhdl->nh_evhdl = fmev_shdl_init(LIBFMEVENT_VERSION_2, NULL, NULL, NULL); + if (nhdl->nh_evhdl == NULL) { + (void) sleep(5); + nd_abort(nhdl, "failed to initialize libfmevent: %s", + fmev_strerror(fmev_errno)); + } + + /* + * If we're in the global zone, reset all of our privilege sets to + * the minimum set of required privileges. Since we've already + * initialized our libmevent handle, we no no longer need to run as + * root, so we change our uid/gid to noaccess (60002). + * + * __init_daemon_priv will also set the process core path for us + * + */ + if (getzoneid() == GLOBAL_ZONEID) + if (__init_daemon_priv( + PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS, + 60002, 60002, PRIV_PROC_SETID, NULL) != 0) + nd_abort(nhdl, "additional privileges required to run"); + + nhdl->nh_msghdl = fmd_msg_init(nhdl->nh_rootdir, FMD_MSG_VERSION); + if (nhdl->nh_msghdl == NULL) + nd_abort(nhdl, "failed to initialize libfmd_msg"); + + (void) gethostname(hostname, MAXHOSTNAMELEN + 1); + /* + * Set up our event subscriptions. We subscribe to everything and then + * consult libscf when we receive an event to determine whether to send + * an email notification. + */ + nd_debug(nhdl, "Subscribing to ireport.* events"); + if (fmev_shdl_subscribe(nhdl->nh_evhdl, "ireport.*", irpt_cbfunc, + NULL) != FMEV_SUCCESS) { + nd_abort(nhdl, "fmev_shdl_subscribe failed: %s", + fmev_strerror(fmev_errno)); + } + + nd_debug(nhdl, "Subscribing to list.* events"); + if (fmev_shdl_subscribe(nhdl->nh_evhdl, "list.*", listev_cb, + NULL) != FMEV_SUCCESS) { + nd_abort(nhdl, "fmev_shdl_subscribe failed: %s", + fmev_strerror(fmev_errno)); + } + + /* + * We run until someone kills us + */ + while (nhdl->nh_keep_running) + (void) sigsuspend(&set); + + free(nhdl->nh_rootdir); + free(nhdl); + + return (0); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/smtp-notify/common/smtp-notify.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/smtp-notify/common/smtp-notify.xml Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/smtp-notify/i386/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/smtp-notify/i386/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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. +# + +include ../../../../Makefile.cmd +include ../Makefile.com diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/smtp-notify/sparc/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/smtp-notify/sparc/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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. +# + +include ../../../../Makefile.cmd +include ../Makefile.com diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/snmp-notify/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/snmp-notify/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,28 @@ +# +# 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. +# + +SUBDIRS = $(MACH) + +include ../Makefile.subdirs diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/snmp-notify/Makefile.com --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/snmp-notify/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,103 @@ +# +# 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. +# + +.KEEP_STATE: +.SUFFIXES: + +SRCS += snmp-notify.c +OBJS = $(SRCS:%.c=%.o) +LINTFILES = $(SRCS:%.c=%.ln) + +PROG = snmp-notify +ROOTLIBFM = $(ROOT)/usr/lib/fm +ROOTLIBNOTIFY = $(ROOT)/usr/lib/fm/notify +ROOTPROG = $(ROOTLIBNOTIFY)/$(PROG) + +ROOTMANIFESTDIR = $(ROOTSVCSYSTEM)/fm +ROOTMANIFEST = $(ROOTMANIFESTDIR)/$(PROG).xml +ROOTNOTIFYPARAMS = $(ROOTMANIFESTDIR)/notify-params.xml +$(ROOTMANIFEST) := FILEMODE = 0444 +$(ROOTNOTIFYPARAMS) := FILEMODE = 0444 + +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG +CPPFLAGS += -I. -I../common -I../../../../../lib/fm/libfmnotify/common +C99MODE = $(C99_ENABLE) +CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) +LDLIBS += -L$(ROOT)/usr/lib/fm -lnvpair -lfmevent -lfmd_msg -lfmnotify \ + -lumem -lnetsnmp -lnetsnmpagent +LDFLAGS += -R/usr/lib/fm +LINTFLAGS += -mnu + +.NO_PARALLEL: +.PARALLEL: $(OBJS) $(LINTFILES) + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(CTFMERGE) -L VERSION -o $@ $(OBJS) + $(POST_PROCESS) + +%.o: ../common/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.o: %.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +clean: + $(RM) $(OBJS) $(LINTFILES) + +clobber: clean + $(RM) $(PROG) + +%.ln: ../common/%.c + $(LINT.c) -c $< + +%.ln: %.c + $(LINT.c) -c $< + +lint: $(LINTFILES) + $(LINT) $(LINTFLAGS) $(LINTFILES) + +$(ROOTLIBNOTIFY): + $(INS.dir) + +$(ROOTLIBNOTIFY)/%: % + $(INS.file) + +$(ROOTMANIFESTDIR): + $(INS.dir) + +$(ROOTMANIFESTDIR)/%.xml: ../common/%.xml + $(INS.file) + +$(ROOTMANIFESTDIR)/notify-params.xml: ../../notify-params.xml + $(INS.file) ../../notify-params.xml + +install_h: + +install: all $(ROOTLIBNOTIFY) $(ROOTPROG) $(ROOTMANIFESTDIR) $(ROOTMANIFEST) $(ROOTNOTIFYPARAMS) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/snmp-notify/common/snmp-notify.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/snmp-notify/common/snmp-notify.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,687 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libfmnotify.h" + +/* + * Debug messages can be enabled by setting the debug property to true + * + * # svccfg -s svc:/system/fm/snmp-notify setprop config/debug=true + */ +#define SVCNAME "system/fm/snmp-notify" + +typedef struct ireport_trap { + char *host; + char *msgid; + char *desc; + long long tstamp; + char *fmri; + uint32_t from_state; + uint32_t to_state; + char *reason; + boolean_t is_stn_event; +} ireport_trap_t; + +static nd_hdl_t *nhdl; +static const char optstr[] = "dfR:"; +static const char SNMP_SUPPCONF[] = "fmd-trapgen"; +static char hostname[MAXHOSTNAMELEN + 1]; + +static int +usage(const char *pname) +{ + (void) fprintf(stderr, "Usage: %s [-df] [-R ]\n", pname); + + (void) fprintf(stderr, + "\t-d enable debug mode\n" + "\t-f stay in foreground\n" + "\t-R specify alternate root\n"); + + return (1); +} + +/* + * If someone does an "svcadm refresh" on us, then this function gets called, + * which rereads our service configuration. + */ +static void +get_svc_config() +{ + int s = 0; + uint8_t val; + + s = nd_get_boolean_prop(nhdl, SVCNAME, "config", "debug", &val); + nhdl->nh_debug = val; + + s += nd_get_astring_prop(nhdl, SVCNAME, "config", "rootdir", + &(nhdl->nh_rootdir)); + + if (s != 0) + nd_error(nhdl, "Failed to read retrieve service " + "properties"); +} + +static void +nd_sighandler(int sig) +{ + if (sig == SIGHUP) + get_svc_config(); + else + nd_cleanup(nhdl); +} + +static int +get_snmp_prefs(nd_hdl_t *nhdl, nvlist_t **pref_nvl, uint_t npref) +{ + boolean_t *a1, *a2; + uint_t n; + int r; + + /* + * For SMF state transition events, pref_nvl contain two sets of + * preferences, which will have to be merged. + * + * The "snmp" nvlist currently only supports a single boolean member, + * "active" which will be set to true, if it is true in either set + */ + if (npref == 2) { + r = nvlist_lookup_boolean_array(pref_nvl[0], "active", &a1, &n); + r += nvlist_lookup_boolean_array(pref_nvl[1], "active", &a2, + &n); + if (r != 0) { + nd_debug(nhdl, "Malformed snmp notification " + "preferences"); + nd_dump_nvlist(nhdl, pref_nvl[0]); + nd_dump_nvlist(nhdl, pref_nvl[1]); + return (-1); + } else if (!a1[0] && !a2[0]) { + nd_debug(nhdl, "SNMP notification is disabled"); + return (-1); + } + } else { + if (nvlist_lookup_boolean_array(pref_nvl[0], "active", + &a1, &n)) { + nd_debug(nhdl, "Malformed snmp notification " + "preferences"); + nd_dump_nvlist(nhdl, pref_nvl[0]); + return (-1); + } else if (!a1[0]) { + nd_debug(nhdl, "SNMP notification is disabled"); + return (-1); + } + } + return (0); +} + +static void +send_ireport_trap(ireport_trap_t *t) +{ + static const oid sunIreportTrap_oid[] = + { SUNIREPORTTRAP_OID }; + const size_t sunIreportTrap_len = + OID_LENGTH(sunIreportTrap_oid); + + static const oid sunIreportHostname_oid[] = + { SUNIREPORTHOSTNAME_OID }; + static const oid sunIreportMsgid_oid[] = + { SUNIREPORTMSGID_OID }; + static const oid sunIreportDescription_oid[] = + { SUNIREPORTDESCRIPTION_OID }; + static const oid sunIreportTime_oid[] = + { SUNIREPORTTIME_OID }; + + static const oid sunIreportSmfFmri_oid[] = + { SUNIREPORTSMFFMRI_OID }; + static const oid sunIreportSmfFromState_oid[] = + { SUNIREPORTSMFFROMSTATE_OID }; + static const oid sunIreportSmfToState_oid[] = + { SUNIREPORTSMFTOSTATE_OID }; + static const oid sunIreportSmfTransitionReason_oid[] = + { SUNIREPORTTRANSITIONREASON_OID }; + const size_t + sunIreport_base_len = OID_LENGTH(sunIreportHostname_oid); + + size_t var_len = sunIreport_base_len + 1; + oid var_name[MAX_OID_LEN]; + + netsnmp_variable_list *notification_vars = NULL; + + size_t dt_len; + uchar_t dt[11], *tdt; + time_t ts = t->tstamp; + + tdt = date_n_time(&ts, &dt_len); + /* + * We know date_n_time is broken, it returns a buffer from + * its stack. So we copy before we step over it! + */ + for (int i = 0; i < dt_len; ++i) + dt[i] = tdt[i]; + + if (var_len > MAX_OID_LEN) { + nd_error(nhdl, "var_len %d > MAX_OID_LEN %d\n", var_len, + MAX_OID_LEN); + return; + } + + (void) memcpy(var_name, sunIreportHostname_oid, sunIreport_base_len * + sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, + sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->host, + strlen(t->host)); + + (void) memcpy(var_name, sunIreportMsgid_oid, + sunIreport_base_len * sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, + sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->msgid, + strlen(t->msgid)); + + (void) memcpy(var_name, sunIreportDescription_oid, + sunIreport_base_len * sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, + sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->desc, + strlen(t->desc)); + + (void) memcpy(var_name, sunIreportTime_oid, sunIreport_base_len * + sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, + sunIreport_base_len + 1, ASN_OCTET_STR, dt, dt_len); + + if (t->is_stn_event) { + (void) memcpy(var_name, sunIreportSmfFmri_oid, + sunIreport_base_len * sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, + sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->fmri, + strlen(t->fmri)); + + (void) memcpy(var_name, sunIreportSmfFromState_oid, + sunIreport_base_len * sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, + sunIreport_base_len + 1, ASN_INTEGER, + (uchar_t *)&t->from_state, sizeof (uint32_t)); + + (void) memcpy(var_name, sunIreportSmfToState_oid, + sunIreport_base_len * sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, + sunIreport_base_len + 1, ASN_INTEGER, + (uchar_t *)&t->to_state, sizeof (uint32_t)); + + (void) memcpy(var_name, sunIreportSmfTransitionReason_oid, + sunIreport_base_len * sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, + sunIreport_base_len + 1, ASN_OCTET_STR, + (uchar_t *)t->reason, strlen(t->reason)); + } + + /* + * This function is capable of sending both v1 and v2/v3 traps. + * Which is sent to a specific destination is determined by the + * configuration file(s). + */ + send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC, + sunIreportTrap_oid[sunIreportTrap_len - 1], + (oid *)sunIreportTrap_oid, sunIreportTrap_len - 2, + notification_vars); + nd_debug(nhdl, "Sent SNMP trap for %s", t->msgid); + + snmp_free_varbind(notification_vars); + +} + +/*ARGSUSED*/ +static void +send_fm_trap(const char *uuid, const char *code, const char *url) +{ + static const oid sunFmProblemTrap_oid[] = { SUNFMPROBLEMTRAP_OID }; + const size_t sunFmProblemTrap_len = OID_LENGTH(sunFmProblemTrap_oid); + + static const oid sunFmProblemUUID_oid[] = + { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_UUID }; + static const oid sunFmProblemCode_oid[] = + { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_CODE }; + static const oid sunFmProblemURL_oid[] = + { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_URL }; + + const size_t sunFmProblem_base_len = OID_LENGTH(sunFmProblemUUID_oid); + + size_t uuid_len = strlen(uuid); + size_t var_len = sunFmProblem_base_len + 1 + uuid_len; + oid var_name[MAX_OID_LEN]; + + netsnmp_variable_list *notification_vars = NULL; + + /* + * The format of our trap varbinds' oids is as follows: + * + * +-----------------------+---+--------+----------+------+ + * | SUNFMPROBLEMTABLE_OID | 1 | column | uuid_len | uuid | + * +-----------------------+---+--------+----------+------+ + * \---- index ----/ + * + * A common mistake here is to send the trap with varbinds that + * do not contain the index. All the indices are the same, and + * all the oids are the same length, so the only thing we need to + * do for each varbind is set the table and column parts of the + * variable name. + */ + + if (var_len > MAX_OID_LEN) + return; + + var_name[sunFmProblem_base_len] = (oid)uuid_len; + for (int i = 0; i < uuid_len; i++) + var_name[i + sunFmProblem_base_len + 1] = (oid)uuid[i]; + + /* + * Ordinarily, we would need to add the OID of the trap itself + * to the head of the variable list; this is required by SNMP v2. + * However, send_enterprise_trap_vars does this for us as a part + * of converting between v1 and v2 traps, so we skip directly to + * the objects we're sending. + */ + + (void) memcpy(var_name, sunFmProblemUUID_oid, + sunFmProblem_base_len * sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len, + ASN_OCTET_STR, (uchar_t *)uuid, strlen(uuid)); + (void) memcpy(var_name, sunFmProblemCode_oid, + sunFmProblem_base_len * sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len, + ASN_OCTET_STR, (uchar_t *)code, strlen(code)); + (void) memcpy(var_name, sunFmProblemURL_oid, + sunFmProblem_base_len * sizeof (oid)); + (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len, + ASN_OCTET_STR, (uchar_t *)url, strlen(url)); + + /* + * This function is capable of sending both v1 and v2/v3 traps. + * Which is sent to a specific destination is determined by the + * configuration file(s). + */ + send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC, + sunFmProblemTrap_oid[sunFmProblemTrap_len - 1], + (oid *)sunFmProblemTrap_oid, sunFmProblemTrap_len - 2, + notification_vars); + nd_debug(nhdl, "Sent SNMP trap for %s", code); + + snmp_free_varbind(notification_vars); +} + +/* + * The SUN-IREPORT-MIB declares the following enum to represent SMF service + * states. + * + * offline(0), online(1), degraded(2), disabled(3), maintenance(4), + * uninitialized(5) + * + * This function converts a string representation of an SMF service state + * to it's corresponding enum val. + */ +static int +state_to_val(char *statestr, uint32_t *stateval) +{ + if (strcmp(statestr, "offline") == 0) + *stateval = 0; + else if (strcmp(statestr, "online") == 0) + *stateval = 1; + else if (strcmp(statestr, "degraded") == 0) + *stateval = 2; + else if (strcmp(statestr, "disabled") == 0) + *stateval = 3; + else if (strcmp(statestr, "maintenance") == 0) + *stateval = 4; + else if (strcmp(statestr, "uninitialized") == 0) + *stateval = 5; + else + return (-1); + return (0); +} + +/*ARGSUSED*/ +static void +ireport_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg) +{ + nvlist_t **pref_nvl = NULL; + nd_ev_info_t *ev_info = NULL; + ireport_trap_t swtrap; + uint_t npref; + int ret; + + nd_debug(nhdl, "Received event of class %s", class); + + ret = nd_get_notify_prefs(nhdl, "snmp", ev, &pref_nvl, &npref); + if (ret == SCF_ERROR_NOT_FOUND) { + /* + * No snmp notification preferences specified for this type of + * event, so we're done + */ + return; + } else if (ret != 0) { + nd_error(nhdl, "Failed to retrieve notification preferences " + "for this event"); + return; + } + + if (get_snmp_prefs(nhdl, pref_nvl, npref) != 0) + goto irpt_done; + + if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0) + goto irpt_done; + + swtrap.host = hostname; + swtrap.msgid = ev_info->ei_diagcode; + swtrap.desc = ev_info->ei_descr; + swtrap.tstamp = (time_t)fmev_time_sec(ev); + + if (strncmp(class, "ireport.os.smf", 14) == 0) { + swtrap.fmri = ev_info->ei_fmri; + if (state_to_val(ev_info->ei_from_state, &swtrap.from_state) + < 0 || + state_to_val(ev_info->ei_to_state, &swtrap.to_state) < 0) { + nd_error(nhdl, "Malformed event - invalid svc state"); + nd_dump_nvlist(nhdl, ev_info->ei_payload); + goto irpt_done; + } + swtrap.reason = ev_info->ei_reason; + swtrap.is_stn_event = B_TRUE; + } + send_ireport_trap(&swtrap); +irpt_done: + if (ev_info) + nd_free_event_info(ev_info); + nd_free_nvlarray(pref_nvl, npref); +} + +/*ARGSUSED*/ +static void +list_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg) +{ + char *uuid; + uint8_t version; + nd_ev_info_t *ev_info = NULL; + nvlist_t **pref_nvl = NULL; + uint_t npref; + int ret; + boolean_t domsg; + + nd_debug(nhdl, "Received event of class %s", class); + + ret = nd_get_notify_prefs(nhdl, "snmp", ev, &pref_nvl, &npref); + if (ret == SCF_ERROR_NOT_FOUND) { + /* + * No snmp notification preferences specified for this type of + * event, so we're done + */ + return; + } else if (ret != 0) { + nd_error(nhdl, "Failed to retrieve notification preferences " + "for this event"); + return; + } + + if (get_snmp_prefs(nhdl, pref_nvl, npref) != 0) + goto listcb_done; + + if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0) + goto listcb_done; + + /* + * If the message payload member is set to 0, then it's an event we + * typically suppress messaging on, so we won't send a trap for it. + */ + if (nvlist_lookup_boolean_value(ev_info->ei_payload, FM_SUSPECT_MESSAGE, + &domsg) == 0 && !domsg) { + nd_debug(nhdl, "Messaging suppressed for this event"); + goto listcb_done; + } + + if (nvlist_lookup_uint8(ev_info->ei_payload, FM_VERSION, &version) + != 0 || version > FM_SUSPECT_VERSION) { + nd_error(nhdl, "invalid event version: %u", version); + goto listcb_done; + } + + (void) nvlist_lookup_string(ev_info->ei_payload, FM_SUSPECT_UUID, + &uuid); + + if (strcmp(ev_info->ei_url, ND_UNKNOWN) != 0) + send_fm_trap(uuid, ev_info->ei_diagcode, ev_info->ei_url); + else + nd_error(nhdl, "failed to format url for %s", uuid); +listcb_done: + nd_free_nvlarray(pref_nvl, npref); + if (ev_info) + nd_free_event_info(ev_info); +} + +static int +init_sma(void) +{ + int err; + + /* + * The only place we could possibly log is syslog, but the + * full agent doesn't normally log there. It would be confusing + * if this agent did so; therefore we disable logging entirely. + */ + snmp_disable_log(); + + /* + * Net-SNMP has a provision for reading an arbitrary number of + * configuration files. A configuration file is read if it has + * had any handlers registered for it, or if it's the value in + * of NETSNMP_DS_LIB_APPTYPE. Our objective here is to read + * both snmpd.conf and fmd-trapgen.conf. + */ + if ((err = netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_ROLE, 0 /* MASTER_AGENT */)) != SNMPERR_SUCCESS) + return (err); + + init_agent_read_config("snmpd"); + if ((err = netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_APPTYPE, SNMP_SUPPCONF)) != SNMPERR_SUCCESS) + return (err); + if (register_app_config_handler("trapsink", snmpd_parse_config_trapsink, + snmpd_free_trapsinks, "host [community] [port]") == NULL) + return (SNMPERR_MALLOC); + if (register_app_config_handler("trap2sink", + snmpd_parse_config_trap2sink, NULL, "host [community] [port]") == + NULL) + return (SNMPERR_MALLOC); + if (register_app_config_handler("trapsess", snmpd_parse_config_trapsess, + NULL, "[snmpcmdargs] host") == NULL) + return (SNMPERR_MALLOC); + + init_traps(); + init_snmp(SNMP_SUPPCONF); + + return (SNMPERR_SUCCESS); +} + +int +main(int argc, char *argv[]) +{ + struct rlimit rlim; + struct sigaction act; + sigset_t set; + char c; + boolean_t run_fg = B_FALSE; + + if ((nhdl = malloc(sizeof (nd_hdl_t))) == NULL) { + (void) fprintf(stderr, "Failed to allocate space for notifyd " + "handle (%s)", strerror(errno)); + return (1); + } + bzero(nhdl, sizeof (nd_hdl_t)); + nhdl->nh_keep_running = B_TRUE; + nhdl->nh_log_fd = stderr; + nhdl->nh_pname = argv[0]; + + get_svc_config(); + + /* + * In the case where we get started outside of SMF, args passed on the + * command line override SMF property setting + */ + while (optind < argc) { + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'd': + nhdl->nh_debug = B_TRUE; + break; + case 'f': + run_fg = B_TRUE; + break; + case 'R': + nhdl->nh_rootdir = strdup(optarg); + break; + default: + free(nhdl); + return (usage(nhdl->nh_pname)); + } + } + } + + /* + * Set up a signal handler for SIGTERM (and SIGINT if we'll + * be running in the foreground) to ensure sure we get a chance to exit + * in an orderly fashion. We also catch SIGHUP, which will be sent to + * us by SMF if the service is refreshed. + */ + (void) sigfillset(&set); + (void) sigfillset(&act.sa_mask); + act.sa_handler = nd_sighandler; + act.sa_flags = 0; + + (void) sigaction(SIGTERM, &act, NULL); + (void) sigdelset(&set, SIGTERM); + (void) sigaction(SIGHUP, &act, NULL); + (void) sigdelset(&set, SIGHUP); + + if (run_fg) { + (void) sigaction(SIGINT, &act, NULL); + (void) sigdelset(&set, SIGINT); + } else + nd_daemonize(nhdl); + + rlim.rlim_cur = RLIM_INFINITY; + rlim.rlim_max = RLIM_INFINITY; + (void) setrlimit(RLIMIT_CORE, &rlim); + + /* + * We need to be root initialize our libfmevent handle (because that + * involves reading/writing to /dev/sysevent), so we do this before + * calling __init_daemon_priv. + */ + nhdl->nh_evhdl = fmev_shdl_init(LIBFMEVENT_VERSION_2, NULL, NULL, NULL); + if (nhdl->nh_evhdl == NULL) { + (void) sleep(5); + nd_abort(nhdl, "failed to initialize libfmevent: %s", + fmev_strerror(fmev_errno)); + } + + /* + * If we're in the global zone, reset all of our privilege sets to + * the minimum set of required privileges. We also change our + * uid/gid to noaccess/noaccess + * + * __init_daemon_priv will also set the process core path for us + * + */ + if (getzoneid() == GLOBAL_ZONEID) + if (__init_daemon_priv( + PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS, + 60002, 60002, PRIV_FILE_DAC_READ, NULL) != 0) + nd_abort(nhdl, "additional privileges required to run"); + + nhdl->nh_msghdl = fmd_msg_init(nhdl->nh_rootdir, FMD_MSG_VERSION); + if (nhdl->nh_msghdl == NULL) + nd_abort(nhdl, "failed to initialize libfmd_msg"); + + if (init_sma() != SNMPERR_SUCCESS) + nd_abort(nhdl, "SNMP initialization failed"); + + (void) gethostname(hostname, MAXHOSTNAMELEN + 1); + /* + * Set up our event subscriptions. We subscribe to everything and then + * consult libscf when we receive an event to determine what (if any) + * notification to send. + */ + nd_debug(nhdl, "Subscribing to ireport.os.smf.* events"); + if (fmev_shdl_subscribe(nhdl->nh_evhdl, "ireport.os.smf.*", + ireport_cb, NULL) != FMEV_SUCCESS) { + nd_abort(nhdl, "fmev_shdl_subscribe failed: %s", + fmev_strerror(fmev_errno)); + } + + nd_debug(nhdl, "Subscribing to list.* events"); + if (fmev_shdl_subscribe(nhdl->nh_evhdl, "list.*", list_cb, + NULL) != FMEV_SUCCESS) { + nd_abort(nhdl, "fmev_shdl_subscribe failed: %s", + fmev_strerror(fmev_errno)); + } + + /* + * We run until someone kills us + */ + while (nhdl->nh_keep_running) + (void) sigsuspend(&set); + + /* + * snmp_shutdown, which we would normally use here, calls free_slots, + * a callback that is supposed to tear down the pkcs11 state; however, + * it abuses C_Finalize, causing fmd to drop core on shutdown. Avoid + * this by shutting down the library piecemeal. + */ + snmp_store(SNMP_SUPPCONF); + snmp_alarm_unregister_all(); + (void) snmp_close_sessions(); + shutdown_mib(); + unregister_all_config_handlers(); + netsnmp_ds_shutdown(); + + free(nhdl->nh_rootdir); + free(nhdl); + + return (0); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/snmp-notify/common/snmp-notify.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/snmp-notify/common/snmp-notify.xml Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/snmp-notify/i386/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/snmp-notify/i386/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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. +# + +include ../../../../Makefile.cmd +include ../Makefile.com diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/notify/snmp-notify/sparc/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/notify/snmp-notify/sparc/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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. +# + +include ../../../../Makefile.cmd +include ../Makefile.com diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/schemes/Makefile --- a/usr/src/cmd/fm/schemes/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/schemes/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # SUBDIRS = \ @@ -32,6 +31,7 @@ mem \ mod \ pkg \ + sw \ svc \ zfs diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/schemes/sw/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/schemes/sw/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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.cmd + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +include ../../Makefile.subdirs diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/schemes/sw/Makefile.com --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/schemes/sw/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,26 @@ +# +# 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 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/schemes/sw/amd64/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/schemes/sw/amd64/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,34 @@ +# +# 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 +include $(SRC)/Makefile.master.64 +include ../../Makefile.targ + +LDLIBS += -ltopo +LDFLAGS += -L$(ROOT)/usr/lib/fm/$(MACH64) -R/usr/lib/fm/$(MACH64) +LINTFLAGS += -L$(ROOT)/usr/lib/fm/$(MACH64) + +install: all $(ROOTPROG64) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/schemes/sw/i386/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/schemes/sw/i386/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,33 @@ +# +# 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 +include ../../Makefile.targ + +LDLIBS += -ltopo +LDFLAGS += -L$(ROOT)/usr/lib/fm -R/usr/lib/fm +LINTFLAGS += -L$(ROOT)/usr/lib/fm + +install: all $(ROOTPROG) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/schemes/sw/scheme.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/schemes/sw/scheme.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,96 @@ +/* + * 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 +#include +#include +#include +#include + +int +fmd_fmri_init(void) +{ + return (0); +} + +void +fmd_fmri_fini(void) +{ +} + +ssize_t +fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) +{ + int err; + ssize_t len; + topo_hdl_t *thp; + char *str; + + if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) + return (fmd_fmri_set_errno(EINVAL)); + + if (topo_fmri_nvl2str(thp, nvl, &str, &err) != 0) { + fmd_fmri_topo_rele(thp); + return (fmd_fmri_set_errno(EINVAL)); + } + + if (buf != NULL) + len = snprintf(buf, buflen, "%s", str); + else + len = strlen(str); + + topo_hdl_strfree(thp, str); + fmd_fmri_topo_rele(thp); + + return (len); +} + +/*ARGSUSED*/ +int +fmd_fmri_present(nvlist_t *nvl) +{ + return (1); +} + +/*ARGSUSED*/ +int +fmd_fmri_replaced(nvlist_t *nvl) +{ + return (FMD_OBJ_STATE_UNKNOWN); +} + +/*ARGSUSED*/ +int +fmd_fmri_service_state(nvlist_t *nvl) +{ + return (FMD_SERVICE_STATE_UNKNOWN); +} + +/*ARGSUSED*/ +int +fmd_fmri_unusable(nvlist_t *nvl) +{ + return (0); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/schemes/sw/sparc/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/schemes/sw/sparc/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,33 @@ +# +# 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 +include ../../Makefile.targ + +LDLIBS += -ltopo +LDFLAGS += -L$(ROOT)/usr/lib/fm -R/usr/lib/fm +LINTFLAGS += -L$(ROOT)/usr/lib/fm + +install: all $(ROOTPROG) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/schemes/sw/sparcv9/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/schemes/sw/sparcv9/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,34 @@ +# +# 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 +include $(SRC)/Makefile.master.64 +include ../../Makefile.targ + +LDLIBS += -ltopo +LDFLAGS += -L$(ROOT)/usr/lib/fm/$(MACH64) -R/usr/lib/fm/$(MACH64) +LINTFLAGS += -L$(ROOT)/usr/lib/fm/$(MACH64) + +install: all $(ROOTPROG64) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/fm/scripts/dictck.pl --- a/usr/src/cmd/fm/scripts/dictck.pl Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/fm/scripts/dictck.pl Fri Jul 30 17:04:17 2010 +1000 @@ -19,10 +19,7 @@ # # CDDL HEADER END # -# ident "%Z%%M% %I% %E% SMI" -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # # # dictck -- Sanity check a .dict file and optionally the corresponding .po file @@ -56,6 +53,11 @@ }; # +# Category 1 event classes +# +my @cat1ev = qw(fault defect upset ereport list ireport); + +# # usage -- print a usage message and exit # sub usage { @@ -182,10 +184,11 @@ # check for duplicate or unexpected keys my %keys; + my $cat1pat = join('|', @cat1ev); foreach my $e (split(/\s/, $lhs)) { die "$name:$line: unknown event type \"$e\"\n" unless $e =~ - /^(fault|defect|upset|ereport|list)\..*[^.]$/; + /^($cat1pat)\..*[^.]$/; die "$name:$line: key repeated: \"$e\"\n" if defined($keys{$e}); $keys{$e} = 1; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/logadm/Makefile --- a/usr/src/cmd/logadm/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/logadm/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. # PROG= logadm @@ -40,6 +39,18 @@ CLOBBERFILES += $(TESTS) +LOGADMDIR = $(ROOT)/etc/logadm.d + +MFSTFILES = logadm-upgrade.xml +MANIFESTDIR = $(ROOT)/lib/svc/manifest/system +MANIFEST = $(MFSTFILES:%=$(MANIFESTDIR)/%) +$(MANIFEST) := FILEMODE = 0444 + +METHODFILES = logadm-upgrade +METHODDIR = $(ROOT)/lib/svc/method +METHOD = $(METHODFILES:%=$(METHODDIR)/%) +$(METHOD) := FILEMODE = 0555 + .KEEP_STATE: all: $(PROG) @@ -51,7 +62,23 @@ $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) -install: all $(ROOTUSRSBINPROG) $(ROOTETC)/$(CONFIGFILE) +install: all $(ROOTUSRSBINPROG) $(ROOTETC)/$(CONFIGFILE) $(LOGADMDIR) \ + $(MANIFESTDIR) $(MANIFEST) $(METHODDIR) $(METHOD) + +$(LOGADMDIR): + $(INS.dir) + +$(MANIFESTDIR): + $(INS.dir) + +$(MANIFESTDIR)/% : % + $(INS.file) + +$(METHODDIR): + $(INS.dir) + +$(METHODDIR)/% : % + $(INS.file) $(POFILE): $(POFILES) $(RM) $@ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/logadm/logadm-upgrade --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/logadm/logadm-upgrade Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,138 @@ +#!/sbin/sh +# +# 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. +# + +. /lib/svc/share/smf_include.sh + +LOGADM=/etc/logadm.conf +LOGADM_D=${LOGADM%conf}d +LS=/usr/bin/ls +AWK=/usr/bin/awk +GREP=/usr/bin/grep + +# +# This is a temporary service to allow addition (only) to /etc/logadm.conf +# It is temporary in the sense that logadm(1M) should have its configuration +# migrated to SMF in the future. +# + +# +# Display error message and exits with error code +# +msg_exit() +{ + exit_code=$1 + msg=$2 + + echo "${msg}" + exit ${exit_code} +} + +# +# If there is no /etc/logadm.d we can bail +# +if [ ! -d ${LOGADM_D} ]; then + exit ${SMF_EXIT_OK} +fi + +# +# Cache files +# +files=$(${LS} -t ${LOGADM} ${LOGADM_D}/*) + +# +# If there is no /etc/logadm.conf create it and make sure it has the +# right ownership and permissions. +# Make sure this is done AFTER $files is set. Otherwise /etc/logadm.conf will be +# newer than all files is /etc/logadm.d and they will be skipped. +# +if [ ! -f ${LOGADM} ]; then + touch ${LOGADM} + chmod 644 ${LOGADM} + chown root:sys ${LOGADM} +fi + +for f in ${files} +do + # + # If it is not a file, we skip it. + # + if [ ! -f ${f} ]; then + continue + fi + + # + # We stop when files at /etc/logadm.d are older than /etc/logadm.conf + # + if [ ${f} = ${LOGADM} ]; then + break + fi + + # + # We ignore files that are not owned by root, group sys + # and have permissions different than 444 + # + perm=$(${LS} -l ${f} | ${AWK} '{printf("%s %s:%s", $1, $3, $4)}') + if [ $? != 0 ]; then + msg_exit ${SMF_EXIT_ERR_FATAL} "${perm}" + fi + if [ "${perm}" != "-r--r--r-- root:sys" ]; then + echo "Unexpected permission/ownership for ${f}" + echo " expected -r--r--r-- root:sys but got ${perm}" + echo " skipping ${f}" + continue + fi + + # + # Discard comments (lines starting with #) + # + ${GREP} -v '^#' ${f} | while read entry + do + sig=$(echo ${entry} | ${AWK} '{printf("%s\>", $1);}' 2>&1) + if [ $? != 0 ]; then # only happens if awk(1) fails + msg_exit ${SMF_EXIT_ERR_FATAL} "${sig}" + fi + + # + # if ${sig} is null but the previous command succeeded, we skip + # + if [ ! ${sig} ]; then + continue; + fi + + err_msg=$(${GREP} ^${sig} ${LOGADM} 2>&1) + case $? in + '1') + echo "${entry}" >> ${LOGADM} + ;; + '0') + ;; + *) + msg_exit ${SMF_EXIT_ERR_FATAL} "${err_msg}" + esac + done +done + +exit ${SMF_EXIT_OK} + diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/logadm/logadm-upgrade.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/logadm/logadm-upgrade.xml Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/logadm/logadm.conf --- a/usr/src/cmd/logadm/logadm.conf Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/logadm/logadm.conf Fri Jul 30 17:04:17 2010 +1000 @@ -18,8 +18,7 @@ # # CDDL HEADER END # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. # # logadm.conf # diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c --- a/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -546,6 +545,7 @@ { kmt_data_t *kmt = mdb.m_target->t_data; struct utsname uts; + char uuid[37]; kreg_t tt; if (mdb_tgt_readsym(mdb.m_target, MDB_TGT_AS_VIRT, &uts, sizeof (uts), @@ -561,6 +561,17 @@ mdb_printf("operating system: %s %s (%s)\n", uts.release, uts.version, uts.machine); + if (mdb_tgt_readsym(mdb.m_target, MDB_TGT_AS_VIRT, uuid, sizeof (uuid), + "genunix", "dump_osimage_uuid") != sizeof (uuid)) { + warn("failed to read 'dump_osimage_uuid' string from kernel\n"); + (void) strcpy(uuid, "(error)"); + } else if (*uuid == '\0') { + (void) strcpy(uuid, "(not set)"); + } else if (uuid[36] != '\0') { + (void) strcpy(uuid, "(invalid)"); + } + mdb_printf("image uuid: %s\n", uuid); + if (kmt->kmt_cpu != NULL) { mdb_printf("CPU-specific support: %s\n", kmt_cpu_name(kmt->kmt_cpu)); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/mdb/common/mdb/mdb_kvm.c --- a/usr/src/cmd/mdb/common/mdb/mdb_kvm.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/mdb/common/mdb/mdb_kvm.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -485,9 +484,18 @@ if (kt->k_dumphdr) { dumphdr_t *dh = kt->k_dumphdr; + mdb_printf("image uuid: %s\n", dh->dump_uuid[0] != '\0' ? + dh->dump_uuid : "(not set)"); mdb_printf("panic message: %s\n", dh->dump_panicstring); kt->k_dump_print_content(dh, kt->k_dumpcontent); + } else { + char uuid[37]; + + if (mdb_readsym(uuid, 37, "dump_osimage_uuid") == 37 && + uuid[36] == '\0') { + mdb_printf("image uuid: %s\n", uuid); + } } return (DCMD_OK); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/mdb/common/modules/svc.startd/startd.c --- a/usr/src/cmd/mdb/common/modules/svc.startd/startd.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/mdb/common/modules/svc.startd/startd.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include @@ -59,6 +56,14 @@ u_longlong_t lookups; u_longlong_t dep_inserts, dep_cycle_ns, dep_insert_ns; size_t graph_num, restarter_num; + uint64_t ct_maint; + uint64_t ct_hwerr; + uint64_t ct_service; + uint64_t ct_global; + uint64_t ct_noprefs; + uint64_t ct_from_uninit; + uint64_t ct_bad_state; + uint64_t ct_ovr_prefs; if (mdb_readvar(&lookups, "dictionary_lookups") == -1) { mdb_warn("failed to read 'dictionary_lookups' value\n"); @@ -109,18 +114,71 @@ return (DCMD_ERR); } + if (mdb_readvar(&ct_maint, "stev_ct_maint") == -1) { + mdb_warn("failed to read 'stev_ct_maint'\n"); + return (DCMD_ERR); + } + + if (mdb_readvar(&ct_hwerr, "stev_ct_hwerr") == -1) { + mdb_warn("failed to read 'stev_ct_hwerr'\n"); + return (DCMD_ERR); + } + + if (mdb_readvar(&ct_service, "stev_ct_service") == -1) { + mdb_warn("failed to read 'stev_ct_service'\n"); + return (DCMD_ERR); + } + + if (mdb_readvar(&ct_global, "stev_ct_global") == -1) { + mdb_warn("failed to read 'stev_ct_global'\n"); + return (DCMD_ERR); + } + + if (mdb_readvar(&ct_noprefs, "stev_ct_noprefs") == -1) { + mdb_warn("failed to read 'stev_ct_noprefs'\n"); + return (DCMD_ERR); + } + + if (mdb_readvar(&ct_from_uninit, "stev_ct_from_uninit") == -1) { + mdb_warn("failed to read 'stev_ct_from_uninit'\n"); + return (DCMD_ERR); + } + + if (mdb_readvar(&ct_bad_state, "stev_ct_bad_state") == -1) { + mdb_warn("failed to read 'stev_ct_bad_state'\n"); + return (DCMD_ERR); + } + + if (mdb_readvar(&ct_ovr_prefs, "stev_ct_ovr_prefs") == -1) { + mdb_warn("failed to read 'stev_ct_ovr_prefs'\n"); + return (DCMD_ERR); + } + mdb_printf( - " dictionary lookups: %llu\n" - " average lookup time: %llu us\n" - "graph dependency insertions: %llu\n" - " average cycle-check time: %llu us\n" - " avg dependency insert time: %llu us\n" - "number of nodes in dgraph: %llu\n" - "number of nodes in instance_list: %llu\n", lookups, + "General stats\n" + " dictionary lookups: %llu\n" + " average lookup time: %llu us\n" + " graph dependency insertions: %llu\n" + " average cycle-check time: %llu us\n" + " avg dependency insert time: %llu us\n" + " number of nodes in dgraph: %llu\n" + "number of nodes in instance_list: %llu\n" + "\nState Transition Events\n" + " maintenance: %llu\n" + " hardware error: %llu\n" + " service specific pref: %llu\n" + " system wide pref: %llu\n" + " no prefs, not raised: %llu\n" + " from unint, not raised: %llu\n" + " bad state, not raised: %llu\n" + " override pref, raised: %llu\n", lookups, lookups ? ns_total / (1000 * lookups) : 0, dep_inserts, dep_inserts ? dep_cycle_ns / (1000 * dep_inserts) : 0, dep_inserts ? dep_insert_ns / (1000 * dep_inserts) : 0, - (u_longlong_t)graph_num, (u_longlong_t)restarter_num); + (u_longlong_t)graph_num, (u_longlong_t)restarter_num, + ct_maint, ct_hwerr, ct_service, ct_global, ct_noprefs, + ct_from_uninit, ct_bad_state, ct_ovr_prefs); + return (DCMD_OK); } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/savecore/Makefile.com --- a/usr/src/cmd/savecore/Makefile.com Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/savecore/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. # PROG= savecore @@ -29,10 +28,20 @@ include ../../Makefile.cmd +C99MODE = $(C99_ENABLE) + CFLAGS += $(CCVERBOSE) CFLAGS64 += $(CCVERBOSE) CPPFLAGS += -D_LARGEFILE64_SOURCE=1 -DBZ_NO_STDIO -I$(SRC)/uts/common +# +# savecore is compiled with bits from $(SRC)/common/bzip2 and some function +# symbols there are defined as weak; if you leave them out of +# savecore.c it will compile, but trying to call that function +# will jump to 0. So we use -ztext to avoid that. +# +LDFLAGS += -ztext + BZIP2OBJS = bz2blocksort.o \ bz2compress.o \ bz2decompress.o \ @@ -52,7 +61,22 @@ clean: $(RM) $(OBJS) $(BZIP2OBJS) -lint: lint_SRCS +lint := CPPFLAGS += -I$(SRC)/common + +# +# Linting the usr/src/common/bzip2 source produces reams of complaints. +# So we only lint regular SRCS, but we need to excuse two complaints +# related to bz_internal_error. +# + +lint := BZ2LINTCOPOUTS = -erroff=E_NAME_USED_NOT_DEF2 +lint := BZ2LINTCOPOUTS += -erroff=E_NAME_DEF_NOT_USED2 + +lint := LINTFLAGS += $(BZ2LINTCOPOUTS) +lint := LINTFLAGS64 += $(BZ2LINTCOPOUTS) + +lint: $(LINTSRCS) + $(LINT.c) $(SRCS) $(LDLIBS) include ../../Makefile.targ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/savecore/amd64/Makefile --- a/usr/src/cmd/savecore/amd64/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/savecore/amd64/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -20,13 +19,13 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # include ../Makefile.com include ../../Makefile.cmd.64 +LDLIBS += -L$(ROOT)/usr/lib/fm/amd64 -lfmevent -lnvpair +LDFLAGS += -R/usr/lib/fm/amd64 + install: all $(ROOTPROG64) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/savecore/i386/Makefile --- a/usr/src/cmd/savecore/i386/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/savecore/i386/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -19,13 +18,12 @@ # # CDDL HEADER END # -# -# Copyright (c) 1998 by Sun Microsystems, Inc. -# All rights reserved. -# -#ident "%Z%%M% %I% %E% SMI" +# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. # include ../Makefile.com +LDLIBS += -L$(ROOT)/usr/lib/fm -lfmevent -lnvpair +LDFLAGS += -R/usr/lib/fm + install: all $(ROOTPROG32) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/savecore/savecore.c --- a/usr/src/cmd/savecore/savecore.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/savecore/savecore.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -37,15 +36,22 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #include #include #include #include +#include +#include +#include + /* fread/fwrite buffer size */ #define FBUFSIZE (1ULL << 20) @@ -56,13 +62,15 @@ /* create this file if metrics collection is enabled in the kernel */ #define METRICSFILE "METRICS.csv" -static char progname[9] = "savecore"; +static char progname[9] = "savecore"; static char *savedir; /* savecore directory */ static char *dumpfile; /* source of raw crash dump */ -static long bounds; /* numeric suffix */ +static long bounds = -1; /* numeric suffix */ static long pagesize; /* dump pagesize */ static int dumpfd = -1; /* dumpfile descriptor */ static dumphdr_t corehdr, dumphdr; /* initial and terminal dumphdrs */ +static boolean_t dump_incomplete; /* dumphdr indicates incomplete */ +static boolean_t fm_panic; /* dump is the result of fm_panic */ static offset_t endoff; /* offset of end-of-dump header */ static int verbose; /* chatty mode */ static int disregard_valid_flag; /* disregard valid flag */ @@ -76,6 +84,75 @@ static volatile uint64_t zpages; /* count of zero pages not written */ static dumpdatahdr_t datahdr; /* compression info */ static long coreblksize; /* preferred write size (st_blksize) */ +static int cflag; /* run as savecore -c */ +static int mflag; /* run as savecore -m */ + +/* + * Payload information for the events we raise. These are used + * in raise_event to determine what payload to include. + */ +#define SC_PAYLOAD_SAVEDIR 0x0001 /* Include savedir in event */ +#define SC_PAYLOAD_INSTANCE 0x0002 /* Include bounds instance number */ +#define SC_PAYLOAD_IMAGEUUID 0x0004 /* Include dump OS instance uuid */ +#define SC_PAYLOAD_CRASHTIME 0x0008 /* Include epoch crashtime */ +#define SC_PAYLOAD_PANICSTR 0x0010 /* Include panic string */ +#define SC_PAYLOAD_PANICSTACK 0x0020 /* Include panic string */ +#define SC_PAYLOAD_FAILREASON 0x0040 /* Include failure reason */ +#define SC_PAYLOAD_DUMPCOMPLETE 0x0080 /* Include completeness indicator */ +#define SC_PAYLOAD_ISCOMPRESSED 0x0100 /* Dump is in vmdump.N form */ +#define SC_PAYLOAD_DUMPADM_EN 0x0200 /* Is dumpadm enabled or not? */ +#define SC_PAYLOAD_FM_PANIC 0x0400 /* Panic initiated by FMA */ +#define SC_PAYLOAD_JUSTCHECKING 0x0800 /* Run with -c flag? */ + +enum sc_event_type { + SC_EVENT_DUMP_PENDING, + SC_EVENT_SAVECORE_FAILURE, + SC_EVENT_DUMP_AVAILABLE +}; + +/* + * Common payload + */ +#define _SC_PAYLOAD_CMN \ + SC_PAYLOAD_IMAGEUUID | \ + SC_PAYLOAD_CRASHTIME | \ + SC_PAYLOAD_PANICSTR | \ + SC_PAYLOAD_PANICSTACK | \ + SC_PAYLOAD_DUMPCOMPLETE | \ + SC_PAYLOAD_FM_PANIC | \ + SC_PAYLOAD_SAVEDIR + +static const struct { + const char *sce_subclass; + uint32_t sce_payload; +} sc_event[] = { + /* + * SC_EVENT_DUMP_PENDING + */ + { + "dump_pending_on_device", + _SC_PAYLOAD_CMN | SC_PAYLOAD_DUMPADM_EN | + SC_PAYLOAD_JUSTCHECKING + }, + + /* + * SC_EVENT_SAVECORE_FAILURE + */ + { + "savecore_failure", + _SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_FAILREASON + }, + + /* + * SC_EVENT_DUMP_AVAILABLE + */ + { + "dump_available", + _SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_ISCOMPRESSED + }, +}; + +static void raise_event(enum sc_event_type, char *); static void usage(void) @@ -85,22 +162,83 @@ exit(1); } +#define SC_SL_NONE 0x0001 /* no syslog */ +#define SC_SL_ERR 0x0002 /* syslog if !interactive, LOG_ERR */ +#define SC_SL_WARN 0x0004 /* syslog if !interactive, LOG_WARNING */ +#define SC_IF_VERBOSE 0x0008 /* message only if -v */ +#define SC_IF_ISATTY 0x0010 /* message only if interactive */ +#define SC_EXIT_OK 0x0020 /* exit(0) */ +#define SC_EXIT_ERR 0x0040 /* exit(1) */ +#define SC_EXIT_PEND 0x0080 /* exit(2) */ +#define SC_EXIT_FM 0x0100 /* exit(3) */ + +#define _SC_ALLEXIT (SC_EXIT_OK | SC_EXIT_ERR | SC_EXIT_PEND | SC_EXIT_FM) + static void -logprint(int logpri, int showmsg, int exitcode, char *message, ...) +logprint(uint32_t flags, char *message, ...) { va_list args; char buf[1024]; + int do_always = ((flags & (SC_IF_VERBOSE | SC_IF_ISATTY)) == 0); + int do_ifverb = (flags & SC_IF_VERBOSE) && verbose; + int do_ifisatty = (flags & SC_IF_ISATTY) && interactive; + int code; + static int logprint_raised = 0; - if (showmsg) { + if (do_always || do_ifverb || do_ifisatty) { va_start(args, message); + /*LINTED: E_SEC_PRINTF_VAR_FMT*/ (void) vsnprintf(buf, sizeof (buf), message, args); (void) fprintf(stderr, "%s: %s\n", progname, buf); - if (!interactive && logpri >= 0) - syslog(logpri, buf); + if (!interactive) { + switch (flags & (SC_SL_NONE | SC_SL_ERR | SC_SL_WARN)) { + case SC_SL_ERR: + /*LINTED: E_SEC_PRINTF_VAR_FMT*/ + syslog(LOG_ERR, buf); + break; + + case SC_SL_WARN: + /*LINTED: E_SEC_PRINTF_VAR_FMT*/ + syslog(LOG_WARNING, buf); + break; + + default: + break; + } + } va_end(args); } - if (exitcode >= 0) - exit(exitcode); + + switch (flags & _SC_ALLEXIT) { + case 0: + return; + + case SC_EXIT_OK: + code = 0; + break; + + case SC_EXIT_PEND: + code = 2; + break; + + case SC_EXIT_FM: + code = 3; + break; + + case SC_EXIT_ERR: + default: + /* + * Raise an ireport saying why we are exiting. Do not + * raise if run as savecore -m. If something in the + * raise_event codepath calls logprint avoid recursion. + */ + if (!mflag && logprint_raised++ == 0) + raise_event(SC_EVENT_SAVECORE_FAILURE, buf); + code = 1; + break; + } + + exit(code); } /* @@ -112,7 +250,7 @@ int fd; if ((fd = open64(name, oflags, mode)) == -1) - logprint(LOG_ERR, 1, 1, "open(\"%s\"): %s", + logprint(SC_SL_ERR | SC_EXIT_ERR, "open(\"%s\"): %s", name, strerror(errno)); return (fd); } @@ -121,7 +259,7 @@ Fread(void *buf, size_t size, FILE *f) { if (fread(buf, size, 1, f) != 1) - logprint(LOG_ERR, 1, 1, "fread: ferror %d feof %d", + logprint(SC_SL_ERR | SC_EXIT_ERR, "fread: ferror %d feof %d", ferror(f), feof(f)); } @@ -129,14 +267,16 @@ Fwrite(void *buf, size_t size, FILE *f) { if (fwrite(buf, size, 1, f) != 1) - logprint(LOG_ERR, 1, 1, "fwrite: %s", strerror(errno)); + logprint(SC_SL_ERR | SC_EXIT_ERR, "fwrite: %s", + strerror(errno)); } static void Fseek(offset_t off, FILE *f) { if (fseeko64(f, off, SEEK_SET) != 0) - logprint(LOG_ERR, 1, 1, "fseeko64: %s", strerror(errno)); + logprint(SC_SL_ERR | SC_EXIT_ERR, "fseeko64: %s", + strerror(errno)); } typedef struct stat64 Stat_t; @@ -145,7 +285,7 @@ Fstat(int fd, Stat_t *sb, const char *fname) { if (fstat64(fd, sb) != 0) - logprint(LOG_ERR, 1, 1, "fstat(\"%s\"): %s", fname, + logprint(SC_SL_ERR | SC_EXIT_ERR, "fstat(\"%s\"): %s", fname, strerror(errno)); } @@ -153,7 +293,7 @@ Stat(const char *fname, Stat_t *sb) { if (stat64(fname, sb) != 0) - logprint(LOG_ERR, 1, 1, "stat(\"%s\"): %s", fname, + logprint(SC_SL_ERR | SC_EXIT_ERR, "stat(\"%s\"): %s", fname, strerror(errno)); } @@ -163,10 +303,10 @@ ssize_t sz = pread64(fd, buf, size, off); if (sz < 0) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "pread: %s", strerror(errno)); else if (sz != size) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "pread: size %ld != %ld", sz, size); } @@ -174,7 +314,8 @@ Pwrite(int fd, void *buf, size_t size, off64_t off) { if (pwrite64(fd, buf, size, off) != size) - logprint(LOG_ERR, 1, 1, "pwrite: %s", strerror(errno)); + logprint(SC_SL_ERR | SC_EXIT_ERR, "pwrite: %s", + strerror(errno)); } static void * @@ -183,7 +324,8 @@ void *buf; if ((buf = calloc(size, 1)) == NULL) - logprint(LOG_ERR, 1, 1, "calloc: %s", strerror(errno)); + logprint(SC_SL_ERR | SC_EXIT_ERR, "calloc: %s", + strerror(errno)); return (buf); } @@ -214,30 +356,31 @@ pagesize = dumphdr.dump_pagesize; if (dumphdr.dump_magic != DUMP_MAGIC) - logprint(-1, 1, 0, "bad magic number %x", + logprint(SC_SL_NONE | SC_EXIT_OK, "bad magic number %x", dumphdr.dump_magic); if ((dumphdr.dump_flags & DF_VALID) == 0 && !disregard_valid_flag) - logprint(-1, verbose, 0, "dump already processed"); + logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK, + "dump already processed"); if (dumphdr.dump_version != DUMP_VERSION) - logprint(-1, verbose, 0, + logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK, "dump version (%d) != %s version (%d)", dumphdr.dump_version, progname, DUMP_VERSION); if (dumphdr.dump_wordsize != DUMP_WORDSIZE) - logprint(-1, 1, 0, + logprint(SC_SL_NONE | SC_EXIT_OK, "dump is from %u-bit kernel - cannot save on %u-bit kernel", dumphdr.dump_wordsize, DUMP_WORDSIZE); if (datahdr.dump_datahdr_magic == DUMP_DATAHDR_MAGIC) { if (datahdr.dump_datahdr_version != DUMP_DATAHDR_VERSION) - logprint(-1, verbose, 0, + logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK, "dump data version (%d) != %s data version (%d)", datahdr.dump_datahdr_version, progname, DUMP_DATAHDR_VERSION); } else { - memset(&datahdr, 0, sizeof (datahdr)); + (void) memset(&datahdr, 0, sizeof (datahdr)); datahdr.dump_maxcsize = pagesize; } @@ -257,7 +400,8 @@ */ if (!filemode) Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff); - logprint(LOG_ERR, 1, 1, "initial dump header corrupt"); + logprint(SC_SL_ERR | SC_EXIT_ERR, + "initial dump header corrupt"); } } @@ -268,7 +412,8 @@ int64_t spacefree, dumpsize, minfree, datasize; if (statvfs(".", &fsb) < 0) - logprint(LOG_ERR, 1, 1, "statvfs: %s", strerror(errno)); + logprint(SC_SL_ERR | SC_EXIT_ERR, "statvfs: %s", + strerror(errno)); dumpsize = dumphdr.dump_data - dumphdr.dump_start; datasize = dumphdr.dump_npages * pagesize; @@ -279,10 +424,11 @@ spacefree = (int64_t)fsb.f_bavail * fsb.f_frsize; minfree = 1024LL * read_number_from_file("minfree", 1024); - if (spacefree < minfree + dumpsize) - logprint(LOG_ERR, 1, 1, + if (spacefree < minfree + dumpsize) { + logprint(SC_SL_ERR | SC_EXIT_ERR, "not enough space in %s (%lld MB avail, %lld MB needed)", savedir, spacefree >> 20, (minfree + dumpsize) >> 20); + } } static void @@ -296,7 +442,7 @@ char *inbuf = Zalloc(FBUFSIZE); FILE *in = fdopen(dup(dumpfd), "rb"); - setvbuf(in, inbuf, _IOFBF, FBUFSIZE); + (void) setvbuf(in, inbuf, _IOFBF, FBUFSIZE); Fseek(dumphdr.dump_map, in); corehdr.dump_data = corehdr.dump_map + roundup(dump_mapsize, pagesize); @@ -339,7 +485,7 @@ Pwrite(corefd, dmp, dump_mapsize, corehdr.dump_map); free(dmp); - fclose(in); + (void) fclose(in); free(inbuf); } @@ -369,7 +515,7 @@ * This supports older kernels with latest savecore. */ static void -CopyPages(offset_t dumpoff, offset_t *offp, int fd, char *buf, size_t sz) +CopyPages(offset_t *offp, int fd, char *buf, size_t sz) { uint32_t csize; FILE *in = fdopen(dup(dumpfd), "rb"); @@ -378,8 +524,8 @@ char *outbuf = Zalloc(FBUFSIZE); pgcnt_t np = dumphdr.dump_npages; - setvbuf(out, outbuf, _IOFBF, FBUFSIZE); - setvbuf(in, buf, _IOFBF, sz); + (void) setvbuf(out, outbuf, _IOFBF, FBUFSIZE); + (void) setvbuf(in, buf, _IOFBF, sz); Fseek(dumphdr.dump_data, in); Fseek(*offp, out); @@ -388,7 +534,7 @@ Fwrite(&csize, sizeof (uint32_t), out); *offp += sizeof (uint32_t); if (csize > pagesize || csize == 0) { - logprint(LOG_ERR, 1, -1, + logprint(SC_SL_ERR, "CopyPages: page %lu csize %d (0x%x) pagesize %d", dumphdr.dump_npages - np, csize, csize, pagesize); @@ -399,8 +545,8 @@ *offp += csize; np--; } - fclose(in); - fclose(out); + (void) fclose(in); + (void) fclose(out); free(outbuf); free(buf); } @@ -418,7 +564,7 @@ offset_t coreoff; size_t nb; - logprint(LOG_ERR, verbose, -1, + logprint(SC_SL_ERR | SC_IF_VERBOSE, "Copying %s to %s/%s\n", dumpfile, savedir, corefile); /* @@ -465,7 +611,7 @@ Copy(dumphdr.dump_data, datahdr.dump_data_csize, &coreoff, corefd, inbuf, bufsz); else - CopyPages(dumphdr.dump_data, &coreoff, corefd, inbuf, bufsz); + CopyPages(&coreoff, corefd, inbuf, bufsz); /* * Now write the modified dump header to front and end of the copy. @@ -478,7 +624,7 @@ * * Pad with zeros to each DUMP_OFFSET boundary. */ - memset(inbuf, 0, DUMP_OFFSET); + (void) memset(inbuf, 0, DUMP_OFFSET); nb = DUMP_OFFSET - (coreoff & (DUMP_OFFSET - 1)); if (nb > 0) { @@ -628,7 +774,7 @@ } /* init worker threads */ - pthread_mutex_lock(&lock); + (void) pthread_mutex_lock(&lock); threads_active = 1; threads_stop = 0; for (t = tinfo; t != endtinfo; t++) { @@ -639,10 +785,10 @@ break; } if (pthread_create(&t->tid, NULL, runstreams, t) != 0) - logprint(LOG_ERR, 1, 1, "pthread_create: %s", + logprint(SC_SL_ERR | SC_EXIT_ERR, "pthread_create: %s", strerror(errno)); } - pthread_mutex_unlock(&lock); + (void) pthread_mutex_unlock(&lock); } static void @@ -650,12 +796,12 @@ { stream_t *s; - pthread_mutex_lock(&lock); + (void) pthread_mutex_lock(&lock); for (s = streams; s != endstreams; s++) { while (s->bound || s->blocks.head != NULL) - pthread_cond_wait(&cvbarrier, &lock); + (void) pthread_cond_wait(&cvbarrier, &lock); } - pthread_mutex_unlock(&lock); + (void) pthread_mutex_unlock(&lock); } static void @@ -665,12 +811,12 @@ if (threads_active) { sbarrier(); - pthread_mutex_lock(&lock); + (void) pthread_mutex_lock(&lock); threads_stop = 1; - pthread_cond_signal(&cvwork); - pthread_mutex_unlock(&lock); + (void) pthread_cond_signal(&cvwork); + (void) pthread_mutex_unlock(&lock); for (t = tinfo; t != endtinfo; t++) - pthread_join(t->tid, NULL); + (void) pthread_join(t->tid, NULL); free(tinfo); tinfo = NULL; threads_active = 0; @@ -682,10 +828,10 @@ { block_t *b; - pthread_mutex_lock(&lock); + (void) pthread_mutex_lock(&lock); while ((b = deqh(&freeblocks)) == NULL) - pthread_cond_wait(&cvfree, &lock); - pthread_mutex_unlock(&lock); + (void) pthread_cond_wait(&cvfree, &lock); + (void) pthread_mutex_unlock(&lock); return (b); } @@ -707,6 +853,7 @@ size_t sz; uint64_t *pl; + /*LINTED:E_BAD_PTR_CAST_ALIGN*/ pl = (uint64_t *)(buf); for (sz = 0; sz < pagesize; sz += sizeof (*pl)) if (*pl++ != 0) @@ -732,7 +879,6 @@ static void lzjbblock(int corefd, stream_t *s, char *block, size_t blocksz) { - int rc = 0; int in = 0; int csize; int doflush; @@ -750,13 +896,13 @@ while (in < blocksz) { switch (s->state) { case STREAMSTART: - memcpy(&sh, block + in, sizeof (sh)); + (void) memcpy(&sh, block + in, sizeof (sh)); in += sizeof (sh); if (strcmp(DUMP_STREAM_MAGIC, sh.stream_magic) != 0) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "LZJB STREAMSTART: bad stream header"); if (sh.stream_npages > datahdr.dump_maxrange) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "LZJB STREAMSTART: bad range: %d > %d", sh.stream_npages, datahdr.dump_maxrange); s->pagenum = sh.stream_pagenum; @@ -767,18 +913,18 @@ s->state = STREAMPAGES; break; case STREAMPAGES: - memcpy(&sc, block + in, cs); + (void) memcpy(&sc, block + in, cs); in += cs; csize = DUMP_GET_CSIZE(sc); if (csize > pagesize) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "LZJB STREAMPAGES: bad csize=%d", csize); out = s->blkbuf + PTOB(s->nout); dsize = decompress(block + in, out, csize, pagesize); if (dsize != pagesize) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "LZJB STREAMPAGES: dsize %d != pagesize %d", dsize, pagesize); @@ -811,7 +957,7 @@ void bz_internal_error(int errcode) { - logprint(LOG_ERR, 1, 1, "bz_internal_error: err %s\n", + logprint(SC_SL_ERR | SC_EXIT_ERR, "bz_internal_error: err %s\n", BZ2_bzErrorString(errcode)); } @@ -836,7 +982,7 @@ if (rc == BZ_STREAM_END) { rc = BZ2_bzDecompressReset(&s->strm); if (rc != BZ_OK) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "BZ2_bzDecompressReset: %s", BZ2_bzErrorString(rc)); continue; @@ -864,7 +1010,7 @@ s->init = 1; rc = BZ2_bzDecompressInit(&s->strm, 0, 0); if (rc != BZ_OK) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "BZ2_bzDecompressInit: %s", BZ2_bzErrorString(rc)); if (s->blkbuf == NULL) s->blkbuf = Zalloc(coreblksize); @@ -880,10 +1026,10 @@ if (!bz2decompress(s, &s->sh, sizeof (s->sh))) return; if (strcmp(DUMP_STREAM_MAGIC, s->sh.stream_magic) != 0) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "BZ2 STREAMSTART: bad stream header"); if (s->sh.stream_npages > datahdr.dump_maxrange) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "BZ2 STREAMSTART: bad range: %d > %d", s->sh.stream_npages, datahdr.dump_maxrange); s->pagenum = s->sh.stream_pagenum; @@ -950,7 +1096,7 @@ block_t *b; int bound; - pthread_mutex_lock(&lock); + (void) pthread_mutex_lock(&lock); while (!threads_stop) { bound = 0; for (s = streams; s != endstreams; s++) { @@ -958,10 +1104,10 @@ continue; s->bound = 1; bound = 1; - pthread_cond_signal(&cvwork); + (void) pthread_cond_signal(&cvwork); while (s->blocks.head != NULL) { b = deqh(&s->blocks); - pthread_mutex_unlock(&lock); + (void) pthread_mutex_unlock(&lock); if (datahdr.dump_clevel < DUMP_CLEVEL_BZIP2) lzjbblock(t->corefd, s, b->block, @@ -970,21 +1116,21 @@ bz2block(t->corefd, s, b->block, b->size); - pthread_mutex_lock(&lock); + (void) pthread_mutex_lock(&lock); enqt(&freeblocks, b); - pthread_cond_signal(&cvfree); + (void) pthread_cond_signal(&cvfree); report_progress(); } s->bound = 0; - pthread_cond_signal(&cvbarrier); + (void) pthread_cond_signal(&cvbarrier); } if (!bound && !threads_stop) - pthread_cond_wait(&cvwork, &lock); + (void) pthread_cond_wait(&cvwork, &lock); } - close(t->corefd); - pthread_cond_signal(&cvwork); - pthread_mutex_unlock(&lock); + (void) close(t->corefd); + (void) pthread_cond_signal(&cvwork); + (void) pthread_mutex_unlock(&lock); return (arg); } @@ -1041,18 +1187,19 @@ char *inbuf = Zalloc(insz); uint32_t csize; dumpcsize_t dcsize; - dumpstreamhdr_t sh; int nstreams = datahdr.dump_nstreams; int maxcsize = datahdr.dump_maxcsize; int nout, tag, doflush; dumpf = fdopen(dup(dumpfd), "rb"); if (dumpf == NULL) - logprint(LOG_ERR, 1, 1, "fdopen: %s", strerror(errno)); + logprint(SC_SL_ERR | SC_EXIT_ERR, "fdopen: %s", + strerror(errno)); - setvbuf(dumpf, inbuf, _IOFBF, insz); + (void) setvbuf(dumpf, inbuf, _IOFBF, insz); Fseek(dumphdr.dump_data, dumpf); + /*LINTED: E_CONSTANT_CONDITION*/ while (1) { /* @@ -1067,16 +1214,16 @@ if (tag != 0) { /* a stream block */ if (nstreams == 0) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "starting data header is missing"); if (tag > nstreams) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "stream tag %d not in range 1..%d", tag, nstreams); if (csize > maxcsize) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "block size 0x%x > max csize 0x%x", csize, maxcsize); @@ -1089,16 +1236,16 @@ b->size = csize; Fread(b->block, csize, dumpf); - pthread_mutex_lock(&lock); + (void) pthread_mutex_lock(&lock); enqt(&s->blocks, b); if (!s->bound) - pthread_cond_signal(&cvwork); - pthread_mutex_unlock(&lock); + (void) pthread_cond_signal(&cvwork); + (void) pthread_mutex_unlock(&lock); } else if (csize > 0) { /* one lzjb page */ if (csize > pagesize) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "csize 0x%x > pagesize 0x%x", csize, pagesize); @@ -1115,7 +1262,7 @@ dsize = decompress(cpage, out, csize, pagesize); if (dsize != pagesize) - logprint(LOG_ERR, 1, 1, + logprint(SC_SL_ERR | SC_EXIT_ERR, "dsize 0x%x != pagesize 0x%x", dsize, pagesize); @@ -1161,8 +1308,8 @@ stopstreams(); if (tracef != NULL) - fclose(tracef); - fclose(dumpf); + (void) fclose(tracef); + (void) fclose(dumpf); if (inbuf) free(inbuf); if (cpage) @@ -1195,7 +1342,8 @@ Fstat(corefd, &st, corefile); if (verbose > 1) - printf("%s: %ld block size\n", corefile, st.st_blksize); + (void) printf("%s: %ld block size\n", corefile, + (long)st.st_blksize); coreblksize = st.st_blksize; if (coreblksize < MINCOREBLKSIZE || !ISP2(coreblksize)) coreblksize = MINCOREBLKSIZE; @@ -1218,7 +1366,7 @@ ksyms_dsize = decompress(ksyms_cbase, ksyms_base, ksyms_csize, ksyms_size); if (ksyms_dsize != ksyms_size) - logprint(LOG_WARNING, 1, -1, + logprint(SC_SL_WARN, "bad data in symbol table, %lu of %lu bytes saved", ksyms_dsize, ksyms_size); @@ -1257,7 +1405,7 @@ dumphdr.dump_npages); if (saved != dumphdr.dump_npages) - logprint(LOG_WARNING, 1, -1, "bad data after page %ld", saved); + logprint(SC_SL_WARN, "bad data after page %ld", saved); /* * Write out the modified dump headers. @@ -1314,18 +1462,19 @@ break; if (ld.ld_magic != LOG_MAGIC) - logprint(LOG_ERR, verbose, 0, "bad magic %x", - ld.ld_magic); + logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_ERR, + "bad magic %x", ld.ld_magic); if (dat.len >= DUMP_LOGSIZE) - logprint(LOG_ERR, verbose, 0, "bad size %d", - ld.ld_msgsize); + logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_ERR, + "bad size %d", ld.ld_msgsize); Pread(dumpfd, ctl.buf, ctl.len, dumpoff); dumpoff += ctl.len; if (ld.ld_csum != checksum32(ctl.buf, ctl.len)) - logprint(LOG_ERR, verbose, 0, "bad log_ctl checksum"); + logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_OK, + "bad log_ctl checksum"); lc.flags |= SL_LOGONLY; @@ -1333,10 +1482,12 @@ dumpoff += dat.len; if (ld.ld_msum != checksum32(dat.buf, dat.len)) - logprint(LOG_ERR, verbose, 0, "bad message checksum"); + logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_OK, + "bad message checksum"); if (putpmsg(logfd, &ctl, &dat, 1, MSG_BAND) == -1) - logprint(LOG_ERR, 1, 1, "putpmsg: %s", strerror(errno)); + logprint(SC_SL_ERR | SC_EXIT_ERR, "putpmsg: %s", + strerror(errno)); ld.ld_magic = 0; /* clear magic so we never save twice */ Pwrite(dumpfd, &ld, sizeof (log_dump_t), ldoff); @@ -1350,25 +1501,152 @@ long b = -1; const char *p = strrchr(f, '/'); - sscanf(p ? p + 1 : f, "vmdump.%ld", &b); + (void) sscanf(p ? p + 1 : f, "vmdump.%ld", &b); return (b); } +static void +stack_retrieve(char *stack) +{ + summary_dump_t sd; + offset_t dumpoff = -(DUMP_OFFSET + DUMP_LOGSIZE + + DUMP_ERPTSIZE); + dumpoff -= DUMP_SUMMARYSIZE; + + dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644); + dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET; + + Pread(dumpfd, &sd, sizeof (summary_dump_t), dumpoff); + dumpoff += sizeof (summary_dump_t); + + if (sd.sd_magic == 0) { + *stack = '\0'; + return; + } + + if (sd.sd_magic != SUMMARY_MAGIC) { + *stack = '\0'; + logprint(SC_SL_NONE | SC_IF_VERBOSE, + "bad summary magic %x", sd.sd_magic); + return; + } + Pread(dumpfd, stack, STACK_BUF_SIZE, dumpoff); + if (sd.sd_ssum != checksum32(stack, STACK_BUF_SIZE)) + logprint(SC_SL_NONE | SC_IF_VERBOSE, "bad stack checksum"); +} + +static void +raise_event(enum sc_event_type evidx, char *warn_string) +{ + uint32_t pl = sc_event[evidx].sce_payload; + char panic_stack[STACK_BUF_SIZE]; + nvlist_t *attr = NULL; + char uuidbuf[36 + 1]; + int err = 0; + + if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0) + goto publish; /* try to send payload-free event */ + + if (pl & SC_PAYLOAD_SAVEDIR && savedir != NULL) + err |= nvlist_add_string(attr, "dumpdir", savedir); + + if (pl & SC_PAYLOAD_INSTANCE && bounds != -1) + err |= nvlist_add_int64(attr, "instance", bounds); + + if (pl & SC_PAYLOAD_ISCOMPRESSED) { + err |= nvlist_add_boolean_value(attr, "compressed", + csave ? B_TRUE : B_FALSE); + } + + if (pl & SC_PAYLOAD_DUMPADM_EN) { + char *disabled = defread("DUMPADM_ENABLE=no"); + + err |= nvlist_add_boolean_value(attr, "savecore-enabled", + disabled ? B_FALSE : B_TRUE); + } + + if (pl & SC_PAYLOAD_IMAGEUUID) { + (void) strncpy(uuidbuf, corehdr.dump_uuid, 36); + uuidbuf[36] = '\0'; + err |= nvlist_add_string(attr, "os-instance-uuid", uuidbuf); + } + + if (pl & SC_PAYLOAD_CRASHTIME) { + err |= nvlist_add_int64(attr, "crashtime", + (int64_t)corehdr.dump_crashtime); + } + + if (pl & SC_PAYLOAD_PANICSTR && corehdr.dump_panicstring[0] != '\0') { + err |= nvlist_add_string(attr, "panicstr", + corehdr.dump_panicstring); + } + + if (pl & SC_PAYLOAD_PANICSTACK) { + stack_retrieve(panic_stack); + + if (panic_stack[0] != '\0') { + /* + * The summary page may not be present if the dump + * was previously recorded compressed. + */ + (void) nvlist_add_string(attr, "panicstack", + panic_stack); + } + } + + /* add warning string if this is an ireport for dump failure */ + if (pl & SC_PAYLOAD_FAILREASON && warn_string != NULL) + (void) nvlist_add_string(attr, "failure-reason", warn_string); + + if (pl & SC_PAYLOAD_DUMPCOMPLETE) + err |= nvlist_add_boolean_value(attr, "dump-incomplete", + dump_incomplete ? B_TRUE : B_FALSE); + + if (pl & SC_PAYLOAD_FM_PANIC) { + err |= nvlist_add_boolean_value(attr, "fm-panic", + fm_panic ? B_TRUE : B_FALSE); + } + + if (pl & SC_PAYLOAD_JUSTCHECKING) { + err |= nvlist_add_boolean_value(attr, "will-attempt-savecore", + cflag ? B_FALSE : B_TRUE); + } + + if (err) + logprint(SC_SL_WARN, "Errors while constructing '%s' " + "event payload; will try to publish anyway."); +publish: + if (fmev_rspublish_nvl(FMEV_RULESET_ON_SUNOS, + "panic", sc_event[evidx].sce_subclass, FMEV_HIPRI, + attr) != FMEV_SUCCESS) { + logprint(SC_SL_ERR, "failed to publish '%s' event: %s", + sc_event[evidx].sce_subclass, fmev_strerror(fmev_errno)); + nvlist_free(attr); + } + +} + + int main(int argc, char *argv[]) { - int i, n, c, bfd; - int mflag = 0; + int i, c, bfd; Stat_t st; struct rlimit rl; long filebounds = -1; char namelist[30], corefile[30], boundstr[30]; + if (geteuid() != 0) { + (void) fprintf(stderr, "%s: %s %s\n", progname, + gettext("you must be root to use"), progname); + exit(1); + } + startts = gethrtime(); - getrlimit(RLIMIT_NOFILE, &rl); + (void) getrlimit(RLIMIT_NOFILE, &rl); rl.rlim_cur = rl.rlim_max; - setrlimit(RLIMIT_NOFILE, &rl); + (void) setrlimit(RLIMIT_NOFILE, &rl); openlog(progname, LOG_ODELAY, LOG_AUTH); @@ -1377,7 +1655,7 @@ if (savedir != NULL) savedir = strdup(savedir); - while ((c = getopt(argc, argv, "Lvdmf:")) != EOF) { + while ((c = getopt(argc, argv, "Lvcdmf:")) != EOF) { switch (c) { case 'L': livedump++; @@ -1385,6 +1663,9 @@ case 'v': verbose++; break; + case 'c': + cflag++; + break; case 'd': disregard_valid_flag++; break; @@ -1402,13 +1683,16 @@ interactive = isatty(STDOUT_FILENO); + if (cflag && livedump) + usage(); + if (dumpfile == NULL || livedump) dumpfd = Open("/dev/dump", O_RDONLY, 0444); if (dumpfile == NULL) { dumpfile = Zalloc(MAXPATHLEN); if (ioctl(dumpfd, DIOCGETDEV, dumpfile) == -1) - logprint(-1, interactive, 1, + logprint(SC_SL_NONE | SC_IF_ISATTY | SC_EXIT_ERR, "no dump device configured"); } @@ -1422,7 +1706,8 @@ usage(); if (livedump && ioctl(dumpfd, DIOCDUMP, NULL) == -1) - logprint(-1, 1, 1, "dedicated dump device required"); + logprint(SC_SL_NONE | SC_EXIT_ERR, + "dedicated dump device required"); (void) close(dumpfd); dumpfd = -1; @@ -1452,8 +1737,10 @@ STRLOG_MAKE_MSGID(fmt, msgid); + /* LINTED: E_SEC_SPRINTF_UNBOUNDED_COPY */ (void) sprintf(msg, "%s: [ID %u FACILITY_AND_PRIORITY] ", progname, msgid); + /* LINTED: E_SEC_PRINTF_VAR_FMT */ (void) sprintf(msg + strlen(msg), fmt, dumphdr.dump_panicstring); @@ -1471,15 +1758,54 @@ (void) close(logfd); } - if (chdir(savedir) == -1) - logprint(LOG_ERR, 1, 1, "chdir(\"%s\"): %s", - savedir, strerror(errno)); + if ((dumphdr.dump_flags & DF_COMPLETE) == 0) { + logprint(SC_SL_WARN, "incomplete dump on dump device"); + dump_incomplete = B_TRUE; + } + + if (dumphdr.dump_fm_panic) + fm_panic = B_TRUE; + + /* + * We have a valid dump on a dump device and know as much about + * it as we're going to at this stage. Raise an event for + * logging and so that FMA can open a case for this panic. + * Avoid this step for FMA-initiated panics - FMA will replay + * ereports off the dump device independently of savecore and + * will make a diagnosis, so we don't want to open two cases + * for the same event. Also avoid raising an event for a + * livedump, or when we inflating a compressed dump. + */ + if (!fm_panic && !livedump && !filemode) + raise_event(SC_EVENT_DUMP_PENDING, NULL); + + logprint(SC_SL_WARN, "System dump time: %s", + ctime(&dumphdr.dump_crashtime)); - if ((dumphdr.dump_flags & DF_COMPLETE) == 0) - logprint(LOG_WARNING, 1, -1, "incomplete dump on dump device"); + /* + * Option -c is designed for use from svc-dumpadm where we know + * that dumpadm -n is in effect but run savecore -c just to + * get the above dump_pending_on_device event raised. If it is run + * interactively then just print further panic details. + */ + if (cflag) { + char *disabled = defread("DUMPADM_ENABLE=no"); + int lvl = interactive ? SC_SL_WARN : SC_SL_ERR; + int ec = fm_panic ? SC_EXIT_FM : SC_EXIT_PEND; - logprint(LOG_WARNING, 1, -1, "System dump time: %s", - ctime(&dumphdr.dump_crashtime)); + logprint(lvl | ec, + "Panic crashdump pending on dump device%s " + "run savecore(1M) manually to extract. " + "Image UUID %s%s.", + disabled ? " but dumpadm -n in effect;" : ";", + corehdr.dump_uuid, + fm_panic ? "(fault-management initiated)" : ""); + /*NOTREACHED*/ + } + + if (chdir(savedir) == -1) + logprint(SC_SL_ERR | SC_EXIT_ERR, "chdir(\"%s\"): %s", + savedir, strerror(errno)); check_space(csave); @@ -1495,12 +1821,20 @@ datahdr.dump_metrics = 0; - logprint(LOG_ERR, 1, -1, + logprint(SC_SL_ERR, "Saving compressed system crash dump in %s/%s", savedir, corefile); copy_crashfile(corefile); + /* + * Raise a fault management event that indicates the system + * has panicked. We know a reasonable amount about the + * condition at this time, but the dump is still compressed. + */ + if (!livedump && !fm_panic) + raise_event(SC_EVENT_DUMP_AVAILABLE, NULL); + if (metrics_size > 0) { int sec = (gethrtime() - startts) / 1000 / 1000 / 1000; FILE *mfile = fopen(METRICSFILE, "a"); @@ -1513,37 +1847,39 @@ sec = 1; if (mfile == NULL) { - logprint(LOG_WARNING, 1, -1, + logprint(SC_SL_WARN, "Can't create %s:\n%s", METRICSFILE, metrics); } else { - fprintf(mfile, "[[[[,,,"); + (void) fprintf(mfile, "[[[[,,,"); for (i = 0; i < argc; i++) - fprintf(mfile, "%s ", argv[i]); - fprintf(mfile, "\n"); - fprintf(mfile, ",,,%s %s %s %s %s\n", + (void) fprintf(mfile, "%s ", argv[i]); + (void) fprintf(mfile, "\n"); + (void) fprintf(mfile, ",,,%s %s %s %s %s\n", dumphdr.dump_utsname.sysname, dumphdr.dump_utsname.nodename, dumphdr.dump_utsname.release, dumphdr.dump_utsname.version, dumphdr.dump_utsname.machine); - fprintf(mfile, ",,,%s dump time %s\n", + (void) fprintf(mfile, ",,,%s dump time %s\n", dumphdr.dump_flags & DF_LIVE ? "Live" : "Crash", ctime(&dumphdr.dump_crashtime)); - fprintf(mfile, ",,,%s/%s\n", savedir, corefile); - fprintf(mfile, "Metrics:\n%s\n", metrics); - fprintf(mfile, "Copy pages,%ld\n", dumphdr. - dump_npages); - fprintf(mfile, "Copy time,%d\n", sec); - fprintf(mfile, "Copy pages/sec,%ld\n", + (void) fprintf(mfile, ",,,%s/%s\n", savedir, + corefile); + (void) fprintf(mfile, "Metrics:\n%s\n", + metrics); + (void) fprintf(mfile, "Copy pages,%ld\n", + dumphdr. dump_npages); + (void) fprintf(mfile, "Copy time,%d\n", sec); + (void) fprintf(mfile, "Copy pages/sec,%ld\n", dumphdr.dump_npages / sec); - fprintf(mfile, "]]]]\n"); - fclose(mfile); + (void) fprintf(mfile, "]]]]\n"); + (void) fclose(mfile); } free(metrics); } - logprint(LOG_ERR, 1, -1, + logprint(SC_SL_ERR, "Decompress the crash dump with " "\n'savecore -vf %s/%s'", savedir, corefile); @@ -1554,17 +1890,20 @@ if (interactive && filebounds >= 0 && access(corefile, F_OK) == 0) - logprint(-1, 1, 1, + logprint(SC_SL_NONE | SC_EXIT_ERR, "%s already exists: remove with " "'rm -f %s/{unix,vmcore}.%ld'", corefile, savedir, bounds); - logprint(LOG_ERR, 1, -1, + logprint(SC_SL_ERR, "saving system crash dump in %s/{unix,vmcore}.%ld", savedir, bounds); build_corefile(namelist, corefile); + if (!livedump && !filemode && !fm_panic) + raise_event(SC_EVENT_DUMP_AVAILABLE, NULL); + if (access(METRICSFILE, F_OK) == 0) { int sec = (gethrtime() - startts) / 1000 / 1000 / 1000; FILE *mfile = fopen(METRICSFILE, "a"); @@ -1572,23 +1911,24 @@ if (sec < 1) sec = 1; - fprintf(mfile, "[[[[,,,"); + (void) fprintf(mfile, "[[[[,,,"); for (i = 0; i < argc; i++) - fprintf(mfile, "%s ", argv[i]); - fprintf(mfile, "\n"); - fprintf(mfile, ",,,%s/%s\n", savedir, corefile); - fprintf(mfile, ",,,%s %s %s %s %s\n", + (void) fprintf(mfile, "%s ", argv[i]); + (void) fprintf(mfile, "\n"); + (void) fprintf(mfile, ",,,%s/%s\n", savedir, corefile); + (void) fprintf(mfile, ",,,%s %s %s %s %s\n", dumphdr.dump_utsname.sysname, dumphdr.dump_utsname.nodename, dumphdr.dump_utsname.release, dumphdr.dump_utsname.version, dumphdr.dump_utsname.machine); - fprintf(mfile, "Uncompress pages,%ld\n", saved); - fprintf(mfile, "Uncompress time,%d\n", sec); - fprintf(mfile, "Uncompress pages/sec,%ld\n", - saved / sec); - fprintf(mfile, "]]]]\n"); - fclose(mfile); + (void) fprintf(mfile, "Uncompress pages,%"PRIu64"\n", + saved); + (void) fprintf(mfile, "Uncompress time,%d\n", sec); + (void) fprintf(mfile, "Uncompress pages/sec,%" + PRIu64"\n", saved / sec); + (void) fprintf(mfile, "]]]]\n"); + (void) fclose(mfile); } } @@ -1602,7 +1942,7 @@ if (verbose) { int sec = (gethrtime() - startts) / 1000 / 1000 / 1000; - printf("%d:%02d dump %s is done\n", + (void) printf("%d:%02d dump %s is done\n", sec / 60, sec % 60, csave ? "copy" : "decompress"); } @@ -1612,11 +1952,11 @@ for (i = 1, nw = 0; i <= BTOP(coreblksize); ++i) nw += hist[i] * i; - printf("pages count %%\n"); + (void) printf("pages count %%\n"); for (i = 0; i <= BTOP(coreblksize); ++i) { if (hist[i] == 0) continue; - printf("%3d %5u %6.2f\n", + (void) printf("%3d %5u %6.2f\n", i, hist[i], 100.0 * hist[i] * i / nw); } } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/savecore/sparc/Makefile --- a/usr/src/cmd/savecore/sparc/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/savecore/sparc/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -20,12 +19,12 @@ # CDDL HEADER END # # -# Copyright (c) 1998 by Sun Microsystems, Inc. -# All rights reserved. -# -#ident "%Z%%M% %I% %E% SMI" +# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. # include ../Makefile.com +LDLIBS += -L$(ROOT)/usr/lib/fm -lfmevent -lnvpair +LDFLAGS += -R/usr/lib/fm + install: all $(ROOTPROG32) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/savecore/sparcv9/Makefile --- a/usr/src/cmd/savecore/sparcv9/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/savecore/sparcv9/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -20,13 +19,13 @@ # CDDL HEADER END # # -# Copyright (c) 1998 by Sun Microsystems, Inc. -# All rights reserved. -# -#ident "%Z%%M% %I% %E% SMI" +# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. # include ../Makefile.com include ../../Makefile.cmd.64 +LDLIBS += -L$(ROOT)/usr/lib/fm/sparcv9 -lfmevent -lnvpair +LDFLAGS += -R/usr/lib/fm/sparcv9 + install: all $(ROOTPROG64) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/svc/common/notify_params.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/svc/common/notify_params.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,333 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "notify_params.h" + +static struct events { + const char *s; + int32_t c; +} smf_st_events[] = { + { "to-uninitialized", SCF_TRANS(0, SCF_STATE_UNINIT) }, + { "from-uninitialized", SCF_TRANS(SCF_STATE_UNINIT, 0) }, + { "uninitialized", SCF_TRANS(SCF_STATE_UNINIT, SCF_STATE_UNINIT) }, + { "to-maintenance", SCF_TRANS(0, SCF_STATE_MAINT) }, + { "from-maintenance", SCF_TRANS(SCF_STATE_MAINT, 0) }, + { "maintenance", SCF_TRANS(SCF_STATE_MAINT, SCF_STATE_MAINT) }, + { "to-offline", SCF_TRANS(0, SCF_STATE_OFFLINE) }, + { "from-offline", SCF_TRANS(SCF_STATE_OFFLINE, 0) }, + { "offline", SCF_TRANS(SCF_STATE_OFFLINE, SCF_STATE_OFFLINE) }, + { "to-disabled", SCF_TRANS(0, SCF_STATE_DISABLED) }, + { "from-disabled", SCF_TRANS(SCF_STATE_DISABLED, 0) }, + { "disabled", SCF_TRANS(SCF_STATE_DISABLED, SCF_STATE_DISABLED) }, + { "to-online", SCF_TRANS(0, SCF_STATE_ONLINE) }, + { "from-online", SCF_TRANS(SCF_STATE_ONLINE, 0) }, + { "online", SCF_TRANS(SCF_STATE_ONLINE, SCF_STATE_ONLINE) }, + { "to-degraded", SCF_TRANS(0, SCF_STATE_DEGRADED) }, + { "from-degraded", SCF_TRANS(SCF_STATE_DEGRADED, 0) }, + { "degraded", SCF_TRANS(SCF_STATE_DEGRADED, SCF_STATE_DEGRADED) }, + { "to-all", SCF_TRANS(0, SCF_STATE_ALL) }, + { "from-all", SCF_TRANS(SCF_STATE_ALL, 0) }, + { "all", SCF_TRANS(SCF_STATE_ALL, SCF_STATE_ALL) }, + { NULL, 0 } +}; + +static struct fma_tags { + const char *t; + const char *s; +} fma_tags[] = { + { "problem-diagnosed", "list.suspect" }, + { "problem-updated", "list.updated" }, + { "problem-repaired", "list.repaired" }, + { "problem-resolved", "list.resolved" }, + { NULL, NULL } +}; + +static char *fma_classes[] = { + "list.", + "ireport.", + NULL +}; + +/* + * get_fma_tag() + * return a pointer to the fma tag at the passed index. NULL if no entry exist + * for index + */ +const char * +get_fma_tag(uint32_t index) +{ + if (index > (sizeof (fma_tags) / sizeof (struct fma_tags))) + return (NULL); + + return (fma_tags[index].t); +} + +/* + * get_fma_class() + * return a pointer to the fma class at the passed index. NULL if no entry exist + * for index + */ +const char * +get_fma_class(uint32_t index) +{ + if (index > (sizeof (fma_tags) / sizeof (struct fma_tags))) + return (NULL); + + return (fma_tags[index].s); +} + +/* + * is_fma_token() + * check if the parameter is an fma token by comparing with the + * fma_classes[] and the fma_tags[] arrays. + */ +int +is_fma_token(const char *t) +{ + int i; + + for (i = 0; fma_classes[i]; ++i) + if (strncmp(t, fma_classes[i], strlen(fma_classes[i])) == 0) + return (1); + + for (i = 0; fma_tags[i].t; ++i) + if (strcmp(t, fma_tags[i].t) == 0) + return (1); + + return (0); +} + +/* + * has_fma_tag() + * returns 1 if there is an fma tag for the passed class, 0 otherwise + */ +int +has_fma_tag(const char *c) +{ + int i; + + for (i = 0; fma_tags[i].s; ++i) + if (strcmp(c, fma_tags[i].s) == 0) + return (1); + + return (0); +} + +const char * +de_tag(const char *tag) +{ + int i; + + for (i = 0; fma_tags[i].t; ++i) + if (strcmp(tag, fma_tags[i].t) == 0) + return (fma_tags[i].s); + + return (tag); +} + +const char * +re_tag(const char *fma_event) +{ + int i; + + for (i = 0; fma_tags[i].s; ++i) + if (strcmp(fma_event, fma_tags[i].s) == 0) + return (fma_tags[i].t); + + return (fma_event); +} + +int32_t +string_to_tset(const char *str) +{ + int i; + + for (i = 0; smf_st_events[i].s != NULL; ++i) { + if (strcmp(str, smf_st_events[i].s) == 0) + return (smf_st_events[i].c); + } + + return (0); +} + +const char * +tset_to_string(int32_t t) +{ + int i; + + for (i = 0; smf_st_events[i].s != NULL; ++i) { + if (smf_st_events[i].c == t) + return (smf_st_events[i].s); + } + + return (NULL); +} + +void +safe_printf(const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + if (vprintf(fmt, va) < 0) + uu_die(gettext("Error writing to stdout")); + va_end(va); +} + +static uint32_t +notify_params_get_version(nvlist_t *nvl) +{ + uint32_t v; + + if (nvl == NULL) + return (0xFFFFFFFFU); + + if (nvlist_lookup_uint32(nvl, SCF_NOTIFY_NAME_VERSION, &v) != 0) + return (0xFFFFFFFFU); + else + return (v); +} + +static void +nvpair_print(nvpair_t *p) +{ + char **v; + uint_t n; + int i; + + safe_printf(" %s:", nvpair_name(p)); + (void) nvpair_value_string_array(p, &v, &n); + for (i = 0; i < n; ++i) { + safe_printf(" %s", v[i]); + } + safe_printf("\n"); +} + +static void +params_type_print(nvlist_t *p, const char *name, const char *fmri) +{ + nvpair_t *tnvp, *nvp; + nvlist_t *nvl; + boolean_t *a; + uint_t n; + int has_output = 0; + + /* for each event e print all notification parameters */ + for (tnvp = nvlist_next_nvpair(p, NULL); tnvp != NULL; + tnvp = nvlist_next_nvpair(p, tnvp)) { + /* We only want the NVLIST memebers */ + if (nvpair_type(tnvp) != DATA_TYPE_NVLIST) + continue; + + if (nvpair_value_nvlist(tnvp, &nvl) != 0) + uu_die("nvpair_value_nvlist"); + + if (!has_output) + if (fmri == NULL) + safe_printf(gettext(" Event: %s\n"), name); + else + safe_printf(gettext( + " Event: %s (source: %s)\n"), + name, fmri); + + has_output = 1; + + safe_printf(gettext(" Notification Type: %s\n"), + nvpair_name(tnvp)); + + if (nvlist_lookup_boolean_array(nvl, PARAM_ACTIVE, &a, &n) != 0) + uu_warn(gettext("Missing 'active' property")); + else + safe_printf(gettext(" Active: %s\n"), + *a ? "true" : "false"); + + for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; + nvp = nvlist_next_nvpair(nvl, nvp)) { + if (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY) + continue; + nvpair_print(nvp); + } + safe_printf("\n"); + } +} + +void +listnotify_print(nvlist_t *nvl, const char *event) +{ + char *fmri; + nvlist_t **params; + size_t n; + int32_t tset; + int i; + + /* + * Check the nvl we got is from a version we understand + */ + if (nvl != NULL && notify_params_get_version(nvl) != + SCF_NOTIFY_PARAMS_VERSION) + uu_die(gettext("libscf(3LIB) mismatch\n")); + + if (nvl != NULL && nvlist_lookup_nvlist_array(nvl, SCF_NOTIFY_PARAMS, + ¶ms, &n) != 0) + /* Sanity check. If we get here nvl is bad! */ + uu_die(gettext("nvlist_lookup_nvlist_array\n")); + + if (event == NULL) { + /* this is an SMF state transition nvlist */ + for (i = 0; i < n; ++i) { + nvlist_t *p = *(params + i); + + if (nvlist_lookup_string(p, + SCF_NOTIFY_PARAMS_SOURCE_NAME, &fmri) != 0) + fmri = NULL; + if (nvlist_lookup_int32(p, SCF_NOTIFY_NAME_TSET, + &tset) != 0) + uu_die("nvlist_lookup_int32"); + params_type_print(p, tset_to_string(tset), fmri); + } + } else { + /* this is FMA event nvlist */ + if (nvl == NULL) { /* preferences not found */ + return; + } + for (i = 0; i < n; ++i) { + nvlist_t *p = *(params + i); + + if (nvlist_lookup_string(p, + SCF_NOTIFY_PARAMS_SOURCE_NAME, &fmri) != 0) + fmri = NULL; + params_type_print(p, event, fmri); + } + } +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/svc/common/notify_params.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/svc/common/notify_params.h Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,54 @@ +/* + * 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 _CMD_COMMON_NOTIFY_PARAMS_H +#define _CMD_COMMON_NOTIFY_PARAMS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PARAM_ACTIVE ((const char *) "active") +#define PARAM_INACTIVE ((const char *) "inactive") +#define PARAM_SMTP_TO ((const char *) "to") + +const char *get_fma_tag(uint32_t); +const char *get_fma_class(uint32_t); +int is_fma_token(const char *); +int has_fma_tag(const char *); +const char *de_tag(const char *); +const char *re_tag(const char *); +int32_t string_to_tset(const char *); +const char *tset_to_string(int32_t); +void listnotify_print(nvlist_t *, const char *); +void safe_printf(const char *, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* _CMD_COMMON_NOTIFY_PARAMS_H */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/cmd/svc/dtd/service_bundle.dtd.1 --- a/usr/src/cmd/svc/dtd/service_bundle.dtd.1 Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/cmd/svc/dtd/service_bundle.dtd.1 Fri Jul 30 17:04:17 2010 +1000 @@ -939,6 +939,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -257,6 +256,12 @@ nvl->nvl_pad = 0; } +uint_t +nvlist_nvflag(nvlist_t *nvl) +{ + return (nvl->nvl_nvflag); +} + /* * nvlist_alloc - Allocate nvlist. */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/Makefile --- a/usr/src/lib/fm/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -35,6 +35,8 @@ libfmd_msg \ libfmd_snmp \ libfmevent \ + .WAIT \ + libfmnotify \ topo sparc_SUBDIRS = \ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmd_msg/common/fmd_msg.c --- a/usr/src/lib/fm/libfmd_msg/common/fmd_msg.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmd_msg/common/fmd_msg.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 #include +#include #include #include #include @@ -106,6 +108,7 @@ #include #include #include +#include #include #include @@ -1130,6 +1133,125 @@ } /* + * 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 + * % - 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 @@ 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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmd_msg/common/fmd_msg.h --- a/usr/src/lib/fm/libfmd_msg/common/fmd_msg.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmd_msg/common/fmd_msg.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmd_msg/common/mapfile-vers --- a/usr/src/lib/fm/libfmd_msg/common/mapfile-vers Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmd_msg/common/mapfile-vers Fri Jul 30 17:04:17 2010 +1000 @@ -38,11 +38,13 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmd_snmp/Makefile --- a/usr/src/lib/fm/libfmd_snmp/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmd_snmp/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h --- a/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ /* * 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 @@ #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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmd_snmp/mibs/SUN-FM-MIB.mib --- a/usr/src/lib/fm/libfmd_snmp/mibs/SUN-FM-MIB.mib Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmd_snmp/mibs/SUN-FM-MIB.mib Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmd_snmp/mibs/SUN-IREPORT-MIB.mib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmd_snmp/mibs/SUN-IREPORT-MIB.mib Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/Makefile --- a/usr/src/lib/fm/libfmevent/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/Makefile.com --- a/usr/src/lib/fm/libfmevent/Makefile.com Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ 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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/amd64/Makefile --- a/usr/src/lib/fm/libfmevent/amd64/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/amd64/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/common/fmev_channels.h --- a/usr/src/lib/fm/libfmevent/common/fmev_channels.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/common/fmev_channels.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/common/fmev_evaccess.c --- a/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ ASSERT(EVENT_VALID(iep)); - API_ENTERV1(iep); + (void) FMEV_API_ENTER(iep, 1); atomic_inc_32(&iep->ei_refcnt); } @@ -149,7 +147,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/common/fmev_impl.h --- a/usr/src/lib/fm/libfmevent/common/fmev_impl.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/common/fmev_impl.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ #include #include #include +#include + +#include "fmev_channels.h" #ifdef DEBUG #define ASSERT(x) (assert(x)) @@ -59,8 +61,14 @@ 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 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/common/fmev_publish.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/fmev_publish.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 +#include +#include +#include +#include +#include +#include + +#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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/common/fmev_subscribe.c --- a/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 #include #include -#include #include +#include #include #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 @@ #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_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_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_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_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_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 @@ 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 @@ 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 @@ 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_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_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 @@ } 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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/common/fmev_util.c --- a/usr/src/lib/fm/libfmevent/common/fmev_util.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/common/fmev_util.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/common/libfmevent.h --- a/usr/src/lib/fm/libfmevent/common/libfmevent.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/common/libfmevent.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ * 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 @@ 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_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 @@ * 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_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 @@ 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 + * 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 + +/* + * 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/common/libfmevent_ruleset.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/libfmevent_ruleset.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/common/mapfile-vers --- a/usr/src/lib/fm/libfmevent/common/mapfile-vers Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/common/mapfile-vers Fri Jul 30 17:04:17 2010 +1000 @@ -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 SUNWprivate { global: + fmev_pri_string; + fmev_publish { FLAGS = NODYNSORT }; + fmev_rspublish { FLAGS = NODYNSORT }; + _i_fmev_publish; + _i_fmev_publish_nvl; __fmev_errno; local: *; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/i386/Makefile --- a/usr/src/lib/fm/libfmevent/i386/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/i386/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/sparc/Makefile --- a/usr/src/lib/fm/libfmevent/sparc/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/sparc/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmevent/sparcv9/Makefile --- a/usr/src/lib/fm/libfmevent/sparcv9/Makefile Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/libfmevent/sparcv9/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/Makefile.com --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/amd64/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/amd64/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/common/libfmnotify.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/common/libfmnotify.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 + +#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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/common/libfmnotify.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/common/libfmnotify.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/common/llib-lfmnotify --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/common/llib-lfmnotify Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/common/mapfile-vers --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/common/mapfile-vers Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/i386/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/i386/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/sparc/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/sparc/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/libfmnotify/sparcv9/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmnotify/sparcv9/Makefile Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/Makefile.com --- a/usr/src/lib/fm/topo/libtopo/Makefile.com Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ mod.c \ pkg.c \ svc.c \ + sw.c \ zfs.c LIBSRCS = \ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/dev.c --- a/usr/src/lib/fm/topo/libtopo/common/dev.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/dev.c Fri Jul 30 17:04:17 2010 +1000 @@ -114,6 +114,11 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/fmd.c --- a/usr/src/lib/fm/topo/libtopo/common/fmd.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/fmd.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 #include @@ -96,6 +94,11 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/hc.c --- a/usr/src/lib/fm/topo/libtopo/common/hc.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/hc.c Fri Jul 30 17:04:17 2010 +1000 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -311,6 +312,7 @@ 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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/mem.c --- a/usr/src/lib/fm/topo/libtopo/common/mem.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/mem.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 #include #include #include #include #include +#include #include #include #include @@ -96,9 +94,10 @@ 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 @@ } } - 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/mod.c --- a/usr/src/lib/fm/topo/libtopo/common/mod.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/mod.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ -94,6 +93,11 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/pkg.c --- a/usr/src/lib/fm/topo/libtopo/common/pkg.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/pkg.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ -74,7 +73,7 @@ { 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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/svc.c --- a/usr/src/lib/fm/topo/libtopo/common/svc.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/svc.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 #include #include +#include #include #include #include @@ -67,11 +67,13 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ } /* - * 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 @@ } } - /* - * 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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/sw.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/topo/libtopo/common/sw.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 +#include + +#include +#include + +#include +#include +#include + +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://[]/ + * [:root= + * [#] + * + * is one of + * + * :token= + * or + * :file=[:func=][: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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/sw.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/topo/libtopo/common/sw.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/topo_builtin.c --- a/usr/src/lib/fm/topo/libtopo/common/topo_builtin.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_builtin.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ -39,6 +38,7 @@ #include #include #include +#include #include static const struct topo_builtin _topo_builtins[] = { @@ -48,6 +48,7 @@ { "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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/topo_mod.c --- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/topo_mod.h --- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/topo_node.c --- a/usr/src/lib/fm/topo/libtopo/common/topo_node.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_node.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/topo_snap.c --- a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 #include #include +#include #include #include @@ -379,7 +379,7 @@ /* * 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 -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/fm/topo/libtopo/common/zfs.c --- a/usr/src/lib/fm/topo/libtopo/common/zfs.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/zfs.c Fri Jul 30 17:04:17 2010 +1000 @@ -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 @@ -103,6 +102,11 @@ 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); } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libnvpair/libnvpair.c --- a/usr/src/lib/libnvpair/libnvpair.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libnvpair/libnvpair.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -28,6 +27,8 @@ #include #include #include +#include +#include #include "libnvpair.h" /* @@ -38,21 +39,531 @@ * between kernel and userland, and possibly saving onto disk files. */ +/* + * Print control structure. + */ + +#define DEFINEOP(opname, vtype) \ + struct { \ + int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \ + const char *, vtype); \ + void *arg; \ + } opname + +#define DEFINEARROP(opname, vtype) \ + struct { \ + int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \ + const char *, vtype, uint_t); \ + void *arg; \ + } opname + +struct nvlist_printops { + DEFINEOP(print_boolean, int); + DEFINEOP(print_boolean_value, boolean_t); + DEFINEOP(print_byte, uchar_t); + DEFINEOP(print_int8, int8_t); + DEFINEOP(print_uint8, uint8_t); + DEFINEOP(print_int16, int16_t); + DEFINEOP(print_uint16, uint16_t); + DEFINEOP(print_int32, int32_t); + DEFINEOP(print_uint32, uint32_t); + DEFINEOP(print_int64, int64_t); + DEFINEOP(print_uint64, uint64_t); + DEFINEOP(print_double, double); + DEFINEOP(print_string, char *); + DEFINEOP(print_hrtime, hrtime_t); + DEFINEOP(print_nvlist, nvlist_t *); + DEFINEARROP(print_boolean_array, boolean_t *); + DEFINEARROP(print_byte_array, uchar_t *); + DEFINEARROP(print_int8_array, int8_t *); + DEFINEARROP(print_uint8_array, uint8_t *); + DEFINEARROP(print_int16_array, int16_t *); + DEFINEARROP(print_uint16_array, uint16_t *); + DEFINEARROP(print_int32_array, int32_t *); + DEFINEARROP(print_uint32_array, uint32_t *); + DEFINEARROP(print_int64_array, int64_t *); + DEFINEARROP(print_uint64_array, uint64_t *); + DEFINEARROP(print_string_array, char **); + DEFINEARROP(print_nvlist_array, nvlist_t **); +}; + +struct nvlist_prtctl { + FILE *nvprt_fp; /* output destination */ + enum nvlist_indent_mode nvprt_indent_mode; /* see above */ + int nvprt_indent; /* absolute indent, or tab depth */ + int nvprt_indentinc; /* indent or tab increment */ + const char *nvprt_nmfmt; /* member name format, max one %s */ + const char *nvprt_eomfmt; /* after member format, e.g. "\n" */ + const char *nvprt_btwnarrfmt; /* between array members */ + int nvprt_btwnarrfmt_nl; /* nvprt_eoamfmt includes newline? */ + struct nvlist_printops *nvprt_dfltops; + struct nvlist_printops *nvprt_custops; +}; + +#define DFLTPRTOP(pctl, type) \ + ((pctl)->nvprt_dfltops->print_##type.op) + +#define DFLTPRTOPARG(pctl, type) \ + ((pctl)->nvprt_dfltops->print_##type.arg) + +#define CUSTPRTOP(pctl, type) \ + ((pctl)->nvprt_custops->print_##type.op) + +#define CUSTPRTOPARG(pctl, type) \ + ((pctl)->nvprt_custops->print_##type.arg) + +#define RENDER(pctl, type, nvl, name, val) \ + { \ + int done = 0; \ + if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \ + done = CUSTPRTOP(pctl, type)(pctl, \ + CUSTPRTOPARG(pctl, type), nvl, name, val); \ + } \ + if (!done) { \ + (void) DFLTPRTOP(pctl, type)(pctl, \ + DFLTPRTOPARG(pctl, type), nvl, name, val); \ + } \ + (void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \ + } + +#define ARENDER(pctl, type, nvl, name, arrp, count) \ + { \ + int done = 0; \ + if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \ + done = CUSTPRTOP(pctl, type)(pctl, \ + CUSTPRTOPARG(pctl, type), nvl, name, arrp, count); \ + } \ + if (!done) { \ + (void) DFLTPRTOP(pctl, type)(pctl, \ + DFLTPRTOPARG(pctl, type), nvl, name, arrp, count); \ + } \ + (void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \ + } + +static void nvlist_print_with_indent(nvlist_t *, nvlist_prtctl_t); + +/* + * ====================================================================== + * | | + * | Indentation | + * | | + * ====================================================================== + */ + static void -indent(FILE *fp, int depth) +indent(nvlist_prtctl_t pctl, int onemore) +{ + int depth; + + switch (pctl->nvprt_indent_mode) { + case NVLIST_INDENT_ABS: + (void) fprintf(pctl->nvprt_fp, "%*s", + pctl->nvprt_indent + onemore * pctl->nvprt_indentinc, ""); + break; + + case NVLIST_INDENT_TABBED: + depth = pctl->nvprt_indent + onemore; + while (depth-- > 0) + (void) fprintf(pctl->nvprt_fp, "\t"); + } +} + +/* + * ====================================================================== + * | | + * | Default nvlist member rendering functions. | + * | | + * ====================================================================== + */ + +/* + * Generate functions to print single-valued nvlist members. + * + * type_and_variant - suffix to form function name + * vtype - C type for the member value + * ptype - C type to cast value to for printing + * vfmt - format string for pair value, e.g "%d" or "0x%llx" + */ + +#define NVLIST_PRTFUNC(type_and_variant, vtype, ptype, vfmt) \ +static int \ +nvprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \ + nvlist_t *nvl, const char *name, vtype value) \ +{ \ + FILE *fp = pctl->nvprt_fp; \ + NOTE(ARGUNUSED(private)) \ + NOTE(ARGUNUSED(nvl)) \ + indent(pctl, 1); \ + (void) fprintf(fp, pctl->nvprt_nmfmt, name); \ + (void) fprintf(fp, vfmt, (ptype)value); \ + return (1); \ +} + +NVLIST_PRTFUNC(boolean, int, int, "%d") +NVLIST_PRTFUNC(boolean_value, boolean_t, int, "%d") +NVLIST_PRTFUNC(byte, uchar_t, uchar_t, "0x%2.2x") +NVLIST_PRTFUNC(int8, int8_t, int, "%d") +NVLIST_PRTFUNC(uint8, uint8_t, uint8_t, "0x%x") +NVLIST_PRTFUNC(int16, int16_t, int16_t, "%d") +NVLIST_PRTFUNC(uint16, uint16_t, uint16_t, "0x%x") +NVLIST_PRTFUNC(int32, int32_t, int32_t, "%d") +NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x") +NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld") +NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx") +NVLIST_PRTFUNC(double, double, double, "0x%llf") +NVLIST_PRTFUNC(string, char *, char *, "%s") +NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx") + +/* + * Generate functions to print array-valued nvlist members. + */ + +#define NVLIST_ARRPRTFUNC(type_and_variant, vtype, ptype, vfmt) \ +static int \ +nvaprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \ + nvlist_t *nvl, const char *name, vtype *valuep, uint_t count) \ +{ \ + FILE *fp = pctl->nvprt_fp; \ + uint_t i; \ + NOTE(ARGUNUSED(private)) \ + NOTE(ARGUNUSED(nvl)) \ + for (i = 0; i < count; i++) { \ + if (i == 0 || pctl->nvprt_btwnarrfmt_nl) { \ + indent(pctl, 1); \ + (void) fprintf(fp, pctl->nvprt_nmfmt, name); \ + if (pctl->nvprt_btwnarrfmt_nl) \ + (void) fprintf(fp, "[%d]: ", i); \ + } \ + if (i != 0) \ + (void) fprintf(fp, pctl->nvprt_btwnarrfmt); \ + (void) fprintf(fp, vfmt, (ptype)valuep[i]); \ + } \ + return (1); \ +} + +NVLIST_ARRPRTFUNC(boolean_array, boolean_t, boolean_t, "%d") +NVLIST_ARRPRTFUNC(byte_array, uchar_t, uchar_t, "0x%2.2x") +NVLIST_ARRPRTFUNC(int8_array, int8_t, int8_t, "%d") +NVLIST_ARRPRTFUNC(uint8_array, uint8_t, uint8_t, "0x%x") +NVLIST_ARRPRTFUNC(int16_array, int16_t, int16_t, "%d") +NVLIST_ARRPRTFUNC(uint16_array, uint16_t, uint16_t, "0x%x") +NVLIST_ARRPRTFUNC(int32_array, int32_t, int32_t, "%d") +NVLIST_ARRPRTFUNC(uint32_array, uint32_t, uint32_t, "0x%x") +NVLIST_ARRPRTFUNC(int64_array, int64_t, longlong_t, "%lld") +NVLIST_ARRPRTFUNC(uint64_array, uint64_t, u_longlong_t, "0x%llx") +NVLIST_ARRPRTFUNC(string_array, char *, char *, "%s") + +/*ARGSUSED*/ +static int +nvprint_nvlist(nvlist_prtctl_t pctl, void *private, + nvlist_t *nvl, const char *name, nvlist_t *value) +{ + FILE *fp = pctl->nvprt_fp; + + indent(pctl, 1); + (void) fprintf(fp, "%s = (embedded nvlist)\n", name); + + pctl->nvprt_indent += pctl->nvprt_indentinc; + nvlist_print_with_indent(value, pctl); + pctl->nvprt_indent -= pctl->nvprt_indentinc; + + indent(pctl, 1); + (void) fprintf(fp, "(end %s)\n", name); + + return (1); +} + +/*ARGSUSED*/ +static int +nvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private, + nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count) { - while (depth-- > 0) - (void) fprintf(fp, "\t"); + FILE *fp = pctl->nvprt_fp; + uint_t i; + + indent(pctl, 1); + (void) fprintf(fp, "%s = (array of embedded nvlists)\n", name); + + for (i = 0; i < count; i++) { + indent(pctl, 1); + (void) fprintf(fp, "(start %s[%d])\n", name, i); + + pctl->nvprt_indent += pctl->nvprt_indentinc; + nvlist_print_with_indent(valuep[i], pctl); + pctl->nvprt_indent -= pctl->nvprt_indentinc; + + indent(pctl, 1); + (void) fprintf(fp, "(end %s[%d])\n", name, i); + } + + return (1); +} + +/* + * ====================================================================== + * | | + * | Interfaces that allow control over formatting. | + * | | + * ====================================================================== + */ + +void +nvlist_prtctl_setdest(nvlist_prtctl_t pctl, FILE *fp) +{ + pctl->nvprt_fp = fp; +} + +FILE * +nvlist_prtctl_getdest(nvlist_prtctl_t pctl) +{ + return (pctl->nvprt_fp); +} + + +void +nvlist_prtctl_setindent(nvlist_prtctl_t pctl, enum nvlist_indent_mode mode, + int start, int inc) +{ + if (mode < NVLIST_INDENT_ABS || mode > NVLIST_INDENT_TABBED) + mode = NVLIST_INDENT_TABBED; + + if (start < 0) + start = 0; + + if (inc < 0) + inc = 1; + + pctl->nvprt_indent_mode = mode; + pctl->nvprt_indent = start; + pctl->nvprt_indentinc = inc; +} + +void +nvlist_prtctl_doindent(nvlist_prtctl_t pctl, int onemore) +{ + indent(pctl, onemore); +} + + +void +nvlist_prtctl_setfmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, + const char *fmt) +{ + switch (which) { + case NVLIST_FMT_MEMBER_NAME: + if (fmt == NULL) + fmt = "%s = "; + pctl->nvprt_nmfmt = fmt; + break; + + case NVLIST_FMT_MEMBER_POSTAMBLE: + if (fmt == NULL) + fmt = "\n"; + pctl->nvprt_eomfmt = fmt; + break; + + case NVLIST_FMT_BTWN_ARRAY: + if (fmt == NULL) { + pctl->nvprt_btwnarrfmt = " "; + pctl->nvprt_btwnarrfmt_nl = 0; + } else { + pctl->nvprt_btwnarrfmt = fmt; + pctl->nvprt_btwnarrfmt_nl = (strstr(fmt, "\n") != NULL); + } + break; + + default: + break; + } +} + + +void +nvlist_prtctl_dofmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, ...) +{ + FILE *fp = pctl->nvprt_fp; + va_list ap; + char *name; + + va_start(ap, which); + + switch (which) { + case NVLIST_FMT_MEMBER_NAME: + name = va_arg(ap, char *); + (void) fprintf(fp, pctl->nvprt_nmfmt, name); + break; + + case NVLIST_FMT_MEMBER_POSTAMBLE: + (void) fprintf(fp, pctl->nvprt_eomfmt); + break; + + case NVLIST_FMT_BTWN_ARRAY: + (void) fprintf(fp, pctl->nvprt_btwnarrfmt); \ + break; + + default: + break; + } + + va_end(ap); } /* + * ====================================================================== + * | | + * | Interfaces to allow appointment of replacement rendering functions.| + * | | + * ====================================================================== + */ + +#define NVLIST_PRINTCTL_REPLACE(type, vtype) \ +void \ +nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \ + int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype), \ + void *private) \ +{ \ + CUSTPRTOP(pctl, type) = func; \ + CUSTPRTOPARG(pctl, type) = private; \ +} + +NVLIST_PRINTCTL_REPLACE(boolean, int) +NVLIST_PRINTCTL_REPLACE(boolean_value, boolean_t) +NVLIST_PRINTCTL_REPLACE(byte, uchar_t) +NVLIST_PRINTCTL_REPLACE(int8, int8_t) +NVLIST_PRINTCTL_REPLACE(uint8, uint8_t) +NVLIST_PRINTCTL_REPLACE(int16, int16_t) +NVLIST_PRINTCTL_REPLACE(uint16, uint16_t) +NVLIST_PRINTCTL_REPLACE(int32, int32_t) +NVLIST_PRINTCTL_REPLACE(uint32, uint32_t) +NVLIST_PRINTCTL_REPLACE(int64, int64_t) +NVLIST_PRINTCTL_REPLACE(uint64, uint64_t) +NVLIST_PRINTCTL_REPLACE(double, double) +NVLIST_PRINTCTL_REPLACE(string, char *) +NVLIST_PRINTCTL_REPLACE(hrtime, hrtime_t) +NVLIST_PRINTCTL_REPLACE(nvlist, nvlist_t *) + +#define NVLIST_PRINTCTL_AREPLACE(type, vtype) \ +void \ +nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \ + int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, \ + uint_t), void *private) \ +{ \ + CUSTPRTOP(pctl, type) = func; \ + CUSTPRTOPARG(pctl, type) = private; \ +} + +NVLIST_PRINTCTL_AREPLACE(boolean_array, boolean_t *) +NVLIST_PRINTCTL_AREPLACE(byte_array, uchar_t *) +NVLIST_PRINTCTL_AREPLACE(int8_array, int8_t *) +NVLIST_PRINTCTL_AREPLACE(uint8_array, uint8_t *) +NVLIST_PRINTCTL_AREPLACE(int16_array, int16_t *) +NVLIST_PRINTCTL_AREPLACE(uint16_array, uint16_t *) +NVLIST_PRINTCTL_AREPLACE(int32_array, int32_t *) +NVLIST_PRINTCTL_AREPLACE(uint32_array, uint32_t *) +NVLIST_PRINTCTL_AREPLACE(int64_array, int64_t *) +NVLIST_PRINTCTL_AREPLACE(uint64_array, uint64_t *) +NVLIST_PRINTCTL_AREPLACE(string_array, char **) +NVLIST_PRINTCTL_AREPLACE(nvlist_array, nvlist_t **) + +/* + * ====================================================================== + * | | + * | Interfaces to manage nvlist_prtctl_t cookies. | + * | | + * ====================================================================== + */ + + +static const struct nvlist_printops defprtops = { + { nvprint_boolean, NULL }, + { nvprint_boolean_value, NULL }, + { nvprint_byte, NULL }, + { nvprint_int8, NULL }, + { nvprint_uint8, NULL }, + { nvprint_int16, NULL }, + { nvprint_uint16, NULL }, + { nvprint_int32, NULL }, + { nvprint_uint32, NULL }, + { nvprint_int64, NULL }, + { nvprint_uint64, NULL }, + { nvprint_double, NULL }, + { nvprint_string, NULL }, + { nvprint_hrtime, NULL }, + { nvprint_nvlist, NULL }, + { nvaprint_boolean_array, NULL }, + { nvaprint_byte_array, NULL }, + { nvaprint_int8_array, NULL }, + { nvaprint_uint8_array, NULL }, + { nvaprint_int16_array, NULL }, + { nvaprint_uint16_array, NULL }, + { nvaprint_int32_array, NULL }, + { nvaprint_uint32_array, NULL }, + { nvaprint_int64_array, NULL }, + { nvaprint_uint64_array, NULL }, + { nvaprint_string_array, NULL }, + { nvaprint_nvlist_array, NULL }, +}; + +static void +prtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl, + struct nvlist_printops *ops) +{ + pctl->nvprt_fp = fp; + pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED; + pctl->nvprt_indent = 0; + pctl->nvprt_indentinc = 1; + pctl->nvprt_nmfmt = "%s = "; + pctl->nvprt_eomfmt = "\n"; + pctl->nvprt_btwnarrfmt = " "; + pctl->nvprt_btwnarrfmt_nl = 0; + + pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops; + pctl->nvprt_custops = ops; +} + +nvlist_prtctl_t +nvlist_prtctl_alloc(void) +{ + struct nvlist_prtctl *pctl; + struct nvlist_printops *ops; + + if ((pctl = malloc(sizeof (*pctl))) == NULL) + return (NULL); + + if ((ops = calloc(1, sizeof (*ops))) == NULL) { + free(pctl); + return (NULL); + } + + prtctl_defaults(stdout, pctl, ops); + + return (pctl); +} + +void +nvlist_prtctl_free(nvlist_prtctl_t pctl) +{ + if (pctl != NULL) { + free(pctl->nvprt_custops); + free(pctl); + } +} + +/* + * ====================================================================== + * | | + * | Top-level print request interfaces. | + * | | + * ====================================================================== + */ + +/* * nvlist_print - Prints elements in an event buffer */ -static -void -nvlist_print_with_indent(FILE *fp, nvlist_t *nvl, int depth) +static void +nvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl) { - int i; + FILE *fp = pctl->nvprt_fp; char *name; uint_t nelem; nvpair_t *nvp; @@ -60,7 +571,7 @@ if (nvl == NULL) return; - indent(fp, depth); + indent(pctl, 0); (void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl)); nvp = nvlist_next_nvpair(nvl, NULL); @@ -68,199 +579,174 @@ while (nvp) { data_type_t type = nvpair_type(nvp); - indent(fp, depth); name = nvpair_name(nvp); - (void) fprintf(fp, "\t%s =", name); nelem = 0; + switch (type) { case DATA_TYPE_BOOLEAN: { - (void) fprintf(fp, " 1"); + RENDER(pctl, boolean, nvl, name, 1); break; } case DATA_TYPE_BOOLEAN_VALUE: { boolean_t val; (void) nvpair_value_boolean_value(nvp, &val); - (void) fprintf(fp, " %d", val); + RENDER(pctl, boolean_value, nvl, name, val); break; } case DATA_TYPE_BYTE: { uchar_t val; (void) nvpair_value_byte(nvp, &val); - (void) fprintf(fp, " 0x%2.2x", val); + RENDER(pctl, byte, nvl, name, val); break; } case DATA_TYPE_INT8: { int8_t val; (void) nvpair_value_int8(nvp, &val); - (void) fprintf(fp, " %d", val); + RENDER(pctl, int8, nvl, name, val); break; } case DATA_TYPE_UINT8: { uint8_t val; (void) nvpair_value_uint8(nvp, &val); - (void) fprintf(fp, " 0x%x", val); + RENDER(pctl, uint8, nvl, name, val); break; } case DATA_TYPE_INT16: { int16_t val; (void) nvpair_value_int16(nvp, &val); - (void) fprintf(fp, " %d", val); + RENDER(pctl, int16, nvl, name, val); break; } case DATA_TYPE_UINT16: { uint16_t val; (void) nvpair_value_uint16(nvp, &val); - (void) fprintf(fp, " 0x%x", val); + RENDER(pctl, uint16, nvl, name, val); break; } case DATA_TYPE_INT32: { int32_t val; (void) nvpair_value_int32(nvp, &val); - (void) fprintf(fp, " %d", val); + RENDER(pctl, int32, nvl, name, val); break; } case DATA_TYPE_UINT32: { uint32_t val; (void) nvpair_value_uint32(nvp, &val); - (void) fprintf(fp, " 0x%x", val); + RENDER(pctl, uint32, nvl, name, val); break; } case DATA_TYPE_INT64: { int64_t val; (void) nvpair_value_int64(nvp, &val); - (void) fprintf(fp, " %lld", (longlong_t)val); + RENDER(pctl, int64, nvl, name, val); break; } case DATA_TYPE_UINT64: { uint64_t val; (void) nvpair_value_uint64(nvp, &val); - (void) fprintf(fp, " 0x%llx", (u_longlong_t)val); + RENDER(pctl, uint64, nvl, name, val); break; } case DATA_TYPE_DOUBLE: { double val; (void) nvpair_value_double(nvp, &val); - (void) fprintf(fp, " 0x%llf", val); + RENDER(pctl, double, nvl, name, val); break; } case DATA_TYPE_STRING: { char *val; (void) nvpair_value_string(nvp, &val); - (void) fprintf(fp, " %s", val); + RENDER(pctl, string, nvl, name, val); break; } case DATA_TYPE_BOOLEAN_ARRAY: { boolean_t *val; (void) nvpair_value_boolean_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " %d", val[i]); + ARENDER(pctl, boolean_array, nvl, name, val, nelem); break; } case DATA_TYPE_BYTE_ARRAY: { uchar_t *val; (void) nvpair_value_byte_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " 0x%2.2x", val[i]); + ARENDER(pctl, byte_array, nvl, name, val, nelem); break; } case DATA_TYPE_INT8_ARRAY: { int8_t *val; (void) nvpair_value_int8_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " %d", val[i]); + ARENDER(pctl, int8_array, nvl, name, val, nelem); break; } case DATA_TYPE_UINT8_ARRAY: { uint8_t *val; (void) nvpair_value_uint8_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " 0x%x", val[i]); + ARENDER(pctl, uint8_array, nvl, name, val, nelem); break; } case DATA_TYPE_INT16_ARRAY: { int16_t *val; (void) nvpair_value_int16_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " %d", val[i]); + ARENDER(pctl, int16_array, nvl, name, val, nelem); break; } case DATA_TYPE_UINT16_ARRAY: { uint16_t *val; (void) nvpair_value_uint16_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " 0x%x", val[i]); + ARENDER(pctl, uint16_array, nvl, name, val, nelem); break; } case DATA_TYPE_INT32_ARRAY: { int32_t *val; (void) nvpair_value_int32_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " %d", val[i]); + ARENDER(pctl, int32_array, nvl, name, val, nelem); break; } case DATA_TYPE_UINT32_ARRAY: { uint32_t *val; (void) nvpair_value_uint32_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " 0x%x", val[i]); + ARENDER(pctl, uint32_array, nvl, name, val, nelem); break; } case DATA_TYPE_INT64_ARRAY: { int64_t *val; (void) nvpair_value_int64_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " %lld", (longlong_t)val[i]); + ARENDER(pctl, int64_array, nvl, name, val, nelem); break; } case DATA_TYPE_UINT64_ARRAY: { uint64_t *val; (void) nvpair_value_uint64_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " 0x%llx", - (u_longlong_t)val[i]); + ARENDER(pctl, uint64_array, nvl, name, val, nelem); break; } case DATA_TYPE_STRING_ARRAY: { char **val; (void) nvpair_value_string_array(nvp, &val, &nelem); - for (i = 0; i < nelem; i++) - (void) fprintf(fp, " %s", val[i]); + ARENDER(pctl, string_array, nvl, name, val, nelem); break; } case DATA_TYPE_HRTIME: { hrtime_t val; (void) nvpair_value_hrtime(nvp, &val); - (void) fprintf(fp, " 0x%llx", val); + RENDER(pctl, hrtime, nvl, name, val); break; } case DATA_TYPE_NVLIST: { nvlist_t *val; (void) nvpair_value_nvlist(nvp, &val); - (void) fprintf(fp, " (embedded nvlist)\n"); - nvlist_print_with_indent(fp, val, depth + 1); - indent(fp, depth + 1); - (void) fprintf(fp, "(end %s)\n", name); + RENDER(pctl, nvlist, nvl, name, val); break; } case DATA_TYPE_NVLIST_ARRAY: { nvlist_t **val; (void) nvpair_value_nvlist_array(nvp, &val, &nelem); - (void) fprintf(fp, " (array of embedded nvlists)\n"); - for (i = 0; i < nelem; i++) { - indent(fp, depth + 1); - (void) fprintf(fp, - "(start %s[%d])\n", name, i); - nvlist_print_with_indent(fp, val[i], depth + 1); - indent(fp, depth + 1); - (void) fprintf(fp, "(end %s[%d])\n", name, i); - } + ARENDER(pctl, nvlist_array, nvl, name, val, nelem); break; } default: (void) fprintf(fp, " unknown data type (%d)", type); break; } - (void) fprintf(fp, "\n"); nvp = nvlist_next_nvpair(nvl, nvp); } } @@ -268,9 +754,17 @@ void nvlist_print(FILE *fp, nvlist_t *nvl) { - nvlist_print_with_indent(fp, nvl, 0); + struct nvlist_prtctl pc; + + prtctl_defaults(fp, &pc, NULL); + nvlist_print_with_indent(nvl, &pc); } +void +nvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl) +{ + nvlist_print_with_indent(nvl, pctl); +} #define NVP(elem, type, vtype, ptype, format) { \ vtype value; \ @@ -422,6 +916,14 @@ } /* + * ====================================================================== + * | | + * | Misc private interface. | + * | | + * ====================================================================== + */ + +/* * Determine if string 'value' matches 'nvp' value. The 'value' string is * converted, depending on the type of 'nvp', prior to match. For numeric * types, a radix independent sscanf conversion of 'value' is used. If 'nvp' diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libnvpair/libnvpair.h --- a/usr/src/lib/libnvpair/libnvpair.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libnvpair/libnvpair.h Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LIBNVPAIR_H @@ -35,10 +34,158 @@ extern "C" { #endif -void nvlist_print(FILE *, nvlist_t *); -int nvpair_value_match(nvpair_t *, int, char *, char **); -int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *, char **); -void dump_nvlist(nvlist_t *, int); +/* + * All interfaces described in this file are private to Solaris, and + * are subject to change at any time and without notice. The public + * nvlist/nvpair interfaces, as documented in manpage sections 3NVPAIR, + * are all imported from included above. + */ + +extern int nvpair_value_match(nvpair_t *, int, char *, char **); +extern int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *, + char **); + +extern void nvlist_print(FILE *, nvlist_t *); +extern void dump_nvlist(nvlist_t *, int); + +/* + * Private nvlist printing interface that allows the caller some control + * over output rendering (as opposed to nvlist_print and dump_nvlist). + * + * Obtain an opaque nvlist_prtctl_t cookie using nvlist_prtctl_alloc + * (NULL on failure); on return the cookie is set up for default formatting + * and rendering. Quote the cookie in subsequent customisation functions and + * then pass the cookie to nvlist_prt to render the nvlist. Finally, + * use nvlist_prtctl_free to release the cookie. + * + * For all nvlist_lookup_xxx and nvlist_lookup_xxx_array functions + * we have a corresponding brace of functions that appoint replacement + * rendering functions: + * + * extern void nvlist_prtctl_xxx(nvlist_prtctl_t, + * void (*)(nvlist_prtctl_t ctl, void *private, const char *name, + * xxxtype value)) + * + * and + * + * extern void nvlist_prtctl_xxx_array(nvlist_prtctl_t, + * void (*)(nvlist_prtctl_t ctl, void *private, const char *name, + * xxxtype value, uint_t count)) + * + * where xxxtype is the C datatype corresponding to xxx, eg int8_t for "int8" + * and char * for "string". The function that is appointed to render the + * specified datatype receives as arguments the cookie, the nvlist + * member name, the value of that member (or a pointer for array function), + * and (for array rendering functions) a count of the number of elements. + */ + +typedef struct nvlist_prtctl *nvlist_prtctl_t; /* opaque */ + +enum nvlist_indent_mode { + NVLIST_INDENT_ABS, /* Absolute indentation */ + NVLIST_INDENT_TABBED /* Indent with tabstops */ +}; + +extern nvlist_prtctl_t nvlist_prtctl_alloc(void); +extern void nvlist_prtctl_free(nvlist_prtctl_t); +extern void nvlist_prt(nvlist_t *, nvlist_prtctl_t); + +/* Output stream */ +extern void nvlist_prtctl_setdest(nvlist_prtctl_t, FILE *); +extern FILE *nvlist_prtctl_getdest(nvlist_prtctl_t); + +/* Indentation mode, start indent, indent increment; default tabbed/0/1 */ +extern void nvlist_prtctl_setindent(nvlist_prtctl_t, enum nvlist_indent_mode, + int, int); +extern void nvlist_prtctl_doindent(nvlist_prtctl_t, int); + +enum nvlist_prtctl_fmt { + NVLIST_FMT_MEMBER_NAME, /* name fmt; default "%s = " */ + NVLIST_FMT_MEMBER_POSTAMBLE, /* after nvlist member; default "\n" */ + NVLIST_FMT_BTWN_ARRAY /* between array members; default " " */ +}; + +extern void nvlist_prtctl_setfmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt, + const char *); +extern void nvlist_prtctl_dofmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt, ...); + +/* + * Function prototypes for interfaces that appoint a new rendering function + * for single-valued nvlist members. + * + * A replacement function receives arguments as follows: + * + * nvlist_prtctl_t Print control structure; do not change preferences + * for this object from a print callback function. + * + * void * The function-private cookie argument registered + * when the replacement function was appointed. + * + * nvlist_t * The full nvlist that is being processed. The + * rendering function is called to render a single + * member (name and value passed as below) but it may + * want to reference or incorporate other aspects of + * the full nvlist. + * + * const char * Member name to render + * + * valtype Value of the member to render + * + * The function must return non-zero if it has rendered output for this + * member, or 0 if it wants to default to standard rendering for this + * one member. + */ + +#define NVLIST_PRINTCTL_SVDECL(funcname, valtype) \ + extern void funcname(nvlist_prtctl_t, \ + int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, valtype), \ + void *) + +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean, int); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean_value, boolean_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_byte, uchar_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int8, int8_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint8, uint8_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int16, int16_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint16, uint16_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int32, int32_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint32, uint32_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int64, int64_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint64, uint64_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_double, double); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_string, char *); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_hrtime, hrtime_t); +NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_nvlist, nvlist_t *); + +#undef NVLIST_PRINTCTL_SVDECL /* was just for "clarity" above */ + +/* + * Function prototypes for interfaces that appoint a new rendering function + * for array-valued nvlist members. + * + * One additional argument is taken: uint_t for the number of array elements + * + * Return values as above. + */ +#define NVLIST_PRINTCTL_AVDECL(funcname, vtype) \ + extern void funcname(nvlist_prtctl_t, \ + int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, uint_t), \ + void *) + +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_boolean_array, boolean_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_byte_array, uchar_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int8_array, int8_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint8_array, uint8_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int16_array, int16_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint16_array, uint16_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int32_array, int32_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint32_array, uint32_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int64_array, int64_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint64_array, uint64_t *); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_string_array, char **); +NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_nvlist_array, nvlist_t **); + +#undef NVLIST_PRINTCTL_AVDECL /* was just for "clarity" above */ #ifdef __cplusplus } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libnvpair/mapfile-vers --- a/usr/src/lib/libnvpair/mapfile-vers Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libnvpair/mapfile-vers Fri Jul 30 17:04:17 2010 +1000 @@ -43,6 +43,7 @@ nvlist_add_double; nvlist_empty; nvlist_lookup_double; + nvlist_nvflag; nvlist_prev_nvpair; nvlist_remove_nvpair; nvpair_value_double; @@ -174,6 +175,42 @@ nvlist_add_hrtime; nvlist_lookup_hrtime; nvlist_print; + nvlist_prt; + nvlist_prtctl_alloc; + nvlist_prtctl_free; + nvlist_prtctl_getdest; + nvlist_prtctl_dofmt; + nvlist_prtctl_doindent; + nvlist_prtctl_setdest; + nvlist_prtctl_setfmt; + nvlist_prtctl_setindent; + nvlist_prtctlop_byte; + nvlist_prtctlop_byte_array; + nvlist_prtctlop_boolean; + nvlist_prtctlop_boolean_array; + nvlist_prtctlop_boolean_value; + nvlist_prtctlop_double; + nvlist_prtctlop_hrtime; + nvlist_prtctlop_int8; + nvlist_prtctlop_int8_array; + nvlist_prtctlop_int16; + nvlist_prtctlop_int16_array; + nvlist_prtctlop_int32; + nvlist_prtctlop_int32_array; + nvlist_prtctlop_int64; + nvlist_prtctlop_int64_array; + nvlist_prtctlop_nvlist; + nvlist_prtctlop_nvlist_array; + nvlist_prtctlop_string; + nvlist_prtctlop_string_array; + nvlist_prtctlop_uint8; + nvlist_prtctlop_uint8_array; + nvlist_prtctlop_uint16; + nvlist_prtctlop_uint16_array; + nvlist_prtctlop_uint32; + nvlist_prtctlop_uint32_array; + nvlist_prtctlop_uint64; + nvlist_prtctlop_uint64_array; nvpair_value_hrtime; nvpair_type_is_array; nvlist_lookup_nvpair_embedded_index; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/librestart/common/librestart.c --- a/usr/src/lib/librestart/common/librestart.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/librestart/common/librestart.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,10 +20,10 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ +#include #include #include #include @@ -108,6 +108,334 @@ }; /* + * Long reasons must all parse/read correctly in the following contexts: + * + * "A service instance transitioned state: %s." + * "A service failed: %s." + * "Reason: %s." + * "The service transitioned state (%s) and ..." + * + * With the exception of restart_str_none they must also fit the following + * moulds: + * + * "An instance transitioned because %s, and ..." + * "An instance transitioned to because %s, and ..." + * + * Note that whoever is rendering the long message must provide the + * terminal punctuation - don't include it here. Similarly, do not + * provide an initial capital letter in reason-long. + * + * The long reason strings are Volatile - within the grammatical constraints + * above we may improve them as need be. The intention is that a consumer + * may blindly render the string along the lines of the above examples, + * but has no other guarantees as to the exact wording. Long reasons + * are localized. + * + * We define revisions of the set of short reason strings in use. Within + * a given revision, all short reasons are Committed. Consumers must check + * the revision in use before relying on the semantics of the short reason + * codes - if the version exceeds that which they are familiar with they should + * fail gracefully. Having checked for version compatability, a consumer + * is assured that + * + * "short_reason_A iff semantic_A", provided: + * + * . the restarter uses this short reason code at all, + * . the short reason is not "none" (which a restarter could + * specifiy for any transition semantics) + * + * To split/refine such a Committed semantic_A into further cases, + * we are required to bump the revision number. This should be an + * infrequent occurence. If you bump the revision number you may + * need to make corresponding changes in any source that calls + * restarter_str_version (e.g., FMA event generation). + * + * To add additional reasons to the set you must also bump the version + * number. + */ + +/* + * The following describes revision 0 of the set of transition reasons. + * Read the preceding block comment before making any changes. + */ +static const struct restarter_state_transition_reason restarter_str[] = { + /* + * Any transition for which the restarter has not provided a reason. + */ + { + restarter_str_none, + "none", + "the restarter gave no reason" + }, + + /* + * A transition to maintenance state due to a + * 'svcadm mark maintenance '. *Not* used if the libscf + * interface smf_maintain_instance(3SCF) is used to request maintenance. + */ + { + restarter_str_administrative_request, + "administrative_request", + "maintenance was requested by an administrator" + }, + + /* + * A transition to maintenance state if a repository inconsistency + * exists when the service/instance state is first read by startd + * into the graph engine (this can also happen during startd restart). + */ + { + restarter_str_bad_repo_state, + "bad_repo_state", + "an SMF repository inconsistecy exists" + }, + + /* + * A transition 'maintenance -> uninitialized' resulting always + * from 'svcadm clear '. *Not* used if the libscf interface + * smf_restore_instance(3SCF) is used. + */ + { + restarter_str_clear_request, + "clear_request", + "maintenance clear was requested by an administrator" + }, + + /* + * A transition 'online -> offline' due to a process core dump. + */ + { + restarter_str_ct_ev_core, + "ct_ev_core", + "a process dumped core" + }, + + /* + * A transition 'online -> offline' due to an empty process contract, + * i.e., the last process in a contract type service has exited. + */ + { + restarter_str_ct_ev_exit, + "ct_ev_exit", + "all processes in the service have exited" + }, + + /* + * A transition 'online -> offline' due to a hardware error. + */ + { + restarter_str_ct_ev_hwerr, + "ct_ev_hwerr", + "a process was killed due to uncorrectable hardware error" + }, + + /* + * A transition 'online -> offline' due to a process in the service + * having received a fatal signal originating from outside the + * service process contract. + */ + { + restarter_str_ct_ev_signal, + "ct_ev_signal", + "a process received a fatal signal from outside the service" + }, + + /* + * A transition 'offline -> online' when all dependencies for the + * service have been met. + */ + { + restarter_str_dependencies_satisfied, + "dependencies_satisfied", + "all dependencies have been satisfied" + }, + + /* + * A transition 'online -> offline' because some dependency for the + * service is no-longer met. + */ + { + restarter_str_dependency_activity, + "dependency_activity", + "a dependency activity required a stop" + }, + + /* + * A transition to maintenance state due to a cycle in the + * service dependencies. + */ + { + restarter_str_dependency_cycle, + "dependency_cycle", + "a dependency cycle exists" + }, + + /* + * A transition 'online -> offline -> disabled' due to a + * 'svcadm disable [-t] ' or smf_disable_instance(3SCF) call. + */ + { + restarter_str_disable_request, + "disable_request", + "a disable was requested" + }, + + /* + * A transition 'disabled -> offline' due to a + * 'svcadm enable [-t] ' or smf_enable_instance(3SCF) call. + */ + { + restarter_str_enable_request, + "enable_request", + "an enable was requested" + }, + + /* + * A transition to maintenance state when a method fails + * repeatedly for a retryable reason. + */ + { + restarter_str_fault_threshold_reached, + "fault_threshold_reached", + "a method is failing in a retryable manner but too often" + }, + + /* + * A transition to uninitialized state when startd reads the service + * configuration and inserts it into the graph engine. + */ + { + restarter_str_insert_in_graph, + "insert_in_graph", + "the instance was inserted in the graph" + }, + + /* + * A transition to maintenance state due to an invalid dependency + * declared for the service. + */ + { + restarter_str_invalid_dependency, + "invalid_dependency", + "a service has an invalid dependency" + }, + + /* + * A transition to maintenance state because the service-declared + * restarter is invalid. + */ + { + restarter_str_invalid_restarter, + "invalid_restarter", + "the service restarter is invalid" + }, + + /* + * A transition to maintenance state because a restarter method + * exited with one of SMF_EXIT_ERR_CONFIG, SMF_EXIT_ERR_NOSMF, + * SMF_EXIT_ERR_PERM, or SMF_EXIT_ERR_FATAL. + */ + { + restarter_str_method_failed, + "method_failed", + "a start, stop or refresh method failed" + }, + + /* + * A transition 'uninitialized -> {disabled|offline}' after + * "insert_in_graph" to match the state configured in the + * repository. + */ + { + restarter_str_per_configuration, + "per_configuration", + "the SMF repository configuration specifies this state" + }, + + /* + * Refresh requested - no state change. + */ + { + restarter_str_refresh, + NULL, + "a refresh was requested (no change of state)" + }, + + /* + * A transition 'online -> offline -> online' due to a + * 'svcadm restart or equivlaent libscf API call. + * Both the 'online -> offline' and 'offline -> online' transtions + * specify this reason. + */ + { + restarter_str_restart_request, + "restart_request", + "a restart was requested" + }, + + /* + * A transition to maintenance state because the start method is + * being executed successfully but too frequently. + */ + { + restarter_str_restarting_too_quickly, + "restarting_too_quickly", + "the instance is restarting too quickly" + }, + + /* + * A transition to maintenance state due a service requesting + * 'svcadm mark maintenance ' or equivalent libscf API call. + * A command line 'svcadm mark maintenance ' does not produce + * this reason - it produces administrative_request instead. + */ + { + restarter_str_service_request, + "service_request", + "maintenance was requested by another service" + }, + + /* + * An instanced inserted into the graph at its existing state + * during a startd restart - no state change. + */ + { + restarter_str_startd_restart, + NULL, + "the instance was inserted in the graph due to startd restart" + } +}; + +uint32_t +restarter_str_version(void) +{ + return (RESTARTER_STRING_VERSION); +} + +const char * +restarter_get_str_short(restarter_str_t key) +{ + int i; + for (i = 0; i < sizeof (restarter_str) / + sizeof (struct restarter_state_transition_reason); i++) + if (key == restarter_str[i].str_key) + return (restarter_str[i].str_short); + return (NULL); +} + +const char * +restarter_get_str_long(restarter_str_t key) +{ + int i; + for (i = 0; i < sizeof (restarter_str) / + sizeof (struct restarter_state_transition_reason); i++) + if (key == restarter_str[i].str_key) + return (dgettext(TEXT_DOMAIN, + restarter_str[i].str_long)); + return (NULL); +} + +/* * A static no memory error message mc_error_t structure * to be used in cases when memory errors are to be returned * This avoids the need to attempt to allocate memory for the @@ -495,8 +823,6 @@ * Commit the state, next state, and auxiliary state into the repository. * Let the graph engine know about the state change and error. On success, * return 0. On error, return - * EINVAL - aux has spaces - * - inst is invalid or not an instance FMRI * EPROTO - librestart compiled against different libscf * ENOMEM - out of memory * - repository server out of resources @@ -517,27 +843,18 @@ restarter_instance_state_t new_cur_state, restarter_instance_state_t next_state, restarter_instance_state_t new_next_state, restarter_error_t e, - const char *aux) + restarter_str_t aux) { nvlist_t *attr; scf_handle_t *scf_h; instance_data_t id; int ret = 0; - char *p = (char *)aux; + const char *p = restarter_get_str_short(aux); assert(h->reh_master_channel != NULL); assert(h->reh_master_channel_name != NULL); assert(h->reh_master_subscriber_id != NULL); - /* Validate format of auxiliary state: no spaces allowed */ - if (p != NULL) { - while (*p != '\0') { - if (isspace(*p)) - return (EINVAL); - p++; - } - } - if ((scf_h = scf_handle_create(SCF_VERSION)) == NULL) { switch (scf_error()) { case SCF_ERROR_VERSION_MISMATCH: @@ -572,7 +889,8 @@ nvlist_add_int32(attr, RESTARTER_NAME_NEXT_STATE, new_next_state) != 0 || nvlist_add_int32(attr, RESTARTER_NAME_ERROR, e) != 0 || - nvlist_add_string(attr, RESTARTER_NAME_INSTANCE, inst) != 0) { + nvlist_add_string(attr, RESTARTER_NAME_INSTANCE, inst) != 0 || + nvlist_add_int32(attr, RESTARTER_NAME_REASON, aux) != 0) { ret = ENOMEM; } else { id.i_fmri = inst; @@ -580,7 +898,7 @@ id.i_next_state = next_state; ret = _restarter_commit_states(scf_h, &id, new_cur_state, - new_next_state, aux); + new_next_state, p); if (ret == 0) { ret = restarter_event_publish_retry( diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/librestart/common/librestart.h --- a/usr/src/lib/librestart/common/librestart.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/librestart/common/librestart.h Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LIBRESTART_H @@ -74,7 +73,7 @@ * protocol. In practice, increment RESTARTER_EVENT_VERSION whenever the * protocol might have changed. */ -#define RESTARTER_EVENT_VERSION 4 +#define RESTARTER_EVENT_VERSION 5 #define RESTARTER_FLAG_DEBUG 1 @@ -192,6 +191,43 @@ restarter_instance_state_t *, restarter_instance_state_t *); /* + * State transition reasons + */ + +typedef enum { + restarter_str_none, + restarter_str_administrative_request, + restarter_str_bad_repo_state, + restarter_str_clear_request, + restarter_str_ct_ev_core, + restarter_str_ct_ev_exit, + restarter_str_ct_ev_hwerr, + restarter_str_ct_ev_signal, + restarter_str_dependencies_satisfied, + restarter_str_dependency_activity, + restarter_str_dependency_cycle, + restarter_str_disable_request, + restarter_str_enable_request, + restarter_str_fault_threshold_reached, + restarter_str_insert_in_graph, + restarter_str_invalid_dependency, + restarter_str_invalid_restarter, + restarter_str_method_failed, + restarter_str_per_configuration, + restarter_str_refresh, + restarter_str_restart_request, + restarter_str_restarting_too_quickly, + restarter_str_service_request, + restarter_str_startd_restart +} restarter_str_t; + +struct restarter_state_transition_reason { + restarter_str_t str_key; + const char *str_short; + const char *str_long; +}; + +/* * Functions for updating the repository. */ @@ -207,10 +243,20 @@ int restarter_set_states(restarter_event_handle_t *, const char *, restarter_instance_state_t, restarter_instance_state_t, restarter_instance_state_t, restarter_instance_state_t, restarter_error_t, - const char *); + restarter_str_t); int restarter_event_publish_retry(evchan_t *, const char *, const char *, const char *, const char *, nvlist_t *, uint32_t); +/* + * functions for retrieving the state transition reason messages + */ + +#define RESTARTER_STRING_VERSION 1 + +uint32_t restarter_str_version(void); +const char *restarter_get_str_short(restarter_str_t); +const char *restarter_get_str_long(restarter_str_t); + int restarter_store_contract(scf_instance_t *, ctid_t, restarter_contract_type_t); int restarter_remove_contract(scf_instance_t *, ctid_t, diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/librestart/common/librestart_priv.h --- a/usr/src/lib/librestart/common/librestart_priv.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/librestart/common/librestart_priv.h Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LIBRESTART_PRIV_H #define _LIBRESTART_PRIV_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include @@ -42,6 +38,7 @@ #define RESTARTER_NAME_NEXT_STATE SCF_PROPERTY_NEXT_STATE #define RESTARTER_NAME_AUX_STATE SCF_PROPERTY_AUX_STATE #define RESTARTER_NAME_ERROR "error" +#define RESTARTER_NAME_REASON "reason" #define RESTARTER_CHANNEL_MASTER 0 #define RESTARTER_CHANNEL_DELEGATE 1 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/librestart/common/mapfile-vers --- a/usr/src/lib/librestart/common/mapfile-vers Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/librestart/common/mapfile-vers Fri Jul 30 17:04:17 2010 +1000 @@ -63,12 +63,15 @@ restarter_state_to_string; restarter_store_contract; restarter_string_to_state; + restarter_str_version; restarter_inst_validate_ractions_aux_fmri; restarter_inst_ractions_from_tty; restarter_inst_reset_ractions_aux_fmri; restarter_inst_reset_aux_fmri; restarter_inst_set_aux_fmri; restarter_mc_error_destroy; + restarter_get_str_short; + restarter_get_str_long; local: *; }; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libscf/Makefile.com --- a/usr/src/lib/libscf/Makefile.com Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libscf/Makefile.com Fri Jul 30 17:04:17 2010 +1000 @@ -29,6 +29,7 @@ error.o \ lowlevel.o \ midlevel.o \ + notify_params.o \ highlevel.o \ scf_tmpl.o \ scf_type.o @@ -43,7 +44,7 @@ $(NATIVE_BUILD)LIBS = $(DYNLIB) LDLIBS_i386 += -lsmbios -LDLIBS += -luutil -lc -lgen -lnsl +LDLIBS += -luutil -lc -lgen -lnsl -lnvpair LDLIBS += $(LDLIBS_$(MACH)) SRCDIR = ../common @@ -64,7 +65,7 @@ -DNATIVE_BUILD $(DTEXTDOM) \ -I../inc -I$(COMDIR) -I$(LIBUUTIL)/common -I$(ROOTHDRDIR) MY_NATIVE_LDLIBS = -L$(LIBUUTIL)/native -R$(LIBUUTIL)/native -luutil -lc -lgen \ - -lnsl + -lnsl -lnvpair MY_NATIVE_LDLIBS_i386 = -lsmbios MY_NATIVE_LDLIBS += $(MY_NATIVE_LDLIBS_$(MACH)) diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libscf/common/libscf_impl.h --- a/usr/src/lib/libscf/common/libscf_impl.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libscf/common/libscf_impl.h Fri Jul 30 17:04:17 2010 +1000 @@ -20,15 +20,12 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LIBSCF_IMPL_H #define _LIBSCF_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include @@ -58,7 +55,10 @@ SCF_MSG_PATTERN_LEGACY } scf_msg_t; +scf_type_t scf_true_base_type(scf_type_t); const char *scf_get_msg(scf_msg_t); +int ismember(const scf_error_t, const scf_error_t[]); +int32_t state_from_string(const char *, size_t); #ifdef __cplusplus } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libscf/common/lowlevel.c --- a/usr/src/lib/libscf/common/lowlevel.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libscf/common/lowlevel.c Fri Jul 30 17:04:17 2010 +1000 @@ -793,6 +793,38 @@ return (ret); } +/* + * Fails with + * _NO_MEMORY + * _NO_SERVER - server door could not be open()ed + * door call failed + * door_info() failed + * _VERSION_MISMATCH - server returned bad file descriptor + * server claimed bad request + * server reported version mismatch + * server refused with unknown reason + * _INVALID_ARGUMENT + * _NO_RESOURCES - server is out of memory + * _PERMISSION_DENIED + * _INTERNAL - could not set up entities or iters + * server response too big + */ +scf_handle_t * +_scf_handle_create_and_bind(scf_version_t ver) +{ + scf_handle_t *h; + + h = scf_handle_create(ver); + if (h == NULL) + return (NULL); + + if (scf_handle_bind(h) == -1) { + scf_handle_destroy(h); + return (NULL); + } + return (h); +} + int scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v) { @@ -4073,6 +4105,9 @@ void scf_transaction_destroy_children(scf_transaction_t *tran) { + if (tran == NULL) + return; + scf_transaction_reset_impl(tran, 1, 0); } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libscf/common/mapfile-vers --- a/usr/src/lib/libscf/common/mapfile-vers Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libscf/common/mapfile-vers Fri Jul 30 17:04:17 2010 +1000 @@ -92,6 +92,11 @@ scf_tmpl_visibility_to_string; scf_type_to_string; scf_values_destroy; + smf_notify_del_params; + smf_notify_get_params; + smf_notify_set_params; + smf_state_from_string; + smf_state_to_string; } SUNW_1.1; SYMBOL_VERSION SUNW_1.1 { @@ -275,16 +280,20 @@ SYMBOL_VERSION SUNWprivate_1.1 { global: gen_filenms_from_fmri; + ismember; scf_canonify_fmri; scf_cmp_pattern; _scf_create_errors; scf_decode32; scf_encode32; scf_general_pg_setup; + _scf_get_fma_notify_params; + _scf_get_svc_notify_params; _scf_handle_decorations; scf_is_compatible_type; _scf_notify_add_pgname; _scf_notify_add_pgtype; + _scf_notify_get_params; _scf_notify_wait; scf_parse_file_fmri; scf_parse_fmri; @@ -320,6 +329,8 @@ scf_is_fastboot_default; scf_fastreboot_default_set_transient; _check_services; + _scf_handle_create_and_bind; + _smf_refresh_all_instances; local: *; }; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libscf/common/midlevel.c --- a/usr/src/lib/libscf/common/midlevel.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libscf/common/midlevel.c Fri Jul 30 17:04:17 2010 +1000 @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -51,25 +50,6 @@ /* Path to speedy files area must end with a slash */ #define SMF_SPEEDY_FILES_PATH "/etc/svc/volatile/" -/* - * Internal private function that creates and binds a handle. - */ -static scf_handle_t * -handle_create(void) -{ - scf_handle_t *h; - - h = scf_handle_create(SCF_VERSION); - if (h == NULL) - return (NULL); - - if (scf_handle_bind(h) == -1) { - scf_handle_destroy(h); - return (NULL); - } - return (h); -} - void scf_simple_handle_destroy(scf_simple_handle_t *simple_h) { @@ -939,7 +919,7 @@ scf_instance_t *inst; int ret = -1; - h = handle_create(); + h = _scf_handle_create_and_bind(SCF_VERSION); if (h == NULL) return (-1); @@ -1082,7 +1062,7 @@ return (ret); } - if ((h = handle_create()) == NULL) + if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL) return (ret); if ((inst = scf_instance_create(h)) == NULL) { @@ -1184,6 +1164,35 @@ } int +_smf_refresh_all_instances(scf_service_t *s) +{ + scf_handle_t *h = scf_service_handle(s); + scf_instance_t *i = scf_instance_create(h); + scf_iter_t *it = scf_iter_create(h); + int err, r = -1; + + if (h == NULL || i == NULL || it == NULL) + goto error; + + if (scf_iter_service_instances(it, s) != 0) + goto error; + + while ((err = scf_iter_next_instance(it, i)) == 1) + if (_smf_refresh_instance_i(i) != 0) + goto error; + + if (err == -1) + goto error; + + r = 0; +error: + scf_instance_destroy(i); + scf_iter_destroy(it); + + return (r); +} + +int smf_refresh_instance(const char *instance) { return (set_inst_action(instance, SCF_PROPERTY_REFRESH)); @@ -1320,7 +1329,7 @@ return (NULL); } else { - ret->h = handle_create(); + ret->h = _scf_handle_create_and_bind(SCF_VERSION); ret->inst = scf_instance_create(ret->h); ret->snap = scf_snapshot_create(ret->h); ret->running_pg = scf_pg_create(ret->h); @@ -1564,7 +1573,7 @@ int svc_iter_ret, inst_iter_ret; int inst_state; - if ((h = handle_create()) == NULL) + if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL) return (ret); if (((scope = scf_scope_create(h)) == NULL) || @@ -1654,7 +1663,7 @@ local_h = B_FALSE; } - if (local_h && ((h = handle_create()) == NULL)) + if (local_h && ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)) return (NULL); if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) { @@ -1795,7 +1804,7 @@ local_h = B_FALSE; } - if (local_h && ((h = handle_create()) == NULL)) + if (local_h && ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)) return (NULL); if (inst_fmri == NULL) { @@ -2495,7 +2504,7 @@ return (0); } -static scf_type_t +scf_type_t scf_true_base_type(scf_type_t type) { scf_type_t base = type; @@ -2576,7 +2585,7 @@ scf_read_propvec(const char *fmri, const char *pgname, boolean_t running, scf_propvec_t *properties, scf_propvec_t **badprop) { - scf_handle_t *h = handle_create(); + scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); scf_service_t *s = scf_service_create(h); scf_instance_t *i = scf_instance_create(h); scf_snapshot_t *snap = running ? scf_snapshot_create(h) : NULL; @@ -2742,7 +2751,7 @@ scf_write_propvec(const char *fmri, const char *pgname, scf_propvec_t *properties, scf_propvec_t **badprop) { - scf_handle_t *h = handle_create(); + scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); scf_service_t *s = scf_service_create(h); scf_instance_t *inst = scf_instance_create(h); scf_snapshot_t *snap = scf_snapshot_create(h); @@ -3052,3 +3061,86 @@ } } } + +/*ARGSUSED*/ +static int +str_compare(const char *s1, const char *s2, size_t n) +{ + return (strcmp(s1, s2)); +} + +static int +str_n_compare(const char *s1, const char *s2, size_t n) +{ + return (strncmp(s1, s2, n)); +} + +int32_t +state_from_string(const char *state, size_t l) +{ + int (*str_cmp)(const char *, const char *, size_t); + + if (l == 0) + str_cmp = str_compare; + else + str_cmp = str_n_compare; + + if (str_cmp(SCF_STATE_STRING_UNINIT, state, l) == 0) + return (SCF_STATE_UNINIT); + else if (str_cmp(SCF_STATE_STRING_MAINT, state, l) == 0) + return (SCF_STATE_MAINT); + else if (str_cmp(SCF_STATE_STRING_OFFLINE, state, l) == 0) + return (SCF_STATE_OFFLINE); + else if (str_cmp(SCF_STATE_STRING_DISABLED, state, l) == 0) + return (SCF_STATE_DISABLED); + else if (str_cmp(SCF_STATE_STRING_ONLINE, state, l) == 0) + return (SCF_STATE_ONLINE); + else if (str_cmp(SCF_STATE_STRING_DEGRADED, state, l) == 0) + return (SCF_STATE_DEGRADED); + else if (str_cmp("all", state, l) == 0) + return (SCF_STATE_ALL); + else + return (-1); +} + +/* + * int32_t smf_state_from_string() + * return the value of the macro SCF_STATE_* for the corresponding state + * it returns SCF_STATE_ALL if "all" is passed. -1 if the string passed doesn't + * correspond to any valid state. + */ +int32_t +smf_state_from_string(const char *state) +{ + return (state_from_string(state, 0)); +} + +/* + * smf_state_to_string() + * Takes an int32_t representing an SMF state and returns + * the corresponding string. The string is read only and need not to be + * freed. + * returns NULL on invalid input. + */ +const char * +smf_state_to_string(int32_t s) +{ + switch (s) { + case SCF_STATE_UNINIT: + return (SCF_STATE_STRING_UNINIT); + case SCF_STATE_MAINT: + return (SCF_STATE_STRING_MAINT); + case SCF_STATE_OFFLINE: + return (SCF_STATE_STRING_OFFLINE); + case SCF_STATE_DISABLED: + return (SCF_STATE_STRING_DISABLED); + case SCF_STATE_ONLINE: + return (SCF_STATE_STRING_ONLINE); + case SCF_STATE_DEGRADED: + return (SCF_STATE_STRING_DEGRADED); + case SCF_STATE_ALL: + return ("all"); + default: + return (NULL); + } +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libscf/common/notify_params.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libscf/common/notify_params.c Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,1979 @@ +/* + * 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 "libscf_impl.h" + +#include +#include + +/* + * Errors returned by smf_notify_{del|get|set}_params() + */ +static const scf_error_t errs_1[] = { + SCF_ERROR_BACKEND_ACCESS, + SCF_ERROR_BACKEND_READONLY, + SCF_ERROR_CONNECTION_BROKEN, + SCF_ERROR_DELETED, + SCF_ERROR_INTERNAL, + SCF_ERROR_INVALID_ARGUMENT, + SCF_ERROR_NO_MEMORY, + SCF_ERROR_NO_RESOURCES, + SCF_ERROR_NOT_FOUND, + SCF_ERROR_PERMISSION_DENIED, + 0 +}; + +/* + * Errors returned by smf_notify_{del|get|set}_params() + * Except SCF_ERROR_INVALID_ARGUMENT + */ +static const scf_error_t errs_2[] = { + SCF_ERROR_BACKEND_ACCESS, + SCF_ERROR_BACKEND_READONLY, + SCF_ERROR_CONNECTION_BROKEN, + SCF_ERROR_DELETED, + SCF_ERROR_INTERNAL, + SCF_ERROR_NO_MEMORY, + SCF_ERROR_NO_RESOURCES, + SCF_ERROR_NOT_FOUND, + SCF_ERROR_PERMISSION_DENIED, + 0 +}; + +/* + * Helper function that abort() on unexpected errors. + * The expected error set is a zero-terminated array of scf_error_t + */ +static int +check_scf_error(scf_error_t e, const scf_error_t *errs) +{ + if (ismember(e, errs)) + return (1); + + assert(0); + abort(); + + /*NOTREACHED*/ +} + +/* + * Mapping of state transition to pgname. + */ +static struct st_pgname { + const char *st_pgname; + int32_t st_state; +} st_pgnames[] = { + { "to-uninitialized", SCF_TRANS(0, SCF_STATE_UNINIT) }, + { "from-uninitialized", SCF_TRANS(SCF_STATE_UNINIT, 0) }, + { "to-maintenance", SCF_TRANS(0, SCF_STATE_MAINT) }, + { "from-maintenance", SCF_TRANS(SCF_STATE_MAINT, 0) }, + { "to-offline", SCF_TRANS(0, SCF_STATE_OFFLINE) }, + { "from-offline", SCF_TRANS(SCF_STATE_OFFLINE, 0) }, + { "to-disabled", SCF_TRANS(0, SCF_STATE_DISABLED) }, + { "from-disabled", SCF_TRANS(SCF_STATE_DISABLED, 0) }, + { "to-online", SCF_TRANS(0, SCF_STATE_ONLINE) }, + { "from-online", SCF_TRANS(SCF_STATE_ONLINE, 0) }, + { "to-degraded", SCF_TRANS(0, SCF_STATE_DEGRADED) }, + { "from-degraded", SCF_TRANS(SCF_STATE_DEGRADED, 0) }, + { NULL, 0 } +}; + +/* + * Check if class matches or is a subclass of SCF_SVC_TRANSITION_CLASS + * + * returns 1, otherwise return 0 + */ +static boolean_t +is_svc_stn(const char *class) +{ + int n = strlen(SCF_SVC_TRANSITION_CLASS); + + if (class && strncmp(class, SCF_SVC_TRANSITION_CLASS, n) == 0) + if (class[n] == '\0' || class[n] == '.') + return (1); + return (0); +} + +/* + * Return the len of the base class. For instance, "class.class1.class2.*" + * will return the length of "class.class1.class2" + * This function does not check if the class or base class is valid. + * A class such as "class.class1....****" is not valid but will return the + * length of "class.class1....***" + */ +static size_t +base_class_len(const char *c) +{ + const char *p; + size_t n; + + if ((n = strlen(c)) == 0) + return (0); + + p = c + n; + + /* get rid of any trailing asterisk */ + if (*--p == '*') + n--; + + /* make sure the class doesn't end in '.' */ + while (p >= c && *--p == '.') + n--; + + return (n); +} + +/* + * Allocates and builds the pgname for an FMA dotted class. + * The pgname will be of the form "class.class1.class2,SCF_NOTIFY_PG_POSTFIX" + * + * NULL on error + */ +static char * +class_to_pgname(const char *class) +{ + size_t n; + ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; + char *pgname = NULL; + + n = base_class_len(class); + + if (n == 0) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + return (NULL); + } + + if ((pgname = malloc(sz)) == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto error; + } + + if (snprintf(pgname, sz, "%.*s,%s", (int)n, class, + SCF_NOTIFY_PG_POSTFIX) >= sz) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto error; + } + return (pgname); + +error: + free(pgname); + pgname = NULL; + + return (pgname); +} + +/* + * Get the pg from the running snapshot of the instance (composed or not) + */ +static int +get_pg(scf_service_t *s, scf_instance_t *i, const char *n, + scf_propertygroup_t *pg, int composed) +{ + scf_handle_t *h = scf_instance_handle(i); + scf_error_t scf_e = scf_error(); + scf_snapshot_t *snap = scf_snapshot_create(h); + scf_snaplevel_t *slvl = scf_snaplevel_create(h); + int r = -1; + + if (h == NULL) { + /* + * Use the error stored in scf_e + */ + (void) scf_set_error(scf_e); + goto out; + } + if (s == NULL) { + if (snap == NULL || slvl == NULL) + goto out; + if (scf_instance_get_snapshot(i, "running", snap) != 0) + goto out; + + if (composed) { + if (scf_instance_get_pg_composed(i, snap, n, pg) != 0) + goto out; + } else { + if (scf_snapshot_get_base_snaplevel(snap, slvl) != 0 || + scf_snaplevel_get_pg(slvl, n, pg) != 0) + goto out; + } + } else { + if (scf_service_get_pg(s, n, pg) != 0) + goto out; + } + + r = 0; +out: + scf_snaplevel_destroy(slvl); + scf_snapshot_destroy(snap); + + return (r); +} + +/* + * Add a pg if it does not exist, or get it if it exists. + * It operates on the instance if the service parameter is NULL. + * + * returns 0 on success or -1 on failure + */ +static int +get_or_add_pg(scf_service_t *s, scf_instance_t *i, const char *n, const char *t, + uint32_t flags, scf_propertygroup_t *pg) +{ + int r; + + if (s == NULL) + r = scf_instance_add_pg(i, n, t, flags, pg); + else + r = scf_service_add_pg(s, n, t, flags, pg); + + if (r == 0) + return (0); + else if (scf_error() != SCF_ERROR_EXISTS) + return (-1); + + if (s == NULL) + r = scf_instance_get_pg(i, n, pg); + else + r = scf_service_get_pg(s, n, pg); + + return (r); +} + +/* + * Delete the property group form the instance or service. + * If service is NULL, use instance, otherwise use only the service. + * + * Return SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_BACKEND_READONLY + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_HANDLE_MISMATCH + * SCF_ERROR_INTERNAL + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_BOUND + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_NOT_SET + * SCF_ERROR_PERMISSION_DENIED + */ +static int +del_pg(scf_service_t *s, scf_instance_t *i, const char *n, + scf_propertygroup_t *pg) +{ + if ((s == NULL ? scf_instance_get_pg(i, n, pg) : + scf_service_get_pg(s, n, pg)) != SCF_SUCCESS) + if (scf_error() == SCF_ERROR_NOT_FOUND) + return (SCF_SUCCESS); + else + return (SCF_FAILED); + + if (scf_pg_delete(pg) != SCF_SUCCESS) + if (scf_error() == SCF_ERROR_DELETED) + return (SCF_SUCCESS); + else + return (SCF_FAILED); + + return (SCF_SUCCESS); +} + +static scf_type_t +get_scf_type(nvpair_t *p) +{ + switch (nvpair_type(p)) { + case DATA_TYPE_BOOLEAN: + case DATA_TYPE_BOOLEAN_VALUE: + case DATA_TYPE_BOOLEAN_ARRAY: + return (SCF_TYPE_BOOLEAN); + + case DATA_TYPE_BYTE: + case DATA_TYPE_UINT8: + case DATA_TYPE_UINT16: + case DATA_TYPE_UINT32: + case DATA_TYPE_UINT64: + case DATA_TYPE_BYTE_ARRAY: + case DATA_TYPE_UINT8_ARRAY: + case DATA_TYPE_UINT16_ARRAY: + case DATA_TYPE_UINT32_ARRAY: + case DATA_TYPE_UINT64_ARRAY: + return (SCF_TYPE_COUNT); + + case DATA_TYPE_INT8: + case DATA_TYPE_INT16: + case DATA_TYPE_INT32: + case DATA_TYPE_INT64: + case DATA_TYPE_INT8_ARRAY: + case DATA_TYPE_INT16_ARRAY: + case DATA_TYPE_INT32_ARRAY: + case DATA_TYPE_INT64_ARRAY: + return (SCF_TYPE_INTEGER); + + case DATA_TYPE_STRING: + case DATA_TYPE_STRING_ARRAY: + return (SCF_TYPE_ASTRING); + + default: + return (SCF_TYPE_INVALID); + } +} + +static int +add_entry(scf_transaction_entry_t *te, scf_value_t *val) +{ + if (scf_entry_add_value(te, val) != 0) { + scf_value_destroy(val); + return (SCF_FAILED); + } + + return (SCF_SUCCESS); +} + +static int +add_boolean_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint8_t v) +{ + scf_value_t *val = scf_value_create(h); + + if (val == NULL) + return (SCF_FAILED); + + scf_value_set_boolean(val, v); + + return (add_entry(te, val)); +} + +static int +add_count_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint64_t v) +{ + scf_value_t *val = scf_value_create(h); + + if (val == NULL) + return (SCF_FAILED); + + scf_value_set_count(val, v); + + return (add_entry(te, val)); +} + +static int +add_integer_entry(scf_handle_t *h, scf_transaction_entry_t *te, int64_t v) +{ + scf_value_t *val = scf_value_create(h); + + if (val == NULL) + return (SCF_FAILED); + + scf_value_set_integer(val, v); + + return (add_entry(te, val)); +} + +static int +add_astring_entry(scf_handle_t *h, scf_transaction_entry_t *te, char *s) +{ + scf_value_t *val = scf_value_create(h); + + if (val == NULL) + return (SCF_FAILED); + + if (scf_value_set_astring(val, s) != 0) { + scf_value_destroy(val); + return (SCF_FAILED); + } + + return (add_entry(te, val)); +} + +static int +get_nvpair_vals(scf_handle_t *h, scf_transaction_entry_t *te, nvpair_t *p) +{ + scf_value_t *val = scf_value_create(h); + uint_t n = 1; + int i; + + if (val == NULL) + return (SCF_FAILED); + + switch (nvpair_type(p)) { + case DATA_TYPE_BOOLEAN: + return (add_boolean_entry(h, te, 1)); + case DATA_TYPE_BOOLEAN_VALUE: + { + boolean_t v; + + (void) nvpair_value_boolean_value(p, &v); + return (add_boolean_entry(h, te, (uint8_t)v)); + } + case DATA_TYPE_BOOLEAN_ARRAY: + { + boolean_t *v; + + (void) nvpair_value_boolean_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_boolean_entry(h, te, (uint8_t)v[i]) != + SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_BYTE: + { + uchar_t v; + + (void) nvpair_value_byte(p, &v); + return (add_count_entry(h, te, v)); + } + case DATA_TYPE_UINT8: + { + uint8_t v; + + (void) nvpair_value_uint8(p, &v); + return (add_count_entry(h, te, v)); + } + case DATA_TYPE_UINT16: + { + uint16_t v; + + (void) nvpair_value_uint16(p, &v); + return (add_count_entry(h, te, v)); + } + case DATA_TYPE_UINT32: + { + uint32_t v; + + (void) nvpair_value_uint32(p, &v); + return (add_count_entry(h, te, v)); + } + case DATA_TYPE_UINT64: + { + uint64_t v; + + (void) nvpair_value_uint64(p, &v); + return (add_count_entry(h, te, v)); + } + case DATA_TYPE_BYTE_ARRAY: + { + uchar_t *v; + + (void) nvpair_value_byte_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_UINT8_ARRAY: + { + uint8_t *v; + + (void) nvpair_value_uint8_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_UINT16_ARRAY: + { + uint16_t *v; + + (void) nvpair_value_uint16_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_UINT32_ARRAY: + { + uint32_t *v; + + (void) nvpair_value_uint32_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_UINT64_ARRAY: + { + uint64_t *v; + + (void) nvpair_value_uint64_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_INT8: + { + int8_t v; + + (void) nvpair_value_int8(p, &v); + return (add_integer_entry(h, te, v)); + } + case DATA_TYPE_INT16: + { + int16_t v; + + (void) nvpair_value_int16(p, &v); + return (add_integer_entry(h, te, v)); + } + case DATA_TYPE_INT32: + { + int32_t v; + + (void) nvpair_value_int32(p, &v); + return (add_integer_entry(h, te, v)); + } + case DATA_TYPE_INT64: + { + int64_t v; + + (void) nvpair_value_int64(p, &v); + return (add_integer_entry(h, te, v)); + } + case DATA_TYPE_INT8_ARRAY: + { + int8_t *v; + + (void) nvpair_value_int8_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_integer_entry(h, te, v[i]) != + SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_INT16_ARRAY: + { + int16_t *v; + + (void) nvpair_value_int16_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_integer_entry(h, te, v[i]) != + SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_INT32_ARRAY: + { + int32_t *v; + + (void) nvpair_value_int32_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_integer_entry(h, te, v[i]) != + SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_INT64_ARRAY: + { + int64_t *v; + + (void) nvpair_value_int64_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_integer_entry(h, te, v[i]) != + SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + case DATA_TYPE_STRING: + { + char *str; + + (void) nvpair_value_string(p, &str); + return (add_astring_entry(h, te, str)); + } + case DATA_TYPE_STRING_ARRAY: + { + char **v; + + (void) nvpair_value_string_array(p, &v, &n); + for (i = 0; i < n; ++i) { + if (add_astring_entry(h, te, v[i]) != + SCF_SUCCESS) + return (SCF_FAILED); + } + return (SCF_SUCCESS); + } + default: + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + return (SCF_FAILED); + } + + /*NOTREACHED*/ +} + +/* + * Add new transaction entry to scf_transaction_t + * + * Can fail with + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_INTERNAL + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_FOUND + */ +static int +prep_transaction(scf_transaction_t *tx, scf_transaction_entry_t *te, + const char *prop, scf_type_t type) +{ + if (scf_transaction_property_new(tx, te, prop, type) != SCF_SUCCESS && + (scf_error() != SCF_ERROR_EXISTS || + scf_transaction_property_change(tx, te, prop, type) != + SCF_SUCCESS)) { + if (check_scf_error(scf_error(), errs_2)) { + return (SCF_FAILED); + } + } + + return (SCF_SUCCESS); +} + +/* + * notify_set_params() + * returns 0 on success or -1 on failure + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_BACKEND_READONLY + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_INTERNAL + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_PERMISSION_DENIED + */ +static int +notify_set_params(scf_propertygroup_t *pg, nvlist_t *params) +{ + scf_handle_t *h = scf_pg_handle(pg); + scf_error_t scf_e = scf_error(); + scf_transaction_t *tx = scf_transaction_create(h); + int bufsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; + char *propname = malloc(bufsz); + int r = -1; + int err; + + if (h == NULL) { + /* + * Use the error stored in scf_e + */ + (void) scf_set_error(scf_e); + goto cleanup; + } + if (tx == NULL) + goto cleanup; + + if (propname == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + + do { + nvpair_t *nvp; + + /* + * make sure we have the most recent version of the pg + * start the transaction + */ + if (scf_pg_update(pg) == SCF_FAILED || + scf_transaction_start(tx, pg) != SCF_SUCCESS) { + if (check_scf_error(scf_error(), errs_2)) { + goto cleanup; + } + } + + for (nvp = nvlist_next_nvpair(params, NULL); nvp != NULL; + nvp = nvlist_next_nvpair(params, nvp)) { + nvlist_t *m; + nvpair_t *p; + + /* we ONLY take nvlists here */ + if (nvpair_type(nvp) != DATA_TYPE_NVLIST) { + char *name = nvpair_name(nvp); + + /* + * if this is output from + * smf_notify_get_params() we want to skip + * the tset value of the nvlist + */ + if (strcmp(name, SCF_NOTIFY_NAME_TSET) == 0) + continue; + + (void) scf_set_error( + SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + + if (nvpair_value_nvlist(nvp, &m) != 0) { + (void) scf_set_error( + SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + + /* + * Traverse each mechanism list + */ + for (p = nvlist_next_nvpair(m, NULL); p != NULL; + p = nvlist_next_nvpair(m, p)) { + scf_transaction_entry_t *te = + scf_entry_create(h); + /* map the nvpair type to scf type */ + scf_type_t type = get_scf_type(p); + + if (te == NULL) { + if (scf_error() != + SCF_ERROR_INVALID_ARGUMENT) { + scf_entry_destroy(te); + goto cleanup; + } else { + assert(0); + abort(); + } + } + + if (type == SCF_TYPE_INVALID) { + (void) scf_set_error( + SCF_ERROR_INVALID_ARGUMENT); + scf_entry_destroy(te); + goto cleanup; + } + + if (snprintf(propname, bufsz, "%s,%s", + nvpair_name(nvp), nvpair_name(p)) >= + bufsz) { + (void) scf_set_error( + SCF_ERROR_INVALID_ARGUMENT); + scf_entry_destroy(te); + goto cleanup; + } + + if (prep_transaction(tx, te, propname, type) != + SCF_SUCCESS) { + scf_entry_destroy(te); + goto cleanup; + } + + if (get_nvpair_vals(h, te, p) != SCF_SUCCESS) { + if (check_scf_error(scf_error(), + errs_2)) { + goto cleanup; + } + } + } + } + err = scf_transaction_commit(tx); + scf_transaction_destroy_children(tx); + } while (err == 0); + + if (err == -1) { + if (check_scf_error(scf_error(), errs_2)) { + goto cleanup; + } + } + + r = 0; + +cleanup: + scf_transaction_destroy_children(tx); + scf_transaction_destroy(tx); + free(propname); + + return (r); +} + +/* + * Decode fmri. Populates service OR instance depending on which one is an + * exact match to the fmri parameter. + * + * The function destroys and sets the unused entity (service or instance) to + * NULL. + * + * return SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_CONSTRAINT_VIOLATED + * SCF_ERROR_DELETED + * SCF_ERROR_HANDLE_MISMATCH + * SCF_ERROR_INTERNAL + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_BOUND + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_NOT_SET + */ +static int +decode_fmri(const char *fmri, scf_handle_t *h, scf_service_t **s, + scf_instance_t **i) +{ + if (scf_handle_decode_fmri(h, fmri, NULL, *s, NULL, NULL, NULL, + SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { + if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { + scf_service_destroy(*s); + *s = NULL; + } else { + return (SCF_FAILED); + } + } + if (*s == NULL) + if (scf_handle_decode_fmri(h, fmri, NULL, NULL, *i, + NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { + return (SCF_FAILED); + } + + return (SCF_SUCCESS); +} + +/* + * Return size in bytes for an SCF_TYPE_*. Not all libscf types are supported + */ +static int +get_type_size(scf_type_t t) +{ + switch (t) { + case SCF_TYPE_BOOLEAN: + return (sizeof (uint8_t)); + case SCF_TYPE_COUNT: + return (sizeof (uint64_t)); + case SCF_TYPE_INTEGER: + return (sizeof (int64_t)); + case SCF_TYPE_ASTRING: + case SCF_TYPE_USTRING: + return (sizeof (void *)); + default: + return (-1); + } + + /*NOTREACHED*/ +} + +/* + * Return a pointer to the array of values according to its type + */ +static void ** +get_v_pointer(scf_values_t *v) +{ + switch (v->value_type) { + case SCF_TYPE_BOOLEAN: + return ((void **)&v->values.v_boolean); + case SCF_TYPE_COUNT: + return ((void **)&v->values.v_count); + case SCF_TYPE_INTEGER: + return ((void **)&v->values.v_integer); + case SCF_TYPE_ASTRING: + return ((void **)&v->values.v_astring); + case SCF_TYPE_USTRING: + return ((void **)&v->values.v_ustring); + default: + return (NULL); + } + + /*NOTREACHED*/ +} + +/* + * Populate scf_values_t value array at position c. + */ +static int +get_value(scf_value_t *val, scf_values_t *v, int c, char *buf, int sz) +{ + switch (v->value_type) { + case SCF_TYPE_BOOLEAN: + return (scf_value_get_boolean(val, v->values.v_boolean + c)); + case SCF_TYPE_COUNT: + return (scf_value_get_count(val, v->values.v_count + c)); + case SCF_TYPE_INTEGER: + return (scf_value_get_integer(val, v->values.v_integer + c)); + case SCF_TYPE_ASTRING: + if (scf_value_get_astring(val, buf, sz) < 0 || + (v->values.v_astring[c] = strdup(buf)) == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + return (-1); + } + return (0); + case SCF_TYPE_USTRING: + if (scf_value_get_ustring(val, buf, sz) < 0 || + (v->values.v_ustring[c] = strdup(buf)) == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + return (-1); + } + return (0); + default: + return (-1); + } + + /*NOTREACHED*/ +} + +/* + * Populate scf_values_t structure with values from prop + */ +static int +values_get(scf_property_t *prop, scf_values_t *v) +{ + scf_handle_t *h = scf_property_handle(prop); + scf_error_t scf_e = scf_error(); + scf_value_t *val = scf_value_create(h); + scf_iter_t *it = scf_iter_create(h); + scf_type_t type = SCF_TYPE_INVALID; + ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1; + char *buf = malloc(sz); + void **p; + int err, elem_sz, count, cursz; + int r = SCF_FAILED; + + assert(v != NULL); + assert(v->reserved == NULL); + if (buf == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + if (h == NULL) { + /* + * Use the error stored in scf_e + */ + (void) scf_set_error(scf_e); + goto cleanup; + } + if (val == NULL || it == NULL) + goto cleanup; + + if (scf_property_type(prop, &type) != SCF_SUCCESS) + goto cleanup; + if (scf_property_is_type(prop, v->value_type) != SCF_SUCCESS) + goto error; + + elem_sz = get_type_size(type); + assert(elem_sz > 0); + + p = get_v_pointer(v); + assert(p != NULL); + + cursz = count = v->value_count; + if (scf_iter_property_values(it, prop) != 0) { + goto error; + } + + while ((err = scf_iter_next_value(it, val)) == 1) { + if (count + 1 >= cursz) { + void *tmp; + + /* set initial size or double it */ + cursz = cursz ? 2 * cursz : 8; + if ((tmp = realloc(*p, cursz * elem_sz)) == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto error; + } + *p = tmp; + } + + if (get_value(val, v, count, buf, sz) != 0) + goto error; + + count++; + } + + v->value_count = count; + + if (err != 0) + goto error; + + r = SCF_SUCCESS; + goto cleanup; + +error: + v->value_count = count; + scf_values_destroy(v); + +cleanup: + free(buf); + scf_iter_destroy(it); + scf_value_destroy(val); + return (r); +} + +/* + * Add values from property p to existing nvlist_t nvl. The data type in the + * nvlist is inferred from the scf_type_t of the property. + * + * Returns SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_HANDLE_DESTROYED + * SCF_ERROR_HANDLE_MISMATCH + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_BOUND + * SCF_ERROR_NOT_SET + * SCF_ERROR_PERMISSION_DENIED + * SCF_ERROR_TYPE_MISMATCH + */ +static int +add_prop_to_nvlist(scf_property_t *p, const char *pname, nvlist_t *nvl, + int array) +{ + scf_values_t vals = { 0 }; + scf_type_t type, base_type; + int r = SCF_FAILED; + int err = 0; + + if (p == NULL || pname == NULL || *pname == '\0' || nvl == NULL) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + return (r); + } + + if (scf_property_type(p, &type) != 0) + goto cleanup; + + /* + * scf_values_t does not support subtypes of SCF_TYPE_USTRING, + * mapping them all to SCF_TYPE_USTRING + */ + base_type = scf_true_base_type(type); + if (base_type == SCF_TYPE_ASTRING && type != SCF_TYPE_ASTRING) + type = SCF_TYPE_USTRING; + + vals.value_type = type; + if (values_get(p, &vals) != SCF_SUCCESS) { + if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { + assert(0); + abort(); + } + goto cleanup; + } + + switch (vals.value_type) { + case SCF_TYPE_BOOLEAN: + { + boolean_t *v; + int i; + int n = vals.value_count; + + v = calloc(n, sizeof (boolean_t)); + if (v == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + for (i = 0; i < n; ++i) + v[i] = (boolean_t)vals.values.v_boolean[i]; + + if (n == 1 && !array) + err = nvlist_add_boolean_value(nvl, pname, *v); + else + err = nvlist_add_boolean_array(nvl, pname, + v, n); + if (err != 0) { + free(v); + goto cleanup; + } + free(v); + } + break; + + case SCF_TYPE_COUNT: + if (vals.value_count == 1 && !array) + err = nvlist_add_uint64(nvl, pname, + *vals.values.v_count); + else + err = nvlist_add_uint64_array(nvl, pname, + vals.values.v_count, vals.value_count); + if (err != 0) + goto cleanup; + + break; + + case SCF_TYPE_INTEGER: + if (vals.value_count == 1 && !array) + err = nvlist_add_int64(nvl, pname, + *vals.values.v_integer); + else + err = nvlist_add_int64_array(nvl, pname, + vals.values.v_integer, vals.value_count); + if (err != 0) + goto cleanup; + + break; + + case SCF_TYPE_ASTRING: + if (vals.value_count == 1 && !array) + err = nvlist_add_string(nvl, pname, + *vals.values.v_astring); + else + err = nvlist_add_string_array(nvl, pname, + vals.values.v_astring, vals.value_count); + if (err != 0) + goto cleanup; + break; + + default: + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + + r = SCF_SUCCESS; +cleanup: + scf_values_destroy(&vals); + switch (err) { + case 0: + break; + case EINVAL: + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + break; + case ENOMEM: + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + break; + default: + /* we should *never* get here */ + abort(); + } + + return (r); +} + +/* + * Parse property name "mechanism,parameter" into separate mechanism + * and parameter. *mech must be freed by caller. *val points into + * *mech and must not be freed. + * + * Returns SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NOT_FOUND + */ +static int +get_mech_name(const char *name, char **mech, char **val) +{ + char *p; + char *m; + + if ((m = strdup(name)) == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + return (SCF_FAILED); + } + if ((p = strchr(m, ',')) == NULL) { + free(m); + (void) scf_set_error(SCF_ERROR_NOT_FOUND); + return (SCF_FAILED); + } + *p = '\0'; + *val = p + 1; + *mech = m; + + return (SCF_SUCCESS); +} + +/* + * Return the number of transitions in a transition set. + * If the transition set is invalid, it returns zero. + */ +static uint_t +num_of_transitions(int32_t t) +{ + int i; + int n = 0; + + if (SCF_TRANS_VALID(t)) { + for (i = 0x1; i < SCF_STATE_ALL; i <<= 1) { + if (i & t) + ++n; + if (SCF_TRANS_INITIAL_STATE(t) & i) + ++n; + } + } + + return (n); +} + +/* + * Return the SCF_STATE_* macro value for the state in the FMA classes for + * SMF state transitions. They are of type: + * SCF_SVC_TRANSITION_CLASS. + * ireport.os.smf.state-transition. + */ +static int32_t +class_to_transition(const char *c) +{ + const char *p; + int r = 0; + size_t n; + + if (!is_svc_stn(c)) { + return (0); + } + + /* + * if we get here, c is SCF_SVC_TRANSITION_CLASS or longer + */ + p = c + strlen(SCF_SVC_TRANSITION_CLASS); + if (*p == '.') + ++p; + else + return (0); + + if ((n = base_class_len(p)) == 0) + return (0); + + if ((r = state_from_string(p, n)) == -1) + r = 0; + + return (r); +} + +/* + * return SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_BACKEND_READONLY + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_INTERNAL + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_PERMISSION_DENIED + */ +int +smf_notify_set_params(const char *class, nvlist_t *attr) +{ + uint32_t ver; + int32_t tset; + scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); + scf_error_t scf_e = scf_error(); + scf_service_t *s = scf_service_create(h); + scf_instance_t *i = scf_instance_create(h); + scf_propertygroup_t *pg = scf_pg_create(h); + nvlist_t *params = NULL; + char *fmri = (char *)SCF_NOTIFY_PARAMS_INST; + char *pgname = NULL; + int r = SCF_FAILED; + boolean_t is_stn; + int j; + + assert(class != NULL); + if (h == NULL) { + /* + * use saved error if _scf_handle_create_and_bind() fails + */ + (void) scf_set_error(scf_e); + goto cleanup; + } + if (i == NULL || s == NULL || pg == NULL) + goto cleanup; + + /* check version */ + if (nvlist_lookup_uint32(attr, SCF_NOTIFY_NAME_VERSION, &ver) != 0 || + ver != SCF_NOTIFY_PARAMS_VERSION) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + + if (nvlist_lookup_nvlist(attr, SCF_NOTIFY_PARAMS, ¶ms) != 0) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + + is_stn = is_svc_stn(class); + /* special case SMF state transition notification */ + if (is_stn && + (nvlist_lookup_string(attr, SCF_NOTIFY_NAME_FMRI, &fmri) != 0 || + nvlist_lookup_int32(attr, SCF_NOTIFY_NAME_TSET, &tset) != 0 || + !SCF_TRANS_VALID(tset))) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS) + if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + } else if (check_scf_error(scf_error(), errs_1)) { + goto cleanup; + } + + if (is_stn) { + tset |= class_to_transition(class); + + if (!SCF_TRANS_VALID(tset)) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + + for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) { + /* if this transition is not in the tset, continue */ + if (!(tset & st_pgnames[j].st_state)) + continue; + + if (get_or_add_pg(s, i, st_pgnames[j].st_pgname, + SCF_NOTIFY_PARAMS_PG_TYPE, 0, pg) != 0 && + check_scf_error(scf_error(), errs_2)) + goto cleanup; + + if (notify_set_params(pg, params) != 0) + goto cleanup; + } + if (s == NULL) { + /* We only need to refresh the instance */ + if (_smf_refresh_instance_i(i) != 0 && + check_scf_error(scf_error(), errs_1)) + goto cleanup; + } else { + /* We have to refresh all instances in the service */ + if (_smf_refresh_all_instances(s) != 0 && + check_scf_error(scf_error(), errs_1)) + goto cleanup; + } + } else { + if ((pgname = class_to_pgname(class)) == NULL) + goto cleanup; + if (get_or_add_pg(s, i, pgname, SCF_GROUP_APPLICATION, 0, pg) != + 0) { + if (check_scf_error(scf_error(), errs_2)) { + goto cleanup; + } + } + if (notify_set_params(pg, params) != 0) { + goto cleanup; + } + if (_smf_refresh_instance_i(i) != 0 && + check_scf_error(scf_error(), errs_1)) + goto cleanup; + } + + r = SCF_SUCCESS; +cleanup: + scf_instance_destroy(i); + scf_service_destroy(s); + scf_pg_destroy(pg); + scf_handle_destroy(h); + free(pgname); + + return (r); +} + +/* + * returns SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_HANDLE_DESTROYED + * SCF_ERROR_HANDLE_MISMATCH + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_BOUND + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_NOT_SET + * SCF_ERROR_PERMISSION_DENIED + */ +int +_scf_notify_get_params(scf_propertygroup_t *pg, nvlist_t *params) +{ + scf_handle_t *h = scf_pg_handle(pg); + scf_error_t scf_e = scf_error(); + scf_property_t *p = scf_property_create(h); + scf_iter_t *it = scf_iter_create(h); + int sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; + char *name = malloc(sz); + int r = SCF_FAILED; + int err; + + if (h == NULL) { + /* + * Use the error stored in scf_e + */ + (void) scf_set_error(scf_e); + goto cleanup; + } + if (it == NULL || p == NULL) + goto cleanup; + + if (name == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + + if (scf_iter_pg_properties(it, pg) != SCF_SUCCESS) { + if (check_scf_error(scf_error(), errs_1)) { + goto cleanup; + } + } + + while ((err = scf_iter_next_property(it, p)) == 1) { + nvlist_t *nvl; + int nvl_new = 0; + char *mech; + char *val; + + if (scf_property_get_name(p, name, sz) == SCF_FAILED) { + if (check_scf_error(scf_error(), errs_1)) { + goto cleanup; + } + } + + if (get_mech_name(name, &mech, &val) != SCF_SUCCESS) { + if (scf_error() == SCF_ERROR_NOT_FOUND) + continue; + goto cleanup; + } + + if (nvlist_lookup_nvlist(params, mech, &nvl) != 0) { + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + free(mech); + goto cleanup; + } + nvl_new = 1; + } + + if (add_prop_to_nvlist(p, val, nvl, 1) != SCF_SUCCESS) { + if (check_scf_error(scf_error(), errs_2)) { + free(mech); + nvlist_free(nvl); + goto cleanup; + } + } + if (nvl_new) { + if (nvlist_add_nvlist(params, mech, nvl) != 0) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + free(mech); + nvlist_free(nvl); + goto cleanup; + } + nvlist_free(nvl); + } + + free(mech); + } + + if (err == 0) { + r = SCF_SUCCESS; + } else if (check_scf_error(scf_error(), errs_2)) { + goto cleanup; + } + +cleanup: + scf_iter_destroy(it); + scf_property_destroy(p); + free(name); + + return (r); +} + +/* + * Look up pg containing an SMF state transition parameters. If it cannot find + * the pg in the composed view of the instance, it will look in the global + * instance for the system wide parameters. + * Instance, service and global instance have to be passed by caller. + * + * returns SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_HANDLE_DESTROYED + * SCF_ERROR_HANDLE_MISMATCH + * SCF_ERROR_INTERNAL + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_BOUND + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_NOT_SET + */ +static int +get_stn_pg(scf_service_t *s, scf_instance_t *i, scf_instance_t *g, + const char *pgname, scf_propertygroup_t *pg) +{ + if (get_pg(s, i, pgname, pg, 1) == 0 || + scf_error() == SCF_ERROR_NOT_FOUND && + get_pg(NULL, g, pgname, pg, 0) == 0) + return (SCF_SUCCESS); + + return (SCF_FAILED); +} + +/* + * Populates nvlist_t params with the source fmri for the pg + * + * return SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_DELETED + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_NO_MEMORY + */ +static int +get_pg_source(scf_propertygroup_t *pg, nvlist_t *params) +{ + size_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1; + char *fmri = malloc(sz); + char *p; + int r = SCF_FAILED; + + if (fmri == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto out; + } + + if (scf_pg_to_fmri(pg, fmri, sz) == -1) { + if (check_scf_error(scf_error(), errs_1)) { + goto out; + } + } + + /* get rid of the properties part of the pg source */ + if ((p = strrchr(fmri, ':')) != NULL && p > fmri) + *(p - 1) = '\0'; + if (nvlist_add_string(params, SCF_NOTIFY_PARAMS_SOURCE_NAME, fmri) != + 0) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto out; + } + + r = SCF_SUCCESS; +out: + free(fmri); + return (r); +} + +/* + * Specialized function to get SMF state transition notification parameters + * + * return SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_INTERNAL + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_PERMISSION_DENIED + */ +int +_scf_get_svc_notify_params(const char *fmri, nvlist_t *nvl, int32_t tset, + int getsource, int getglobal) +{ + scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); + scf_error_t scf_e = scf_error(); + scf_service_t *s = scf_service_create(h); + scf_instance_t *i = scf_instance_create(h); + scf_instance_t *g = scf_instance_create(h); + scf_propertygroup_t *pg = scf_pg_create(h); + int r = SCF_FAILED; + nvlist_t **params = NULL; + uint_t c, nvl_num = 0; + int not_found = 1; + int j; + const char *pgname; + + assert(fmri != NULL && nvl != NULL); + if (h == NULL) { + /* + * use saved error if _scf_handle_create_and_bind() fails + */ + (void) scf_set_error(scf_e); + goto cleanup; + } + if (s == NULL || i == NULL || g == NULL || pg == NULL) + goto cleanup; + + if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS || + scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, g, NULL, + NULL, SCF_DECODE_FMRI_EXACT) != 0) { + if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + } else if (check_scf_error(scf_error(), errs_1)) { + goto cleanup; + } + } + + nvl_num = num_of_transitions(tset); + if ((params = calloc(nvl_num, sizeof (nvlist_t *))) == NULL) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + + for (c = 0; c < nvl_num; ++c) + if (nvlist_alloc(params + c, NV_UNIQUE_NAME, 0) != 0) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + + for (c = 0, j = 0; st_pgnames[j].st_pgname != NULL; ++j) { + /* if this transition is not in the tset, continue */ + if (!(tset & st_pgnames[j].st_state)) + continue; + + assert(c < nvl_num); + pgname = st_pgnames[j].st_pgname; + + if (nvlist_add_int32(params[c], SCF_NOTIFY_NAME_TSET, + st_pgnames[j].st_state) != 0) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + if ((getglobal ? get_stn_pg(s, i, g, pgname, pg) : + get_pg(s, i, pgname, pg, 1)) == SCF_SUCCESS) { + not_found = 0; + if (_scf_notify_get_params(pg, params[c]) != + SCF_SUCCESS) + goto cleanup; + if (getsource && get_pg_source(pg, params[c]) != + SCF_SUCCESS) + goto cleanup; + } else if (scf_error() == SCF_ERROR_NOT_FOUND || + scf_error() == SCF_ERROR_DELETED) { + /* keep driving */ + /*EMPTY*/ + } else if (check_scf_error(scf_error(), errs_1)) { + goto cleanup; + } + ++c; + } + + if (not_found) { + (void) scf_set_error(SCF_ERROR_NOT_FOUND); + goto cleanup; + } + + assert(c == nvl_num); + + if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, params, nvl_num) != + 0 || nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, + SCF_NOTIFY_PARAMS_VERSION) != 0) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + + r = SCF_SUCCESS; + +cleanup: + scf_pg_destroy(pg); + scf_instance_destroy(i); + scf_instance_destroy(g); + scf_service_destroy(s); + scf_handle_destroy(h); + if (params != NULL) + for (c = 0; c < nvl_num; ++c) + nvlist_free(params[c]); + free(params); + + return (r); +} + +/* + * Specialized function to get fma notification parameters + * + * return SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_INTERNAL + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_PERMISSION_DENIED + */ +int +_scf_get_fma_notify_params(const char *class, nvlist_t *nvl, int getsource) +{ + scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); + scf_error_t scf_e = scf_error(); + scf_instance_t *i = scf_instance_create(h); + scf_propertygroup_t *pg = scf_pg_create(h); + int r = SCF_FAILED; + nvlist_t *params = NULL; + char *pgname = NULL; + + if (h == NULL) { + /* + * use saved error if _scf_handle_create_and_bind() fails + */ + (void) scf_set_error(scf_e); + goto cleanup; + } + if (i == NULL || pg == NULL) + goto cleanup; + + if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL, NULL, i, + NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { + if (check_scf_error(scf_error(), errs_1)) { + goto cleanup; + } + } + + if ((pgname = class_to_pgname(class)) == NULL) + goto cleanup; + + while (get_pg(NULL, i, pgname, pg, 0) != 0) { + if (scf_error() == SCF_ERROR_NOT_FOUND) { + char *p = strrchr(pgname, '.'); + + if (p != NULL) { + *p = ','; + /* + * since the resulting string is shorter, + * there is no risk of buffer overflow + */ + (void) strcpy(p + 1, SCF_NOTIFY_PG_POSTFIX); + continue; + } + } + + if (check_scf_error(scf_error(), errs_1)) { + goto cleanup; + } + } + + if (nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + + if (_scf_notify_get_params(pg, params) != SCF_SUCCESS) + goto cleanup; + + if (getsource && get_pg_source(pg, params) != SCF_SUCCESS) + goto cleanup; + + if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, ¶ms, 1) != 0 || + nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, + SCF_NOTIFY_PARAMS_VERSION) != 0) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + goto cleanup; + } + + r = SCF_SUCCESS; + +cleanup: + if (params) + nvlist_free(params); + scf_pg_destroy(pg); + scf_instance_destroy(i); + scf_handle_destroy(h); + free(pgname); + + return (r); +} + +/* + * Retrieve the notification parameters for the Event described in the + * input nvlist_t nvl. + * The function will allocate an nvlist_t to store the notification + * parameters. The notification parameters in the output nvlist will have + * the following format: + * + * version (uint32_t) + * SCF_NOTIFY_PARAMS (array of embedded nvlists) + * (start of notify-params[0]) + * tset (int32_t) + * (embedded nvlist) + * + * ... + * (end ) + * ... + * (end of notify-params[0]) + * ... + * + * return SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_INTERNAL + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_PERMISSION_DENIED + */ +int +smf_notify_get_params(nvlist_t **params, nvlist_t *nvl) +{ + char *class; + char *from; /* from state */ + char *to; /* to state */ + nvlist_t *attr; + char *fmri; + int32_t tset = 0; + int r = SCF_FAILED; + + if (params == NULL || nvlist_lookup_string(nvl, "class", &class) != 0) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + return (r); + } + if (nvlist_alloc(params, NV_UNIQUE_NAME, 0) != 0) { + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + return (r); + } + + if (is_svc_stn(class)) { + if (nvlist_lookup_nvlist(nvl, "attr", &attr) != 0 || + nvlist_lookup_string(attr, "svc-string", &fmri) != 0 || + nvlist_lookup_string(attr, "from-state", &from) != 0 || + nvlist_lookup_string(attr, "to-state", &to) != 0) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + + tset = SCF_TRANS(smf_state_from_string(from), + smf_state_from_string(to)); + if (!SCF_TRANS_VALID(tset)) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + tset |= class_to_transition(class); + + r = _scf_get_svc_notify_params(fmri, *params, tset, 0, 1); + } else { + r = _scf_get_fma_notify_params(class, *params, 0); + } + +cleanup: + if (r == SCF_FAILED) { + nvlist_free(*params); + *params = NULL; + } + + return (r); +} + +/* + * return SCF_SUCCESS or SCF_FAILED on + * SCF_ERROR_BACKEND_ACCESS + * SCF_ERROR_BACKEND_READONLY + * SCF_ERROR_CONNECTION_BROKEN + * SCF_ERROR_DELETED + * SCF_ERROR_INTERNAL + * SCF_ERROR_INVALID_ARGUMENT + * SCF_ERROR_NO_MEMORY + * SCF_ERROR_NO_RESOURCES + * SCF_ERROR_NOT_FOUND + * SCF_ERROR_PERMISSION_DENIED + */ +int +smf_notify_del_params(const char *class, const char *fmri, int32_t tset) +{ + scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); + scf_error_t scf_e = scf_error(); + scf_service_t *s = scf_service_create(h); + scf_instance_t *i = scf_instance_create(h); + scf_propertygroup_t *pg = scf_pg_create(h); + int r = SCF_FAILED; + char *pgname = NULL; + int j; + + if (class == NULL) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + + if (h == NULL) { + /* + * use saved error if _scf_handle_create_and_bind() fails + */ + (void) scf_set_error(scf_e); + goto cleanup; + } + if (s == NULL || i == NULL || pg == NULL) + goto cleanup; + + if (is_svc_stn(class)) { + tset |= class_to_transition(class); + + if (!SCF_TRANS_VALID(tset) || fmri == NULL) { + (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); + goto cleanup; + } + + if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS) { + if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) + (void) scf_set_error( + SCF_ERROR_INVALID_ARGUMENT); + if (check_scf_error(scf_error(), errs_1)) { + goto cleanup; + } + } + + for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) { + /* if this transition is not in the tset, continue */ + if (!(tset & st_pgnames[j].st_state)) + continue; + + if (del_pg(s, i, st_pgnames[j].st_pgname, pg) != + SCF_SUCCESS && + scf_error() != SCF_ERROR_DELETED && + scf_error() != SCF_ERROR_NOT_FOUND) { + if (check_scf_error(scf_error(), + errs_1)) { + goto cleanup; + } + } + } + if (s == NULL) { + /* We only need to refresh the instance */ + if (_smf_refresh_instance_i(i) != 0 && + check_scf_error(scf_error(), errs_1)) + goto cleanup; + } else { + /* We have to refresh all instances in the service */ + if (_smf_refresh_all_instances(s) != 0 && + check_scf_error(scf_error(), errs_1)) + goto cleanup; + } + } else { + if ((pgname = class_to_pgname(class)) == NULL) + goto cleanup; + + if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL, + NULL, i, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) + goto cleanup; + + if (del_pg(NULL, i, pgname, pg) != SCF_SUCCESS && + scf_error() != SCF_ERROR_DELETED && + scf_error() != SCF_ERROR_NOT_FOUND) { + if (check_scf_error(scf_error(), errs_1)) { + goto cleanup; + } + } + + if (_smf_refresh_instance_i(i) != 0 && + check_scf_error(scf_error(), errs_1)) + goto cleanup; + } + + + r = SCF_SUCCESS; + +cleanup: + scf_pg_destroy(pg); + scf_instance_destroy(i); + scf_service_destroy(s); + scf_handle_destroy(h); + free(pgname); + + return (r); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libscf/common/scf_tmpl.c --- a/usr/src/lib/libscf/common/scf_tmpl.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libscf/common/scf_tmpl.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -152,8 +151,8 @@ * Returns 1 if the supplied error is a member of the error array, 0 * if it is not. */ -static scf_error_t -ismember(const int error, const scf_error_t error_array[]) +int +ismember(const scf_error_t error, const scf_error_t error_array[]) { int i; @@ -505,7 +504,7 @@ } /* - * char **_append_astrings_values() + * static char ** _append_astrings_values() * * This function reads the values from the property prop_name in pg and * appends to an existing scf_values_t *vals. vals may be empty, but @@ -4093,11 +4092,13 @@ { int i; char **items = NULL; - char **str = vals->values_as_strings; + char **str = NULL; if (vals == NULL) return; + str = vals->values_as_strings; + /* free values */ switch (vals->value_type) { case SCF_TYPE_BOOLEAN: diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libscf/inc/libscf.h --- a/usr/src/lib/libscf/inc/libscf.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libscf/inc/libscf.h Fri Jul 30 17:04:17 2010 +1000 @@ -29,6 +29,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -286,6 +287,7 @@ /* * Standard property names */ +#define SCF_PROPERTY_ACTIVE_POSTFIX ((const char *)"active") #define SCF_PROPERTY_AUX_STATE ((const char *)"auxiliary_state") #define SCF_PROPERTY_AUX_FMRI ((const char *)"auxiliary_fmri") #define SCF_PROPERTY_AUX_TTY ((const char *)"auxiliary_tty") @@ -401,6 +403,38 @@ #define SCF_STATE_DEGRADED 0x00000020 #define SCF_STATE_ALL 0x0000003F +/* + * software fma svc-transition class + */ +#define SCF_NOTIFY_PARAMS_VERSION 0X0 +#define SCF_NOTIFY_NAME_FMRI ((const char *)"fmri") +#define SCF_NOTIFY_NAME_VERSION ((const char *)"version") +#define SCF_NOTIFY_NAME_TSET ((const char *)"tset") +#define SCF_NOTIFY_PG_POSTFIX ((const char *)"fmnotify") +#define SCF_NOTIFY_PARAMS ((const char *)"notify-params") +#define SCF_NOTIFY_PARAMS_INST \ + ((const char *)"svc:/system/fm/notify-params:default") +#define SCF_SVC_TRANSITION_CLASS \ + ((const char *)"ireport.os.smf.state-transition") +#define SCF_NOTIFY_PARAMS_PG_TYPE ((const char *)"notify_params") + +/* + * Useful transition macros + */ +#define SCF_TRANS_SHIFT_INITIAL_STATE(s) ((s) << 16) +#define SCF_TRANSITION_ALL \ + (SCF_TRANS_SHIFT_INITIAL_STATE(SCF_STATE_ALL) | SCF_STATE_ALL) +#define SCF_TRANS(f, t) (SCF_TRANS_SHIFT_INITIAL_STATE(f) | (t)) +#define SCF_TRANS_VALID(t) (!((t) & ~SCF_TRANSITION_ALL)) +#define SCF_TRANS_INITIAL_STATE(t) ((t) >> 16 & SCF_STATE_ALL) +#define SCF_TRANS_FINAL_STATE(t) ((t) & SCF_STATE_ALL) + +/* + * Prefixes for states in state transition notification + */ +#define SCF_STN_PREFIX_FROM ((const char *)"from-") +#define SCF_STN_PREFIX_TO ((const char *)"to-") + #define SCF_PG_FLAG_NONPERSISTENT 0x1 #define SCF_TRACE_LIBRARY 0x1 @@ -775,6 +809,27 @@ void scf_simple_prop_next_reset(scf_simple_prop_t *); /* + * smf_state_from_string() + * return SCF_STATE_* value for the input + * -1 on error. String "all" maps to SCF_STATE_ALL macro + */ +int32_t smf_state_from_string(const char *); + +/* + * smf_state_to_string() + * return SCF_STATE_STRING* value for the input + * NULL on error. + */ +const char *smf_state_to_string(int32_t); + +/* + * Notification interfaces + */ +int smf_notify_set_params(const char *, nvlist_t *); +int smf_notify_get_params(nvlist_t **, nvlist_t *); +int smf_notify_del_params(const char *, const char *, int32_t); + +/* * SMF exit status definitions */ #define SMF_EXIT_OK 0 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libscf/inc/libscf_priv.h --- a/usr/src/lib/libscf/inc/libscf_priv.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libscf/inc/libscf_priv.h Fri Jul 30 17:04:17 2010 +1000 @@ -552,6 +552,41 @@ */ void _check_services(char **); +/* + * _scf_handle_create_and_bind() + * convenience function that creates and binds a handle + */ +scf_handle_t *_scf_handle_create_and_bind(scf_version_t); + +/* + * _smf_refresh_all_instances() + * refresh all intances of a service + * return SCF_SUCCESS or SCF_FAILED on _PERMISSION_DENIED, _BACKEND_ACCESS + * or _BACKEND_READONLY. + */ +int _smf_refresh_all_instances(scf_service_t *); + +/* + * _scf_get_fma_notify_params() + * Specialized fuction to get fma notifitation parameters + */ +int _scf_get_fma_notify_params(const char *, nvlist_t *, int); + +/* + * _scf_get_svc_notify_params() + * Specialized function to get SMF state transition notification parameters + */ +int _scf_get_svc_notify_params(const char *, nvlist_t *, int32_t, int, int); + +/* + * _scf_notify_get_params() + * Specialized function to get notification parametes from a pg into an + * nvlist_t + */ +int _scf_notify_get_params(scf_propertygroup_t *, nvlist_t *); + +#define SCF_NOTIFY_PARAMS_SOURCE_NAME ((const char *)"preference_source") + #ifdef __cplusplus } #endif diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libsecdb/auth_attr.txt --- a/usr/src/lib/libsecdb/auth_attr.txt Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libsecdb/auth_attr.txt Fri Jul 30 17:04:17 2010 +1000 @@ -150,6 +150,8 @@ solaris.smf.manage.routing:::Manage Routing Service States::help=SmfRoutingStates.html solaris.smf.manage.rpc.bind:::Manage RPC Program number mapper::help=SmfRPCBind.html solaris.smf.manage.sendmail:::Manage Sendmail Service States::help=SmfSendmailStates.html +solaris.smf.manage.smtp-notify:::Manage Email Event Notification Agent:: +solaris.smf.manage.snmp-notify:::Manage SNMP Event Notification Agent:: solaris.smf.manage.ssh:::Manage Secure Shell Service States::help=SmfSshStates.html solaris.smf.manage.stmf:::Manage STMF Service States::help=SmfSTMFStates.html solaris.smf.manage.system-log:::Manage Syslog Service States::help=SmfSyslogStates.html @@ -175,6 +177,8 @@ solaris.smf.value.nwam:::Change Values of SMF Network Auto-Magic Properties::help=SmfValueNWAM.html solaris.smf.value.smb:::Change Values of SMB Service Properties::help=SmfValueSMB.html solaris.smf.read.smb:::Read permission for protected SMF SMB Service Properties::help=AuthReadSMB.html +solaris.smf.value.smtp-notify:::Change values of Email Event Notification Agent properties:: +solaris.smf.value.snmp-notify:::Change values of SNMP Event Notification Agent properties:: solaris.smf.read.stmf:::Read STMF Provider Private Data::help=SmfSTMFRead.html solaris.smf.value.routing:::Change Values of SMF Routing Properties::help=SmfValueRouting.html solaris.smf.value.tnd:::Change Trusted Network Daemon Service Property Values::help=ValueTND.html diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libsecdb/prof_attr.txt --- a/usr/src/lib/libsecdb/prof_attr.txt Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libsecdb/prof_attr.txt Fri Jul 30 17:04:17 2010 +1000 @@ -102,6 +102,7 @@ Project Management:::Add/Modify/Remove projects:help=RtProjManagement.html VSCAN Management:::Manage the VSCAN service:auths=solaris.smf.manage.vscan,solaris.smf.value.vscan,solaris.smf.modify.application;help=RtVscanMngmnt.html WUSB Management:::Manage Wireless USB:auths=solaris.admin.wusb.*,solaris.smf.manage.wusb;help=WUSBmgmt.html +Event Notification Agent Management:::Manage Event Notification Agents:auths=solaris.smf.manage.smtp-notify,solaris.smf.manage.snmp-notify,solaris.smf.value.smtp-notify,solaris.smf.value.snmp-notify # # Trusted Extensions profiles: # diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libsysevent/libevchannel.c --- a/usr/src/lib/libsysevent/libevchannel.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libsysevent/libevchannel.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -435,7 +434,6 @@ kill_door_servers(evchan_subscr_t *subp) { door_arg_t da; - int i; bzero(&da, sizeof (da)); subp->evsub_state = EVCHAN_SUB_STATE_CLOSING; @@ -603,7 +601,6 @@ int (*event_handler)(sysevent_t *ev, void *cookie), void *cookie, uint32_t flags, sysevent_subattr_t *attr) { - struct sysevent_subattr_impl sa; struct sysevent_subattr_impl *xsa; if (attr != NULL) { @@ -809,11 +806,13 @@ rc = ioctl(EV_FD(scp), SEV_CHAN_CONTROL, (intptr_t)&uargs); *chlenp = uargs.value; break; + case EVCH_SET_CHAN_LEN: /* Range change will be handled in framework */ uargs.value = va_arg(ap, uint32_t); rc = ioctl(EV_FD(scp), SEV_CHAN_CONTROL, (intptr_t)&uargs); break; + default: rc = EINVAL; } @@ -828,3 +827,91 @@ return (errno = rc); } + +int +sysevent_evc_setpropnvl(evchan_t *scp, nvlist_t *nvl) +{ + sev_propnvl_args_t uargs; + char *buf = NULL; + size_t nvlsz = 0; + int rc; + + if (scp == NULL || misaligned(scp)) + return (errno = EINVAL); + + if (nvl != NULL && + nvlist_pack(nvl, &buf, &nvlsz, NV_ENCODE_NATIVE, 0) != 0) + return (errno); + + uargs.packednvl.name = (uint64_t)(uintptr_t)buf; + uargs.packednvl.len = (uint32_t)nvlsz; + + rc = ioctl(EV_FD(scp), SEV_SETPROPNVL, (intptr_t)&uargs); + + if (buf) + free(buf); + + return (rc); +} + +int +sysevent_evc_getpropnvl(evchan_t *scp, nvlist_t **nvlp) +{ + sev_propnvl_args_t uargs; + char buf[1024], *bufp = buf; /* stack buffer */ + size_t sz = sizeof (buf); + char *buf2 = NULL; /* allocated if stack buf too small */ + int64_t expgen = -1; + int rc; + + if (scp == NULL || misaligned(scp) || nvlp == NULL) + return (errno = EINVAL); + + *nvlp = NULL; + +again: + uargs.packednvl.name = (uint64_t)(uintptr_t)bufp; + uargs.packednvl.len = (uint32_t)sz; + + rc = ioctl(EV_FD(scp), SEV_GETPROPNVL, (intptr_t)&uargs); + + if (rc == E2BIG) + return (errno = E2BIG); /* driver refuses to copyout */ + + /* + * If the packed nvlist is too big for the buffer size we offered + * then the ioctl returns EOVERFLOW and indicates in the 'len' + * the size required for the current property nvlist generation + * (itself returned in the generation member). + */ + if (rc == EOVERFLOW && + (buf2 == NULL || uargs.generation != expgen)) { + if (buf2 != NULL) + free(buf2); + + if ((sz = uargs.packednvl.len) > 1024 * 1024) + return (E2BIG); + + bufp = buf2 = malloc(sz); + + if (buf2 == NULL) + return (errno = ENOMEM); + + expgen = uargs.generation; + goto again; + } + + /* + * The chan prop nvlist can be absent, in which case the ioctl + * returns success and uargs.packednvl.len of 0; we have already + * set *nvlp to NULL. Otherwise we must unpack the nvl. + */ + if (rc == 0 && uargs.packednvl.len != 0 && + nvlist_unpack(bufp, uargs.packednvl.len, nvlp, 0) != 0) + rc = EINVAL; + + if (buf2 != NULL) + free(buf2); + + return (rc ? errno = rc : 0); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libsysevent/libsysevent.c --- a/usr/src/lib/libsysevent/libsysevent.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libsysevent/libsysevent.c Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -35,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -764,6 +764,10 @@ sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp); + /* See hack alert in sysevent_bind_subscriber_cmn */ + if (sub_info->sp_handler_tid == NULL) + sub_info->sp_handler_tid = thr_self(); + (void) mutex_lock(&sub_info->sp_qlock); for (;;) { while (sub_info->sp_evq_head == NULL && SH_BOUND(shp)) { @@ -2038,18 +2042,72 @@ return (-1); } -/* - * sysevent_bind_subscriber - Bind an event receiver to an event channel - */ -int -sysevent_bind_subscriber(sysevent_handle_t *shp, - void (*event_handler)(sysevent_t *ev)) +static pthread_once_t xdoor_thrattr_once = PTHREAD_ONCE_INIT; +static pthread_attr_t xdoor_thrattr; + +static void +xdoor_thrattr_init(void) +{ + (void) pthread_attr_init(&xdoor_thrattr); + (void) pthread_attr_setdetachstate(&xdoor_thrattr, + PTHREAD_CREATE_DETACHED); + (void) pthread_attr_setscope(&xdoor_thrattr, PTHREAD_SCOPE_SYSTEM); +} + +static int +xdoor_server_create(door_info_t *dip, void *(*startf)(void *), + void *startfarg, void *cookie) +{ + struct sysevent_subattr_impl *xsa = cookie; + pthread_attr_t *thrattr; + sigset_t oset; + int err; + + if (xsa->xs_thrcreate) { + return (xsa->xs_thrcreate(dip, startf, startfarg, + xsa->xs_thrcreate_cookie)); + } + + if (xsa->xs_thrattr == NULL) { + (void) pthread_once(&xdoor_thrattr_once, xdoor_thrattr_init); + thrattr = &xdoor_thrattr; + } else { + thrattr = xsa->xs_thrattr; + } + + (void) pthread_sigmask(SIG_SETMASK, &xsa->xs_sigmask, &oset); + err = pthread_create(NULL, thrattr, startf, startfarg); + (void) pthread_sigmask(SIG_SETMASK, &oset, NULL); + + return (err == 0 ? 1 : -1); +} + +static void +xdoor_server_setup(void *cookie) +{ + struct sysevent_subattr_impl *xsa = cookie; + + if (xsa->xs_thrsetup) { + xsa->xs_thrsetup(xsa->xs_thrsetup_cookie); + } else { + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + } +} + +static int +sysevent_bind_subscriber_cmn(sysevent_handle_t *shp, + void (*event_handler)(sysevent_t *ev), + sysevent_subattr_t *subattr) { int fd = -1; int error = 0; uint32_t sub_id = 0; char door_name[MAXPATHLEN]; subscriber_priv_t *sub_info; + int created; + struct sysevent_subattr_impl *xsa = + (struct sysevent_subattr_impl *)subattr; if (shp == NULL || event_handler == NULL) { errno = EINVAL; @@ -2124,8 +2182,18 @@ * syseventd will use this door service to propagate * events to the client. */ - if ((SH_DOOR_DESC(shp) = door_create(event_deliver_service, - (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { + if (subattr == NULL) { + SH_DOOR_DESC(shp) = door_create(event_deliver_service, + (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL); + } else { + SH_DOOR_DESC(shp) = door_xcreate(event_deliver_service, + (void *)shp, + DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_NO_DEPLETION_CB, + xdoor_server_create, xdoor_server_setup, + (void *)subattr, 1); + } + + if (SH_DOOR_DESC(shp) == -1) { dprint("sysevent_bind_subscriber: door create failed: " "%s\n", strerror(errno)); error = EFAULT; @@ -2151,10 +2219,33 @@ SH_TYPE(shp) = SUBSCRIBER; SH_PRIV_DATA(shp) = (void *)sub_info; + /* Create an event handler thread */ + if (xsa == NULL || xsa->xs_thrcreate == NULL) { + created = thr_create(NULL, NULL, + (void *(*)(void *))subscriber_event_handler, + shp, THR_BOUND, &sub_info->sp_handler_tid) == 0; + } else { + /* + * A terrible hack. We will use the extended private + * door thread creation function the caller passed in to + * create the event handler thread. That function will + * be called with our chosen thread start function and arg + * instead of the usual libc-provided ones, but that's ok + * as it is required to use them verbatim anyway. We will + * pass a NULL door_info_t pointer to the function - so + * callers depending on this hack had better be prepared + * for that. All this allow the caller to rubberstamp + * the created thread as it wishes. But we don't get + * the created threadid with this, so we modify the + * thread start function to stash it. + */ - /* Create an event handler thread */ - if (thr_create(NULL, NULL, (void *(*)(void *))subscriber_event_handler, - shp, THR_BOUND, &sub_info->sp_handler_tid) != 0) { + created = xsa->xs_thrcreate(NULL, + (void *(*)(void *))subscriber_event_handler, + shp, xsa->xs_thrcreate_cookie) == 1; + } + + if (!created) { error = EFAULT; goto fail; } @@ -2190,6 +2281,27 @@ } /* + * sysevent_bind_subscriber - Bind an event receiver to an event channel + */ +int +sysevent_bind_subscriber(sysevent_handle_t *shp, + void (*event_handler)(sysevent_t *ev)) +{ + return (sysevent_bind_subscriber_cmn(shp, event_handler, NULL)); +} + +/* + * sysevent_bind_xsubscriber - Bind a subscriber using door_xcreate with + * attributes specified. + */ +int +sysevent_bind_xsubscriber(sysevent_handle_t *shp, + void (*event_handler)(sysevent_t *ev), sysevent_subattr_t *subattr) +{ + return (sysevent_bind_subscriber_cmn(shp, event_handler, subattr)); +} + +/* * sysevent_register_event - register an event class and associated subclasses * for an event subscriber */ @@ -2389,7 +2501,6 @@ (void) door_revoke(SH_DOOR_DESC(shp)); (void) fdetach(SH_DOOR_NAME(shp)); - /* * Release resources and wait for pending event delivery to * complete. @@ -2399,7 +2510,8 @@ /* Signal event handler and drain the subscriber's event queue */ (void) cond_signal(&sub_info->sp_cv); (void) mutex_unlock(&sub_info->sp_qlock); - (void) thr_join(sub_info->sp_handler_tid, NULL, NULL); + if (sub_info->sp_handler_tid != NULL) + (void) thr_join(sub_info->sp_handler_tid, NULL, NULL); (void) cond_destroy(&sub_info->sp_cv); (void) mutex_destroy(&sub_info->sp_qlock); @@ -2447,12 +2559,9 @@ * Evolving APIs to subscribe to syseventd(1M) system events. */ -/* - * sysevent_bind_handle - Bind application event handler for syseventd - * subscription. - */ -sysevent_handle_t * -sysevent_bind_handle(void (*event_handler)(sysevent_t *ev)) +static sysevent_handle_t * +sysevent_bind_handle_cmn(void (*event_handler)(sysevent_t *ev), + sysevent_subattr_t *subattr) { sysevent_handle_t *shp; @@ -2470,8 +2579,7 @@ return (NULL); } - if (sysevent_bind_subscriber(shp, event_handler) != 0) { - + if (sysevent_bind_xsubscriber(shp, event_handler, subattr) != 0) { /* * Ask syseventd to clean-up any stale subcribers and try to * to bind again @@ -2496,7 +2604,8 @@ (void) close(pub_fd); /* Try to bind again */ - if (sysevent_bind_subscriber(shp, event_handler) != 0) { + if (sysevent_bind_xsubscriber(shp, event_handler, + subattr) != 0) { sysevent_close_channel(shp); return (NULL); } @@ -2510,6 +2619,27 @@ } /* + * sysevent_bind_handle - Bind application event handler for syseventd + * subscription. + */ +sysevent_handle_t * +sysevent_bind_handle(void (*event_handler)(sysevent_t *ev)) +{ + return (sysevent_bind_handle_cmn(event_handler, NULL)); +} + +/* + * sysevent_bind_xhandle - Bind application event handler for syseventd + * subscription, using door_xcreate and attributes as specified. + */ +sysevent_handle_t * +sysevent_bind_xhandle(void (*event_handler)(sysevent_t *ev), + sysevent_subattr_t *subattr) +{ + return (sysevent_bind_handle_cmn(event_handler, subattr)); +} + +/* * sysevent_unbind_handle - Unbind caller from syseventd subscriptions */ void diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libsysevent/libsysevent.h --- a/usr/src/lib/libsysevent/libsysevent.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libsysevent/libsysevent.h Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LIBSYSEVENT_H #define _LIBSYSEVENT_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -83,6 +79,8 @@ /* syseventd subscriber interfaces */ sysevent_handle_t *sysevent_bind_handle(void (*event_handler)(sysevent_t *ev)); +sysevent_handle_t *sysevent_bind_xhandle(void (*event_handler)(sysevent_t *ev), + sysevent_subattr_t *); void sysevent_unbind_handle(sysevent_handle_t *sysevent_hdl); int sysevent_subscribe_event(sysevent_handle_t *sysevent_hdl, const char *event_class, const char **event_subclass_list, @@ -99,6 +97,8 @@ void sysevent_close_channel(sysevent_handle_t *shp); int sysevent_bind_subscriber(sysevent_handle_t *shp, void (*event_handler)(sysevent_t *ev)); +int sysevent_bind_xsubscriber(sysevent_handle_t *shp, + void (*event_handler)(sysevent_t *ev), sysevent_subattr_t *); void sysevent_unbind_subscriber(sysevent_handle_t *shp); int sysevent_bind_publisher(sysevent_handle_t *shp); void sysevent_unbind_publisher(sysevent_handle_t *shp); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/lib/libsysevent/mapfile-vers --- a/usr/src/lib/libsysevent/mapfile-vers Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/lib/libsysevent/mapfile-vers Fri Jul 30 17:04:17 2010 +1000 @@ -75,13 +75,17 @@ sysevent_attr_value; sysevent_bind_publisher; sysevent_bind_subscriber; + sysevent_bind_xhandle; + sysevent_bind_xsubscriber; sysevent_cleanup_publishers; sysevent_cleanup_subscribers; sysevent_close_channel; sysevent_dup; sysevent_evc_bind; sysevent_evc_control; + sysevent_evc_getpropnvl; sysevent_evc_publish; + sysevent_evc_setpropnvl; sysevent_evc_subscribe; sysevent_evc_unbind; sysevent_evc_unsubscribe; diff -r 19d842faf8e4 -r ab9ae749152f usr/src/pkg/manifests/SUNWcs.mf --- a/usr/src/pkg/manifests/SUNWcs.mf Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/pkg/manifests/SUNWcs.mf Fri Jul 30 17:04:17 2010 +1000 @@ -47,6 +47,7 @@ dir path=etc/inet group=sys dir path=etc/init.d group=sys dir path=etc/lib group=sys +dir path=etc/logadm.d group=sys dir path=etc/mail group=mail dir path=etc/net group=sys dir path=etc/net/ticlts group=sys @@ -579,6 +580,7 @@ file path=lib/svc/manifest/system/identity.xml group=sys mode=0444 file path=lib/svc/manifest/system/idmap.xml group=sys mode=0444 file path=lib/svc/manifest/system/keymap.xml group=sys mode=0444 +file path=lib/svc/manifest/system/logadm-upgrade.xml group=sys mode=0444 file path=lib/svc/manifest/system/manifest-import.xml group=sys mode=0444 file path=lib/svc/manifest/system/name-service-cache.xml group=sys mode=0444 file path=lib/svc/manifest/system/pfexecd.xml group=sys mode=0444 @@ -605,6 +607,7 @@ file path=lib/svc/method/inetd-upgrade mode=0555 file path=lib/svc/method/keymap mode=0555 file path=lib/svc/method/ldap-client mode=0555 +file path=lib/svc/method/logadm-upgrade mode=0555 file path=lib/svc/method/manifest-import mode=0555 file path=lib/svc/method/mpxio-upgrade mode=0555 file path=lib/svc/method/net-init mode=0555 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf --- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf Fri Jul 30 17:04:17 2010 +1000 @@ -296,6 +296,7 @@ file path=usr/lib/locale/C/LC_MESSAGES/AMD.po file path=usr/lib/locale/C/LC_MESSAGES/DISK.po file path=usr/lib/locale/C/LC_MESSAGES/FMD.po +file path=usr/lib/locale/C/LC_MESSAGES/FMNOTIFY.po file path=usr/lib/locale/C/LC_MESSAGES/GMCA.po file path=usr/lib/locale/C/LC_MESSAGES/INTEL.po file path=usr/lib/locale/C/LC_MESSAGES/NXGE.po @@ -304,6 +305,7 @@ file path=usr/lib/locale/C/LC_MESSAGES/SCA1000.po file path=usr/lib/locale/C/LC_MESSAGES/SCA500.po file path=usr/lib/locale/C/LC_MESSAGES/SCF.po +file path=usr/lib/locale/C/LC_MESSAGES/SMF.po file path=usr/lib/locale/C/LC_MESSAGES/SENSOR.po file path=usr/lib/locale/C/LC_MESSAGES/STORAGE.po file path=usr/lib/locale/C/LC_MESSAGES/SUN4.po diff -r 19d842faf8e4 -r ab9ae749152f usr/src/pkg/manifests/service-fault-management-smtp-notify.mf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkg/manifests/service-fault-management-smtp-notify.mf Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,52 @@ +# +# 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. +# + +set name=pkg.fmri value=pkg:/service/fault-management/smtp-notify@$(PKGVERS) +set name=pkg.description \ + value="smtp-notify is a small, lightweight daemon that subscribes to both software and FMA problem lifecycle events. Upon receipt of an event, it produces an email notification based on a set of notification preferences which are stored in the SMF service configuration repository." +set name=pkg.summary value="Email Notification Daemon for System Events" +set name=info.classification \ + value="org.opensolaris.category.2010:System/Administration and Configuration" +set name=variant.arch value=$(ARCH) +set name=variant.opensolaris.zone value=global value=nonglobal +dir path=lib/svc/manifest/system group=sys +dir path=lib/svc/manifest/system/fm group=sys +dir path=usr/lib +dir path=usr/lib/fm +dir path=usr/lib/fm/notify +file path=lib/svc/manifest/system/fm/smtp-notify.xml group=sys mode=0444 +file path=usr/lib/fm/notify/process_msg_template.sh mode=0555 +file path=usr/lib/fm/notify/smtp-notify mode=0555 +license cr_Sun license=cr_Sun +license lic_CDDL license=lic_CDDL +# +# snmp-notify depends on libraries delivered in this package +# +depend fmri=service/fault-management type=require +# +# snmp-notify requires the sendmail-client service in order to be able to send +# email notifications. +# +depend fmri=service/network/smtp/sendmail type=require diff -r 19d842faf8e4 -r ab9ae749152f usr/src/pkg/manifests/service-fault-management-snmp-notify.mf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkg/manifests/service-fault-management-snmp-notify.mf Fri Jul 30 17:04:17 2010 +1000 @@ -0,0 +1,51 @@ +# +# 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. +# + +set name=pkg.fmri value=pkg:/service/fault-management/snmp-notify@$(PKGVERS) +set name=pkg.description \ + value="snmp-notify is a small, lightweight daemon that subscribes to both software and FMA problem lifecycle events. Upon receipt of an event, it produces an SNMP notification based on a set of notification preferences which are stored in the SMF service configuration repository." +set name=pkg.summary value="SNMP Notification Daemon for System Events" +set name=info.classification \ + value="org.opensolaris.category.2010:System/Administration and Configuration" +set name=variant.arch value=$(ARCH) +set name=variant.opensolaris.zone value=global value=nonglobal +dir path=lib/svc/manifest/system group=sys +dir path=lib/svc/manifest/system/fm group=sys +dir path=usr/lib +dir path=usr/lib/fm +dir path=usr/lib/fm/notify +file path=lib/svc/manifest/system/fm/snmp-notify.xml group=sys mode=0444 +file path=usr/lib/fm/notify/snmp-notify mode=0555 +license cr_Sun license=cr_Sun +license lic_CDDL license=lic_CDDL +# +# snmp-notify depends on libraries delivered in this package +# +depend fmri=service/fault-management type=require +# +# snmp-notify requires the net-snmp service in order to be able to send +# SNMP notifications. +# +depend fmri=system/management/snmp/net-snmp type=require diff -r 19d842faf8e4 -r ab9ae749152f usr/src/pkg/manifests/service-fault-management.mf --- a/usr/src/pkg/manifests/service-fault-management.mf Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/pkg/manifests/service-fault-management.mf Fri Jul 30 17:04:17 2010 +1000 @@ -35,33 +35,66 @@ set name=info.classification \ value="org.opensolaris.category.2008:System/Administration and Configuration" set name=variant.arch value=$(ARCH) -dir path=etc group=sys -dir path=etc/fm group=sys -dir path=etc/fm/fmd group=sys -dir path=etc/net-snmp -dir path=etc/net-snmp/snmp -dir path=etc/net-snmp/snmp/mibs +# +# Start by describing our directory structure. +# +# The snmp mibs are common to global and non-global zones +# +dir path=etc group=sys variant.opensolaris.zone=__NODEFAULT +dir path=etc/fm group=sys variant.opensolaris.zone=__NODEFAULT +dir path=etc/fm/fmd group=sys variant.opensolaris.zone=__NODEFAULT +dir path=etc/net-snmp variant.opensolaris.zone=__NODEFAULT +dir path=etc/net-snmp/snmp variant.opensolaris.zone=__NODEFAULT +dir path=etc/net-snmp/snmp/mibs variant.opensolaris.zone=__NODEFAULT +# +# Our kernel driver is global zone only +# dir path=kernel group=sys dir path=kernel/drv group=sys dir path=kernel/drv/$(ARCH64) group=sys -dir path=usr group=sys +# +# Our service manifests are common to global and non-global zones +# +dir path=lib/svc/manifest/system group=sys \ + variant.opensolaris.zone=__NODEFAULT +dir path=lib/svc/manifest/system/fm group=sys \ + variant.opensolaris.zone=__NODEFAULT +# +# Our additional /etc/logadm.conf entries are common to global and local zones +# +dir path=etc/logadm.d group=sys variant.opensolaris.zone=__NODEFAULT +# +# usr dirs: +# - most are common to both global and non-global zones +# - those mentioning 'include' will automatically apply to both +# - dictionaries are delivered to both contexts, even if they +# are hardware dictionaries +# - eversholt rules (eft) are global zone only +# - some plugins and all schemes apply to both contexts +# - we don't deliver any topo maps to non-global zones, but we +# create the directory nonetheless; similarly for topo plugins +# - paths mentioning mdb will automatically apply to both +# - usr/platform is global zone only +# +dir path=usr group=sys variant.opensolaris.zone=__NODEFAULT dir path=usr/include dir path=usr/include/fm -dir path=usr/lib -dir path=usr/lib/fm -dir path=usr/lib/fm/$(ARCH64) -dir path=usr/lib/fm/dict +dir path=usr/lib variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm/$(ARCH64) variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm/dict variant.opensolaris.zone=__NODEFAULT dir path=usr/lib/fm/eft -dir path=usr/lib/fm/fmd -dir path=usr/lib/fm/fmd/plugins -dir path=usr/lib/fm/fmd/schemes -dir path=usr/lib/fm/fmd/schemes/$(ARCH64) -dir path=usr/lib/fm/topo -dir path=usr/lib/fm/topo/maps -dir path=usr/lib/fm/topo/plugins -dir path=usr/lib/locale -dir path=usr/lib/locale/C -dir path=usr/lib/locale/C/LC_MESSAGES +dir path=usr/lib/fm/fmd variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm/fmd/plugins variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm/fmd/schemes variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm/fmd/schemes/$(ARCH64) variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm/notify variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm/topo variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm/topo/maps variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/fm/topo/plugins variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/locale variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/locale/C variant.opensolaris.zone=__NODEFAULT +dir path=usr/lib/locale/C/LC_MESSAGES variant.opensolaris.zone=__NODEFAULT dir path=usr/lib/mdb group=sys dir path=usr/lib/mdb/proc group=sys dir path=usr/platform group=sys @@ -186,22 +219,56 @@ $(sparc_ONLY)dir path=usr/platform/sun4v/lib/fm/topo $(sparc_ONLY)dir path=usr/platform/sun4v/lib/fm/topo/maps $(sparc_ONLY)dir path=usr/platform/sun4v/lib/fm/topo/plugins -dir path=usr/sbin -dir path=usr/share group=sys -dir path=usr/share/lib group=sys -dir path=usr/share/lib/xml group=sys -dir path=usr/share/lib/xml/dtd group=sys -dir path=var/fm group=sys -dir path=var/fm/fmd group=sys -dir path=var/fm/fmd/ckpt group=sys -dir path=var/fm/fmd/rsrc group=sys -dir path=var/fm/fmd/xprt group=sys +# +# Some directories common to both global and non-global zones: +# +dir path=usr/sbin variant.opensolaris.zone=__NODEFAULT +dir path=usr/share group=sys variant.opensolaris.zone=__NODEFAULT +dir path=usr/share/lib group=sys variant.opensolaris.zone=__NODEFAULT +dir path=usr/share/lib/xml group=sys variant.opensolaris.zone=__NODEFAULT +dir path=usr/share/lib/xml/dtd group=sys variant.opensolaris.zone=__NODEFAULT +dir path=var/fm group=sys variant.opensolaris.zone=__NODEFAULT +dir path=var/fm/fmd group=sys variant.opensolaris.zone=__NODEFAULT +dir path=var/fm/fmd/ckpt group=sys variant.opensolaris.zone=__NODEFAULT +dir path=var/fm/fmd/rsrc group=sys variant.opensolaris.zone=__NODEFAULT +dir path=var/fm/fmd/xprt group=sys variant.opensolaris.zone=__NODEFAULT +# +# driver is global-zone only +# driver name=fm perms="* 0644 root sys" -file path=etc/net-snmp/snmp/fmd-trapgen.conf mode=0600 -file path=etc/net-snmp/snmp/mibs/SUN-FM-MIB.mib +# +# Now for our file and link payloads +# +# snmp MIBs are common to both global and non-global zones +# +file path=etc/net-snmp/snmp/mibs/SUN-FM-MIB.mib \ + variant.opensolaris.zone=__NODEFAULT +file path=etc/net-snmp/snmp/mibs/SUN-IREPORT-MIB.mib \ + variant.opensolaris.zone=__NODEFAULT +# +# driver is global-zone only +# file path=kernel/drv/$(ARCH64)/fm group=sys $(i386_ONLY)file path=kernel/drv/fm group=sys file path=kernel/drv/fm.conf group=sys +# +# Service manifests are common to both global and non-global zones +# +file path=lib/svc/manifest/system/fm/notify-params.xml group=sys mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=lib/svc/manifest/system/fmd.xml group=sys mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +# +# Our additional /etc/logadm.conf entries are common to global and local zones +# +file path=etc/logadm.d/fmd.logadm.conf group=sys mode=0444 \ + refresh_fmri='svc:/system/logadm-upgrade:default' \ + variant.opensolaris.zone=__NODEFAULT +# +# Headers are automatically included in both contexts. +# While some of these are from global-zone-only components +# there's no harm in including them in both contexts. +# file path=usr/include/fm/diagcode.h file path=usr/include/fm/fmd_adm.h file path=usr/include/fm/fmd_agent.h @@ -212,53 +279,110 @@ file path=usr/include/fm/fmd_snmp.h file path=usr/include/fm/libdiskstatus.h file path=usr/include/fm/libfmevent.h +file path=usr/include/fm/libfmevent_ruleset.h file path=usr/include/fm/libseslog.h file path=usr/include/fm/libtopo.h file path=usr/include/fm/topo_hc.h file path=usr/include/fm/topo_list.h file path=usr/include/fm/topo_method.h file path=usr/include/fm/topo_mod.h -file path=usr/lib/fm/$(ARCH64)/libdiagcode.so.1 -file path=usr/lib/fm/$(ARCH64)/libdiskstatus.so.1 -file path=usr/lib/fm/$(ARCH64)/libfmd_adm.so.1 -file path=usr/lib/fm/$(ARCH64)/libfmd_agent.so.1 -file path=usr/lib/fm/$(ARCH64)/libfmd_log.so.1 -file path=usr/lib/fm/$(ARCH64)/libfmd_msg.so.1 -file path=usr/lib/fm/$(ARCH64)/libfmd_snmp.so.1 -file path=usr/lib/fm/$(ARCH64)/libfmevent.so.1 +# +# 64-bit .so.1 +# +file path=usr/lib/fm/$(ARCH64)/libdiagcode.so.1 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/libdiskstatus.so.1 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/libfmd_adm.so.1 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/libfmd_agent.so.1 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/libfmd_log.so.1 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/libfmd_msg.so.1 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/libfmd_snmp.so.1 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/libfmevent.so.1 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/libfmnotify.so.1 \ + variant.opensolaris.zone=__NODEFAULT $(sparc_ONLY)file path=usr/lib/fm/$(ARCH64)/libldom.so.1 $(sparc_ONLY)file path=usr/lib/fm/$(ARCH64)/libmdesc.so.1 file path=usr/lib/fm/$(ARCH64)/libseslog.so.1 -file path=usr/lib/fm/$(ARCH64)/libtopo.so.1 -file path=usr/lib/fm/$(ARCH64)/llib-ldiagcode.ln -file path=usr/lib/fm/$(ARCH64)/llib-ldiskstatus.ln -file path=usr/lib/fm/$(ARCH64)/llib-lfmd_adm.ln -file path=usr/lib/fm/$(ARCH64)/llib-lfmd_agent.ln -file path=usr/lib/fm/$(ARCH64)/llib-lfmd_log.ln -file path=usr/lib/fm/$(ARCH64)/llib-lfmd_msg.ln -file path=usr/lib/fm/$(ARCH64)/llib-lfmd_snmp.ln -file path=usr/lib/fm/$(ARCH64)/llib-lfmevent.ln +file path=usr/lib/fm/$(ARCH64)/libtopo.so.1 \ + variant.opensolaris.zone=__NODEFAULT +# +# 64-bit lint libraries +# +file path=usr/lib/fm/$(ARCH64)/llib-ldiagcode.ln \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/llib-ldiskstatus.ln \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/llib-lfmd_adm.ln \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/llib-lfmd_agent.ln \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/llib-lfmd_log.ln \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/llib-lfmd_msg.ln \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/llib-lfmd_snmp.ln \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/llib-lfmevent.ln \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/$(ARCH64)/llib-lfmnotify.ln \ + variant.opensolaris.zone=__NODEFAULT $(sparc_ONLY)file path=usr/lib/fm/$(ARCH64)/llib-lldom.ln $(sparc_ONLY)file path=usr/lib/fm/$(ARCH64)/llib-lmdesc.ln file path=usr/lib/fm/$(ARCH64)/llib-lseslog.ln -file path=usr/lib/fm/$(ARCH64)/llib-ltopo.ln -$(i386_ONLY)file path=usr/lib/fm/dict/AMD.dict mode=0444 -file path=usr/lib/fm/dict/DISK.dict mode=0444 -file path=usr/lib/fm/dict/FMD.dict mode=0444 -$(i386_ONLY)file path=usr/lib/fm/dict/GMCA.dict mode=0444 -$(i386_ONLY)file path=usr/lib/fm/dict/INTEL.dict mode=0444 -file path=usr/lib/fm/dict/NXGE.dict mode=0444 -file path=usr/lib/fm/dict/PCI.dict mode=0444 -file path=usr/lib/fm/dict/PCIEX.dict mode=0444 -$(sparc_ONLY)file path=usr/lib/fm/dict/SCF.dict mode=0444 -file path=usr/lib/fm/dict/SENSOR.dict mode=0444 -file path=usr/lib/fm/dict/STORAGE.dict mode=0444 -$(sparc_ONLY)file path=usr/lib/fm/dict/SUN4.dict mode=0444 -$(sparc_ONLY)file path=usr/lib/fm/dict/SUN4U.dict mode=0444 -$(sparc_ONLY)file path=usr/lib/fm/dict/SUN4V.dict mode=0444 -file path=usr/lib/fm/dict/SUNOS.dict mode=0444 -file path=usr/lib/fm/dict/ZFS.dict mode=0444 -file path=usr/lib/fm/eft/disk.eft mode=0444 +file path=usr/lib/fm/$(ARCH64)/llib-ltopo.ln \ + variant.opensolaris.zone=__NODEFAULT +# +# Dictionaries, whether they are hardware-specific or not, are +# common to both global and non-global zones. +# +$(i386_ONLY)file path=usr/lib/fm/dict/AMD.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/DISK.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/FMD.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/FMNOTIFY.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(i386_ONLY)file path=usr/lib/fm/dict/GMCA.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(i386_ONLY)file path=usr/lib/fm/dict/INTEL.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/NXGE.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/PCI.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/PCIEX.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(sparc_ONLY)file path=usr/lib/fm/dict/SCF.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/SENSOR.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/STORAGE.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/SMF.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(sparc_ONLY)file path=usr/lib/fm/dict/SUN4.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(sparc_ONLY)file path=usr/lib/fm/dict/SUN4U.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(sparc_ONLY)file path=usr/lib/fm/dict/SUN4V.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/SUNOS.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/ZFS.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +# +# Eversholt rules are global zone only +# +file path=usr/lib/fm/eft/disk.eft mode=0444 \ + variant.opensolaris.zone=__NODEFAULT file path=usr/lib/fm/eft/neptune_xaui.eft mode=0444 file path=usr/lib/fm/eft/neptune_xfp.eft mode=0444 file path=usr/lib/fm/eft/pci.eft mode=0444 @@ -266,11 +390,24 @@ file path=usr/lib/fm/eft/pciexrc.eft mode=0444 file path=usr/lib/fm/eft/sensor.eft mode=0444 file path=usr/lib/fm/eft/storage.eft mode=0444 -file path=usr/lib/fm/fmd/fmd mode=0555 -file path=usr/lib/fm/fmd/fminject mode=0555 -file path=usr/lib/fm/fmd/fmsim mode=0555 -file path=usr/lib/fm/fmd/fmtopo mode=0555 +# +# usr/lib/fm/fmd executables: +# - fmd is common, as are fminject, fmsim and fmtopo +# - ipmitopo is global zone only +# +file path=usr/lib/fm/fmd/fmd mode=0555 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/fminject mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/fmsim mode=0555 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/fmtopo mode=0555 variant.opensolaris.zone=__NODEFAULT file path=usr/lib/fm/fmd/ipmitopo mode=0555 +# +# fmd plugins: +# - most are hardware-specific and so global zone only +# - ext-event-transport, ip-transport, syslog-msgs, +# software-diagnosis and software-response +# are common to both contexts +# file path=usr/lib/fm/fmd/plugins/cpumem-retire.conf file path=usr/lib/fm/fmd/plugins/cpumem-retire.so mode=0555 file path=usr/lib/fm/fmd/plugins/disk-monitor.conf @@ -279,110 +416,197 @@ file path=usr/lib/fm/fmd/plugins/disk-transport.so mode=0555 file path=usr/lib/fm/fmd/plugins/eft.conf file path=usr/lib/fm/fmd/plugins/eft.so mode=0555 -file path=usr/lib/fm/fmd/plugins/ext-event-transport.conf -file path=usr/lib/fm/fmd/plugins/ext-event-transport.so mode=0555 +file path=usr/lib/fm/fmd/plugins/ext-event-transport.conf \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/plugins/ext-event-transport.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT file path=usr/lib/fm/fmd/plugins/fabric-xlate.conf file path=usr/lib/fm/fmd/plugins/fabric-xlate.so mode=0555 file path=usr/lib/fm/fmd/plugins/fdd-msg.conf file path=usr/lib/fm/fmd/plugins/fdd-msg.so mode=0555 file path=usr/lib/fm/fmd/plugins/io-retire.conf file path=usr/lib/fm/fmd/plugins/io-retire.so mode=0555 -file path=usr/lib/fm/fmd/plugins/ip-transport.conf -file path=usr/lib/fm/fmd/plugins/ip-transport.so mode=0555 +file path=usr/lib/fm/fmd/plugins/ip-transport.conf \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/plugins/ip-transport.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT file path=usr/lib/fm/fmd/plugins/sensor-transport.conf file path=usr/lib/fm/fmd/plugins/sensor-transport.so mode=0555 file path=usr/lib/fm/fmd/plugins/ses-log-transport.conf file path=usr/lib/fm/fmd/plugins/ses-log-transport.so mode=0555 -file path=usr/lib/fm/fmd/plugins/snmp-trapgen.conf -file path=usr/lib/fm/fmd/plugins/snmp-trapgen.so mode=0555 +file path=usr/lib/fm/fmd/plugins/software-diagnosis.conf \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/plugins/software-diagnosis.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/plugins/software-response.conf \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/plugins/software-response.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT file path=usr/lib/fm/fmd/plugins/sp-monitor.conf file path=usr/lib/fm/fmd/plugins/sp-monitor.so mode=0555 -file path=usr/lib/fm/fmd/plugins/syslog-msgs.conf -file path=usr/lib/fm/fmd/plugins/syslog-msgs.so mode=0555 +file path=usr/lib/fm/fmd/plugins/syslog-msgs.conf \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/plugins/syslog-msgs.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT file path=usr/lib/fm/fmd/plugins/zfs-diagnosis.conf file path=usr/lib/fm/fmd/plugins/zfs-diagnosis.so mode=0555 file path=usr/lib/fm/fmd/plugins/zfs-retire.conf file path=usr/lib/fm/fmd/plugins/zfs-retire.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/cpu.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/dev.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/fmd.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/hc.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/legacy-hc.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/mem.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/mod.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/pkg.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/svc.so mode=0555 -file path=usr/lib/fm/fmd/schemes/$(ARCH64)/zfs.so mode=0555 -file path=usr/lib/fm/fmd/schemes/cpu.so mode=0555 -file path=usr/lib/fm/fmd/schemes/dev.so mode=0555 -file path=usr/lib/fm/fmd/schemes/fmd.so mode=0555 -file path=usr/lib/fm/fmd/schemes/hc.so mode=0555 -file path=usr/lib/fm/fmd/schemes/legacy-hc.so mode=0555 -file path=usr/lib/fm/fmd/schemes/mem.so mode=0555 -file path=usr/lib/fm/fmd/schemes/mod.so mode=0555 -file path=usr/lib/fm/fmd/schemes/pkg.so mode=0555 -file path=usr/lib/fm/fmd/schemes/svc.so mode=0555 -file path=usr/lib/fm/fmd/schemes/zfs.so mode=0555 -file path=usr/lib/fm/libdiagcode.so.1 -file path=usr/lib/fm/libdiskstatus.so.1 -file path=usr/lib/fm/libfmd_adm.so.1 -file path=usr/lib/fm/libfmd_agent.so.1 -file path=usr/lib/fm/libfmd_log.so.1 -file path=usr/lib/fm/libfmd_msg.so.1 -file path=usr/lib/fm/libfmd_snmp.so.1 -file path=usr/lib/fm/libfmevent.so.1 +# +# fmri scheme support: all are common to both global and non-global zones +# +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/cpu.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/dev.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/fmd.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/hc.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/legacy-hc.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/mem.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/mod.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/pkg.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/svc.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/sw.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/$(ARCH64)/zfs.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/cpu.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/dev.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/fmd.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/hc.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/legacy-hc.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/mem.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/mod.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/pkg.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/svc.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/sw.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/fmd/schemes/zfs.so mode=0555 \ + variant.opensolaris.zone=__NODEFAULT +# +# Libraries for usr/lib/fm; we include these in both global and non-global +# contexts except for the ldom and seslog libraries. +# +# +# 32-bit .so.1 +# +file path=usr/lib/fm/libdiagcode.so.1 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/libdiskstatus.so.1 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/libfmd_adm.so.1 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/libfmd_agent.so.1 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/libfmd_log.so.1 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/libfmd_msg.so.1 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/libfmd_snmp.so.1 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/libfmevent.so.1 variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/libfmnotify.so.1 variant.opensolaris.zone=__NODEFAULT $(sparc_ONLY)file path=usr/lib/fm/libldom.so.1 $(sparc_ONLY)file path=usr/lib/fm/libmdesc.so.1 file path=usr/lib/fm/libseslog.so.1 -file path=usr/lib/fm/libtopo.so.1 -file path=usr/lib/fm/llib-ldiagcode -file path=usr/lib/fm/llib-ldiagcode.ln -file path=usr/lib/fm/llib-ldiskstatus -file path=usr/lib/fm/llib-ldiskstatus.ln -file path=usr/lib/fm/llib-lfmd_adm -file path=usr/lib/fm/llib-lfmd_adm.ln -file path=usr/lib/fm/llib-lfmd_agent -file path=usr/lib/fm/llib-lfmd_agent.ln -file path=usr/lib/fm/llib-lfmd_log -file path=usr/lib/fm/llib-lfmd_log.ln -file path=usr/lib/fm/llib-lfmd_msg -file path=usr/lib/fm/llib-lfmd_msg.ln -file path=usr/lib/fm/llib-lfmd_snmp -file path=usr/lib/fm/llib-lfmd_snmp.ln -file path=usr/lib/fm/llib-lfmevent -file path=usr/lib/fm/llib-lfmevent.ln +file path=usr/lib/fm/libtopo.so.1 variant.opensolaris.zone=__NODEFAULT +# +# 32-bit lint libraries +# +file path=usr/lib/fm/llib-ldiagcode variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-ldiagcode.ln variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-ldiskstatus variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-ldiskstatus.ln variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_adm variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_adm.ln variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_agent variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_agent.ln variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_log variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_log.ln variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_msg variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_msg.ln variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_snmp variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmd_snmp.ln variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmevent variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmevent.ln variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmnotify variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-lfmnotify.ln variant.opensolaris.zone=__NODEFAULT $(sparc_ONLY)file path=usr/lib/fm/llib-lldom $(sparc_ONLY)file path=usr/lib/fm/llib-lldom.ln $(sparc_ONLY)file path=usr/lib/fm/llib-lmdesc $(sparc_ONLY)file path=usr/lib/fm/llib-lmdesc.ln file path=usr/lib/fm/llib-lseslog file path=usr/lib/fm/llib-lseslog.ln -file path=usr/lib/fm/llib-ltopo -file path=usr/lib/fm/llib-ltopo.ln +file path=usr/lib/fm/llib-ltopo variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/llib-ltopo.ln variant.opensolaris.zone=__NODEFAULT +# +# Topo xml maps are all global-zone only +# file path=usr/lib/fm/topo/maps/xfp-hc-topology.xml mode=0444 file path=usr/lib/fm/topo/plugins/disk.so mode=0555 file path=usr/lib/fm/topo/plugins/fac_prov_ipmi.so mode=0555 file path=usr/lib/fm/topo/plugins/ipmi.so mode=0555 file path=usr/lib/fm/topo/plugins/ses.so mode=0555 file path=usr/lib/fm/topo/plugins/xfp.so mode=0555 -$(i386_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/AMD.mo mode=0444 -file path=usr/lib/locale/C/LC_MESSAGES/DISK.mo mode=0444 -file path=usr/lib/locale/C/LC_MESSAGES/FMD.mo mode=0444 -$(i386_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/GMCA.mo mode=0444 -$(i386_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/INTEL.mo mode=0444 -file path=usr/lib/locale/C/LC_MESSAGES/NXGE.mo mode=0444 -file path=usr/lib/locale/C/LC_MESSAGES/PCI.mo mode=0444 -file path=usr/lib/locale/C/LC_MESSAGES/PCIEX.mo mode=0444 -$(sparc_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/SCF.mo mode=0444 -file path=usr/lib/locale/C/LC_MESSAGES/SENSOR.mo mode=0444 -file path=usr/lib/locale/C/LC_MESSAGES/STORAGE.mo mode=0444 -$(sparc_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/SUN4.mo mode=0444 -$(sparc_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/SUN4U.mo mode=0444 -$(sparc_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/SUN4V.mo mode=0444 -file path=usr/lib/locale/C/LC_MESSAGES/SUNOS.mo mode=0444 -file path=usr/lib/locale/C/LC_MESSAGES/ZFS.mo mode=0444 +# +# Dictionaries, whether they are hardware-specific or not, are +# common to both global and non-global zones. +# +$(i386_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/AMD.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/DISK.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/FMD.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/FMNOTIFY.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(i386_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/GMCA.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(i386_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/INTEL.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/NXGE.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/PCI.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/PCIEX.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(sparc_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/SCF.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/SENSOR.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/STORAGE.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/SMF.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(sparc_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/SUN4.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(sparc_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/SUN4U.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +$(sparc_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/SUN4V.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/SUNOS.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/ZFS.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT +# +# mdb support will automatically be included in both contexts; +# we allow eft.so to be included despite not delivering +# the eft plugin in non-global zones +# file path=usr/lib/mdb/proc/eft.so group=sys mode=0555 file path=usr/lib/mdb/proc/fmd.so group=sys mode=0555 +# +# Platform-specific fmd plugins are global zone only +# $(sparc_ONLY)file \ path=usr/platform/SUNW,Netra-CP3060/lib/fm/fmd/plugins/etm.conf $(sparc_ONLY)file \ @@ -607,10 +831,20 @@ mode=0555 $(sparc_ONLY)file path=usr/platform/sun4v/lib/fm/topo/plugins/zambezi.so \ mode=0555 -file path=usr/sbin/fmadm mode=0555 -file path=usr/sbin/fmdump mode=0555 -file path=usr/sbin/fmstat mode=0555 -file path=usr/share/lib/xml/dtd/topology.dtd.1 +# +# Administrative utilities are common to both contexts +# +file path=usr/sbin/fmadm mode=0555 variant.opensolaris.zone=__NODEFAULT +file path=usr/sbin/fmdump mode=0555 variant.opensolaris.zone=__NODEFAULT +file path=usr/sbin/fmstat mode=0555 variant.opensolaris.zone=__NODEFAULT +# +# Topo DTD is also common +# +file path=usr/share/lib/xml/dtd/topology.dtd.1 \ + variant.opensolaris.zone=__NODEFAULT +# +# legacy packaging and license +# legacy pkg=SUNWfmd arch=$(ARCH) category=system \ desc="Fault Management Daemon and Utilities" \ hotline="Please contact your local service provider" \ @@ -623,30 +857,61 @@ vendor="Sun Microsystems, Inc." version=11.11,REV=2009.11.11 license cr_Sun license=cr_Sun license lic_CDDL license=lic_CDDL -link path=usr/lib/fm/$(ARCH64)/libdiagcode.so target=./libdiagcode.so.1 -link path=usr/lib/fm/$(ARCH64)/libdiskstatus.so target=./libdiskstatus.so.1 -link path=usr/lib/fm/$(ARCH64)/libfmd_adm.so target=./libfmd_adm.so.1 -link path=usr/lib/fm/$(ARCH64)/libfmd_agent.so target=./libfmd_agent.so.1 -link path=usr/lib/fm/$(ARCH64)/libfmd_log.so target=./libfmd_log.so.1 -link path=usr/lib/fm/$(ARCH64)/libfmd_msg.so target=./libfmd_msg.so.1 -link path=usr/lib/fm/$(ARCH64)/libfmd_snmp.so target=./libfmd_snmp.so.1 -link path=usr/lib/fm/$(ARCH64)/libfmevent.so target=./libfmevent.so.1 +# +# 64-bit .so symlinks +# +link path=usr/lib/fm/$(ARCH64)/libdiagcode.so target=./libdiagcode.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/$(ARCH64)/libdiskstatus.so target=./libdiskstatus.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/$(ARCH64)/libfmd_adm.so target=./libfmd_adm.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/$(ARCH64)/libfmd_agent.so target=./libfmd_agent.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/$(ARCH64)/libfmd_log.so target=./libfmd_log.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/$(ARCH64)/libfmd_msg.so target=./libfmd_msg.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/$(ARCH64)/libfmd_snmp.so target=./libfmd_snmp.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/$(ARCH64)/libfmevent.so target=./libfmevent.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/$(ARCH64)/libfmnotify.so target=./libfmnotify.so.1 \ + variant.opensolaris.zone=__NODEFAULT $(sparc_ONLY)link path=usr/lib/fm/$(ARCH64)/libldom.so target=libldom.so.1 $(sparc_ONLY)link path=usr/lib/fm/$(ARCH64)/libmdesc.so target=libmdesc.so.1 link path=usr/lib/fm/$(ARCH64)/libseslog.so target=./libseslog.so.1 -link path=usr/lib/fm/$(ARCH64)/libtopo.so target=libtopo.so.1 -link path=usr/lib/fm/libdiagcode.so target=libdiagcode.so.1 -link path=usr/lib/fm/libdiskstatus.so target=libdiskstatus.so.1 -link path=usr/lib/fm/libfmd_adm.so target=libfmd_adm.so.1 -link path=usr/lib/fm/libfmd_agent.so target=libfmd_agent.so.1 -link path=usr/lib/fm/libfmd_log.so target=libfmd_log.so.1 -link path=usr/lib/fm/libfmd_msg.so target=libfmd_msg.so.1 -link path=usr/lib/fm/libfmd_snmp.so target=libfmd_snmp.so.1 -link path=usr/lib/fm/libfmevent.so target=libfmevent.so.1 +link path=usr/lib/fm/$(ARCH64)/libtopo.so target=libtopo.so.1 \ + variant.opensolaris.zone=__NODEFAULT +# +# 32-bit .so symlinks +# +link path=usr/lib/fm/libdiagcode.so target=libdiagcode.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/libdiskstatus.so target=libdiskstatus.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/libfmd_adm.so target=libfmd_adm.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/libfmd_agent.so target=libfmd_agent.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/libfmd_log.so target=libfmd_log.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/libfmd_msg.so target=libfmd_msg.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/libfmd_snmp.so target=libfmd_snmp.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/libfmevent.so target=libfmevent.so.1 \ + variant.opensolaris.zone=__NODEFAULT +link path=usr/lib/fm/libfmnotify.so target=libfmnotify.so.1 \ + variant.opensolaris.zone=__NODEFAULT $(sparc_ONLY)link path=usr/lib/fm/libldom.so target=libldom.so.1 $(sparc_ONLY)link path=usr/lib/fm/libmdesc.so target=libmdesc.so.1 link path=usr/lib/fm/libseslog.so target=libseslog.so.1 -link path=usr/lib/fm/libtopo.so target=libtopo.so.1 +link path=usr/lib/fm/libtopo.so target=libtopo.so.1 \ + variant.opensolaris.zone=__NODEFAULT +# +# symlinks for fmd plugins for particular platforms +# $(sparc_ONLY)link \ path=usr/platform/SUNW,Netra-CP3060/lib/fm/fmd/plugins/etm.so \ target=../../../../../sun4v/lib/fm/fmd/plugins/etm.so diff -r 19d842faf8e4 -r ab9ae749152f usr/src/pkg/manifests/system-kernel.mf --- a/usr/src/pkg/manifests/system-kernel.mf Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/pkg/manifests/system-kernel.mf Fri Jul 30 17:04:17 2010 +1000 @@ -773,7 +773,6 @@ $(i386_ONLY)file path=kernel/sys/semsys group=sys mode=0755 $(i386_ONLY)file path=kernel/sys/shmsys group=sys mode=0755 file path=lib/svc/manifest/system/dumpadm.xml group=sys mode=0444 -file path=lib/svc/manifest/system/fmd.xml group=sys mode=0444 file path=lib/svc/manifest/system/intrd.xml group=sys mode=0444 file path=lib/svc/manifest/system/scheduler.xml group=sys mode=0444 file path=lib/svc/method/svc-dumpadm mode=0555 diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/io/dump.c --- a/usr/src/uts/common/io/dump.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/io/dump.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -95,6 +94,8 @@ uint64_t dumpsize_in_pages; int error = 0; char *pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); + char uuidbuf[36 + 1]; + size_t len; vnode_t *vp; switch (cmd) { @@ -190,6 +191,23 @@ mutex_exit(&dump_lock); break; + case DIOCSETUUID: + if ((error = copyinstr((char *)arg, uuidbuf, sizeof (uuidbuf), + &len)) != 0) + break; + + if (len != 37) { + error = EINVAL; + break; + } + + error = dump_set_uuid(uuidbuf); + break; + + case DIOCGETUUID: + error = copyoutstr(dump_get_uuid(), (void *)arg, 37, NULL); + break; + default: error = ENXIO; } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/io/sysevent.c --- a/usr/src/uts/common/io/sysevent.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/io/sysevent.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -471,6 +470,116 @@ return (rc); } +/* ARGSUSED */ +static int +sysevent_setpropnvl(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr) +{ + sev_propnvl_args_t uargs; + nvlist_t *nvl = NULL; + evchan_ctl_t *ctl; + size_t bufsz; + char *buf; + + ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev)); + if (ctl == NULL || ctl->chp == NULL) + return (ENXIO); + + if (copyin(arg, &uargs, sizeof (uargs)) != 0) + return (EFAULT); + + if (uargs.packednvl.name != 0) { + bufsz = uargs.packednvl.len; + + if (bufsz == 0) + return (EINVAL); + + if (bufsz > EVCH_MAX_DATA_SIZE) + return (EOVERFLOW); + + buf = kmem_alloc(bufsz, KM_SLEEP); + + if (copyin((void *)(uintptr_t)uargs.packednvl.name, buf, + bufsz) != 0 || + nvlist_unpack(buf, bufsz, &nvl, KM_SLEEP) != 0) { + kmem_free(buf, bufsz); + return (EFAULT); + } + + kmem_free(buf, bufsz); + + if (nvl == NULL) + return (EINVAL); + } + + evch_usrsetpropnvl(ctl->chp, nvl); + return (0); +} + +/* ARGSUSED */ +static int +sysevent_getpropnvl(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr) +{ + sev_propnvl_args_t uargs; + size_t reqsz, avlsz; + evchan_ctl_t *ctl; + nvlist_t *nvl; + int64_t gen; + int rc; + + ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev)); + + if (ctl == NULL || ctl->chp == NULL) + return (ENXIO); + + if (copyin(arg, &uargs, sizeof (uargs)) != 0) + return (EFAULT); + + if ((rc = evch_usrgetpropnvl(ctl->chp, &nvl, &gen)) != 0) + return (rc); + + if (nvl != NULL) { + avlsz = uargs.packednvl.len; + + if (nvlist_size(nvl, &reqsz, NV_ENCODE_NATIVE) != 0) { + nvlist_free(nvl); + return (EINVAL); + } + + if (reqsz > EVCH_MAX_DATA_SIZE) { + nvlist_free(nvl); + return (E2BIG); + } + + if (reqsz <= avlsz) { + char *buf = kmem_alloc(reqsz, KM_SLEEP); + + if (nvlist_pack(nvl, &buf, &reqsz, + NV_ENCODE_NATIVE, 0) != 0 || copyout(buf, + (void *)(uintptr_t)uargs.packednvl.name, + reqsz) != 0) { + kmem_free(buf, reqsz); + nvlist_free(nvl); + return (EFAULT); + } + kmem_free(buf, reqsz); + rc = 0; + } else { + rc = EOVERFLOW; + } + uargs.packednvl.len = (uint32_t)reqsz; + nvlist_free(nvl); + } else { + uargs.packednvl.len = 0; + rc = 0; + } + + uargs.generation = gen; + if (copyout((void *)&uargs, arg, sizeof (uargs)) != 0) + rc = EFAULT; + + return (rc); +} + /*ARGSUSED*/ static int sysevent_ioctl(dev_t dev, int cmd, intptr_t arg, @@ -500,6 +609,12 @@ case SEV_CHANDATA: rc = sysevent_chandata(dev, rvalp, (void *)arg, flag, cr); break; + case SEV_SETPROPNVL: + rc = sysevent_setpropnvl(dev, rvalp, (void *)arg, flag, cr); + break; + case SEV_GETPROPNVL: + rc = sysevent_getpropnvl(dev, rvalp, (void *)arg, flag, cr); + break; default: rc = EINVAL; } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/os/dumpsubr.c --- a/usr/src/uts/common/os/dumpsubr.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/os/dumpsubr.c Fri Jul 30 17:04:17 2010 +1000 @@ -107,6 +107,7 @@ int dump_timeleft; /* portion of dump_timeout remaining */ int dump_ioerr; /* dump i/o error */ int dump_check_used; /* enable check for used pages */ +char *dump_stack_scratch; /* scratch area for saving stack summary */ /* * Tunables for dump compression and parallelism. These can be set via @@ -258,6 +259,12 @@ int off; /* byte offset to first pfn */ }; +static char dump_osimage_uuid[36 + 1]; + +#define isdigit(ch) ((ch) >= '0' && (ch) <= '9') +#define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \ + ((ch) >= 'A' && (ch) <= 'F')) + /* * cqueue_t queues: a uni-directional channel for communication * from the master to helper tasks or vice-versa using put and @@ -1103,6 +1110,9 @@ dumpcfg.pids = kmem_alloc(v.v_proc * sizeof (pid_t), KM_SLEEP); dumpcfg.helpermap = kmem_zalloc(BT_SIZEOFMAP(NCPU), KM_SLEEP); LOCK_INIT_HELD(&dumpcfg.helper_lock); + dump_stack_scratch = kmem_alloc(STACK_BUF_SIZE, KM_SLEEP); + (void) strncpy(dumphdr->dump_uuid, dump_get_uuid(), + sizeof (dumphdr->dump_uuid)); } npages = num_phys_pages(); @@ -1436,6 +1446,48 @@ return (0); } +/* + * The following functions (dump_summary(), dump_ereports(), and + * dump_messages()), write data to an uncompressed area within the + * crashdump. The layout of these is + * + * +------------------------------------------------------------+ + * | compressed pages | summary | ereports | messages | + * +------------------------------------------------------------+ + * + * With the advent of saving a compressed crash dump by default, we + * need to save a little more data to describe the failure mode in + * an uncompressed buffer available before savecore uncompresses + * the dump. Initially this is a copy of the stack trace. Additional + * summary information should be added here. + */ + +void +dump_summary(void) +{ + u_offset_t dumpvp_start; + summary_dump_t sd; + + if (dumpvp == NULL || dumphdr == NULL) + return; + + dumpbuf.cur = dumpbuf.start; + + dumpbuf.vp_limit = dumpvp_size - (DUMP_OFFSET + DUMP_LOGSIZE + + DUMP_ERPTSIZE); + dumpvp_start = dumpbuf.vp_limit - DUMP_SUMMARYSIZE; + dumpbuf.vp_off = dumpvp_start; + + sd.sd_magic = SUMMARY_MAGIC; + sd.sd_ssum = checksum32(dump_stack_scratch, STACK_BUF_SIZE); + dumpvp_write(&sd, sizeof (sd)); + dumpvp_write(dump_stack_scratch, STACK_BUF_SIZE); + + sd.sd_magic = 0; /* indicate end of summary */ + dumpvp_write(&sd, sizeof (sd)); + (void) dumpvp_flush(); +} + void dump_ereports(void) { @@ -2859,6 +2911,10 @@ size -= datahdr.dump_metrics; } + /* record in the header whether this is a fault-management panic */ + if (panicstr) + dumphdr->dump_fm_panic = is_fm_panic(); + /* compression info in data header */ datahdr.dump_datahdr_magic = DUMP_DATAHDR_MAGIC; datahdr.dump_datahdr_version = DUMP_DATAHDR_VERSION; @@ -2905,6 +2961,7 @@ * thing we do because the dump process itself emits messages. */ if (panicstr) { + dump_summary(); dump_ereports(); dump_messages(); } @@ -2967,3 +3024,47 @@ mutex_exit(&dump_lock); return (0); } + +int +dump_set_uuid(const char *uuidstr) +{ + const char *ptr; + int i; + + if (uuidstr == NULL || strnlen(uuidstr, 36 + 1) != 36) + return (EINVAL); + + /* uuid_parse is not common code so check manually */ + for (i = 0, ptr = uuidstr; i < 36; i++, ptr++) { + switch (i) { + case 8: + case 13: + case 18: + case 23: + if (*ptr != '-') + return (EINVAL); + break; + + default: + if (!isxdigit(*ptr)) + return (EINVAL); + break; + } + } + + if (dump_osimage_uuid[0] != '\0') + return (EALREADY); + + (void) strncpy(dump_osimage_uuid, uuidstr, 36 + 1); + + cmn_err(CE_CONT, "?This Solaris instance has UUID %s", + dump_osimage_uuid); + + return (0); +} + +const char * +dump_get_uuid(void) +{ + return (dump_osimage_uuid[0] != '\0' ? dump_osimage_uuid : ""); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/os/evchannels.c --- a/usr/src/uts/common/os/evchannels.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/os/evchannels.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -1165,6 +1164,8 @@ mutex_exit(&chp->ch_mutex); evch_dl_del(&eg->evch_list, &chp->ch_link); evch_evq_destroy(chp->ch_queue); + if (chp->ch_propnvl) + nvlist_free(chp->ch_propnvl); mutex_destroy(&chp->ch_mutex); mutex_destroy(&chp->ch_pubmx); cv_destroy(&chp->ch_pubcv); @@ -1564,6 +1565,47 @@ return (chdlen + buflen); } +static void +evch_chsetpropnvl(evch_bind_t *bp, nvlist_t *nvl) +{ + evch_chan_t *chp = bp->bd_channel; + + mutex_enter(&chp->ch_mutex); + + if (chp->ch_propnvl) + nvlist_free(chp->ch_propnvl); + + chp->ch_propnvl = nvl; + chp->ch_propnvlgen++; + + mutex_exit(&chp->ch_mutex); +} + +static int +evch_chgetpropnvl(evch_bind_t *bp, nvlist_t **nvlp, int64_t *genp) +{ + evch_chan_t *chp = bp->bd_channel; + int rc = 0; + + mutex_enter(&chp->ch_mutex); + + if (chp->ch_propnvl != NULL) + rc = (nvlist_dup(chp->ch_propnvl, nvlp, 0) == 0) ? 0 : ENOMEM; + else + *nvlp = NULL; /* rc still 0 */ + + if (genp) + *genp = chp->ch_propnvlgen; + + mutex_exit(&chp->ch_mutex); + + if (rc != 0) + *nvlp = NULL; + + return (rc); + +} + /* * Init iteration of all events of a channel. This function creates a new * event queue and puts all events from the channel into that queue. @@ -1718,6 +1760,8 @@ * sysevent_evc_unsubscribe - Unsubscribe from an event class * sysevent_evc_publish - Publish an event to an event channel * sysevent_evc_control - Various control operation on event channel + * sysevent_evc_setpropnvl - Set channel property nvlist + * sysevent_evc_getpropnvl - Get channel property nvlist * * The function below are for evaluating a sysevent: * @@ -1971,6 +2015,25 @@ return (rc); } +int +sysevent_evc_setpropnvl(evchan_t *scp, nvlist_t *nvl) +{ + nvlist_t *nvlcp = nvl; + + if (nvl != NULL && nvlist_dup(nvl, &nvlcp, 0) != 0) + return (ENOMEM); + + evch_chsetpropnvl((evch_bind_t *)scp, nvlcp); + + return (0); +} + +int +sysevent_evc_getpropnvl(evchan_t *scp, nvlist_t **nvlp) +{ + return (evch_chgetpropnvl((evch_bind_t *)scp, nvlp, NULL)); +} + /* * Project private interface to take a snapshot of all events of the * specified event channel. Argument subscr may be a subscriber id, the empty @@ -2130,6 +2193,8 @@ * evch_usrcontrol_get - Get channel properties * evch_usrgetchnames - Get list of channel names * evch_usrgetchdata - Get data of an event channel + * evch_usrsetpropnvl - Set channel properties nvlist + * evch_usrgetpropnvl - Get channel properties nvlist */ evchan_t * evch_usrchanopen(const char *name, uint32_t flags, int *err) @@ -2267,3 +2332,15 @@ { return (evch_chgetchdata(chname, buf, size)); } + +void +evch_usrsetpropnvl(evchan_t *bp, nvlist_t *nvl) +{ + evch_chsetpropnvl((evch_bind_t *)bp, nvl); +} + +int +evch_usrgetpropnvl(evchan_t *bp, nvlist_t **nvlp, int64_t *genp) +{ + return (evch_chgetpropnvl((evch_bind_t *)bp, nvlp, genp)); +} diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/os/fm.c --- a/usr/src/uts/common/os/fm.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/os/fm.c Fri Jul 30 17:04:17 2010 +1000 @@ -384,6 +384,20 @@ } /* + * Simply tell the caller if fm_panicstr is set, ie. an fma event has + * caused the panic. If so, something other than the default panic + * diagnosis method will diagnose the cause of the panic. + */ +int +is_fm_panic() +{ + if (fm_panicstr) + return (1); + else + return (0); +} + +/* * Print any appropriate FMA banner message before the panic message. This * function is called by panicsys() and prints the message for fm_panic(). * We print the message here so that it comes after the system is quiesced. diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/os/log_sysevent.c --- a/usr/src/uts/common/os/log_sysevent.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/os/log_sysevent.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -280,11 +277,11 @@ } if (retry > 4) { LOG_DEBUG((CE_CONT, - "log_event_upcall: ebadf\n")); + "log_event_upcall: ebadf\n")); return (EBADF); } LOG_DEBUG((CE_CONT, "log_event_upcall: " - "retrying upcall after lookup\n")); + "retrying upcall after lookup\n")); darg = save_arg; break; default: @@ -297,14 +294,14 @@ if (neagain > 0 || neintr > 0) { LOG_DEBUG((CE_CONT, "upcall: eagain=%d eintr=%d nticks=%d\n", - neagain, neintr, nticks)); + neagain, neintr, nticks)); } LOG_DEBUG1((CE_CONT, "log_event_upcall:\n\t" - "error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n", - error, (void *)arg, (void *)darg.rbuf, - (void *)darg.data_ptr, - *((int *)(darg.rbuf)), *((int *)(darg.data_ptr)))); + "error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n", + error, (void *)arg, (void *)darg.rbuf, + (void *)darg.data_ptr, + *((int *)(darg.rbuf)), *((int *)(darg.data_ptr)))); if (!error) { /* @@ -334,7 +331,7 @@ callb_cpr_t cprinfo; CALLB_CPR_INIT(&cprinfo, &eventq_head_mutex, callb_generic_cpr, - "logevent"); + "logevent"); /* * eventq_head_mutex is exited (released) when there are no more @@ -440,7 +437,7 @@ break; default: LOG_DEBUG((CE_CONT, "log_event_deliver: " - "upcall err %d\n", upcall_err)); + "upcall err %d\n", upcall_err)); sysevent_upcall_status = upcall_err; /* * Signal everyone waiting that transport is down @@ -521,8 +518,8 @@ aligned_pub_sz = SE_ALIGN(pub_sz); payload_sz = (aligned_class_sz - sizeof (uint64_t)) + - (aligned_subclass_sz - sizeof (uint64_t)) + - (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t); + (aligned_subclass_sz - sizeof (uint64_t)) + + (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t); /* * Allocate event buffer plus additional sysevent queue @@ -1611,7 +1608,7 @@ /* Unbind old event door */ if (logevent_door_upcall_filename) { kmem_free(logevent_door_upcall_filename, - logevent_door_upcall_filename_size); + logevent_door_upcall_filename_size); if (event_door) { door_ki_rele(event_door); event_door = NULL; @@ -1619,7 +1616,7 @@ } logevent_door_upcall_filename_size = strlen(file) + 1; logevent_door_upcall_filename = kmem_alloc( - logevent_door_upcall_filename_size, KM_SLEEP); + logevent_door_upcall_filename_size, KM_SLEEP); (void) strcpy(logevent_door_upcall_filename, file); /* @@ -1698,7 +1695,7 @@ /* Time stamp and assign ID */ SE_SEQ(ev) = eid->eid_seq = atomic_add_64_nv(&kernel_event_id, - (uint64_t)1); + (uint64_t)1); SE_TIME(ev) = eid->eid_ts = gethrtime(); LOG_DEBUG1((CE_CONT, "log_sysevent: class=%d type=%d id=0x%llx\n", @@ -1756,7 +1753,7 @@ } rval = queue_sysevent(ev_copy, eid, flag); ASSERT(rval == 0 || rval == SE_ENOMEM || rval == SE_EQSIZE || - rval == SE_NO_TRANSPORT); + rval == SE_NO_TRANSPORT); ASSERT(!(flag == SE_SLEEP && (rval == SE_EQSIZE || rval == SE_ENOMEM))); return (rval); } @@ -1775,7 +1772,7 @@ log_eventq_t *qcopy; copy_sz = ev_size + offsetof(log_eventq_t, arg) + - offsetof(log_event_upcall_arg_t, buf); + offsetof(log_event_upcall_arg_t, buf); qcopy = kmem_zalloc(copy_sz, KM_SLEEP); ev_copy = (sysevent_t *)&qcopy->arg.buf; @@ -1825,8 +1822,8 @@ if (sleep_flag == DDI_SLEEP && servicing_interrupt()) { cmn_err(CE_NOTE, "!ddi_log_syevent: driver %s%d - cannot queue " - "event from interrupt context with sleep semantics\n", - ddi_driver_name(dip), ddi_get_instance(dip)); + "event from interrupt context with sleep semantics\n", + ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_ECONTEXT); } @@ -1836,7 +1833,7 @@ publisher = pubstr; } else { publisher = kmem_alloc(n, - (sleep_flag == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); + (sleep_flag == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); if (publisher == NULL) { return (DDI_ENOMEM); } @@ -1880,7 +1877,7 @@ } uint64_t -log_sysevent_new_id() +log_sysevent_new_id(void) { return (atomic_add_64_nv(&kernel_event_id, (uint64_t)1)); } diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/os/panic.c --- a/usr/src/uts/common/os/panic.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/os/panic.c Fri Jul 30 17:04:17 2010 +1000 @@ -256,6 +256,9 @@ pdp->pd_version = PANICBUFVERS; pdp->pd_msgoff = sizeof (panic_data_t) - sizeof (panic_nv_t); + (void) strncpy(pdp->pd_uuid, dump_get_uuid(), + sizeof (pdp->pd_uuid)); + if (t->t_panic_trap != NULL) panic_savetrap(pdp, t->t_panic_trap); else diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/sys/dumpadm.h --- a/usr/src/uts/common/sys/dumpadm.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/sys/dumpadm.h Fri Jul 30 17:04:17 2010 +1000 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright (c) 1998-2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_DUMPADM_H #define _SYS_DUMPADM_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -44,6 +40,8 @@ #define DIOCSETDEV (DDIOC | 0x14) #define DIOCTRYDEV (DDIOC | 0x15) #define DIOCDUMP (DDIOC | 0x16) +#define DIOCSETUUID (DDIOC | 0x17) +#define DIOCGETUUID (DDIOC | 0x18) /* * Kernel-controlled dump state flags for dump_conflags diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/sys/dumphdr.h --- a/usr/src/uts/common/sys/dumphdr.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/sys/dumphdr.h Fri Jul 30 17:04:17 2010 +1000 @@ -43,7 +43,7 @@ * overwritten by swap activity. See dumpadm(1M) for dump configuration. */ #define DUMP_MAGIC 0xdefec8edU /* dump magic number */ -#define DUMP_VERSION 9 /* version of this dumphdr */ +#define DUMP_VERSION 10 /* version of this dumphdr */ #define DUMP_WORDSIZE (sizeof (long) * NBBY) /* word size (32 or 64) */ #define DUMP_PANICSIZE 200 /* Max panic string copied */ #define DUMP_COMPRESS_RATIO 2 /* conservative; usually 2.5+ */ @@ -54,6 +54,10 @@ (ERPT_EVCH_MAX + \ ERPT_MAX_ERRS * ERPT_HIWAT), \ DUMP_OFFSET)) /* ereport save area */ +#define DUMP_SUMMARYSIZE (P2ROUNDUP( \ + (STACK_BUF_SIZE + \ + sizeof (summary_dump_t) + 1024), \ + DUMP_OFFSET)) /* summary save area */ typedef struct dumphdr { uint32_t dump_magic; /* magic number */ @@ -76,6 +80,8 @@ pgcnt_t dump_npages; /* number of data pages */ size_t dump_ksyms_size; /* kernel symbol table size */ size_t dump_ksyms_csize; /* compressed symbol table size */ + uint32_t dump_fm_panic; /* initiated from fm subsystems */ + char dump_uuid[36 + 1]; /* os image uuid */ } dumphdr_t; /* @@ -190,6 +196,8 @@ extern int dump_plat_addr(void); extern void dump_plat_pfn(void); extern int dump_plat_data(void *); +extern int dump_set_uuid(const char *); +extern const char *dump_get_uuid(void); /* * Define a CPU count threshold that determines when to employ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/sys/fm/protocol.h --- a/usr/src/uts/common/sys/fm/protocol.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/sys/fm/protocol.h Fri Jul 30 17:04:17 2010 +1000 @@ -43,12 +43,13 @@ #define FM_CLASS "class" #define FM_VERSION "version" -/* FM event class values */ +/* FM protocol category 1 class names */ #define FM_EREPORT_CLASS "ereport" #define FM_FAULT_CLASS "fault" #define FM_DEFECT_CLASS "defect" #define FM_RSRC_CLASS "resource" #define FM_LIST_EVENT "list" +#define FM_IREPORT_CLASS "ireport" /* FM list.* event class values */ #define FM_LIST_SUSPECT_CLASS FM_LIST_EVENT ".suspect" @@ -72,6 +73,12 @@ /* list.* event payload member names */ #define FM_LIST_EVENT_SIZE "list-sz" +/* ireport.* event payload member names */ +#define FM_IREPORT_DETECTOR "detector" +#define FM_IREPORT_UUID "uuid" +#define FM_IREPORT_PRIORITY "pri" +#define FM_IREPORT_ATTRIBUTES "attr" + /* * list.suspect, isolated, updated, repaired and resolved * versions/payload member names. @@ -192,6 +199,7 @@ #define FM_FMRI_SCHEME_PKG "pkg" #define FM_FMRI_SCHEME_LEGACY "legacy-hc" #define FM_FMRI_SCHEME_ZFS "zfs" +#define FM_FMRI_SCHEME_SW "sw" /* Scheme versions */ #define FMD_SCHEME_VERSION0 0 @@ -215,6 +223,8 @@ #define FM_SVC_SCHEME_VERSION SVC_SCHEME_VERSION0 #define ZFS_SCHEME_VERSION0 0 #define FM_ZFS_SCHEME_VERSION ZFS_SCHEME_VERSION0 +#define SW_SCHEME_VERSION0 0 +#define FM_SW_SCHEME_VERSION SW_SCHEME_VERSION0 /* hc scheme member names */ #define FM_FMRI_HC_SERIAL_ID "serial" @@ -299,6 +309,25 @@ #define FM_FMRI_ZFS_POOL "pool" #define FM_FMRI_ZFS_VDEV "vdev" +/* sw scheme member names - extra indentation for members of an nvlist */ +#define FM_FMRI_SW_OBJ "object" +#define FM_FMRI_SW_OBJ_PATH "path" +#define FM_FMRI_SW_OBJ_ROOT "root" +#define FM_FMRI_SW_OBJ_PKG "pkg" +#define FM_FMRI_SW_SITE "site" +#define FM_FMRI_SW_SITE_TOKEN "token" +#define FM_FMRI_SW_SITE_MODULE "module" +#define FM_FMRI_SW_SITE_FILE "file" +#define FM_FMRI_SW_SITE_LINE "line" +#define FM_FMRI_SW_SITE_FUNC "func" +#define FM_FMRI_SW_CTXT "context" +#define FM_FMRI_SW_CTXT_ORIGIN "origin" +#define FM_FMRI_SW_CTXT_EXECNAME "execname" +#define FM_FMRI_SW_CTXT_PID "pid" +#define FM_FMRI_SW_CTXT_ZONE "zone" +#define FM_FMRI_SW_CTXT_CTID "ctid" +#define FM_FMRI_SW_CTXT_STACK "stack" + extern nv_alloc_t *fm_nva_xcreate(char *, size_t); extern void fm_nva_xdestroy(nv_alloc_t *); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/sys/fm/util.h --- a/usr/src/uts/common/sys/fm/util.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/sys/fm/util.h Fri Jul 30 17:04:17 2010 +1000 @@ -20,15 +20,12 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_FM_UTIL_H #define _SYS_FM_UTIL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -96,6 +93,7 @@ extern void fm_payload_stack_add(nvlist_t *, const pc_t *, int); +extern int is_fm_panic(); #endif /* _KERNEL */ #ifdef __cplusplus diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/sys/nvpair.h --- a/usr/src/uts/common/sys/nvpair.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/sys/nvpair.h Fri Jul 30 17:04:17 2010 +1000 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_NVPAIR_H @@ -158,6 +157,8 @@ int nvlist_dup(nvlist_t *, nvlist_t **, int); int nvlist_merge(nvlist_t *, nvlist_t *, int); +uint_t nvlist_nvflag(nvlist_t *); + int nvlist_xalloc(nvlist_t **, uint_t, nv_alloc_t *); int nvlist_xpack(nvlist_t *, char **, size_t *, int, nv_alloc_t *); int nvlist_xunpack(char *, size_t, nvlist_t **, nv_alloc_t *); diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/sys/panic.h --- a/usr/src/uts/common/sys/panic.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/sys/panic.h Fri Jul 30 17:04:17 2010 +1000 @@ -19,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_PANIC_H #define _SYS_PANIC_H -#pragma ident "%Z%%M% %I% %E% SMI" - #if !defined(_ASM) #include #include @@ -45,10 +42,13 @@ #endif #define PANICBUFSIZE 8192 -#define PANICBUFVERS 1 +#define PANICBUFVERS 2 #define PANICNVNAMELEN 16 +#define STACK_BUF_SIZE 2048 +#define SUMMARY_MAGIC 0xdead0d8a + /* * Panicbuf Format: * @@ -80,9 +80,19 @@ typedef struct panic_data { uint32_t pd_version; /* Version number of panic_data_t */ uint32_t pd_msgoff; /* Message byte offset in panicbuf */ + char pd_uuid[36 + 1]; /* image uuid */ panic_nv_t pd_nvdata[1]; /* Array of named data */ } panic_data_t; +typedef struct summary_dump { + uint32_t sd_magic; /* magic number */ + uint32_t sd_ssum; /* checsksum32(stack buffer) */ + /* + * stack buffer and other summary data follow here -- see + * dump_summary() + */ +} summary_dump_t; + #if defined(_KERNEL) /* diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/sys/sysevent.h --- a/usr/src/uts/common/sys/sysevent.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/sys/sysevent.h Fri Jul 30 17:04:17 2010 +1000 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_SYSEVENT_H @@ -226,6 +225,8 @@ extern int sysevent_evc_publish(evchan_t *, const char *, const char *, const char *, const char *, nvlist_t *, uint32_t); extern int sysevent_evc_control(evchan_t *, int, ...); +extern int sysevent_evc_setpropnvl(evchan_t *, nvlist_t *); +extern int sysevent_evc_getpropnvl(evchan_t *, nvlist_t **); #ifndef _KERNEL diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/common/sys/sysevent_impl.h --- a/usr/src/uts/common/sys/sysevent_impl.h Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/common/sys/sysevent_impl.h Fri Jul 30 17:04:17 2010 +1000 @@ -18,9 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_SYSEVENT_IMPL_H @@ -76,7 +76,7 @@ /* * sysevent event header information - - * contained in every event generated. The header and the event + * contained in every event generated. The header and the event * must remain 64-bit aligned. The header, up to the attribute * offset, can be contained in a single cache line. */ @@ -98,7 +98,7 @@ se_data_t se_class_name; /* class string in contig memory */ se_data_t se_subclass_name; /* subclass string in contig memory */ se_data_t se_pub; /* publisher string in contig mem */ - se_data_t se_attr_buf; /* contiguous attribute memory */ + se_data_t se_attr_buf; /* contiguous attribute memory */ } sysevent_impl_t; /* Helpful defines */ @@ -237,14 +237,14 @@ /* * log_sysevent private interfaces */ -void log_event_init(void); -void log_sysevent_flushq(int cmd, uint_t flag); -int log_sysevent_filename(char *file); -int log_usr_sysevent(sysevent_t *ev, int ev_size, sysevent_id_t *eid); -int log_sysevent_copyout_data(sysevent_id_t *eid, size_t ubuflen, caddr_t ubuf); -int log_sysevent_free_data(sysevent_id_t *eid); -int log_sysevent_register(char *channel_name, char *data, se_pubsub_t *udata); -uint64_t log_sysevent_new_id(); +extern void log_event_init(void); +extern void log_sysevent_flushq(int, uint_t); +extern int log_sysevent_filename(char *); +extern int log_usr_sysevent(sysevent_t *, int, sysevent_id_t *); +extern int log_sysevent_copyout_data(sysevent_id_t *, size_t, caddr_t); +extern int log_sysevent_free_data(sysevent_id_t *); +extern int log_sysevent_register(char *, char *, se_pubsub_t *); +extern uint64_t log_sysevent_new_id(void); /* * Structures and definitions for general purpose event channels @@ -281,8 +281,8 @@ typedef struct { evch_qelem_t *sq_head; evch_qelem_t *sq_tail; - uint32_t sq_count; - uint32_t sq_highwm; + uint32_t sq_count; + uint32_t sq_highwm; } evch_squeue_t; /* @@ -394,6 +394,8 @@ int ch_maxsubscr; /* Maximum number of subscriptions */ int ch_holdpend; /* Hold pending events mode if != 0 */ time_t ch_ctime; /* Channel creation time */ + nvlist_t *ch_propnvl; /* Channel properties nvlist */ + int64_t ch_propnvlgen; /* Properties generation number */ } evch_chan_t; /* @@ -413,26 +415,28 @@ sysevent_impl_t *sn_nxtev; /* Pointer to find next event */ } evchanq_t; -/* Project privat interfaces */ -evchan_t *evch_usrchanopen(const char *name, uint32_t flags, int *err); -void evch_usrchanclose(evchan_t *cbp); -sysevent_impl_t *evch_usrallocev(size_t evsize, uint32_t flags); -void evch_usrfreeev(sysevent_impl_t *ev); -int evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags); -int evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class, +/* Project private interfaces */ +extern evchan_t *evch_usrchanopen(const char *name, uint32_t flags, int *err); +extern void evch_usrchanclose(evchan_t *cbp); +extern sysevent_impl_t *evch_usrallocev(size_t evsize, uint32_t flags); +extern void evch_usrfreeev(sysevent_impl_t *ev); +extern int evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags); +extern int evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class, int d, uint32_t flags); -int evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value); -int evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value); -void evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flag); -int evch_usrgetchnames(char *buf, size_t size); -int evch_usrgetchdata(char *chname, void *buf, size_t size); +extern int evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value); +extern int evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value); +extern void evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flag); +extern int evch_usrgetchnames(char *buf, size_t size); +extern int evch_usrgetchdata(char *chname, void *buf, size_t size); +extern void evch_usrsetpropnvl(evchan_t *bp, nvlist_t *nvl); +extern int evch_usrgetpropnvl(evchan_t *bp, nvlist_t **nvlp, int64_t *genp); -void sysevent_evc_init(); -void sysevent_evc_thrinit(); -evchanq_t *sysevent_evc_walk_init(evchan_t *, char *); -sysevent_t *sysevent_evc_walk_step(evchanq_t *); -void sysevent_evc_walk_fini(evchanq_t *); -char *sysevent_evc_event_attr(sysevent_t *, size_t *); +extern void sysevent_evc_init(); +extern void sysevent_evc_thrinit(); +extern evchanq_t *sysevent_evc_walk_init(evchan_t *, char *); +extern sysevent_t *sysevent_evc_walk_step(evchanq_t *); +extern void sysevent_evc_walk_fini(evchanq_t *); +extern char *sysevent_evc_event_attr(sysevent_t *, size_t *); #endif /* _KERNEL */ @@ -508,6 +512,8 @@ #define SEV_UNSUBSCRIBE SEV_BASE | 0x05 #define SEV_CHANNAMES SEV_BASE | 0x06 #define SEV_CHANDATA SEV_BASE | 0x07 +#define SEV_SETPROPNVL SEV_BASE | 0x08 +#define SEV_GETPROPNVL SEV_BASE | 0x09 #define DEVSYSEVENT "/dev/sysevent" #define DEVICESYSEVENT "/devices/pseudo/sysevent@0:sysevent" @@ -560,6 +566,11 @@ sev_box_t out_data; } sev_chandata_args_t; +typedef struct propnvl_args { + sev_box_t packednvl; /* input and output */ + int64_t generation; /* output on get operation */ +} sev_propnvl_args_t; + #if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 #pragma pack() #endif diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/intel/ia32/os/archdep.c --- a/usr/src/uts/intel/ia32/os/archdep.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/intel/ia32/os/archdep.c Fri Jul 30 17:04:17 2010 +1000 @@ -1129,10 +1129,17 @@ /* * Print a stack backtrace using the specified frame pointer. We delay two - * seconds before continuing, unless this is the panic traceback. Note - * that the frame for the starting stack pointer value is omitted because + * seconds before continuing, unless this is the panic traceback. + * If we are in the process of panicking, we also attempt to write the + * stack backtrace to a staticly assigned buffer, to allow the panic + * code to find it and write it in to uncompressed pages within the + * system crash dump. + * Note that the frame for the starting stack pointer value is omitted because * the corresponding %eip is not known. */ + +extern char *dump_stack_scratch; + #if defined(__amd64) void @@ -1143,10 +1150,17 @@ uintptr_t pc, nextpc; ulong_t off; char args[TR_ARG_MAX * 2 + 16], *sym; + uint_t offset = 0; + uint_t next_offset = 0; + char stack_buffer[1024]; if (!panicstr) printf("traceback: %%fp = %p\n", (void *)fp); + if (panicstr && !dump_stack_scratch) { + printf("Warning - stack not written to the dump buffer\n"); + } + fp = (struct frame *)plat_traceback(fpreg); if ((uintptr_t)fp < KERNELBASE) goto out; @@ -1177,9 +1191,33 @@ if ((sym = kobj_getsymname(pc, &off)) != NULL) { printf("%016lx %s:%s+%lx (%s)\n", (uintptr_t)fp, mod_containing_pc((caddr_t)pc), sym, off, args); + (void) snprintf(stack_buffer, sizeof (stack_buffer), + "%s:%s+%lx (%s) | ", + mod_containing_pc((caddr_t)pc), sym, off, args); } else { printf("%016lx %lx (%s)\n", (uintptr_t)fp, pc, args); + (void) snprintf(stack_buffer, sizeof (stack_buffer), + "%lx (%s) | ", pc, args); + } + + if (panicstr && dump_stack_scratch) { + next_offset = offset + strlen(stack_buffer); + if (next_offset < STACK_BUF_SIZE) { + bcopy(stack_buffer, dump_stack_scratch + offset, + strlen(stack_buffer)); + offset = next_offset; + } else { + /* + * In attempting to save the panic stack + * to the dumpbuf we have overflowed that area. + * Print a warning and continue to printf the + * stack to the msgbuf + */ + printf("Warning: stack in the dump buffer" + " may be incomplete\n"); + offset = next_offset; + } } pc = nextpc; @@ -1189,6 +1227,8 @@ if (!panicstr) { printf("end of traceback\n"); DELAY(2 * MICROSEC); + } else if (dump_stack_scratch) { + dump_stack_scratch[offset] = '\0'; } } @@ -1200,6 +1240,9 @@ struct frame *fp = (struct frame *)fpreg; struct frame *nextfp, *minfp, *stacktop; uintptr_t pc, nextpc; + uint_t offset = 0; + uint_t next_offset = 0; + char stack_buffer[1024]; cpu_t *cpu; @@ -1215,6 +1258,10 @@ if (!panicstr) printf("traceback: %%fp = %p\n", (void *)fp); + if (panicstr && !dump_stack_scratch) { + printf("Warning - stack not written to the dumpbuf\n"); + } + /* * If we are panicking, all high-level interrupt information in * CPU was overwritten. panic_cpu has the correct values. @@ -1275,9 +1322,35 @@ if ((sym = kobj_getsymname(pc, &off)) != NULL) { printf("%08lx %s:%s+%lx (%s)\n", (uintptr_t)fp, mod_containing_pc((caddr_t)pc), sym, off, args); + (void) snprintf(stack_buffer, sizeof (stack_buffer), + "%s:%s+%lx (%s) | ", + mod_containing_pc((caddr_t)pc), sym, off, args); + } else { printf("%08lx %lx (%s)\n", (uintptr_t)fp, pc, args); + (void) snprintf(stack_buffer, sizeof (stack_buffer), + "%lx (%s) | ", pc, args); + + } + + if (panicstr && dump_stack_scratch) { + next_offset = offset + strlen(stack_buffer); + if (next_offset < STACK_BUF_SIZE) { + bcopy(stack_buffer, dump_stack_scratch + offset, + strlen(stack_buffer)); + offset = next_offset; + } else { + /* + * In attempting to save the panic stack + * to the dumpbuf we have overflowed that area. + * Print a warning and continue to printf the + * stack to the msgbuf + */ + printf("Warning: stack in the dumpbuf" + " may be incomplete\n"); + offset = next_offset; + } } minfp = fp; @@ -1288,7 +1361,10 @@ if (!panicstr) { printf("end of traceback\n"); DELAY(2 * MICROSEC); + } else if (dump_stack_scratch) { + dump_stack_scratch[offset] = '\0'; } + } #endif /* __i386 */ diff -r 19d842faf8e4 -r ab9ae749152f usr/src/uts/sparc/os/archdep.c --- a/usr/src/uts/sparc/os/archdep.c Thu Jul 29 22:45:58 2010 -0700 +++ b/usr/src/uts/sparc/os/archdep.c Fri Jul 30 17:04:17 2010 +1000 @@ -19,16 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -255,10 +252,18 @@ /* * Print a stack backtrace using the specified stack pointer. We delay two - * seconds before continuing, unless this is the panic traceback. Note - * that the frame for the starting stack pointer value is omitted because + * seconds before continuing, unless this is the panic traceback. + * If we are in the process of panicking, we also attempt to write the + * stack backtrace to a staticly assigned buffer, to allow the panic + * code to find it and write it in to uncompressed pages within the + * system crash dump. + * + * Note that the frame for the starting stack pointer value is omitted because * the corresponding %pc is not known. */ + +extern char *dump_stack_scratch; + void traceback(caddr_t sp) { @@ -268,11 +273,20 @@ cpu_t *cpu; + uint_t offset = 0; + uint_t next_offset = 0; + char stack_buffer[2048]; + char local_buffer[1024]; + flush_windows(); if (!panicstr) printf("traceback: %%sp = %p\n", (void *)sp); + if (panicstr && !dump_stack_scratch) { + printf("Warning - stack not written to the dumpbuf\n"); + } + /* * If we are panicking, the high-level interrupt information in * CPU was overwritten. panic_cpu has the correct values. @@ -321,20 +335,53 @@ nextfp->fr_arg[0], nextfp->fr_arg[1], nextfp->fr_arg[2], nextfp->fr_arg[3], nextfp->fr_arg[4], nextfp->fr_arg[5]); + (void) snprintf(stack_buffer, sizeof (stack_buffer), + "%s:%s+%lx " + "(%lx, %lx, %lx, %lx, %lx, %lx) | ", + mod_containing_pc((caddr_t)pc), sym, off, + nextfp->fr_arg[0], nextfp->fr_arg[1], + nextfp->fr_arg[2], nextfp->fr_arg[3], + nextfp->fr_arg[4], nextfp->fr_arg[5]); } else { - printf("%016lx %p (%lx, %lx, %lx, %lx, %lx, %lx)\n", + (void) printf("%016lx %p (%lx, %lx, %lx, " + "%lx, %lx, %lx)\n", (ulong_t)nextfp, (void *)pc, nextfp->fr_arg[0], nextfp->fr_arg[1], nextfp->fr_arg[2], nextfp->fr_arg[3], nextfp->fr_arg[4], nextfp->fr_arg[5]); + (void) snprintf(stack_buffer, sizeof (stack_buffer), + "%p (%lx, %lx, %lx, %lx, %lx, %lx) | ", + (void *)pc, + nextfp->fr_arg[0], nextfp->fr_arg[1], + nextfp->fr_arg[2], nextfp->fr_arg[3], + nextfp->fr_arg[4], nextfp->fr_arg[5]); } - printf(" %%l0-3: %016lx %016lx %016lx %016lx\n" + (void) snprintf(local_buffer, sizeof (local_buffer), + " %%l0-3: %016lx %016lx %016lx %016lx\n" " %%l4-7: %016lx %016lx %016lx %016lx\n", nextfp->fr_local[0], nextfp->fr_local[1], nextfp->fr_local[2], nextfp->fr_local[3], nextfp->fr_local[4], nextfp->fr_local[5], nextfp->fr_local[6], nextfp->fr_local[7]); + if (panicstr && dump_stack_scratch) { + next_offset = offset + strlen(stack_buffer); + if (next_offset < STACK_BUF_SIZE) { + bcopy(stack_buffer, dump_stack_scratch + offset, + strlen(stack_buffer)); + offset = next_offset; + } else { + /* + * In attempting to save the panic stack + * to the dumpbuf we have overflowed that area. + * Print a warning and continue to printf the + * stack to the msgbuf + */ + printf("Warning: stack in the dump buffer" + " may be incomplete\n"); + } + } + printf("%s", local_buffer); fp = nextfp; minfp = fp; @@ -343,6 +390,8 @@ if (!panicstr) { printf("end of traceback\n"); DELAY(2 * MICROSEC); + } else if (dump_stack_scratch) { + dump_stack_scratch[offset] = '\0'; } }