f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * CDDL HEADER START
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * The contents of this file are subject to the terms of the
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * Common Development and Distribution License (the "License").
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * You may not use this file except in compliance with the License.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * See the License for the specific language governing permissions
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * and limitations under the License.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * When distributing Covered Code, include this CDDL HEADER in each
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * If applicable, add the following below this CDDL HEADER, with the
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * fields enclosed by brackets "[]" replaced with your own identifying
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * information: Portions Copyright [yyyy] [name of copyright owner]
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * CDDL HEADER END
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby (void) strftime(buf, bufsize, "%b %d %H:%M:%S", p_tm);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby/* PRINTFLIKE2 */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_debug(nd_hdl_t *nhdl, const char *format, ...)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby (void) fprintf(nhdl->nh_log_fd, "[ %s ", timestamp);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby/* PRINTFLIKE2 */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_error(nd_hdl_t *nhdl, const char *format, ...)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby (void) fprintf(nhdl->nh_log_fd, "[ %s ", timestamp);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby/* PRINTFLIKE2 */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_abort(nd_hdl_t *nhdl, const char *format, ...)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby (void) fprintf(nhdl->nh_log_fd, "[ %s ", timestamp);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_abort(nhdl, "Failed to fork child (%s)", strerror(errno));
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby else if (pid > 0)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * We leave stderr open so we can write debug/err messages to the SMF
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * service log
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * This function returns a pointer to the specified SMF property group for the
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * specified SMF service. The caller is responsible for freeing the property
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * group. On failure, the function returns NULL.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_get_pg(nd_hdl_t *nhdl, scf_handle_t *handle, const char *svcname,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Failed to allocate libscf structures");
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, sc) != -1 &&
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby scf_scope_get_service(sc, svcname, svc) != -1 &&
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_get_astring_prop(nd_hdl_t *nhdl, const char *svcname, const char *pgname,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((handle = scf_handle_create(SCF_VERSION)) == NULL)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((pg = nd_get_pg(nhdl, handle, svcname, pgname)) == NULL) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Failed to allocate SMF structures");
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (scf_pg_get_property(pg, propname, prop) == -1 ||
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby scf_value_get_astring(value, strval, 255) == -1) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Failed to retrieve %s prop (%s)", propname,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_get_boolean_prop(nd_hdl_t *nhdl, const char *svcname, const char *pgname,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((handle = scf_handle_create(SCF_VERSION)) == NULL)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((pg = nd_get_pg(nhdl, handle, svcname, pgname)) == NULL) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Failed to allocate SMF structures");
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (scf_pg_get_property(pg, propname, prop) == -1 ||
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Failed to retrieve %s prop (%s)", propname,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Failed to lookup event attr nvlist");
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (nvlist_lookup_nvlist(ev_nvl, "attr", &attr_nvl) ||
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nvlist_lookup_string(attr_nvl, "svc-string", &svcname)) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Malformed event 0x%p", (void *)ev_nvl);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_get_notify_prefs(nd_hdl_t *nhdl, const char *mech, fmev_t ev,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nvlist_t *ev_nvl, *top_nvl, **np_nvlarr, *mech_nvl;
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Failed to lookup event attr nvlist");
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (-1);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((ret = smf_notify_get_params(&top_nvl, ev_nvl)) != SCF_SUCCESS) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_debug(nhdl, "No notification preferences specified "
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby "for this event");
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Error looking up notification "
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (nvlist_lookup_nvlist_array(top_nvl, SCF_NOTIFY_PARAMS, &np_nvlarr,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby *pref_nvl = malloc(nelem * sizeof (nvlist_t *));
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby for (int i = 0; i < nelem; i++) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (nvlist_lookup_nvlist(np_nvlarr[i], mech, &mech_nvl) == 0) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby (void) nvlist_dup(mech_nvl, *pref_nvl + *nprefs, 0);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_debug(nhdl, "No %s notification preferences specified",
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_seq_search(char *key, char **list, uint_t nelem)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby for (int i = 0; i < nelem; i++)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * This function takes a single string list and splits it into
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * an string array (analogous to PERL split)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * The caller is responsible for freeing the array.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_split_list(nd_hdl_t *nhdl, char *list, char *delim, char ***arr,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((*arr = calloc(size, sizeof (char *))) == NULL) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Error allocating memory (%s)", strerror(errno));
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (-1);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * This function merges two string arrays into a single array, removing any
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * duplicates
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * The caller is responsible for freeing the merged array.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_merge_strarray(nd_hdl_t *nhdl, char **arr1, uint_t n1, char **arr2,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby for (int j = 0; j < n2; j++)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((*buf = calloc(uniq, sizeof (char *))) == NULL) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Error allocating memory (%s)", strerror(errno));
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby for (int j = 0; j < uniq; j++) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (-1);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * This function joins all the strings in a string array into a single string
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * Each element will be delimited by a comma
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * The caller is responsible for freeing the joined string.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_join_strarray(nd_hdl_t *nhdl, char **arr, uint_t arrsz, char **buf)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * First, figure out how much space we need to allocate to store the
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * joined string.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby for (i = 0; i < arrsz; i++)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((jbuf = calloc(len, sizeof (char))) == NULL) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Error allocating memory (%s)", strerror(errno));
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (-1);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby (void) snprintf(jbuf, len, "%s,%s", jbuf, arr[i]);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * This function takes a dictionary name and event class and then uses
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * libdiagcode to compute the MSG ID. We need this for looking up messages
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * for the committed ireport.* events. For FMA list.* events, the MSG ID is
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * is contained in the event payload.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_get_diagcode(nd_hdl_t *nhdl, const char *dict, const char *class, char *buf,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby dlen = (strlen(nhdl->nh_rootdir) + strlen(ND_DICTDIR) + 2);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby (void) snprintf(dirpath, dlen, "%s/%s", nhdl->nh_rootdir, ND_DICTDIR);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((dhp = fm_dc_opendict(FM_DC_VERSION, dirpath, dict)) == NULL) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "fm_dc_opendict failed for %s/%s",
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (-1);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (fm_dc_key2code(dhp, key, buf, buflen) < 0) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "fm_dc_key2code failed for %s", key[0]);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * This function takes an event and extracts the bits of the event payload that
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * are of interest to notification daemons and conveniently tucks them into a
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * single struct.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * The caller is responsible for freeing ev_info and any contained strings and
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * nvlists. A convenience function, nd_free_event_info(), is provided for this
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbynd_get_event_info(nd_hdl_t *nhdl, const char *class, fmev_t ev,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby char *code, *uuid, *fmri, *from_state, *to_state, *reason;
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((evi = calloc(1, sizeof (nd_ev_info_t))) == NULL) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (-1);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * Hold event; class and payload will be valid for as long as
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * we hold the event.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * Lookup the MSGID, event description and severity and KA URL
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * For FMA list.* events we just pull it out of the the event nvlist.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * For all other events we call a utility function that computes the
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * diagcode using the dict name and class.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((nvlist_lookup_string(ev_nvl, FM_SUSPECT_DIAG_CODE, &code) == 0 &&
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_get_diagcode(nhdl, "SMF", class, evi->ei_diagcode, 32)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby evi->ei_severity = fmd_msg_getitem_id(nhdl->nh_msghdl,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby NULL, evi->ei_diagcode, FMD_MSG_ITEM_SEVERITY);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby evi->ei_descr = fmd_msg_getitem_id(nhdl->nh_msghdl,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby evi->ei_url = fmd_msg_getitem_id(nhdl->nh_msghdl,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (nvlist_lookup_string(ev_nvl, FM_SUSPECT_UUID, &uuid) == 0)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (-1);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (strncmp(class, "ireport.os.smf", 14) == 0) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((fmri = nd_get_event_fmri(nhdl, ev)) == NULL) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nd_error(nhdl, "Failed to get fmri from event payload");
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (-1);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (nvlist_lookup_nvlist(evi->ei_payload, "attr", &attr_nvl) ||
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nvlist_lookup_string(attr_nvl, "from-state", &from_state) ||
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nvlist_lookup_string(attr_nvl, "to-state", &to_state) ||
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby nvlist_lookup_string(attr_nvl, "reason-long", &reason)) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (-1);