Print this page
6659 nvlist_free(NULL) is a no-op
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/fm/libfmevent/common/fmev_publish.c
+++ new/usr/src/lib/fm/libfmevent/common/fmev_publish.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * Simple-minded raw event publication from user context. See extensive
28 28 * comments in libfmevent.h. These interfaces remain Project Private -
29 29 * they have to evolve before rollout to Public levels.
30 30 *
31 31 * Events are dispatched synchronously using the GPEC sysevent mechanism.
32 32 * The caller context must therefore be one in which a sysevent_evc_publish
33 33 * (and possibly sysevent_evc_bind if not already bound) is safe. We will
34 34 * also allocate and manipulate nvlists.
35 35 *
36 36 * Since we use GPEC, which has no least privilege awareness, these interfaces
37 37 * will only work for would-be producers running as root.
38 38 *
39 39 * There is no event rate throttling applied, so we rely on producers
40 40 * to throttle themselves. A future refinement should apply mandatory
41 41 * but tuneable throttling on a per-producer basis. In this first version
42 42 * the only throttle is the publication event queue depth - we'll drop
43 43 * events when the queue is full.
44 44 *
45 45 * We can publish over four channels, for privileged/non-privileged and
46 46 * high/low priority. Since only privileged producers will work now
47 47 * (see above) we hardcode priv == B_TRUE and so only two channels are
48 48 * actually used, separating higher and lower value streams from privileged
49 49 * producers.
50 50 */
51 51
52 52 #include <stdarg.h>
53 53 #include <unistd.h>
54 54 #include <stdlib.h>
55 55 #include <atomic.h>
56 56 #include <errno.h>
57 57 #include <pthread.h>
58 58 #include <strings.h>
59 59
60 60 #include "fmev_impl.h"
61 61
62 62 static struct {
63 63 const char *name; /* channel name */
64 64 evchan_t *binding; /* GPEC binding, once bound */
65 65 const uint32_t flags; /* flags to use in binding */
66 66 } chaninfo[] = {
67 67 { FMEV_CHAN_USER_NOPRIV_LV, NULL, 0 },
68 68 { FMEV_CHAN_USER_NOPRIV_HV, NULL, 0 },
69 69 { FMEV_CHAN_USER_PRIV_LV, NULL, EVCH_HOLD_PEND_INDEF },
70 70 { FMEV_CHAN_USER_PRIV_HV, NULL, EVCH_HOLD_PEND_INDEF}
71 71 };
72 72
73 73 #define CHANIDX(priv, pri) (2 * ((priv) != 0) + (pri == FMEV_HIPRI))
74 74
75 75 #define CHAN_NAME(priv, pri) (chaninfo[CHANIDX(priv, pri)].name)
76 76 #define CHAN_BINDING(priv, pri) (chaninfo[CHANIDX(priv, pri)].binding)
77 77 #define CHAN_FLAGS(priv, pri) (chaninfo[CHANIDX(priv, pri)].flags)
78 78
79 79 /*
80 80 * Called after fork in the new child. We clear the cached event
81 81 * channel bindings which are only valid in the process that created
82 82 * them.
83 83 */
84 84 static void
85 85 clear_bindings(void)
86 86 {
87 87 int i;
88 88
89 89 for (i = 0; i < sizeof (chaninfo) / sizeof chaninfo[0]; i++)
90 90 chaninfo[i].binding = NULL;
91 91 }
92 92
93 93 #pragma init(_fmev_publish_init)
94 94
95 95 static void
96 96 _fmev_publish_init(void)
97 97 {
98 98 (void) pthread_atfork(NULL, NULL, clear_bindings);
99 99 }
100 100
101 101 static evchan_t *
102 102 bind_channel(boolean_t priv, fmev_pri_t pri)
103 103 {
104 104 evchan_t **evcpp = &CHAN_BINDING(priv, pri);
105 105 evchan_t *evc;
106 106
107 107 if (*evcpp != NULL)
108 108 return (*evcpp);
109 109
110 110 if (sysevent_evc_bind(CHAN_NAME(priv, pri), &evc,
111 111 EVCH_CREAT | CHAN_FLAGS(priv, pri)) != 0)
112 112 return (NULL);
113 113
114 114 if (atomic_cas_ptr(evcpp, NULL, evc) != NULL)
115 115 (void) sysevent_evc_unbind(evc);
116 116
117 117 return (*evcpp);
118 118 }
119 119
120 120 static fmev_err_t
121 121 vrfy_ruleset(const char *ruleset)
122 122 {
123 123 if (ruleset != NULL &&
124 124 strnlen(ruleset, FMEV_MAX_RULESET_LEN) == FMEV_MAX_RULESET_LEN)
125 125 return (FMEVERR_STRING2BIG);
126 126
127 127 return (FMEV_OK);
128 128
129 129 }
130 130
131 131 static fmev_err_t
132 132 vrfy_class(const char *class)
133 133 {
134 134 if (class == NULL || *class == '\0')
135 135 return (FMEVERR_API);
136 136
137 137 if (strnlen(class, FMEV_PUB_MAXCLASSLEN) == FMEV_PUB_MAXCLASSLEN)
138 138 return (FMEVERR_STRING2BIG);
139 139
140 140 return (FMEV_OK);
141 141 }
142 142
143 143 static fmev_err_t
144 144 vrfy_subclass(const char *subclass)
145 145 {
146 146 if (subclass == NULL || *subclass == '\0')
147 147 return (FMEVERR_API);
148 148
149 149 if (strnlen(subclass, FMEV_PUB_MAXSUBCLASSLEN) ==
150 150 FMEV_PUB_MAXSUBCLASSLEN)
151 151 return (FMEVERR_STRING2BIG);
152 152
153 153 return (FMEV_OK);
154 154 }
155 155
156 156 static fmev_err_t
157 157 vrfy_pri(fmev_pri_t pri)
158 158 {
159 159 return (pri == FMEV_LOPRI || pri == FMEV_HIPRI ?
160 160 FMEV_OK : FMEVERR_API);
161 161 }
162 162
163 163 const char *
164 164 fmev_pri_string(fmev_pri_t pri)
165 165 {
166 166 static const char *pristr[] = { "low", "high" };
167 167
168 168 if (vrfy_pri(pri) != FMEV_OK)
169 169 return (NULL);
170 170
171 171 return (pristr[pri - FMEV_LOPRI]);
172 172 }
173 173
174 174 static fmev_err_t
175 175 vrfy(const char **rulesetp, const char **classp, const char **subclassp,
176 176 fmev_pri_t *prip)
177 177 {
178 178 fmev_err_t rc = FMEV_OK;
179 179
180 180 if (rulesetp && (rc = vrfy_ruleset(*rulesetp)) != FMEV_OK)
181 181 return (rc);
182 182
183 183 if (classp && (rc = vrfy_class(*classp)) != FMEV_OK ||
184 184 subclassp && (rc = vrfy_subclass(*subclassp)) != FMEV_OK ||
185 185 prip && (rc = vrfy_pri(*prip)) != FMEV_OK)
186 186 return (rc);
187 187
188 188 return (FMEV_OK);
189 189 }
190 190
191 191 uint_t fmev_va2nvl_maxtuples = 100;
192 192
193 193 fmev_err_t
194 194 va2nvl(nvlist_t **nvlp, va_list ap, uint_t ntuples)
195 195 {
196 196 nvlist_t *nvl = NULL;
197 197 uint_t processed = 0;
198 198 char *name;
199 199
200 200 if (ntuples == 0)
201 201 return (FMEVERR_INTERNAL);
202 202
203 203 if ((name = va_arg(ap, char *)) == NULL || name == FMEV_ARG_TERM)
204 204 return (FMEVERR_VARARGS_MALFORMED);
205 205
206 206 if (ntuples > fmev_va2nvl_maxtuples)
207 207 return (FMEVERR_VARARGS_TOOLONG);
208 208
209 209 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
210 210 return (FMEVERR_ALLOC);
211 211
212 212 while (name != NULL && name != FMEV_ARG_TERM && processed <= ntuples) {
213 213 data_type_t type;
214 214 int err, nelem;
215 215
216 216 type = va_arg(ap, data_type_t);
217 217
218 218 switch (type) {
219 219 case DATA_TYPE_BYTE:
220 220 err = nvlist_add_byte(nvl, name,
221 221 va_arg(ap, uint_t));
222 222 break;
223 223 case DATA_TYPE_BYTE_ARRAY:
224 224 nelem = va_arg(ap, int);
225 225 err = nvlist_add_byte_array(nvl, name,
226 226 va_arg(ap, uchar_t *), nelem);
227 227 break;
228 228 case DATA_TYPE_BOOLEAN_VALUE:
229 229 err = nvlist_add_boolean_value(nvl, name,
230 230 va_arg(ap, boolean_t));
231 231 break;
232 232 case DATA_TYPE_BOOLEAN_ARRAY:
233 233 nelem = va_arg(ap, int);
234 234 err = nvlist_add_boolean_array(nvl, name,
235 235 va_arg(ap, boolean_t *), nelem);
236 236 break;
237 237 case DATA_TYPE_INT8:
238 238 err = nvlist_add_int8(nvl, name,
239 239 va_arg(ap, int));
240 240 break;
241 241 case DATA_TYPE_INT8_ARRAY:
242 242 nelem = va_arg(ap, int);
243 243 err = nvlist_add_int8_array(nvl, name,
244 244 va_arg(ap, int8_t *), nelem);
245 245 break;
246 246 case DATA_TYPE_UINT8:
247 247 err = nvlist_add_uint8(nvl, name,
248 248 va_arg(ap, uint_t));
249 249 break;
250 250 case DATA_TYPE_UINT8_ARRAY:
251 251 nelem = va_arg(ap, int);
252 252 err = nvlist_add_uint8_array(nvl, name,
253 253 va_arg(ap, uint8_t *), nelem);
254 254 break;
255 255 case DATA_TYPE_INT16:
256 256 err = nvlist_add_int16(nvl, name,
257 257 va_arg(ap, int));
258 258 break;
259 259 case DATA_TYPE_INT16_ARRAY:
260 260 nelem = va_arg(ap, int);
261 261 err = nvlist_add_int16_array(nvl, name,
262 262 va_arg(ap, int16_t *), nelem);
263 263 break;
264 264 case DATA_TYPE_UINT16:
265 265 err = nvlist_add_uint16(nvl, name,
266 266 va_arg(ap, uint_t));
267 267 break;
268 268 case DATA_TYPE_UINT16_ARRAY:
269 269 nelem = va_arg(ap, int);
270 270 err = nvlist_add_uint16_array(nvl, name,
271 271 va_arg(ap, uint16_t *), nelem);
272 272 break;
273 273 case DATA_TYPE_INT32:
274 274 err = nvlist_add_int32(nvl, name,
275 275 va_arg(ap, int32_t));
276 276 break;
277 277 case DATA_TYPE_INT32_ARRAY:
278 278 nelem = va_arg(ap, int);
279 279 err = nvlist_add_int32_array(nvl, name,
280 280 va_arg(ap, int32_t *), nelem);
281 281 break;
282 282 case DATA_TYPE_UINT32:
283 283 err = nvlist_add_uint32(nvl, name,
284 284 va_arg(ap, uint32_t));
285 285 break;
286 286 case DATA_TYPE_UINT32_ARRAY:
287 287 nelem = va_arg(ap, int);
288 288 err = nvlist_add_uint32_array(nvl, name,
289 289 va_arg(ap, uint32_t *), nelem);
290 290 break;
291 291 case DATA_TYPE_INT64:
292 292 err = nvlist_add_int64(nvl, name,
293 293 va_arg(ap, int64_t));
294 294 break;
295 295 case DATA_TYPE_INT64_ARRAY:
296 296 nelem = va_arg(ap, int);
297 297 err = nvlist_add_int64_array(nvl, name,
298 298 va_arg(ap, int64_t *), nelem);
299 299 break;
300 300 case DATA_TYPE_UINT64:
301 301 err = nvlist_add_uint64(nvl, name,
302 302 va_arg(ap, uint64_t));
303 303 break;
304 304 case DATA_TYPE_UINT64_ARRAY:
305 305 nelem = va_arg(ap, int);
306 306 err = nvlist_add_uint64_array(nvl, name,
307 307 va_arg(ap, uint64_t *), nelem);
308 308 break;
309 309 case DATA_TYPE_STRING:
310 310 err = nvlist_add_string(nvl, name,
311 311 va_arg(ap, char *));
312 312 break;
313 313 case DATA_TYPE_STRING_ARRAY:
314 314 nelem = va_arg(ap, int);
315 315 err = nvlist_add_string_array(nvl, name,
316 316 va_arg(ap, char **), nelem);
317 317 break;
318 318 case DATA_TYPE_NVLIST:
319 319 err = nvlist_add_nvlist(nvl, name,
320 320 va_arg(ap, nvlist_t *));
321 321 break;
322 322 case DATA_TYPE_NVLIST_ARRAY:
323 323 nelem = va_arg(ap, int);
324 324 err = nvlist_add_nvlist_array(nvl, name,
325 325 va_arg(ap, nvlist_t **), nelem);
326 326 break;
327 327 case DATA_TYPE_HRTIME:
328 328 err = nvlist_add_hrtime(nvl, name,
329 329 va_arg(ap, hrtime_t));
330 330 break;
331 331 case DATA_TYPE_DOUBLE:
332 332 err = nvlist_add_double(nvl, name,
333 333 va_arg(ap, double));
334 334 break;
335 335 default:
336 336 err = EINVAL;
337 337 }
338 338
339 339 if (err)
340 340 break; /* terminate on first error */
341 341
342 342 processed++;
343 343 name = va_arg(ap, char *);
344 344 }
345 345
346 346 if (name != FMEV_ARG_TERM || processed != ntuples) {
347 347 *nvlp = NULL;
348 348 nvlist_free(nvl);
349 349 return (FMEVERR_VARARGS_MALFORMED);
350 350 }
351 351
352 352 *nvlp = nvl;
353 353 return (FMEV_SUCCESS);
354 354 }
355 355
356 356 static fmev_err_t
357 357 do_publish(const char *file, const char *func, int64_t line,
358 358 const char *ruleset, const char *class, const char *subclass,
359 359 fmev_pri_t pri, nvlist_t *nvl, uint_t ntuples, va_list ap)
360 360 {
361 361 fmev_err_t rc = FMEVERR_INTERNAL;
362 362 boolean_t priv = B_TRUE;
363 363 nvlist_t *tmpnvl = NULL;
364 364 nvlist_t *pub;
365 365 evchan_t *evc;
366 366
367 367 if (nvl) {
368 368 ASSERT(ntuples == 0);
369 369
370 370 /*
371 371 * Enforce NV_UNIQUE_NAME
372 372 */
373 373 if ((nvlist_nvflag(nvl) & NV_UNIQUE_NAME) != NV_UNIQUE_NAME)
374 374 return (FMEVERR_NVLIST);
375 375
376 376 pub = nvl;
377 377
378 378 } else if (ntuples != 0) {
379 379 fmev_err_t err;
380 380
381 381 err = va2nvl(&tmpnvl, ap, ntuples);
382 382 if (err != FMEV_SUCCESS)
383 383 return (err);
384 384
385 385 pub = tmpnvl;
386 386 } else {
387 387 /*
388 388 * Even if the caller has no tuples to publish (just an event
389 389 * class and subclass), we are going to add some detector
390 390 * information so we need some nvlist.
391 391 */
392 392 if (nvlist_alloc(&tmpnvl, NV_UNIQUE_NAME, 0) != 0)
393 393 return (FMEVERR_ALLOC);
394 394
395 395 pub = tmpnvl;
396 396 }
397 397
398 398 evc = bind_channel(priv, pri);
399 399
400 400 if (evc == NULL) {
401 401 rc = FMEVERR_INTERNAL;
402 402 goto done;
403 403 }
404 404
405 405
406 406 /*
407 407 * Add detector information
408 408 */
409 409 if (file && nvlist_add_string(pub, "__fmev_file", file) != 0 ||
410 410 func && nvlist_add_string(pub, "__fmev_func", func) != 0 ||
411 411 line != -1 && nvlist_add_int64(pub, "__fmev_line", line) != 0 ||
412 412 nvlist_add_int32(pub, "__fmev_pid", getpid()) != 0 ||
413 413 nvlist_add_string(pub, "__fmev_execname", getexecname()) != 0) {
414 414 rc = FMEVERR_ALLOC;
415 415 goto done;
416 416 }
417 417
418 418 if (ruleset == NULL)
419 419 ruleset = FMEV_RULESET_DEFAULT;
420 420
421 421 /*
422 422 * We abuse the GPEC publication arguments as follows:
423 423 *
424 424 * GPEC argument Our usage
425 425 * -------------------- -----------------
426 426 * const char *class Raw class
↓ open down ↓ |
426 lines elided |
↑ open up ↑ |
427 427 * const char *subclass Raw subclass
428 428 * const char *vendor Ruleset name
429 429 * const char *pub_name Unused
430 430 * nvlist_t *attr_list Event attributes
431 431 */
432 432 rc = (sysevent_evc_publish(evc, class, subclass, ruleset, "",
433 433 pub, EVCH_NOSLEEP) == 0) ? FMEV_SUCCESS : FMEVERR_TRANSPORT;
434 434
435 435 done:
436 436 /* Free a passed in nvlist iff success */
437 - if (nvl && rc == FMEV_SUCCESS)
437 + if (rc == FMEV_SUCCESS)
438 438 nvlist_free(nvl);
439 439
440 - if (tmpnvl)
441 - nvlist_free(tmpnvl);
440 + nvlist_free(tmpnvl);
442 441
443 442 return (rc);
444 443 }
445 444
446 445 fmev_err_t
447 446 _i_fmev_publish_nvl(
448 447 const char *file, const char *func, int64_t line,
449 448 const char *ruleset, const char *class, const char *subclass,
450 449 fmev_pri_t pri, nvlist_t *attr)
451 450 {
452 451 fmev_err_t rc;
453 452
454 453 if ((rc = vrfy(&ruleset, &class, &subclass, &pri)) != FMEV_OK)
455 454 return (rc); /* any attr not freed */
456 455
457 456 return (do_publish(file, func, line,
458 457 ruleset, class, subclass,
459 458 pri, attr, 0, NULL)); /* any attr freed iff success */
460 459 }
461 460
462 461 fmev_err_t
463 462 _i_fmev_publish(
464 463 const char *file, const char *func, int64_t line,
465 464 const char *ruleset, const char *class, const char *subclass,
466 465 fmev_pri_t pri,
467 466 uint_t ntuples, ...)
468 467 {
469 468 va_list ap;
470 469 fmev_err_t rc;
471 470
472 471 if ((rc = vrfy(&ruleset, &class, &subclass, &pri)) != FMEV_OK)
473 472 return (rc);
474 473
475 474 if (ntuples != 0)
476 475 va_start(ap, ntuples);
477 476
478 477 rc = do_publish(file, func, line,
479 478 ruleset, class, subclass,
480 479 pri, NULL, ntuples, ap);
481 480
482 481 if (ntuples != 0)
483 482 va_end(ap);
484 483
485 484 return (rc);
486 485 }
487 486
488 487
489 488 #pragma weak fmev_publish = _fmev_publish
490 489 #pragma weak fmev_rspublish = _fmev_rspublish
491 490
492 491 static fmev_err_t
493 492 _fmev_publish(const char *class, const char *subclass, fmev_pri_t pri,
494 493 uint_t ntuples, ...)
495 494 {
496 495 fmev_err_t rc;
497 496 va_list ap;
498 497
499 498 if ((rc = vrfy(NULL, &class, &subclass, &pri)) != FMEV_OK)
500 499 return (rc);
501 500
502 501 if (ntuples != 0)
503 502 va_start(ap, ntuples);
504 503
505 504 rc = do_publish(NULL, NULL, -1,
506 505 FMEV_RULESET_DEFAULT, class, subclass,
507 506 pri, NULL, ntuples, ap);
508 507
509 508 if (ntuples != 0)
510 509 va_end(ap);
511 510
512 511 return (rc);
513 512 }
514 513
515 514 static fmev_err_t
516 515 _fmev_rspublish(const char *ruleset, const char *class, const char *subclass,
517 516 fmev_pri_t pri, uint_t ntuples, ...)
518 517 {
519 518 fmev_err_t rc;
520 519 va_list ap;
521 520
522 521 if ((rc = vrfy(&ruleset, &class, &subclass, &pri)) != FMEV_OK)
523 522 return (rc);
524 523
525 524 if (ntuples != 0)
526 525 va_start(ap, ntuples);
527 526
528 527 rc = do_publish(NULL, NULL, -1,
529 528 ruleset, class, subclass,
530 529 pri, NULL, ntuples, ap);
531 530
532 531 if (ntuples != 0)
533 532 va_end(ap);
534 533
535 534 return (rc);
536 535 }
↓ open down ↓ |
85 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX