/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_SYSEVENT_IMPL_H
#define _SYS_SYSEVENT_IMPL_H
#include <sys/nvpair.h>
#include <sys/id_space.h>
#include <sys/door.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint64_t se_data_t;
/*
* The following data structure assist in loading and extracting event
* header and attribute data into contiguous memory. Access to all typed
* data done so on 64-bit boundaries. *Do Not* alter any of the structures
* defined below without thorough thought and testing.
*/
/* Attribute name */
typedef struct se_name {
int32_t name_sz;
int32_t name_pad;
se_data_t name; /* 64-bit aligned offset */
} se_name_t;
/* Attribute value */
typedef struct se_value {
int32_t value_type; /* data type */
int32_t value_sz;
se_data_t value; /* data value - 64-bit aligned offset */
} se_value_t;
/* sysevent internal attribute name-value pair stored in contiguous memory */
typedef struct sysevent_attr_impl {
int32_t se_attr_sz; /* Size of attribute data */
int32_t se_attr_pad; /* pad */
se_data_t se_attr_name; /* name of data attribute */
se_data_t se_attr_val; /* value and type of data */
} sysevent_attr_impl_t;
/* Attribute list states */
#define ATTR_DETACHED 0
#define ATTR_ATTACHED 1
/*
* The following type definitions describe a sysevent object that is
* generated by a call to sysevent_alloc and sent to userland.
*/
/*
* sysevent event header information -
* contained in every event generated. The header and the event
* must remain 64-bit aligned. The header, up to the attribute
* offset, can be contained in a single cache line.
*/
typedef struct sysevent_hdr {
sysevent_id_t se_id; /* unique identifier */
uint32_t se_version; /* version of this data structure */
uint32_t se_flag;
uint32_t se_class; /* event class id - reserved */
uint32_t se_subclass; /* event subclass id - reserved */
int32_t se_payload_sz; /* size of attr data + strings */
uint16_t se_subclass_off; /* offset to subclass string */
uint16_t se_pub_off; /* offset to publisher string */
uint64_t se_attr_off; /* pointer or offset to attr data */
} sysevent_hdr_t;
/* sysevent event buffer - 64-bit aligned offsets */
typedef struct sys_event_impl {
sysevent_hdr_t se_header;
se_data_t se_class_name; /* class string in contig memory */
se_data_t se_subclass_name; /* subclass string in contig memory */
se_data_t se_pub; /* publisher string in contig mem */
se_data_t se_attr_buf; /* contiguous attribute memory */
} sysevent_impl_t;
/* Helpful defines */
#define seh_version se_header.se_version
#define seh_class se_header.se_class
#define seh_subclass se_header.se_subclass
#define seh_seq se_header.se_id.eid_seq
#define seh_time se_header.se_id.eid_ts
#define seh_subclass_off se_header.se_subclass_off
#define seh_pub_off se_header.se_pub_off
#define seh_attr_off se_header.se_attr_off
#define seh_payload_sz se_header.se_payload_sz
#define seh_flag se_header.se_flag
/* Event buffer version */
#define SYS_EVENT_VERSION 0
/* Event buffer flags */
#define SE_PACKED_BUF 1
#define SYSEVENT_IMPL(ev) ((sysevent_impl_t *)(void *)(ev))
#define SE_VERSION(ev) (SYSEVENT_IMPL(ev)->seh_version)
#define SE_CLASS(ev) (SYSEVENT_IMPL(ev)->seh_class)
#define SE_SUBCLASS(ev) (SYSEVENT_IMPL(ev)->seh_subclass)
#define SE_SEQ(ev) (SYSEVENT_IMPL(ev)->seh_seq)
#define SE_TIME(ev) (SYSEVENT_IMPL(ev)->seh_time)
#define SE_SUBCLASS_OFF(ev) (SYSEVENT_IMPL(ev)->seh_subclass_off)
#define SE_PUB_OFF(ev) (SYSEVENT_IMPL(ev)->seh_pub_off)
#define SE_PAYLOAD_SZ(ev) (SYSEVENT_IMPL(ev)->seh_payload_sz)
#define SE_FLAG(ev) (SYSEVENT_IMPL(ev)->seh_flag)
#define SE_SIZE(ev) (sizeof (sysevent_impl_t) + SE_PAYLOAD_SZ(ev))
#define SE_CLASS_NAME(ev) ((char *)&(SYSEVENT_IMPL(ev)->se_class_name))
#define SE_SUBCLASS_NAME(ev) ((char *)((caddr_t)(ev) + SE_SUBCLASS_OFF(ev)))
#define SE_PUB_NAME(ev) ((char *)((caddr_t)(ev) + SE_PUB_OFF(ev)))
/*
* Attribute data can be stored in contiguous memory or
* as a list of attribute data elements. The storage format is determined
* by the SE_PACKED_BUF flag in the event buffer flags.
*
*/
/* 64-bit boundary alignment function */
#define SE_ALIGN(x) ((((ulong_t)x) + 7ul) & ~7ul)
/* Access to unpacked attribute list */
#define SE_ATTR_PTR(ev) (SYSEVENT_IMPL(ev)->seh_attr_off)
/* Offset to packed attribute data */
#define SE_ATTR_OFF(ev) SE_PUB_OFF(ev) + SE_ALIGN(strlen(SE_PUB_NAME(ev)) + 1)
/* syseventd door */
#define LOGEVENT_DOOR_UPCALL "/var/run/sysevent_door"
/*
* door upcall data structures
*/
typedef struct log_event_upcall_arg {
int32_t retcode;
int32_t pad;
sysevent_impl_t buf;
} log_event_upcall_arg_t;
typedef struct log_eventq {
struct log_eventq *next;
log_event_upcall_arg_t arg;
} log_eventq_t;
/* Syseventd Channel structures */
#define MAX_CHAN 256 /* Maximum channels per system */
#define MAX_SUBSCRIBERS 100 /* Maximum subscribers per channel */
#define MAX_PUBLISHERS 1 /* Maximum publishers per channel */
/*
* Channel-based subscription structures
*/
/* Class hashing defines */
#define CLASS_HASH_SZ 63
#define CLASS_HASH(class_name) ((hash_func(class_name) \
% CLASS_HASH_SZ) + 1)
#define CHAN_HASH_SZ 32
typedef struct subclass_lst {
struct subclass_lst *sl_next;
char *sl_name;
uchar_t sl_num[MAX_SUBSCRIBERS + 1];
} subclass_lst_t;
typedef struct class_lst {
struct class_lst *cl_next;
char *cl_name;
struct subclass_lst *cl_subclass_list;
} class_lst_t;
/* User/Kernel Structure to pass event registration modctl data */
typedef struct se_pubsub {
uint32_t ps_buflen;
uint32_t ps_channel_name_len;
uint32_t ps_id;
uint32_t ps_op;
uint32_t ps_type;
} se_pubsub_t;
/* op defines */
#define SE_REGISTER 0
#define SE_UNREGISTER 1
#define SE_CLEANUP 2
#define SE_OPEN_REGISTRATION 3
#define SE_CLOSE_REGISTRATION 4
#define SE_BIND_REGISTRATION 5
#define SE_UNBIND_REGISTRATION 6
#define SE_GET_REGISTRATION 7
/* type defines */
#define SUBSCRIBER 0
#define PUBLISHER 1
/* nvpair names */
#define CLASS_NAME "class"
#ifdef _KERNEL
typedef struct sysevent_channel_descriptor {
char *scd_channel_name; /* Name of channel */
struct sysevent_channel_descriptor *scd_next;
int scd_ref_cnt; /* Reference count of channel opens */
id_space_t *scd_subscriber_cache; /* cache of subscriber ids */
id_space_t *scd_publisher_cache; /* cache of publisher ids */
uchar_t scd_subscriber_ids[MAX_SUBSCRIBERS + 1]; /* used sub ids */
uchar_t scd_publisher_ids[MAX_PUBLISHERS + 1]; /* used pub ids */
class_lst_t *scd_class_list_tbl[CLASS_HASH_SZ + 1];
} sysevent_channel_descriptor_t;
/*
* log_sysevent private interfaces
*/
extern void log_event_init(void);
extern void log_sysevent_flushq(int, uint_t);
extern int log_sysevent_filename(char *);
extern int log_usr_sysevent(sysevent_t *, int, sysevent_id_t *);
extern int log_sysevent_copyout_data(sysevent_id_t *, size_t, caddr_t);
extern int log_sysevent_free_data(sysevent_id_t *);
extern int log_sysevent_register(char *, char *, se_pubsub_t *);
extern uint64_t log_sysevent_new_id(void);
/*
* Structures and definitions for general purpose event channels
*/
/* Limits */
#define EVCH_MAX_CHANNELS 1024
#define EVCH_MAX_BINDS_PER_CHANNEL 512
#define EVCH_MAX_SUBSCRIPTIONS 32
#define EVCH_SUBPOOLFACT 8
#define EVCH_DEFAULT_EVENTS 2000
#define EVCH_MAX_TRY_DELIVERY 3
/* Linkage element for evch_dlist_t lists */
typedef struct evch_dlelem {
struct evch_dlelem *dl_next;
struct evch_dlelem *dl_prev;
} evch_dlelem_t;
/* List head */
typedef struct {
evch_dlelem_t dh_head;
int dh_count;
} evch_dlist_t;
/* Placeholder for elements in a evch_squeue_t queue */
typedef struct evch_qelem {
struct evch_qelem *q_next;
void *q_objref;
size_t q_objsize;
} evch_qelem_t;
/* Queue head data */
typedef struct {
evch_qelem_t *sq_head;
evch_qelem_t *sq_tail;
uint32_t sq_count;
uint32_t sq_highwm;
} evch_squeue_t;
/*
* Defines for event queue routines
*/
#define EVQ_IGNORE 1
#define EVQ_DELIVER 2
#define EVQ_CONT 0
#define EVQ_AGAIN 1
#define EVQ_SLEEP 2
/* Call back routine typedefs */
typedef int (*filter_f)(void *, void *);
typedef int (*deliver_f)(void *, void *);
typedef int (*kerndlv_f)(void *, void *);
typedef void (*destr_f)(void *, void *);
typedef int (*compare_f)(evch_dlelem_t *, char *);
/*
* Event structure handled by evch_evq_* functions. Sysevent type events are
* stored as the payload.
*/
typedef struct {
uint32_t ge_size; /* Total size of event structure */
uint32_t ge_refcount; /* No of queues event is linked to */
destr_f ge_destruct; /* Destructor for event structure */
uint32_t *ge_dstcookie; /* Cookie for destructor function */
uchar_t ge_payload[1]; /* Placeholder for event data */
} evch_gevent_t;
/*
* Event queue descriptor
*/
typedef struct {
evch_squeue_t eq_eventq; /* Protected by eq_dtmutex */
kt_did_t eq_thrid; /* Id delivery thread */
kmutex_t eq_queuemx; /* Protect. of this struct and ev q */
kcondvar_t eq_thrsleepcv; /* Delivery thread sleeps on empty q */
int eq_dactive; /* Event delivery is in progress */
kcondvar_t eq_dactivecv; /* Unsubscr. has to wait on this */
evch_dlist_t eq_subscr; /* Chain of all evch_evqsub_t */
uint32_t eq_nsleep; /* Statistic: Publisher set to sleep */
int eq_holdmode; /* Hold event delivery */
evch_gevent_t *eq_curevent; /* Event currently beeing delivered */
evch_qelem_t *eq_nextev; /* For iterating over events in a q */
kcondvar_t eq_onholdcv; /* To signal hold mode of deliv. thr. */
uchar_t eq_tabortflag; /* Request to abort delivery thread */
} evch_eventq_t;
/*
* Event queue per subscriber structure
*/
typedef struct {
evch_dlelem_t su_link;
filter_f su_filter; /* Event filter function pointer */
void *su_fcookie; /* cookie for event filter */
deliver_f su_callb; /* Event delivery callback */
void *su_cbcookie; /* callback cookie */
} evch_evqsub_t;
/* Eveny delivery type */
#define EVCH_DELKERN 1 /* Kernel event delivery */
#define EVCH_DELDOOR 2 /* User event delivery via doors */
/*
* Per channel subscriber data structure. Chained in a linked list to an
* event channel and to a binding.
*/
typedef struct chsubd {
evch_dlelem_t sd_link; /* Links all subscribers of this ch. */
struct chsubd *sd_subnxt; /* Links all subscr. for a binding */
char *sd_ident; /* Subscriber identifier */
evch_eventq_t *sd_queue; /* Event queue for this subscriber */
evch_evqsub_t *sd_msub; /* Main event queue subscr. */
char *sd_classname; /* Filter criteria */
size_t sd_clnsize; /* Size of sd_classname buffer */
evch_evqsub_t *sd_ssub; /* Subscriber queue subscr. */
int sd_type; /* Type of event delivery */
kerndlv_f sd_callback; /* Callback for kernel delivery */
void *sd_cbcookie; /* Cookie for kernel delivery */
door_handle_t sd_door; /* Door handle for user delivery */
int sd_active; /* Subscription is in use indicator */
pid_t sd_pid; /* PID of subscribing process */
uint8_t sd_persist; /* Persistent user land subscription */
uint8_t sd_dump; /* Dump with sysevent_evc_walk_* */
} evch_subd_t;
/*
* General purpose event channel descriptor structure. This is the main
* structure for event subscribing, publishing, delivery to/from an event
* channel.
*/
typedef struct {
evch_dlelem_t ch_link; /* Must be first elem. of structure */
char *ch_name; /* Channel name */
size_t ch_namelen; /* Length of channel name buffer */
kmutex_t ch_mutex; /* To protect this structure */
evch_eventq_t *ch_queue; /* Publisher event queue */
evch_dlist_t ch_subscr; /* List of subscr. data (evch_subd_t) */
uint32_t ch_bindings; /* No of bindings to this channel */
int ch_maxbinds; /* Maximum number of binds */
uid_t ch_uid; /* Creators effective user id */
gid_t ch_gid; /* Creators effective group id */
kmutex_t ch_pubmx; /* Mutex for ch_pubcv and ch_nevents */
kcondvar_t ch_pubcv; /* To set publisher to sleep */
uint32_t ch_nevents; /* Current number of events */
uint32_t ch_maxev; /* Maximum number of events */
int ch_maxsubscr; /* Maximum number of subscriptions */
int ch_holdpend; /* Hold pending events mode if != 0 */
time_t ch_ctime; /* Channel creation time */
nvlist_t *ch_propnvl; /* Channel properties nvlist */
int64_t ch_propnvlgen; /* Properties generation number */
} evch_chan_t;
/*
* Channel binding structure. Allocated per binding to a channel. Protected
* by locking the channel structure
*/
typedef struct {
evch_chan_t *bd_channel;
evch_subd_t *bd_sublst; /* chain of all subscriptions */
} evch_bind_t;
/*
* Structure to keep a snapshot of all events of a channel
*/
typedef struct {
evch_eventq_t *sn_queue; /* Event queue with snapshot of ev's */
sysevent_impl_t *sn_nxtev; /* Pointer to find next event */
} evchanq_t;
/* Project private interfaces */
extern evchan_t *evch_usrchanopen(const char *name, uint32_t flags, int *err);
extern void evch_usrchanclose(evchan_t *cbp);
extern sysevent_impl_t *evch_usrallocev(size_t evsize, uint32_t flags);
extern void evch_usrfreeev(sysevent_impl_t *ev);
extern int evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags);
extern int evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class,
int d, uint32_t flags);
extern int evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value);
extern int evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value);
extern void evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flag);
extern int evch_usrgetchnames(char *buf, size_t size);
extern int evch_usrgetchdata(char *chname, void *buf, size_t size);
extern void evch_usrsetpropnvl(evchan_t *bp, nvlist_t *nvl);
extern int evch_usrgetpropnvl(evchan_t *bp, nvlist_t **nvlp, int64_t *genp);
extern void sysevent_evc_init();
extern void sysevent_evc_thrinit();
extern evchanq_t *sysevent_evc_walk_init(evchan_t *, char *);
extern sysevent_t *sysevent_evc_walk_step(evchanq_t *);
extern void sysevent_evc_walk_fini(evchanq_t *);
extern char *sysevent_evc_event_attr(sysevent_t *, size_t *);
#endif /* _KERNEL */
/*
* Structures and limits to deliver channel data to syseventadm
*/
#define EVCH_MAX_DATA_SIZE (1024 * 1024)
typedef struct {
uint32_t sb_nextoff; /* Offset to next subscr info struct */
uint32_t sb_stroff; /* Offset to strings */
uint32_t sb_clnamoff; /* Offset of class in sb_strings */
uint32_t sb_pid; /* Subscriber process id */
uint32_t sb_nevents; /* Current no of event in sub q */
uint32_t sb_evhwm; /* High watermark of sub q */
uint32_t sb_persist; /* != 0 if subscription persists */
uint32_t sb_status; /* != 0 if subscription is inactive */
uint32_t sb_active; /* > 0 if subscription is in use */
uint32_t sb_dump; /* != 0 if sub will be dumped */
char sb_strings[1]; /* String space for subid and class */
} sev_subinfo_t;
typedef struct {
uint32_t cd_version; /* Version of this structure */
uint32_t cd_suboffs; /* Offset of subscriber info struct */
uint64_t cd_ctime; /* Creation time */
uint32_t cd_uid; /* User id */
uint32_t cd_gid; /* Owner group id */
uint32_t cd_perms; /* Permission bits */
uint32_t cd_maxev; /* Max number of events */
uint32_t cd_evhwm; /* High watermark of main event queue */
uint32_t cd_nevents; /* current no of events in main ev q */
uint32_t cd_maxsub; /* Max number of subscriptions */
uint32_t cd_nsub; /* Current number of subscriptions */
uint32_t cd_maxbinds; /* Max number of binds */
uint32_t cd_nbinds; /* Current number of binds */
uint32_t cd_holdpend; /* != 0 when HOLDPEND mode is set */
uint32_t cd_limev; /* Limit of events per channel */
sev_subinfo_t cd_subinfo[1]; /* Per subscriber data */
} sev_chinfo_t;
/*
* Project private flags for sysevent_evc_subscribe. Bits 0 to 7 are reserved
* for the consolidation private interface, so we must use bits 8-15 here.
*/
#define EVCH_SUB_DUMP (0x01 << 8)
/*
* Permission flags
*/
#define EVCH_PUB 0x0004 /* wants to publish events */
#define EVCH_SUB 0x0008 /* wants to subscribe to channel */
#define EVCH_SUBU 0x0001 /* Subscribing allowed for uid */
#define EVCH_PUBU 0x0002 /* Publishing allowed for uid */
#define EVCH_PSUSR 0x0003 /* EVCH_SUBU + EVCH_PUBU */
#define EVCH_SUBG 0x0004 /* Subscribing allowed for gid */
#define EVCH_PUBG 0x0008 /* Publishing allowed for gid */
#define EVCH_PSGRP 0x000C /* EVCH_SUBG + EVCH_PUBG */
#define EVCH_SUBO 0x0010 /* Subscribing allowed to all users */
#define EVCH_PUBO 0x0020 /* Publishing allowed to all users */
#define EVCH_PSOTH 0x0030 /* EVCH_SUBO + EVCH_PUBO */
#define EVCH_PSALL 0x003f /* Mask of all permission bits */
/*
* Sysevent driver ioctls
*/
#define SEV_BASE 0x53455600
#define SEV_PUBLISH SEV_BASE | 0x01
#define SEV_CHAN_OPEN SEV_BASE | 0x02
#define SEV_CHAN_CONTROL SEV_BASE | 0x03
#define SEV_SUBSCRIBE SEV_BASE | 0x04
#define SEV_UNSUBSCRIBE SEV_BASE | 0x05
#define SEV_CHANNAMES SEV_BASE | 0x06
#define SEV_CHANDATA SEV_BASE | 0x07
#define SEV_SETPROPNVL SEV_BASE | 0x08
#define SEV_GETPROPNVL SEV_BASE | 0x09
#define DEVSYSEVENT "/dev/sysevent"
#define DEVICESYSEVENT "/devices/pseudo/sysevent@0:sysevent"
/*
* Maximum allowed binding handles
* It's a limit required by bitmap algorithm design (see sys/bitmap.h).
* Use pack(4) to make sizeof structs be the same on x86 and amd64.
*/
#define SYSEVENT_MINOR_MAX SHRT_MAX
#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
#pragma pack(4)
#endif
/* copyin/copyout data */
typedef struct box {
uint64_t name; /* pointer to something */
uint32_t len;
} sev_box_t;
typedef struct bind_args {
sev_box_t chan_name;
uint32_t flags;
} sev_bind_args_t;
typedef struct control_args {
uint32_t cmd;
uint32_t value;
} sev_control_args_t;
typedef struct publish_args {
sev_box_t ev;
uint32_t flags;
} sev_publish_args_t;
typedef struct subscribe_args {
sev_box_t sid;
sev_box_t class_info;
int door_desc;
uint32_t flags;
} sev_subscribe_args_t;
typedef struct unsubscribe_args {
sev_box_t sid;
} sev_unsubscribe_args_t;
typedef struct chandata {
sev_box_t in_data;
sev_box_t out_data;
} sev_chandata_args_t;
typedef struct propnvl_args {
sev_box_t packednvl; /* input and output */
int64_t generation; /* output on get operation */
} sev_propnvl_args_t;
#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
#pragma pack()
#endif
#ifdef __cplusplus
}
#endif
#endif /* _SYS_SYSEVENT_IMPL_H */