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) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #ifndef _LIBFMEVENT_H 27 #define _LIBFMEVENT_H 28 29 /* 30 * FMA event library. 31 * 32 * A. Protocol event subscription interfaces (Committed). 33 * B. Raw event publication interfaces (Consolidation Private). 34 */ 35 36 #ifdef __cplusplus 37 extern "C" { 38 #endif 39 40 #include <sys/types.h> 41 #include <libnvpair.h> 42 #include <stdlib.h> 43 #include <door.h> 44 #include <sys/time.h> 45 #include <sys/fm/protocol.h> 46 47 /* 48 * Library ABI interface version. Quote the version you are using 49 * to fmev_shdl_init. Only interfaces introduced in or prior to the 50 * quoted version will be available. Once introduced an interface 51 * only ever changes compatibly. 52 * 53 * Introduced in 54 * API Function LIBFMEVENT_VERSION_* 55 * ----------------------- -------------------- 56 * fmev_attr_list; 1 57 * fmev_class; 1 58 * fmev_dup; 1 59 * fmev_ev2shdl 2 60 * fmev_hold; 1 61 * fmev_localtime; 1 62 * fmev_rele; 1 63 * fmev_shdl_alloc; 1 64 * fmev_shdl_init; 1 65 * fmev_shdl_fini; 1 66 * fmev_shdl_free; 1 67 * fmev_shdl_getauthority 2 68 * fmev_shdl_nvl2str 2 69 * fmev_shdl_strdup 2 70 * fmev_shdl_strfree 2 71 * fmev_shdl_subscribe; 1 72 * fmev_shdl_unsubscribe; 1 73 * fmev_shdl_zalloc; 1 74 * fmev_shdlctl_serialize; 1 75 * fmev_shdlctl_sigmask; 1 76 * fmev_shdlctl_thrattr; 1 77 * fmev_shdlctl_thrcreate; 1 78 * fmev_shdlctl_thrsetup; 1 79 * fmev_strerror; 1 80 * fmev_timespec; 1 81 * fmev_time_nsec; 1 82 * fmev_time_sec; 1 83 */ 84 85 #define LIBFMEVENT_VERSION_1 1 86 #define LIBFMEVENT_VERSION_2 2 87 88 #define LIBFMEVENT_VERSION_LATEST LIBFMEVENT_VERSION_2 89 90 /* 91 * Success and error return values. The descriptive comment for each 92 * FMEVERR_* becomes the string that is returned by fmev_strerror for that 93 * error type. 94 */ 95 typedef enum { 96 FMEV_SUCCESS = 0, 97 FMEV_OK = FMEV_SUCCESS, /* alias for FMEV_SUCCESS */ 98 FMEVERR_UNKNOWN = 0xe000, /* Error details unknown */ 99 FMEVERR_VERSION_MISMATCH, /* Library ABI version incompatible with caller */ 100 FMEVERR_API, /* Library API usage violation */ 101 FMEVERR_ALLOC, /* Failed to allocate additional resources */ 102 FMEVERR_MALFORMED_EVENT, /* Event contents are inconsistent or corrupt */ 103 FMEVERR_OVERFLOW, /* Operation would overflow result type */ 104 FMEVERR_INTERNAL, /* Internal library error */ 105 FMEVERR_NOPRIV, /* Insufficient permissions or privilege */ 106 FMEVERR_BUSY, /* Resource is busy */ 107 FMEVERR_DUPLICATE, /* Duplicate request */ 108 FMEVERR_BADCLASS, /* Bad event class or class pattern */ 109 FMEVERR_NOMATCH, /* No match to criteria provided */ 110 FMEVERR_MAX_SUBSCRIBERS, /* Exceeds maximum subscribers per handle */ 111 FMEVERR_INVALIDARG, /* Argument is invalid */ 112 FMEVERR_STRING2BIG, /* String argument exceeds maximum length */ 113 FMEVERR_VARARGS_MALFORMED, /* Varargs list bad or incorrectly terminated */ 114 FMEVERR_VARARGS_TOOLONG, /* Varargs list exceeds maximum length */ 115 FMEVERR_BADRULESET, /* Ruleset selected for publication is bad */ 116 FMEVERR_BADPRI, /* Priority selected for publication is bad */ 117 FMEVERR_TRANSPORT, /* Error in underlying event transport implementation */ 118 FMEVERR_NVLIST /* nvlist argument is not of type NV_UNIQUE_NAME */ 119 } fmev_err_t; 120 121 /* 122 * Some interfaces return an fmev_err_t - FMEV_SUCCESS on success, otherwise 123 * failure of the indicated type. You can use fmev_strerror to render an 124 * fmev_err_t into a string. 125 * 126 * Other interfaces do not return an fmev_err_t directly. For example 127 * where we return a pointer an error is indicated by a NULL return. 128 * In these cases you can retrieve the fmev_err_t describing the reason 129 * for the failure using fmev_errno or get a string with 130 * fmev_strerr(fmev_errno). Note that fmev_errno is per-thread and holds 131 * the error value for any error that occured during the last libfmevent 132 * API call made by the current thread. Use fmev_errno as you would 133 * regular errno, but you should not assign to fmev_errno. 134 */ 135 extern const fmev_err_t *__fmev_errno(void); /* do not use this directly */ 136 #define fmev_errno (*(__fmev_errno())) 137 extern const char *fmev_strerror(fmev_err_t); 138 139 /* 140 * Part A - Protocol Event Subscription 141 * ====== 142 * 143 * Subscribe to FMA protocol events published by the fault management 144 * daemon, receiving a callback for each matching event. 145 * 146 * This is a Committed interface (see attributes(5) for a definition). 147 */ 148 149 /* 150 * Opaque subscription handle and event types. 151 */ 152 typedef struct fmev_shdl *fmev_shdl_t; 153 typedef struct fmev *fmev_t; 154 155 /* 156 * Subscription callback function type for fmev_shdl_subscribe. 157 */ 158 typedef void fmev_cbfunc_t(fmev_t, const char *, nvlist_t *, void *); 159 160 /* 161 * Initialize a new handle using fmev_shdl_init and quoting interface 162 * version number along with alloc, zalloc and free function pointers (all 163 * NULL to use the defaults. 164 * 165 * Close the handle and release resources with fmev_shdl_fini. 166 */ 167 168 extern fmev_shdl_t fmev_shdl_init(uint32_t, 169 void *(*)(size_t), /* alloc */ 170 void *(*)(size_t), /* zalloc */ 171 void (*)(void *, size_t)); /* free */ 172 173 extern fmev_err_t fmev_shdl_fini(fmev_shdl_t); 174 175 /* 176 * Having created a handle you may optionally configure various properties 177 * for this handle using fmev_shdlctl_*. In most cases accepting the defaults 178 * (that are obtained through fmev_shdl_init alone) will provide adequate 179 * semantics - the controls below are provided for applications 180 * that require fine-grained control over event delivery semantics and, in 181 * particular, the service threads used to perform delivery callbacks. 182 * 183 * These controls may only be applied to a subscription handle 184 * that has no current subscriptions in place. You therefore cannot 185 * change the properties once subscriptions are established, and the 186 * handle properties apply uniformly to all subscriptions on that handle. 187 * If you require different properties per subscription then use multiple 188 * handles. 189 * 190 * fmev_shdlctl_serialize() will serialize all callbacks arising from all 191 * subscriptions on a handle. Event deliveries are normally single-threaded 192 * on a per-subscribtion bases, that is a call to fmev_shdl_subscribe 193 * will have deliveries arising from that subscription delivered 194 * in a serialized fashion on a single thread dedicated to the subscription. 195 * If multiple subscriptions are established then each has a dedicated 196 * delivery thread - fmev_shdlctl_serialize arranges that only one of these 197 * threads services a callback at any one time. 198 * 199 * fmev_shdlctl_thrattr() allows you to provide thread attributes for use 200 * in pthread_create() when server threads are created. The attributes 201 * are not copied - the pthread_attr_t object passed must exist for 202 * the duration of all subscriptions on the handle. These attributes only 203 * apply if fmev_shdlctl_thrcreate() is not in use on this handle. 204 * 205 * fmev_shdlctl_sigmask() allows you to provide a sigset_t signal mask 206 * of signals to block in server threads. The pthread_sigmask is set 207 * to this immediately before pthread_create, and restored immediately 208 * after pthread_create. This mask only applies if fmev_shdlctl_thrcreate() 209 * is not in use on this handle. 210 * 211 * fmev_shdlctl_thrsetup() allows you to install a custom door server thread 212 * setup function - see door_xcreate(3C). This will be used with the 213 * default thread creation semantics or with any custom thread creation 214 * function appointed with fmev_shdlctl_thrcreate(). 215 * 216 * fmev_shdlctl_thrcreate() allows you to install a custom door server thread 217 * creation function - see door_xcreate(3C). This option excludes 218 * fmev_shdlctl_{thrattr,sigmask} but the remaining options 219 * of fmev_shdlctl_{serialize,thrsetup} are still available. 220 */ 221 222 extern fmev_err_t fmev_shdlctl_serialize(fmev_shdl_t); 223 extern fmev_err_t fmev_shdlctl_thrattr(fmev_shdl_t, pthread_attr_t *); 224 extern fmev_err_t fmev_shdlctl_sigmask(fmev_shdl_t, sigset_t *); 225 extern fmev_err_t fmev_shdlctl_thrsetup(fmev_shdl_t, 226 door_xcreate_thrsetup_func_t *, void *); 227 extern fmev_err_t fmev_shdlctl_thrcreate(fmev_shdl_t, 228 door_xcreate_server_func_t *, void *); 229 230 /* 231 * Specify subscription choices on a handle using fmev_shdl_subscribe as 232 * many times as needed to describe the full event set. The event class 233 * pattern can be wildcarded using simple '*' wildcarding. When an event 234 * matching a subscription is received a callback is performed to the 235 * nominated function passing a fmev_t handle on the event and the 236 * requested cookie argument. 237 * 238 * See the fault management event protocol specification for a description 239 * of event classes. 240 * 241 * Drop a subscription using fmev_shdl_unsubscribe (which must match an 242 * earlier subscription). 243 */ 244 245 #define FMEV_MAX_CLASS 64 /* Longest class string for subscription */ 246 247 extern fmev_err_t fmev_shdl_subscribe(fmev_shdl_t, const char *, fmev_cbfunc_t, 248 void *); 249 extern fmev_err_t fmev_shdl_unsubscribe(fmev_shdl_t, const char *); 250 251 /* 252 * Retrieve an authority nvlist for the fault manager that is forwarding 253 * events to us. This may be NULL if the fault manager has not yet 254 * started up and made the information available. The caller is 255 * responsible for freeing the nvlist returned. 256 */ 257 extern fmev_err_t fmev_shdl_getauthority(fmev_shdl_t, nvlist_t **); 258 259 /* 260 * Event access. In the common case that the event is processed to 261 * completion in the context of the event callback you need only 262 * use fmev_attr_list to access the nvlist of event attributes, 263 * with no responsibility for freeing the event or the nvlist; for 264 * convenience, fmev_class and fmev_timestamp can both be used to 265 * look inside an event without having to work with the attribute list (and 266 * the callback receives the class as an argument). 267 * 268 * See libnvpair(3LIB) for interfaces to access an nvlist_t. 269 * 270 * The remaining interfaces apply in the case that event handling will 271 * continue beyond the context of the event callback in which it is received. 272 * 273 * The fmev_t handle received in a callback is reference-counted; 274 * the initial reference count on entry to the callback is 1, and the 275 * count is always decremented when the callback completes. To continue 276 * to operate on a received event outside of the context of the callback 277 * in which it is first received, take an fmev_hold during the callback 278 * and later fmev_rele to release your hold (and free the event if the count 279 * drops to 0). 280 * 281 * To access attributes of an event use fmev_attr_list to receive 282 * an nvlist_t pointer valid for the same lifetime as the event itself (i.e., 283 * until its reference count drops to zero). 284 * 285 * If changes are made to a received fmev_t (discouraged) then all who 286 * have a hold on the event share the change. To obtain an independent 287 * copy of an fmev_t, with a reference count of 1, use fmev_dup. When 288 * finished with the copy decrement the reference count 289 * using fmev_rele - the event will be freed if the count reaches 0. 290 * 291 * For convenience you can retrieve the class of an event using fmev_class 292 * (it's also available as an argument to a callback, and within the 293 * event attribute list). The string returned by fmev_class is valid for 294 * the same lifetime as the event itself. 295 * 296 * The time at which a protocol event was generated is available via 297 * fmev_timespec; tv_sec has seconds since the epoch, and tv_nsec nanoseconds 298 * past that second. This can fail with FMEVERR_OVERFLOW if the seconds 299 * value does not fit within a time_t; you can retrieve the 64-bit second 300 * and nanosecond values with fmev_time_sec and fmev_time_nsec. 301 * 302 * An FMRI in an event payload is typically in nvlist form, i.e 303 * DATA_TYPE_NVLIST. That form is useful for extracting individual 304 * component fields, but that requires knowledge of the FMRI scheme and 305 * Public commitment thereof. FMRIs are typically Private, but in some 306 * cases they can be descriptive such as in listing the ASRU(s) affected 307 * by a fault; so we offer an API member which will blindly render any 308 * FMRI in its string form. Use fmev_shdl_nvl2str to format an nvlist_t 309 * as a string (if it is recognized as an FMRI); the caller is responsible 310 * for freeing the returned string using fmev_shdl_strfree. If 311 * fmev_shdl_nvl2str fails it will return NULL with fmev_errno set - 312 * FMEVERR_INVALIDARG if the nvlist_t does not appear to be a valid/known FMRI, 313 * FMEVERR_ALLOC if an allocation for memory for the string failed. 314 * 315 * fmev_ev2shdl will return the fmev_shdl_t with which a received fmev_t 316 * is associated. It should only be used in an event delivery callback 317 * context and for the event received in that callback. 318 */ 319 320 extern nvlist_t *fmev_attr_list(fmev_t); 321 extern const char *fmev_class(fmev_t); 322 323 extern fmev_err_t fmev_timespec(fmev_t, struct timespec *); 324 extern uint64_t fmev_time_sec(fmev_t); 325 extern uint64_t fmev_time_nsec(fmev_t); 326 extern struct tm *fmev_localtime(fmev_t, struct tm *); 327 328 extern void fmev_hold(fmev_t); 329 extern void fmev_rele(fmev_t); 330 extern fmev_t fmev_dup(fmev_t); 331 332 extern char *fmev_shdl_nvl2str(fmev_shdl_t, nvlist_t *); 333 334 extern fmev_shdl_t fmev_ev2shdl(fmev_t); 335 336 /* 337 * The following will allocate and free memory based on the choices made 338 * at fmev_shdl_init. 339 */ 340 void *fmev_shdl_alloc(fmev_shdl_t, size_t); 341 void *fmev_shdl_zalloc(fmev_shdl_t, size_t); 342 void fmev_shdl_free(fmev_shdl_t, void *, size_t); 343 extern char *fmev_shdl_strdup(fmev_shdl_t, char *); 344 extern void fmev_shdl_strfree(fmev_shdl_t, char *); 345 346 /* 347 * Part B - Raw Event Publication 348 * ====== 349 * 350 * The following interfaces are private to the Solaris system and are 351 * subject to change at any time without notice. Applications using 352 * these interfaces will fail to run on future releases. The interfaces 353 * should not be used for any purpose until they are publicly documented 354 * for use outside of Sun. These interface are *certain* to change 355 * incompatibly, as the current interface is very much purpose-built for 356 * a limited application. 357 * 358 * The interfaces below allow a process to publish a "raw" event 359 * which will be transmitted to the fault manager and post-processed 360 * into a full FMA protocol event. The post-processing to be applied 361 * is selected by a "ruleset" specified either implicitly or explicitly 362 * at publication. A ruleset will take the raw event (comprising 363 * class, subclass, priority, raw payload) and mark it up into a full 364 * protocol event; it may also augment the payload through looking up 365 * details that would have been costly to compute at publication time. 366 * 367 * In this first implementation event dispatch is synchronous and blocking, 368 * and not guaranteed to be re-entrant. This limits the call sites 369 * at which publication calls can be placed, and also means that careful 370 * thought is required before sprinkling event publication code throughout 371 * common system libraries. The dispatch mechanism amounts to some 372 * nvlist chicanery followed by a sysevent_evc_publish. A future revision 373 * will relax the context from which one may publish, and add more-powerful 374 * publication interfaces. 375 * 376 * Some publication interfaces (those ending in _nvl) accept a preconstructed 377 * nvlist as raw event payload. We require that such an nvlist be of type 378 * NV_UNIQUE_NAME. The publication interfaces all call nvlist_free on any 379 * nvlist that is passed for publication. 380 * 381 * Other publication interfaces allow you to build up the raw event payload 382 * by specifying the members in a varargs list terminated by FMEV_ARG_TERM. 383 * Again we require that payload member names are unique (that is, you cannot 384 * have two members with the same name but different datatype). See 385 * <sys/nvpair.h> for the data_type_t enumeration of types supported - but 386 * note that DATA_TYPE_BOOLEAN is excluded (DATA_TYPE_BOOLEAN_VALUE is 387 * supported). A single-valued (non-array type) member is specified with 3 388 * consecutive varargs as: 389 * 390 * (char *)name, DATA_TYPE_foo, (type)value 391 * 392 * An array-valued member is specified with 4 consecutive varargs as: 393 * 394 * (char *)name, DATA_TYPE_foo_ARRAY, (int)nelem, (type *)arrayptr 395 * 396 * The varargs list that specifies the nvlist must begin with an 397 * integer that specifies the number of members that follow. For example: 398 * 399 * uint32_t mode; 400 * char *clientname; 401 * uint32_t ins[NARGS]; 402 * 403 * fmev_publish("class", "subclass", FMEV_LOPRI, 404 * 3, 405 * "mode", DATA_TYPE_UINT32, mode, 406 * "client", DATA_TYPE_STRING, clientname, 407 * "ins", DATA_TYPE_UINT32_ARRAY, sizeof (ins) / sizeof (ins[0]), ins, 408 * FMEV_ARG_TERM); 409 * 410 * The following tables summarize the capabilities of the various 411 * publication interfaces. 412 * 413 * Detector 414 * Interface Ruleset? File/Line Func 415 * ---------------------------- -------- --------- ---- 416 * fmev_publish_nvl default Yes No 417 * fmev_publish_nvl (C99) default Yes Yes 418 * fmev_rspublish_nvl chosen Yes No 419 * fmev_rspublish_nvl (C99) chosen Yes Yes 420 * fmev_publish default No No 421 * fmev_publish (C99) default Yes Yes 422 * fmev_rspublish chosen No No 423 * fmev_rspublish (C99) chosen Yes Yes 424 * 425 * Summary: if not using C99 then try to use the _nvl variants as the 426 * varargs variants will not include file, line or function in the 427 * detector. 428 */ 429 430 /* 431 * In publishing an event you must select a "ruleset" (or accept the 432 * defaults). Rulesets are listed in the following header. 433 */ 434 #include <fm/libfmevent_ruleset.h> 435 436 /* 437 * In publishing an event we can specify a class and subclass (which 438 * in post-processing combine in some way selected by the ruleset to 439 * form a full event protocol class). The maximum class and subclass 440 * string lengths are as follows. 441 */ 442 #define FMEV_PUB_MAXCLASSLEN 32 443 #define FMEV_PUB_MAXSUBCLASSLEN 32 444 445 /* 446 * Events are either high-priority (try really hard not to lose) or 447 * low-priority (can drop, throttle etc). Convert a fmev_pri_t to 448 * a string with fmev_pri_string(). 449 */ 450 typedef enum fmev_pri { 451 FMEV_LOPRI = 0x1000, 452 FMEV_HIPRI 453 } fmev_pri_t; 454 455 extern const char *fmev_pri_string(fmev_pri_t); 456 457 /* 458 * The varargs event publication interfaces must terminate the list 459 * of nvpair specifications with FMEV_ARG_TERM. This is to guard 460 * against very easily-made mistakes in those arg lists. 461 */ 462 #define FMEV_ARG_TERM (void *)0xa4a3a2a1 463 464 /* 465 * The following are NOT for direct use. 466 */ 467 extern fmev_err_t _i_fmev_publish_nvl( 468 const char *, const char *, int64_t, 469 const char *, const char *, const char *, 470 fmev_pri_t, nvlist_t *); 471 472 extern fmev_err_t _i_fmev_publish( 473 const char *, const char *, int64_t, 474 const char *, const char *, const char *, 475 fmev_pri_t, 476 uint_t, ...); 477 478 /* 479 * Post-processing will always generate a "detector" payload member. In 480 * the case of the _nvl publishing variants the detector information 481 * includes file and line number, and - if your application is compiled 482 * with C99 enabled - function name. 483 */ 484 #if __STDC_VERSION__ - 0 >= 199901L 485 #define _FMEVFUNC __func__ 486 #else 487 #define _FMEVFUNC NULL 488 #endif 489 490 /* 491 * All these definitions "return" an fmev_err_t. 492 * 493 * In the _nvl variants you pass a preconstructed event payload; otherwise 494 * you include an integer indicating the number of payload 495 * (name, type, value) tuples that follow, then all those tuples, finally 496 * terminated by FMEV_ARG_TERM. 497 * 498 * In the rspublish variants you select a ruleset from 499 * libfmevent_ruleset.h - just use the final suffix (as in 500 * DEFAULT, EREPORT, ISV). 501 * 502 * The primary classification must not be NULL or the empty string. 503 * 504 * arg type Description 505 * ------- --------------- ------------------------------------------- 506 * ruleset const char * Ruleset; can be NULL (implies default ruleset) 507 * cl1 const char * Primary classification string 508 * cl2 const char * Secondary classification string 509 * pri fmev_pri_t Priority 510 * nvl nvlist_t * Preconstructed attributes; caller must free 511 * ntuples int Number of tuples before FMEV_ARG_TERM 512 * suffix - See above. 513 */ 514 515 /* 516 * fmev_publish_nvl - Default ruleset implied; class/subclass, pri and an nvl 517 */ 518 #define fmev_publish_nvl(cl1, cl2, pri, nvl) \ 519 _i_fmev_publish_nvl( \ 520 __FILE__, _FMEVFUNC, __LINE__, \ 521 FMEV_RULESET_DEFAULT, cl1, cl2, \ 522 pri, nvl) 523 524 /* 525 * fmev_rspublish_nvl - As fmev_publish_nvl, but with a chosen ruleset. 526 */ 527 #define fmev_rspublish_nvl(ruleset, cl1, cl2, pri, nvl) \ 528 _i_fmev_publish_nvl( \ 529 __FILE__, _FMEVFUNC, __LINE__, \ 530 ruleset, cl1, cl2, \ 531 pri, nvl) 532 533 #if __STDC_VERSION__ - 0 >= 199901L && !defined(__lint) 534 535 /* 536 * fmev_publish (C99 version) - Default ruleset; class/subclass, pri, nvpairs 537 */ 538 #define fmev_publish(cl1, cl2, pri, ntuples, ...) \ 539 _i_fmev_publish( \ 540 __FILE__, __func__, __LINE__, \ 541 FMEV_RULESET_DEFAULT, cl1, cl2, \ 542 pri, \ 543 ntuples, __VA_ARGS__) 544 545 546 /* 547 * fmev_rspublish (C99 version) - As fmev_publish, but with a chosen ruleset. 548 */ 549 #define fmev_rspublish(ruleset, cl1, cl2, pri, ntuples, ...) \ 550 _i_fmev_publish( \ 551 __FILE__, __func__, __LINE__, \ 552 ruleset, cl1, cl2, \ 553 pri, \ 554 ntuples, __VA_ARGS__) 555 556 #else 557 558 /* 559 * fmev_publish (pre C99) 560 */ 561 extern fmev_err_t fmev_publish(const char *, const char *, 562 fmev_pri_t, uint_t, ...); 563 564 /* 565 * fmev_rspublish (pre C99) 566 */ 567 extern fmev_err_t fmev_rspublish(const char *, const char *, const char *, 568 fmev_pri_t, uint_t, ...); 569 570 #endif /* __STDC_VERSION__ */ 571 572 #ifdef __cplusplus 573 } 574 #endif 575 576 #endif /* _LIBFMEVENT_H */ 577