1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 #include <strings.h>
27 #include <libscf.h>
28 #include <fm/fmd_api.h>
29 #include <fm/libtopo.h>
30 #include <fm/libfmevent.h>
31
32 #include "fmevt.h"
33
34 /*
35 * Post-processing according to the FMEV_RULESET_SMF ruleset.
36 *
37 * Raw event we expect:
38 *
39 * ==========================================================================
40 * Class: "state-transition"
41 * Subclasses: The new state, one of SCF_STATE_STRING_* from libscf.h
42 * Attr:
43 * Name DATA_TYPE_* Description
44 * ------------ --------------- ---------------------------------------------
45 * fmri STRING svc:/... (svc scheme shorthand version)
46 * transition INT32 (old_state << 16) | new_state
47 * reason-version UINT32 reason-short namespace version
48 * reason-short STRING Short/keyword reason for transition
49 * reason-long STRING Long-winded reason for the transition
50 * ==========================================================================
51 *
52 * Protocol event components we return:
53 *
54 * ==========================================================================
55 * Class: ireport.os.smf.state-transition.<new-state>
56 * Attr:
57 * Name DATA_TYPE_* Description
58 * ------------ --------------- ----------------------------------------
59 * svc NVLIST "svc" scheme FMRI of affected service instance
60 * svc-string STRING SMF FMRI in short string form svc:/foo/bar
61 * from-state STRING Previous state; SCF_STATE_STRING_*
62 * to-state STRING New state; SCF_STATE_STRING_*
63 * reason-version UINT32 reason-short namespace version
64 * reason-short STRING Short/keyword reason for transition
65 * reason-long STRING Long-winded reason for the transition
66 * ==========================================================================
67 */
68
69 /*
70 * svc.startd generates events using the FMRI shorthand (svc:/foo/bar)
71 * instead of the standard form (svc:///foo/bar). This function converts to
72 * the standard representation. The caller must free the allocated string.
73 */
74 static char *
shortfmri_to_fmristr(fmd_hdl_t * hdl,const char * shortfmristr)75 shortfmri_to_fmristr(fmd_hdl_t *hdl, const char *shortfmristr)
76 {
77 size_t len;
78 char *fmristr;
79
80 if (strncmp(shortfmristr, "svc:/", 5) != 0)
81 return (NULL);
82
83 len = strlen(shortfmristr) + 3;
84 fmristr = fmd_hdl_alloc(hdl, len, FMD_SLEEP);
85 (void) snprintf(fmristr, len, "svc:///%s", shortfmristr + 5);
86
87 return (fmristr);
88 }
89
90 /*
91 * Convert a shorthand svc FMRI into a full svc FMRI nvlist
92 */
93 static nvlist_t *
shortfmri_to_fmri(fmd_hdl_t * hdl,const char * shortfmristr)94 shortfmri_to_fmri(fmd_hdl_t *hdl, const char *shortfmristr)
95 {
96 nvlist_t *ret, *fmri;
97 topo_hdl_t *thp;
98 char *fmristr;
99 int err;
100
101 if ((fmristr = shortfmri_to_fmristr(hdl, shortfmristr)) == NULL)
102 return (NULL);
103
104 thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
105
106 if (topo_fmri_str2nvl(thp, fmristr, &fmri, &err) != 0) {
107 fmd_hdl_error(hdl, "failed to convert '%s' to nvlist\n",
108 fmristr);
109 fmd_hdl_strfree(hdl, fmristr);
110 fmd_hdl_topo_rele(hdl, thp);
111 return (NULL);
112 }
113
114 fmd_hdl_strfree(hdl, fmristr);
115
116 if ((ret = fmd_nvl_dup(hdl, fmri, FMD_SLEEP)) == NULL) {
117 fmd_hdl_error(hdl, "failed to dup fmri\n");
118 nvlist_free(fmri);
119 fmd_hdl_topo_rele(hdl, thp);
120 return (NULL);
121 }
122
123 nvlist_free(fmri);
124 fmd_hdl_topo_rele(hdl, thp);
125
126 return (ret);
127 }
128
129 /*ARGSUSED*/
130 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)131 fmevt_pp_smf(char *classes[FMEVT_FANOUT_MAX],
132 nvlist_t *attr[FMEVT_FANOUT_MAX], const char *ruleset,
133 const nvlist_t *detector, nvlist_t *rawattr,
134 const struct fmevt_ppargs *eap)
135 {
136 int32_t transition, from, to;
137 const char *fromstr, *tostr;
138 char *svcname, *rsn, *rsnl;
139 nvlist_t *myattr;
140 nvlist_t *fmri;
141 uint32_t ver;
142
143 if (!fmd_prop_get_int32(fmevt_hdl, "inbound_postprocess_smf"))
144 return (0);
145
146 if (rawattr == NULL ||
147 strcmp(eap->pp_rawclass, "state-transition") != 0 ||
148 nvlist_lookup_string(rawattr, "fmri", &svcname) != 0 ||
149 nvlist_lookup_int32(rawattr, "transition", &transition) != 0 ||
150 nvlist_lookup_string(rawattr, "reason-short", &rsn) != 0 ||
151 nvlist_lookup_string(rawattr, "reason-long", &rsnl) != 0 ||
152 nvlist_lookup_uint32(rawattr, "reason-version", &ver) != 0)
153 return (0);
154
155 from = transition >> 16;
156 to = transition & 0xffff;
157
158 fromstr = smf_state_to_string(from);
159 tostr = smf_state_to_string(to);
160
161 if (fromstr == NULL || tostr == NULL)
162 return (0);
163
164 if (strcmp(eap->pp_rawsubclass, tostr) != 0)
165 return (0);
166
167 if ((fmri = shortfmri_to_fmri(fmevt_hdl, svcname)) == NULL)
168 return (0);
169
170 if (snprintf(classes[0], FMEVT_MAX_CLASS, "%s.%s.%s.%s",
171 FM_IREPORT_CLASS, "os.smf", eap->pp_rawclass,
172 eap->pp_rawsubclass) >= FMEVT_MAX_CLASS - 1)
173 return (0);
174
175 if ((myattr = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP)) == NULL)
176 return (0);
177
178 if (nvlist_add_nvlist(myattr, "svc", fmri) != 0 ||
179 nvlist_add_string(myattr, "svc-string", svcname) != 0 ||
180 nvlist_add_string(myattr, "from-state", fromstr) != 0 ||
181 nvlist_add_string(myattr, "to-state", tostr) != 0 ||
182 nvlist_add_uint32(myattr, "reason-version", ver) != 0 ||
183 nvlist_add_string(myattr, "reason-short", rsn) != 0 ||
184 nvlist_add_string(myattr, "reason-long", rsnl) != 0) {
185 nvlist_free(fmri);
186 nvlist_free(myattr);
187 return (0);
188 }
189
190 attr[0] = myattr;
191 nvlist_free(fmri);
192
193 return (1);
194 }
195