1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 #include <umem.h>
17 #include <libintl.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <sys/debug.h>
21 #include <stdarg.h>
22
23 #include <sys/sysevent/krrp.h>
24 #include <sys/krrp.h>
25 #include "libkrrp.h"
26 #include "libkrrp_impl.h"
27 #include "libkrrp_error.h"
28
29 /* Make lint happy */
30 #pragma error_messages(off, E_UNDEFINED_SYMBOL, E_YACC_ERROR, \
31 E_FUNC_VAR_UNUSED, E_BLOCK_DECL_UNUSED, E_RET_INT_IMPLICITLY)
32
33 static struct {
34 char *subclass;
35 libkrrp_ev_type_t ev_type;
36 } krrp_escs[] = {
37 #define LIBKRRP_ESC_EV_TYPE_EXPAND(enum_name) \
38 {ESC_KRRP_##enum_name, LIBKRRP_EV_TYPE_##enum_name},
39 LIBKRRP_EV_TYPE_MAP(LIBKRRP_ESC_EV_TYPE_EXPAND)
40 #undef LIBKRRP_ESC_EV_TYPE_EXPAND
41 };
42
43 #define LIBKRRP_EV_CB_RETRY_COUNT 5
44 #define LIBKRRP_EV_CB_RETRY_PAUSE 300000
45
46 static size_t krrp_escs_sz = sizeof (krrp_escs) / sizeof (krrp_escs[0]);
47
48 static libkrrp_ev_type_t
49 subclass_to_libkrrp_ev_type(const char *subclass)
50 {
51 int i;
52
53 ASSERT(subclass != NULL);
54
55 for (i = 0; i < krrp_escs_sz; i++) {
56 if (strcmp(subclass, krrp_escs[i].subclass) == 0)
57 return (krrp_escs[i].ev_type);
58 }
59
60 return (LIBKRRP_EV_TYPE_UNKNOWN);
61 }
62
63 static int
64 libkrrp_sess_id_parse(libkrrp_event_t *ev, char *sess_id_str,
65 uuid_t sess_id)
66 {
67 ASSERT(sess_id != NULL);
68
69 if ((sess_id_str == NULL) ||
70 (uuid_parse(sess_id_str, sess_id) != 0)) {
71 libkrrp_error_set(&ev->libkrrp_error, LIBKRRP_ERRNO_SESSID,
72 EINVAL, 0);
73
74 return (-1);
75 }
76
77 return (0);
78 }
79
80 static void
81 libkrrp_ev_unpack_sess_send_done(libkrrp_event_t *ev, nvlist_t *attr)
82 {
83 char *sess_id_str = NULL;
84
85 ASSERT(ev != NULL);
86 ASSERT(attr != NULL);
87
88 if (krrp_param_get(KRRP_PARAM_SESS_ID, attr, &sess_id_str) != 0) {
89 libkrrp_error_set(&ev->libkrrp_error, LIBKRRP_ERRNO_SESSID,
90 ENOENT, 0);
91 return;
92 }
93
94 (void) libkrrp_sess_id_parse(ev, sess_id_str,
95 ev->ev_data.sess_send_done.sess_id);
96 }
97
98 static void
99 libkrrp_ev_unpack_sess_error(libkrrp_event_t *ev, nvlist_t *attr)
100 {
101 char *sess_id_str = NULL;
102
103 ASSERT(ev != NULL);
104 ASSERT(attr != NULL);
105
106 if (krrp_param_get(KRRP_PARAM_SESS_ID, attr, &sess_id_str) != 0) {
107 libkrrp_error_set(&ev->libkrrp_error, LIBKRRP_ERRNO_SESSID,
108 ENOENT, 0);
109 return;
110 }
111
112 if (libkrrp_sess_id_parse(ev, sess_id_str,
113 ev->ev_data.sess_error.sess_id) != 0)
114 return;
115
116 if (libkrrp_error_from_nvl(attr,
117 &ev->ev_data.sess_error.libkrrp_error) != 0) {
118 libkrrp_error_set(&ev->libkrrp_error, LIBKRRP_ERRNO_SESSERR,
119 EINVAL, 0);
120 }
121 }
122
123 static void
124 libkrrp_ev_unpack_server_error(libkrrp_event_t *ev, nvlist_t *attr)
125 {
126 ASSERT(ev != NULL);
127 ASSERT(attr != NULL);
128
129 if (libkrrp_error_from_nvl(attr, &ev->ev_data.server_error) != 0) {
130 libkrrp_error_set(&ev->libkrrp_error, LIBKRRP_ERRNO_SESSERR,
131 EINVAL, 0);
132 }
133 }
134
135 static int
136 libkrrp_evc_callback(sysevent_t *ev, void *cookie)
137 {
138 libkrrp_evc_handle_t *hdl = cookie;
139 libkrrp_event_t libkrrp_ev;
140 nvlist_t *attr = NULL;
141 int rc;
142
143 ASSERT(ev != NULL);
144 ASSERT(hdl != NULL);
145
146 libkrrp_error_init(&libkrrp_ev.libkrrp_error);
147 libkrrp_ev.ev_type = subclass_to_libkrrp_ev_type(
148 sysevent_get_subclass_name(ev));
149
150 rc = sysevent_get_attr_list(ev, &attr);
151 if (rc == ENOMEM) {
152 if (hdl->ev_failure_count++ < LIBKRRP_EV_CB_RETRY_COUNT) {
153 (void) usleep(LIBKRRP_EV_CB_RETRY_PAUSE);
154 return (EAGAIN);
155 }
156 }
157
158 hdl->ev_failure_count = 0;
159
160 if (rc != 0) {
161 libkrrp_error_set(&libkrrp_ev.libkrrp_error,
162 LIBKRRP_ERRNO_EVREADFAIL, rc, 0);
163 goto callback;
164 }
165
166 switch (libkrrp_ev.ev_type) {
167 case LIBKRRP_EV_TYPE_SESS_SEND_DONE:
168 libkrrp_ev_unpack_sess_send_done(&libkrrp_ev, attr);
169 break;
170 case LIBKRRP_EV_TYPE_SESS_ERROR:
171 libkrrp_ev_unpack_sess_error(&libkrrp_ev, attr);
172 break;
173 case LIBKRRP_EV_TYPE_SERVER_ERROR:
174 libkrrp_ev_unpack_server_error(&libkrrp_ev, attr);
175 break;
176 default:
177 ASSERT(0);
178 }
179
180 callback:
181 fnvlist_free(attr);
182 rc = hdl->callback(&libkrrp_ev, hdl->cookie);
183 return (rc);
184 }
185
186 void
187 libkrrp_evc_unsubscribe(libkrrp_evc_handle_t *hdl)
188 {
189 VERIFY(hdl != NULL);
190
191 if (hdl->evchan)
192 (void) sysevent_evc_unbind(hdl->evchan);
193
194 umem_free(hdl, sizeof (libkrrp_evc_handle_t));
195 }
196
197 int
198 libkrrp_evc_subscribe(libkrrp_evc_handle_t **res_hdl,
199 int(*callback)(libkrrp_event_t *, void *), void *cookie)
200 {
201 int rc;
202 char sid[13];
203 libkrrp_evc_handle_t *hdl;
204
205 hdl = umem_zalloc(sizeof (libkrrp_evc_handle_t), UMEM_DEFAULT);
206 *res_hdl = hdl;
207
208 if (hdl == NULL)
209 return (-1);
210
211 rc = sysevent_evc_bind(KRRP_EVENT_CHANNEL, &hdl->evchan, EVCH_CREAT);
212
213 if (rc != 0) {
214 libkrrp_error_set(&hdl->libkrrp_error,
215 LIBKRRP_ERRNO_EVBINDFAIL, rc, 0);
216 libkrrp_evc_unsubscribe(hdl);
217 return (-1);
218 }
219
220 hdl->callback = callback;
221 hdl->cookie = cookie;
222
223 (void) sprintf(sid, "libkrrp%d", (int)getpid());
224 rc = sysevent_evc_subscribe(hdl->evchan, sid, EC_KRRP,
225 libkrrp_evc_callback, hdl, 0);
226
227 if (rc != 0) {
228 libkrrp_error_set(&hdl->libkrrp_error,
229 LIBKRRP_ERRNO_EVSUBSRIBEFAIL, rc, 0);
230 libkrrp_evc_unsubscribe(hdl);
231 return (-1);
232 }
233
234 return (0);
235 }
236
237 libkrrp_error_t *
238 libkrrp_evc_error(libkrrp_evc_handle_t *hdl)
239 {
240 VERIFY(hdl != NULL);
241 return (&hdl->libkrrp_error);
242 }
243
244 const char *
245 libkrrp_evc_error_description(libkrrp_evc_handle_t *hdl)
246 {
247 /* LINTED: E_FUNC_SET_NOT_USED */
248 libkrrp_errno_t libkrrp_errno;
249 /* LINTED: E_FUNC_SET_NOT_USED */
250 int unix_errno;
251 /* LINTED: E_FUNC_SET_NOT_USED */
252 int flags = 0;
253 char *descr;
254
255 VERIFY(hdl != NULL);
256
257 descr = hdl->libkrrp_error_descr;
258 descr[0] = '\0';
259 libkrrp_errno = hdl->libkrrp_error.libkrrp_errno;
260 unix_errno = hdl->libkrrp_error.unix_errno;
261
262 SET_ERROR_DESCR(LIBKRRP_ERRDESCR_MAP);
263
264 if (descr[0] == '\0') {
265 (void) snprintf(descr, sizeof (libkrrp_error_descr_t) - 1,
266 dgettext(TEXT_DOMAIN, LIBKRRP_EMSG_UNKNOWN));
267 }
268
269 return (descr);
270 }
271
272 libkrrp_ev_type_t
273 libkrrp_ev_type(libkrrp_event_t *ev)
274 {
275 VERIFY(ev != NULL);
276 return (ev->ev_type);
277 }
278
279 libkrrp_ev_data_t *
280 libkrrp_ev_data(libkrrp_event_t *ev)
281 {
282 VERIFY(ev != NULL);
283 return (&ev->ev_data);
284 }
285
286 libkrrp_error_t *
287 libkrrp_ev_error(libkrrp_event_t *ev)
288 {
289 VERIFY(ev != NULL);
290 return (&ev->libkrrp_error);
291 }
292
293 const char *
294 libkrrp_ev_error_description(libkrrp_event_t *ev)
295 {
296 /* LINTED: E_FUNC_SET_NOT_USED */
297 libkrrp_errno_t libkrrp_errno;
298 /* LINTED: E_FUNC_SET_NOT_USED */
299 int unix_errno;
300 /* LINTED: E_FUNC_SET_NOT_USED */
301 int flags = 0;
302 char *descr;
303
304 VERIFY(ev != NULL);
305
306 descr = ev->libkrrp_error_descr;
307 descr[0] = '\0';
308 libkrrp_errno = ev->libkrrp_error.libkrrp_errno;
309 unix_errno = ev->libkrrp_error.unix_errno;
310
311 SET_ERROR_DESCR(LIBKRRP_ERRDESCR_MAP);
312
313 if (descr[0] == '\0') {
314 (void) snprintf(descr, sizeof (libkrrp_error_descr_t) - 1,
315 dgettext(TEXT_DOMAIN, LIBKRRP_EMSG_UNKNOWN));
316 }
317
318 return (descr);
319 }
320
321 void
322 libkrrp_ev_data_error_description(libkrrp_ev_type_t ev_type,
323 libkrrp_error_t *error, libkrrp_error_descr_t descr)
324 {
325 switch (ev_type) {
326 case LIBKRRP_EV_TYPE_SERVER_ERROR:
327 libkrrp_common_error_description(LIBKRRP_SRV_ERROR, error,
328 descr);
329 break;
330 case LIBKRRP_EV_TYPE_SESS_ERROR:
331 libkrrp_common_error_description(LIBKRRP_SESS_ERROR, error,
332 descr);
333 break;
334 default:
335 break;
336 }
337 }
338
339 libkrrp_event_t *
340 libkrrp_ev_dup(libkrrp_event_t *ev)
341 {
342 libkrrp_event_t *copy;
343
344 VERIFY(ev != NULL);
345
346 copy = umem_zalloc(sizeof (libkrrp_event_t), UMEM_DEFAULT);
347
348 if (copy == NULL)
349 return (NULL);
350
351 (void) memcpy(copy, ev, sizeof (libkrrp_event_t));
352 return (copy);
353 }
354
355 void
356 libkrrp_ev_free(libkrrp_event_t *ev)
357 {
358 VERIFY(ev != NULL);
359 umem_free(ev, sizeof (libkrrp_event_t));
360 }