#include <stddef.h>
#include <strings.h>
#include "../common/sw_impl.h"
#define SW_CASE_DATA_BUFNAME "casedata"
#define SW_CASE_DATA_VERSION_INITIAL 1
#define SW_CASE_DATA_BUFNAMELEN 18
typedef struct swde_case_data {
uint32_t sc_version;
int32_t sc_type;
uint32_t sc_sub_bufvers;
char sc_sub_bufname[SW_CASE_DATA_BUFNAMELEN];
int32_t sc_sub_bufsz;
} swde_case_data_t;
#define SW_CASE_DATA_VERSION SW_CASE_DATA_VERSION_INITIAL
typedef struct swde_case {
fmd_case_t *swc_fmdcase;
swde_case_data_t swc_data;
void *swc_subdata;
} swde_case_t;
static void
swde_case_associate(fmd_hdl_t *hdl, fmd_case_t *cp, swde_case_t *scp,
void *subdata)
{
scp->swc_fmdcase = cp;
scp->swc_subdata = subdata;
fmd_case_setspecific(hdl, cp, scp);
}
static void
swde_case_unserialize(fmd_hdl_t *hdl, fmd_case_t *cp)
{
swde_case_t *scp;
swde_case_data_t *datap;
void *subdata;
size_t sz;
scp = fmd_hdl_zalloc(hdl, sizeof (*scp), FMD_SLEEP);
datap = &scp->swc_data;
fmd_buf_read(hdl, cp, SW_CASE_DATA_BUFNAME, datap, sizeof (*datap));
if (datap->sc_version > SW_CASE_DATA_VERSION_INITIAL) {
fmd_hdl_free(hdl, scp, sizeof (*scp));
return;
}
if ((sz = datap->sc_sub_bufsz) != 0) {
subdata = fmd_hdl_alloc(hdl, sz, FMD_SLEEP);
fmd_buf_read(hdl, cp, datap->sc_sub_bufname, subdata, sz);
if (*((uint32_t *)subdata) != datap->sc_sub_bufvers) {
fmd_hdl_abort(hdl, "unserialize: expected subdata "
"version %u but received %u\n",
datap->sc_sub_bufvers, *((uint32_t *)subdata));
}
}
swde_case_associate(hdl, cp, scp, subdata);
}
static void
swde_subdata(fmd_hdl_t *hdl, fmd_case_t *cp, enum sw_casetype type,
swde_case_t *scp, uint32_t subdata_vers, void *subdata, size_t subdata_sz)
{
swde_case_data_t *datap = &scp->swc_data;
if (*((uint32_t *)subdata) != subdata_vers)
fmd_hdl_abort(hdl, "swde_subdata: subdata version "
"does not match argument\n");
(void) snprintf(datap->sc_sub_bufname, sizeof (datap->sc_sub_bufname),
"%s_%08x", SW_CASE_DATA_BUFNAME, type);
datap->sc_sub_bufsz = subdata_sz;
datap->sc_sub_bufvers = subdata_vers;
fmd_buf_create(hdl, cp, datap->sc_sub_bufname, subdata_sz);
fmd_buf_write(hdl, cp, datap->sc_sub_bufname, subdata, subdata_sz);
}
fmd_case_t *
swde_case_open(fmd_hdl_t *hdl, id_t who, char *req_uuid,
uint32_t subdata_vers, void *subdata, size_t subdata_sz)
{
enum sw_casetype ct = sw_id_to_casetype(hdl, who);
swde_case_data_t *datap;
swde_case_t *scp;
fmd_case_t *cp;
if (ct == SW_CASE_NONE)
fmd_hdl_abort(hdl, "swde_case_open for type SW_CASE_NONE\n");
if (subdata != NULL && subdata_sz <= sizeof (uint32_t) ||
subdata_sz != 0 && subdata == NULL)
fmd_hdl_abort(hdl, "swde_case_open: bad subdata\n", ct);
scp = fmd_hdl_zalloc(hdl, sizeof (*scp), FMD_SLEEP);
datap = &scp->swc_data;
if (req_uuid == NULL) {
cp = fmd_case_open(hdl, (void *)scp);
} else {
cp = fmd_case_open_uuid(hdl, req_uuid, (void *)scp);
if (cp == NULL) {
fmd_hdl_free(hdl, scp, sizeof (*scp));
return (NULL);
}
}
fmd_buf_create(hdl, cp, SW_CASE_DATA_BUFNAME, sizeof (*datap));
datap->sc_version = SW_CASE_DATA_VERSION_INITIAL;
datap->sc_type = ct;
if (subdata)
swde_subdata(hdl, cp, ct, scp, subdata_vers, subdata,
subdata_sz);
fmd_buf_write(hdl, cp, SW_CASE_DATA_BUFNAME, datap, sizeof (*datap));
swde_case_associate(hdl, cp, scp, subdata);
return (cp);
}
void
swde_close(fmd_hdl_t *hdl, fmd_case_t *cp)
{
swde_case_t *scp = fmd_case_getspecific(hdl, cp);
swde_case_data_t *datap = &scp->swc_data;
swsub_case_close_func_t *closefunc;
if ((closefunc = sw_sub_case_close_func(hdl, datap->sc_type)) != NULL)
closefunc(hdl, cp);
if (scp->swc_subdata) {
fmd_hdl_free(hdl, scp->swc_subdata, datap->sc_sub_bufsz);
fmd_buf_destroy(hdl, cp, datap->sc_sub_bufname);
}
fmd_buf_destroy(hdl, cp, SW_CASE_DATA_BUFNAME);
fmd_hdl_free(hdl, scp, sizeof (*scp));
}
fmd_case_t *
swde_case_first(fmd_hdl_t *hdl, id_t who)
{
enum sw_casetype ct = sw_id_to_casetype(hdl, who);
swde_case_t *scp;
fmd_case_t *cp;
if (ct == SW_CASE_NONE)
fmd_hdl_abort(hdl, "swde_case_first for type SW_CASE_NONE\n");
for (cp = fmd_case_next(hdl, NULL); cp; cp = fmd_case_next(hdl, cp)) {
scp = fmd_case_getspecific(hdl, cp);
if (scp->swc_data.sc_type == ct)
break;
}
return (cp);
}
fmd_case_t *
swde_case_next(fmd_hdl_t *hdl, fmd_case_t *lastcp)
{
swde_case_t *scp;
fmd_case_t *cp;
int ct;
if (lastcp == NULL)
fmd_hdl_abort(hdl, "swde_case_next called for NULL lastcp\n");
scp = fmd_case_getspecific(hdl, lastcp);
ct = scp->swc_data.sc_type;
cp = lastcp;
while ((cp = fmd_case_next(hdl, cp)) != NULL) {
scp = fmd_case_getspecific(hdl, cp);
if (scp->swc_data.sc_type == ct)
break;
}
return (cp);
}
void *
swde_case_data(fmd_hdl_t *hdl, fmd_case_t *cp, uint32_t *svp)
{
swde_case_t *scp = fmd_case_getspecific(hdl, cp);
swde_case_data_t *datap = &scp->swc_data;
if (svp != NULL && scp->swc_subdata)
*svp = datap->sc_sub_bufvers;
return (scp->swc_subdata);
}
void
swde_case_data_write(fmd_hdl_t *hdl, fmd_case_t *cp)
{
swde_case_t *scp = fmd_case_getspecific(hdl, cp);
swde_case_data_t *datap = &scp->swc_data;
if (scp->swc_subdata == NULL)
return;
fmd_buf_write(hdl, cp, scp->swc_data.sc_sub_bufname,
scp->swc_subdata, datap->sc_sub_bufsz);
}
void
swde_case_data_upgrade(fmd_hdl_t *hdl, fmd_case_t *cp, uint32_t subdata_vers,
void *subdata, size_t subdata_sz)
{
swde_case_t *scp = fmd_case_getspecific(hdl, cp);
swde_case_data_t *datap = &scp->swc_data;
if (scp->swc_subdata) {
fmd_buf_destroy(hdl, cp, datap->sc_sub_bufname);
fmd_hdl_free(hdl, scp->swc_subdata, datap->sc_sub_bufsz);
scp->swc_subdata = NULL;
datap->sc_sub_bufsz = 0;
datap->sc_sub_bufname[0] = '\0';
}
if (subdata != NULL) {
scp->swc_subdata = subdata;
swde_subdata(hdl, cp, datap->sc_type, scp, subdata_vers,
subdata, subdata_sz);
}
fmd_buf_write(hdl, scp->swc_fmdcase, SW_CASE_DATA_BUFNAME,
datap, sizeof (*datap));
}
static void
swde_case_verify(fmd_hdl_t *hdl, fmd_case_t *cp)
{
swde_case_t *scp = fmd_case_getspecific(hdl, cp);
swde_case_data_t *datap = &scp->swc_data;
sw_case_vrfy_func_t *vrfy_func;
if ((vrfy_func = sw_sub_case_vrfy_func(hdl, datap->sc_type)) != NULL) {
if (vrfy_func(hdl, cp) == 0)
fmd_case_close(hdl, cp);
}
}
void
swde_case_init(fmd_hdl_t *hdl)
{
fmd_case_t *cp;
for (cp = fmd_case_next(hdl, NULL); cp; cp = fmd_case_next(hdl, cp)) {
swde_case_unserialize(hdl, cp);
swde_case_verify(hdl, cp);
}
}
void
swde_case_fini(fmd_hdl_t *hdl)
{
}