10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*11202SStephen.Hanson@Sun.COM * Common Development and Distribution License (the "License").
6*11202SStephen.Hanson@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*11202SStephen.Hanson@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/fm/protocol.h>
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/mkdev.h>
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <alloca.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <limits.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate #include <stdlib.h>
350Sstevel@tonic-gate #include <fcntl.h>
360Sstevel@tonic-gate #include <errno.h>
370Sstevel@tonic-gate #include <libgen.h>
380Sstevel@tonic-gate #include <dirent.h>
390Sstevel@tonic-gate #include <fmd_log_impl.h>
400Sstevel@tonic-gate #include <fmd_log.h>
410Sstevel@tonic-gate
420Sstevel@tonic-gate #define CAT_FMA_RGROUP (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_RFMA)
430Sstevel@tonic-gate #define CAT_FMA_GROUP (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_FMA)
440Sstevel@tonic-gate
450Sstevel@tonic-gate #define CAT_FMA_LABEL (EXT_STRING | EXC_DEFAULT | EXD_FMA_LABEL)
460Sstevel@tonic-gate #define CAT_FMA_VERSION (EXT_STRING | EXC_DEFAULT | EXD_FMA_VERSION)
470Sstevel@tonic-gate #define CAT_FMA_OSREL (EXT_STRING | EXC_DEFAULT | EXD_FMA_OSREL)
480Sstevel@tonic-gate #define CAT_FMA_OSVER (EXT_STRING | EXC_DEFAULT | EXD_FMA_OSVER)
490Sstevel@tonic-gate #define CAT_FMA_PLAT (EXT_STRING | EXC_DEFAULT | EXD_FMA_PLAT)
501052Sdilpreet #define CAT_FMA_UUID (EXT_STRING | EXC_DEFAULT | EXD_FMA_UUID)
510Sstevel@tonic-gate #define CAT_FMA_TODSEC (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_TODSEC)
520Sstevel@tonic-gate #define CAT_FMA_TODNSEC (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_TODNSEC)
530Sstevel@tonic-gate #define CAT_FMA_NVLIST (EXT_RAW | EXC_DEFAULT | EXD_FMA_NVLIST)
540Sstevel@tonic-gate #define CAT_FMA_MAJOR (EXT_UINT32 | EXC_DEFAULT | EXD_FMA_MAJOR)
550Sstevel@tonic-gate #define CAT_FMA_MINOR (EXT_UINT32 | EXC_DEFAULT | EXD_FMA_MINOR)
560Sstevel@tonic-gate #define CAT_FMA_INODE (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_INODE)
570Sstevel@tonic-gate #define CAT_FMA_OFFSET (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_OFFSET)
580Sstevel@tonic-gate
590Sstevel@tonic-gate static int fmd_log_load_record(fmd_log_t *, uint_t, fmd_log_record_t *);
600Sstevel@tonic-gate static void fmd_log_free_record(fmd_log_record_t *);
610Sstevel@tonic-gate static int fmd_log_load_xrefs(fmd_log_t *, uint_t, fmd_log_record_t *);
620Sstevel@tonic-gate
630Sstevel@tonic-gate static const char FMD_CREATOR[] = "fmd";
640Sstevel@tonic-gate
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate * fmd_log_set_errno is used as a utility function throughout the library. It
670Sstevel@tonic-gate * sets both lp->log_errno and errno to the specified value. If the current
680Sstevel@tonic-gate * error is EFDL_EXACCT, we store it internally as that value plus ea_error().
690Sstevel@tonic-gate * If no ea_error() is present, we assume EFDL_BADTAG (catalog tag mismatch).
700Sstevel@tonic-gate */
710Sstevel@tonic-gate static int
fmd_log_set_errno(fmd_log_t * lp,int err)720Sstevel@tonic-gate fmd_log_set_errno(fmd_log_t *lp, int err)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate if (err == EFDL_EXACCT && ea_error() != EXR_OK)
750Sstevel@tonic-gate lp->log_errno = EFDL_EXACCT + ea_error();
760Sstevel@tonic-gate else if (err == EFDL_EXACCT)
770Sstevel@tonic-gate lp->log_errno = EFDL_BADTAG;
780Sstevel@tonic-gate else
790Sstevel@tonic-gate lp->log_errno = err;
800Sstevel@tonic-gate
810Sstevel@tonic-gate errno = lp->log_errno;
820Sstevel@tonic-gate return (-1);
830Sstevel@tonic-gate }
840Sstevel@tonic-gate
850Sstevel@tonic-gate /*PRINTFLIKE2*/
860Sstevel@tonic-gate static void
fmd_log_dprintf(fmd_log_t * lp,const char * format,...)870Sstevel@tonic-gate fmd_log_dprintf(fmd_log_t *lp, const char *format, ...)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate va_list ap;
900Sstevel@tonic-gate
910Sstevel@tonic-gate if (lp->log_flags & FMD_LF_DEBUG) {
920Sstevel@tonic-gate (void) fputs("fmd_log DEBUG: ", stderr);
930Sstevel@tonic-gate va_start(ap, format);
940Sstevel@tonic-gate (void) vfprintf(stderr, format, ap);
950Sstevel@tonic-gate va_end(ap);
960Sstevel@tonic-gate }
970Sstevel@tonic-gate }
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate * fmd_log_load_record() is used to load the exacct object at the current file
1010Sstevel@tonic-gate * location into the specified fmd_log_record structure. Once the caller has
1020Sstevel@tonic-gate * made use of this information, it can clean up using fmd_log_free_record().
1030Sstevel@tonic-gate */
1040Sstevel@tonic-gate static int
fmd_log_load_record(fmd_log_t * lp,uint_t iflags,fmd_log_record_t * rp)1050Sstevel@tonic-gate fmd_log_load_record(fmd_log_t *lp, uint_t iflags, fmd_log_record_t *rp)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate ea_object_t *grp, *obj;
1080Sstevel@tonic-gate off64_t off;
1090Sstevel@tonic-gate int err;
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate if (iflags & FMD_LOG_XITER_OFFS) {
1120Sstevel@tonic-gate ea_clear(&lp->log_ea);
1130Sstevel@tonic-gate off = lseek64(lp->log_fd, 0, SEEK_CUR);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate if ((grp = ea_get_object_tree(&lp->log_ea, 1)) == NULL)
1170Sstevel@tonic-gate return (fmd_log_set_errno(lp, EFDL_EXACCT));
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate if (grp->eo_catalog != CAT_FMA_RGROUP &&
1200Sstevel@tonic-gate grp->eo_catalog != CAT_FMA_GROUP) {
1210Sstevel@tonic-gate fmd_log_dprintf(lp, "bad catalog tag 0x%x\n", grp->eo_catalog);
1220Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
1230Sstevel@tonic-gate return (fmd_log_set_errno(lp, EFDL_EXACCT));
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate bzero(rp, sizeof (fmd_log_record_t));
1270Sstevel@tonic-gate rp->rec_grp = grp;
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate if (iflags & FMD_LOG_XITER_OFFS)
1300Sstevel@tonic-gate rp->rec_off = off;
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate for (obj = grp->eo_group.eg_objs; obj != NULL; obj = obj->eo_next) {
1330Sstevel@tonic-gate switch (obj->eo_catalog) {
1340Sstevel@tonic-gate case CAT_FMA_NVLIST:
1350Sstevel@tonic-gate if ((err = nvlist_unpack(obj->eo_item.ei_raw,
1360Sstevel@tonic-gate obj->eo_item.ei_size, &rp->rec_nvl, 0)) != 0) {
1370Sstevel@tonic-gate fmd_log_free_record(rp);
1380Sstevel@tonic-gate return (fmd_log_set_errno(lp, err));
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate break;
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate case CAT_FMA_TODSEC:
1430Sstevel@tonic-gate rp->rec_sec = obj->eo_item.ei_uint64;
1440Sstevel@tonic-gate break;
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate case CAT_FMA_TODNSEC:
1470Sstevel@tonic-gate rp->rec_nsec = obj->eo_item.ei_uint64;
1480Sstevel@tonic-gate break;
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate case CAT_FMA_GROUP:
1510Sstevel@tonic-gate rp->rec_nrefs += obj->eo_group.eg_nobjs;
1520Sstevel@tonic-gate break;
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate if (rp->rec_nvl == NULL || nvlist_lookup_string(rp->rec_nvl,
1570Sstevel@tonic-gate FM_CLASS, (char **)&rp->rec_class) != 0) {
1580Sstevel@tonic-gate fmd_log_free_record(rp);
1590Sstevel@tonic-gate return (fmd_log_set_errno(lp, EFDL_NOCLASS));
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate if (rp->rec_nrefs != 0 && fmd_log_load_xrefs(lp, iflags, rp) != 0) {
1630Sstevel@tonic-gate err = errno; /* errno is set for us */
1640Sstevel@tonic-gate fmd_log_free_record(rp);
1650Sstevel@tonic-gate return (fmd_log_set_errno(lp, err));
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate return (0);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate * fmd_log_free_record frees memory associated with the specified record. If
1730Sstevel@tonic-gate * cross-references are contained in this record, we proceed recursively.
1740Sstevel@tonic-gate */
1750Sstevel@tonic-gate static void
fmd_log_free_record(fmd_log_record_t * rp)1760Sstevel@tonic-gate fmd_log_free_record(fmd_log_record_t *rp)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate uint_t i;
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate if (rp->rec_xrefs != NULL) {
1810Sstevel@tonic-gate for (i = 0; i < rp->rec_nrefs; i++)
1820Sstevel@tonic-gate fmd_log_free_record(&rp->rec_xrefs[i]);
1830Sstevel@tonic-gate free(rp->rec_xrefs);
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate nvlist_free(rp->rec_nvl);
1870Sstevel@tonic-gate ea_free_object(rp->rec_grp, EUP_ALLOC);
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate * fmd_log_load_xref loads the cross-reference represented by the specified
1920Sstevel@tonic-gate * exacct group 'grp' into the next empty slot in rp->rec_xrefs. This function
1930Sstevel@tonic-gate * is called repeatedly by fmd_log_load_xrefs() for each embedded reference.
1940Sstevel@tonic-gate */
1950Sstevel@tonic-gate static int
fmd_log_load_xref(fmd_log_t * lp,uint_t iflags,fmd_log_record_t * rp,ea_object_t * grp)1960Sstevel@tonic-gate fmd_log_load_xref(fmd_log_t *lp, uint_t iflags,
1970Sstevel@tonic-gate fmd_log_record_t *rp, ea_object_t *grp)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate ea_object_t *obj;
2000Sstevel@tonic-gate fmd_log_t *xlp;
2010Sstevel@tonic-gate dev_t dev;
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate off64_t off = (off64_t)-1L;
2040Sstevel@tonic-gate major_t maj = (major_t)-1L;
2050Sstevel@tonic-gate minor_t min = (minor_t)-1L;
2060Sstevel@tonic-gate ino64_t ino = (ino64_t)-1L;
2071052Sdilpreet char *uuid = NULL;
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate for (obj = grp->eo_group.eg_objs; obj != NULL; obj = obj->eo_next) {
2100Sstevel@tonic-gate switch (obj->eo_catalog) {
2110Sstevel@tonic-gate case CAT_FMA_MAJOR:
2120Sstevel@tonic-gate maj = obj->eo_item.ei_uint32;
2130Sstevel@tonic-gate break;
2140Sstevel@tonic-gate case CAT_FMA_MINOR:
2150Sstevel@tonic-gate min = obj->eo_item.ei_uint32;
2160Sstevel@tonic-gate break;
2170Sstevel@tonic-gate case CAT_FMA_INODE:
2180Sstevel@tonic-gate ino = obj->eo_item.ei_uint64;
2190Sstevel@tonic-gate break;
2200Sstevel@tonic-gate case CAT_FMA_OFFSET:
2210Sstevel@tonic-gate off = obj->eo_item.ei_uint64;
2220Sstevel@tonic-gate break;
2231052Sdilpreet case CAT_FMA_UUID:
2241052Sdilpreet uuid = obj->eo_item.ei_string;
2251052Sdilpreet break;
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate
2291052Sdilpreet if (off == (off64_t)-1L || (uuid == NULL && (ino == (ino64_t)-1L ||
2301052Sdilpreet maj == (major_t)-1L || min == (minor_t)-1L)))
2310Sstevel@tonic-gate return (fmd_log_set_errno(lp, EFDL_BADREF));
2320Sstevel@tonic-gate
2331052Sdilpreet if (uuid == NULL && (dev = makedev(maj, min)) == NODEV)
2340Sstevel@tonic-gate return (fmd_log_set_errno(lp, EFDL_BADDEV));
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate /*
2371052Sdilpreet * Search our xref list for matching (dev_t, ino64_t) or (uuid).
2381052Sdilpreet * If we can't find one, return silently without
2391052Sdilpreet * doing anything. We expect log xrefs to be broken whenever log
2401052Sdilpreet * files are trimmed or removed; their only purpose is to help us
2411052Sdilpreet * debug diagnosis engine algorithms.
2420Sstevel@tonic-gate */
2430Sstevel@tonic-gate for (xlp = lp->log_xrefs; xlp != NULL; xlp = xlp->log_xnext) {
2441052Sdilpreet if (uuid == NULL) {
2451052Sdilpreet if (xlp->log_stat.st_ino == ino &&
2461052Sdilpreet xlp->log_stat.st_dev == dev)
2471052Sdilpreet break;
2481052Sdilpreet } else if (xlp->log_uuid != NULL &&
2491052Sdilpreet strcmp(xlp->log_uuid, uuid) == 0)
2500Sstevel@tonic-gate break;
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate if (xlp == NULL) {
2541052Sdilpreet if (uuid == NULL)
2551052Sdilpreet fmd_log_dprintf(lp, "broken xref dev=%lx ino=%llx\n",
2561052Sdilpreet (ulong_t)dev, (u_longlong_t)ino);
2571052Sdilpreet else
2581052Sdilpreet fmd_log_dprintf(lp, "broken xref uuid=%s\n", uuid);
2591052Sdilpreet
2600Sstevel@tonic-gate return (0);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate xlp->log_flags &= ~FMD_LF_START;
2640Sstevel@tonic-gate ea_clear(&xlp->log_ea);
2650Sstevel@tonic-gate (void) lseek64(xlp->log_fd, off, SEEK_SET);
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate return (fmd_log_load_record(xlp,
2680Sstevel@tonic-gate iflags, &rp->rec_xrefs[rp->rec_nrefs++]));
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate * fmd_log_load_xrdir is called by fmd_log_load_xrefs when the FMD_LF_XREFS bit
2730Sstevel@tonic-gate * is not yet set, indicating we haven't looked for cross-referenced files. We
2740Sstevel@tonic-gate * open the directory associated with the specified log file and attempt to
2750Sstevel@tonic-gate * perform an fmd_log_open() on every file found there (i.e. /var/fm/fmd). If
2760Sstevel@tonic-gate * we are successful, the files are chained on to lp->log_xrefs, where the
2770Sstevel@tonic-gate * fmd_log_load_xref() function can find them by comparing dev/ino to log_stat.
2780Sstevel@tonic-gate */
2790Sstevel@tonic-gate static void
fmd_log_load_xrdir(fmd_log_t * lp)2800Sstevel@tonic-gate fmd_log_load_xrdir(fmd_log_t *lp)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate fmd_log_t *xlp;
2830Sstevel@tonic-gate char dirbuf[PATH_MAX], path[PATH_MAX], *dirpath;
284871Scasper struct dirent *dp;
2850Sstevel@tonic-gate DIR *dirp;
286*11202SStephen.Hanson@Sun.COM struct stat statbuf;
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate lp->log_flags |= FMD_LF_XREFS;
2890Sstevel@tonic-gate (void) strlcpy(dirbuf, lp->log_path, sizeof (dirbuf));
2900Sstevel@tonic-gate dirpath = dirname(dirbuf);
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate if ((dirp = opendir(dirpath)) == NULL)
2930Sstevel@tonic-gate return; /* failed to open directory; just skip it */
2940Sstevel@tonic-gate
295871Scasper while ((dp = readdir(dirp)) != NULL) {
2960Sstevel@tonic-gate if (dp->d_name[0] == '.')
2970Sstevel@tonic-gate continue; /* skip "." and ".." and hidden files */
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate (void) snprintf(path, sizeof (path),
3000Sstevel@tonic-gate "%s/%s", dirpath, dp->d_name);
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate if (strcmp(path, lp->log_path) != 0 &&
303*11202SStephen.Hanson@Sun.COM stat(path, &statbuf) != -1 &&
304*11202SStephen.Hanson@Sun.COM (statbuf.st_mode & S_IFMT) == S_IFREG &&
3050Sstevel@tonic-gate (xlp = fmd_log_open(lp->log_abi, path, NULL)) != NULL) {
3060Sstevel@tonic-gate fmd_log_dprintf(lp, "%s loaded %s for xrefs\n",
3070Sstevel@tonic-gate lp->log_path, xlp->log_path);
3080Sstevel@tonic-gate xlp->log_xnext = lp->log_xrefs;
3090Sstevel@tonic-gate lp->log_xrefs = xlp;
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate /*
3150Sstevel@tonic-gate * fmd_log_load_xrefs iterates again over the record's exacct group and for
3160Sstevel@tonic-gate * each cross-reference (embedded CAT_FMA_GROUP), attempts to fill in the
3170Sstevel@tonic-gate * corresponding xref. rp->rec_nrefs is reset to the number of valid items
3180Sstevel@tonic-gate * in the finished rp->rec_xrefs array; see fmd_log_load_xref() for more info.
3190Sstevel@tonic-gate */
3200Sstevel@tonic-gate static int
fmd_log_load_xrefs(fmd_log_t * lp,uint_t iflags,fmd_log_record_t * rp)3210Sstevel@tonic-gate fmd_log_load_xrefs(fmd_log_t *lp, uint_t iflags, fmd_log_record_t *rp)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate size_t size = sizeof (fmd_log_record_t) * rp->rec_nrefs;
3240Sstevel@tonic-gate ea_object_t *rgrp = rp->rec_grp;
3250Sstevel@tonic-gate ea_object_t *grp, *obj;
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate if (!(iflags & FMD_LOG_XITER_REFS))
3280Sstevel@tonic-gate return (0); /* do not load any xrefs */
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_XREFS))
3310Sstevel@tonic-gate fmd_log_load_xrdir(lp);
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate if ((rp->rec_xrefs = malloc(size)) == NULL)
3340Sstevel@tonic-gate return (fmd_log_set_errno(lp, EFDL_NOMEM));
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate bzero(rp->rec_xrefs, size);
3370Sstevel@tonic-gate rp->rec_nrefs = 0;
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate /*
3400Sstevel@tonic-gate * Make a second pass through the record group to locate and process
3410Sstevel@tonic-gate * each cross-reference sub-group. The structure of the groups is
3420Sstevel@tonic-gate * as follows (left-hand-side symbols named after the variables used):
3430Sstevel@tonic-gate *
3440Sstevel@tonic-gate * rgrp := CAT_FMA_TODSEC CAT_FMA_TODNSEC CAT_FMA_NVLIST grp*
3450Sstevel@tonic-gate * grp := obj* (i.e. zero or more groups of xref items)
3460Sstevel@tonic-gate * obj := CAT_FMA_MAJOR CAT_FMA_MINOR CAT_FMA_INODE CAT_FMA_OFFSET
3470Sstevel@tonic-gate *
3480Sstevel@tonic-gate * For each xref 'obj', we call fmd_log_load_xref() to parse the four
3490Sstevel@tonic-gate * xref members and then load the specified record into rp->rec_xrefs.
3500Sstevel@tonic-gate */
3510Sstevel@tonic-gate for (grp = rgrp->eo_group.eg_objs; grp != NULL; grp = grp->eo_next) {
3520Sstevel@tonic-gate if (grp->eo_catalog != CAT_FMA_GROUP)
3530Sstevel@tonic-gate continue; /* ignore anything that isn't a group */
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate for (obj = grp->eo_group.eg_objs;
3560Sstevel@tonic-gate obj != NULL; obj = obj->eo_next) {
3570Sstevel@tonic-gate if (fmd_log_load_xref(lp, iflags, rp, obj) != 0)
3580Sstevel@tonic-gate return (-1); /* errno is set for us */
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate return (0);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate static fmd_log_t *
fmd_log_open_err(fmd_log_t * lp,int * errp,int err)3660Sstevel@tonic-gate fmd_log_open_err(fmd_log_t *lp, int *errp, int err)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate if (errp != NULL)
3690Sstevel@tonic-gate *errp = err == EFDL_EXACCT ? EFDL_EXACCT + ea_error() : err;
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate if (lp != NULL)
3720Sstevel@tonic-gate fmd_log_close(lp);
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate return (NULL);
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate fmd_log_t *
fmd_log_open(int abi,const char * name,int * errp)3780Sstevel@tonic-gate fmd_log_open(int abi, const char *name, int *errp)
3790Sstevel@tonic-gate {
3800Sstevel@tonic-gate ea_object_t *grp, *obj;
3810Sstevel@tonic-gate fmd_log_t *lp;
3820Sstevel@tonic-gate int fd;
3830Sstevel@tonic-gate
3841052Sdilpreet if (abi > FMD_LOG_VERSION)
3850Sstevel@tonic-gate return (fmd_log_open_err(NULL, errp, EFDL_VERSION));
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate if ((lp = malloc(sizeof (fmd_log_t))) == NULL)
3880Sstevel@tonic-gate return (fmd_log_open_err(NULL, errp, EFDL_NOMEM));
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate bzero(lp, sizeof (fmd_log_t));
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate if ((lp->log_path = strdup(name)) == NULL)
3930Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_NOMEM));
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate if ((lp->log_fd = open64(name, O_RDONLY)) == -1 ||
3960Sstevel@tonic-gate fstat64(lp->log_fd, &lp->log_stat) == -1 ||
3970Sstevel@tonic-gate (fd = dup(lp->log_fd)) == -1)
3980Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, errno));
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate if (ea_fdopen(&lp->log_ea, fd, FMD_CREATOR,
4010Sstevel@tonic-gate EO_VALID_HDR | EO_HEAD, O_RDONLY) == -1) {
4020Sstevel@tonic-gate (void) close(fd);
4030Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_EXACCT));
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate lp->log_abi = abi;
4070Sstevel@tonic-gate lp->log_flags |= FMD_LF_EAOPEN;
4080Sstevel@tonic-gate if (getenv("FMD_LOG_DEBUG") != NULL)
4090Sstevel@tonic-gate lp->log_flags |= FMD_LF_DEBUG;
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate * Read the first group of log meta-data: the write-once read-only
4130Sstevel@tonic-gate * file header. We read all records in this group, ignoring all but
4140Sstevel@tonic-gate * the VERSION and LABEL, which are required and must be verified.
4150Sstevel@tonic-gate */
4160Sstevel@tonic-gate if ((grp = ea_get_object_tree(&lp->log_ea, 1)) == NULL)
4170Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_EXACCT));
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate if (grp->eo_catalog != CAT_FMA_GROUP) {
4200Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
4210Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_EXACCT));
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate for (obj = grp->eo_group.eg_objs; obj != NULL; obj = obj->eo_next) {
4250Sstevel@tonic-gate switch (obj->eo_catalog) {
4260Sstevel@tonic-gate case CAT_FMA_VERSION:
4270Sstevel@tonic-gate lp->log_version = strdup(obj->eo_item.ei_string);
4280Sstevel@tonic-gate if (lp->log_version == NULL) {
4290Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
4300Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_NOMEM));
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate break;
4330Sstevel@tonic-gate case CAT_FMA_LABEL:
4340Sstevel@tonic-gate lp->log_label = strdup(obj->eo_item.ei_string);
4350Sstevel@tonic-gate if (lp->log_label == NULL) {
4360Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
4370Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_NOMEM));
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate break;
4400Sstevel@tonic-gate case CAT_FMA_OSREL:
4410Sstevel@tonic-gate lp->log_osrelease = strdup(obj->eo_item.ei_string);
4420Sstevel@tonic-gate if (lp->log_osrelease == NULL) {
4430Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
4440Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_NOMEM));
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate break;
4470Sstevel@tonic-gate case CAT_FMA_OSVER:
4480Sstevel@tonic-gate lp->log_osversion = strdup(obj->eo_item.ei_string);
4490Sstevel@tonic-gate if (lp->log_osversion == NULL) {
4500Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
4510Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_NOMEM));
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate break;
4540Sstevel@tonic-gate case CAT_FMA_PLAT:
4550Sstevel@tonic-gate lp->log_platform = strdup(obj->eo_item.ei_string);
4560Sstevel@tonic-gate if (lp->log_platform == NULL) {
4570Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
4580Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_NOMEM));
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate break;
4611052Sdilpreet case CAT_FMA_UUID:
4621052Sdilpreet lp->log_uuid = strdup(obj->eo_item.ei_string);
4631052Sdilpreet if (lp->log_uuid == NULL) {
4641052Sdilpreet ea_free_object(grp, EUP_ALLOC);
4651052Sdilpreet return (fmd_log_open_err(lp, errp, EFDL_NOMEM));
4661052Sdilpreet }
4671052Sdilpreet break;
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate if (lp->log_version == NULL || lp->log_label == NULL)
4740Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_BADHDR));
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate /*
4770Sstevel@tonic-gate * Read the second group of log meta-data: the table of contents. At
4780Sstevel@tonic-gate * present there are no records libfmd_log needs in here, so we just
4790Sstevel@tonic-gate * skip over this entire group so that fmd_log_xiter() starts after it.
4800Sstevel@tonic-gate */
4810Sstevel@tonic-gate if ((grp = ea_get_object_tree(&lp->log_ea, 1)) == NULL)
4820Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_EXACCT));
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate if (grp->eo_catalog != CAT_FMA_GROUP) {
4850Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
4860Sstevel@tonic-gate return (fmd_log_open_err(lp, errp, EFDL_EXACCT));
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC);
4900Sstevel@tonic-gate lp->log_flags |= FMD_LF_START;
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate fmd_log_dprintf(lp, "open log %s dev=%lx ino=%llx\n", lp->log_path,
4930Sstevel@tonic-gate (ulong_t)lp->log_stat.st_dev, (u_longlong_t)lp->log_stat.st_ino);
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate return (lp);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate void
fmd_log_close(fmd_log_t * lp)4990Sstevel@tonic-gate fmd_log_close(fmd_log_t *lp)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate fmd_log_t *xlp, *nlp;
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate if (lp == NULL)
5040Sstevel@tonic-gate return; /* permit null lp to simply caller code */
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate for (xlp = lp->log_xrefs; xlp != NULL; xlp = nlp) {
5070Sstevel@tonic-gate nlp = xlp->log_xnext;
5080Sstevel@tonic-gate fmd_log_close(xlp);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate if (lp->log_flags & FMD_LF_EAOPEN)
5120Sstevel@tonic-gate (void) ea_close(&lp->log_ea);
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate if (lp->log_fd >= 0)
5150Sstevel@tonic-gate (void) close(lp->log_fd);
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate free(lp->log_path);
5180Sstevel@tonic-gate free(lp->log_version);
5190Sstevel@tonic-gate free(lp->log_label);
5200Sstevel@tonic-gate free(lp->log_osrelease);
5210Sstevel@tonic-gate free(lp->log_osversion);
5220Sstevel@tonic-gate free(lp->log_platform);
5231052Sdilpreet free(lp->log_uuid);
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate free(lp);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate const char *
fmd_log_label(fmd_log_t * lp)5290Sstevel@tonic-gate fmd_log_label(fmd_log_t *lp)
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate return (lp->log_label);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate void
fmd_log_header(fmd_log_t * lp,fmd_log_header_t * hp)5350Sstevel@tonic-gate fmd_log_header(fmd_log_t *lp, fmd_log_header_t *hp)
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate const char *creator = ea_get_creator(&lp->log_ea);
5380Sstevel@tonic-gate const char *hostname = ea_get_hostname(&lp->log_ea);
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate hp->log_creator = creator ? creator : "";
5410Sstevel@tonic-gate hp->log_hostname = hostname ? hostname : "";
5420Sstevel@tonic-gate hp->log_label = lp->log_label ? lp->log_label : "";
5430Sstevel@tonic-gate hp->log_version = lp->log_version ? lp->log_version : "";
5440Sstevel@tonic-gate hp->log_osrelease = lp->log_osrelease ? lp->log_osrelease : "";
5450Sstevel@tonic-gate hp->log_osversion = lp->log_osversion ? lp->log_osversion : "";
5460Sstevel@tonic-gate hp->log_platform = lp->log_platform ? lp->log_platform : "";
5471052Sdilpreet if (lp->log_abi > 1)
5481052Sdilpreet hp->log_uuid = lp->log_uuid ? lp->log_uuid : "";
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate /*
5520Sstevel@tonic-gate * Note: this will be verrrry slow for big files. If this function becomes
5530Sstevel@tonic-gate * important, we'll need to add a function to libexacct to let us rewind.
5540Sstevel@tonic-gate * Currently libexacct has no notion of seeking other than record-at-a-time.
5550Sstevel@tonic-gate */
5560Sstevel@tonic-gate int
fmd_log_rewind(fmd_log_t * lp)5570Sstevel@tonic-gate fmd_log_rewind(fmd_log_t *lp)
5580Sstevel@tonic-gate {
5590Sstevel@tonic-gate ea_object_t obj, *grp;
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_START)) {
5620Sstevel@tonic-gate while (ea_previous_object(&lp->log_ea, &obj) != EO_ERROR)
5630Sstevel@tonic-gate continue; /* rewind until beginning of file */
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate if ((grp = ea_get_object_tree(&lp->log_ea, 1)) == NULL)
5660Sstevel@tonic-gate return (fmd_log_set_errno(lp, EFDL_EXACCT));
5670Sstevel@tonic-gate else
5680Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); /* hdr group */
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate if ((grp = ea_get_object_tree(&lp->log_ea, 1)) == NULL)
5710Sstevel@tonic-gate return (fmd_log_set_errno(lp, EFDL_EXACCT));
5720Sstevel@tonic-gate else
5730Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); /* toc group */
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate lp->log_flags |= FMD_LF_START;
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate return (0);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate static int
fmd_log_xiter_filter(fmd_log_t * lp,const fmd_log_record_t * rp,uint_t fac,const fmd_log_filtvec_t * fav)5820Sstevel@tonic-gate fmd_log_xiter_filter(fmd_log_t *lp, const fmd_log_record_t *rp,
5830Sstevel@tonic-gate uint_t fac, const fmd_log_filtvec_t *fav)
5840Sstevel@tonic-gate {
5850Sstevel@tonic-gate uint_t i, j;
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate for (i = 0; i < fac; i++) {
5880Sstevel@tonic-gate for (j = 0; j < fav[i].filt_argc; j++) {
5890Sstevel@tonic-gate if (fav[i].filt_argv[j].filt_func(lp, rp,
5900Sstevel@tonic-gate fav[i].filt_argv[j].filt_arg) != 0)
5910Sstevel@tonic-gate break; /* logical OR of this class is true */
5920Sstevel@tonic-gate }
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate if (j == fav[i].filt_argc)
5950Sstevel@tonic-gate return (0); /* logical AND of filter is false */
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate return (1); /* logical AND of filter is true */
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate static int
fmd_log_xiter_filtcmp(const void * lp,const void * rp)6020Sstevel@tonic-gate fmd_log_xiter_filtcmp(const void *lp, const void *rp)
6030Sstevel@tonic-gate {
6040Sstevel@tonic-gate return ((intptr_t)((fmd_log_filter_t *)lp)->filt_func -
6050Sstevel@tonic-gate (intptr_t)((fmd_log_filter_t *)rp)->filt_func);
6060Sstevel@tonic-gate }
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate int
fmd_log_filter(fmd_log_t * lp,uint_t fc,fmd_log_filter_t * fv,const fmd_log_record_t * rp)6090Sstevel@tonic-gate fmd_log_filter(fmd_log_t *lp, uint_t fc, fmd_log_filter_t *fv,
6100Sstevel@tonic-gate const fmd_log_record_t *rp)
6110Sstevel@tonic-gate {
6120Sstevel@tonic-gate fmd_log_filtvec_t *fav = alloca(fc * sizeof (fmd_log_filtvec_t));
6130Sstevel@tonic-gate uint_t i, fac = 0;
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate /*
6160Sstevel@tonic-gate * If a filter array was provided, create an array of filtvec structs
6170Sstevel@tonic-gate * to perform logical AND/OR processing. See fmd_log_xiter(), below.
6180Sstevel@tonic-gate */
6190Sstevel@tonic-gate bzero(fav, fc * sizeof (fmd_log_filtvec_t));
6200Sstevel@tonic-gate qsort(fv, fc, sizeof (fmd_log_filter_t), fmd_log_xiter_filtcmp);
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate for (i = 0; i < fc; i++) {
6230Sstevel@tonic-gate if (i == 0 || fv[i].filt_func != fv[i - 1].filt_func)
6240Sstevel@tonic-gate fav[fac++].filt_argv = &fv[i];
6250Sstevel@tonic-gate fav[fac - 1].filt_argc++;
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate return (fmd_log_xiter_filter(lp, rp, fac, fav));
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate int
fmd_log_xiter(fmd_log_t * lp,uint_t flag,uint_t fc,fmd_log_filter_t * fv,fmd_log_rec_f * rfunc,fmd_log_err_f * efunc,void * private,ulong_t * rcntp)6320Sstevel@tonic-gate fmd_log_xiter(fmd_log_t *lp, uint_t flag, uint_t fc, fmd_log_filter_t *fv,
6330Sstevel@tonic-gate fmd_log_rec_f *rfunc, fmd_log_err_f *efunc, void *private, ulong_t *rcntp)
6340Sstevel@tonic-gate {
6350Sstevel@tonic-gate fmd_log_record_t rec;
6360Sstevel@tonic-gate fmd_log_filtvec_t *fav = NULL;
6370Sstevel@tonic-gate uint_t i, fac = 0;
6380Sstevel@tonic-gate ulong_t rcnt = 0;
6390Sstevel@tonic-gate int rv = 0;
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate if (flag & ~FMD_LOG_XITER_MASK)
6420Sstevel@tonic-gate return (fmd_log_set_errno(lp, EINVAL));
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate /*
6450Sstevel@tonic-gate * If a filter array was provided, create an array of filtvec structs
6460Sstevel@tonic-gate * where each filtvec holds a pointer to an equivalent list of filters,
6470Sstevel@tonic-gate * as determined by their filt_func. We sort the input array by func,
6480Sstevel@tonic-gate * and then fill in the filtvec struct array. We can then compute the
6490Sstevel@tonic-gate * logical OR of equivalent filters by iterating over filt_argv, and
6500Sstevel@tonic-gate * we can compute the logical AND of 'fv' by iterating over filt_argc.
6510Sstevel@tonic-gate */
6520Sstevel@tonic-gate if (fc != 0) {
6530Sstevel@tonic-gate if ((fav = calloc(fc, sizeof (fmd_log_filtvec_t))) == NULL)
6540Sstevel@tonic-gate return (fmd_log_set_errno(lp, EFDL_NOMEM));
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate qsort(fv, fc, sizeof (fmd_log_filter_t), fmd_log_xiter_filtcmp);
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate for (i = 0; i < fc; i++) {
6590Sstevel@tonic-gate if (i == 0 || fv[i].filt_func != fv[i - 1].filt_func)
6600Sstevel@tonic-gate fav[fac++].filt_argv = &fv[i];
6610Sstevel@tonic-gate fav[fac - 1].filt_argc++;
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_START;
6660Sstevel@tonic-gate ea_clear(&lp->log_ea);
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate do {
6690Sstevel@tonic-gate if (fmd_log_load_record(lp, flag, &rec) != 0) {
6700Sstevel@tonic-gate if (lp->log_errno == EFDL_EXACCT + EXR_EOF)
6710Sstevel@tonic-gate break; /* end-of-file reached */
6720Sstevel@tonic-gate rv = efunc ? efunc(lp, private) : -1;
6730Sstevel@tonic-gate rcnt++;
6740Sstevel@tonic-gate } else {
6750Sstevel@tonic-gate if (fc == 0 || fmd_log_xiter_filter(lp, &rec, fac, fav))
6760Sstevel@tonic-gate rv = rfunc(lp, &rec, private);
6770Sstevel@tonic-gate
6780Sstevel@tonic-gate fmd_log_free_record(&rec);
6790Sstevel@tonic-gate rcnt++;
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate } while (rv == 0);
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate if (fac != 0)
6840Sstevel@tonic-gate free(fav);
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate if (rcntp != NULL)
6870Sstevel@tonic-gate *rcntp = rcnt;
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate return (rv);
6900Sstevel@tonic-gate }
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate int
fmd_log_iter(fmd_log_t * lp,fmd_log_rec_f * rfunc,void * private)6930Sstevel@tonic-gate fmd_log_iter(fmd_log_t *lp, fmd_log_rec_f *rfunc, void *private)
6940Sstevel@tonic-gate {
6950Sstevel@tonic-gate return (fmd_log_xiter(lp, 0, 0, NULL, rfunc, NULL, private, NULL));
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate
6980Sstevel@tonic-gate int
fmd_log_seek(fmd_log_t * lp,off64_t off)6990Sstevel@tonic-gate fmd_log_seek(fmd_log_t *lp, off64_t off)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_START;
7020Sstevel@tonic-gate ea_clear(&lp->log_ea);
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate if (lseek64(lp->log_fd, off, SEEK_SET) != off)
7050Sstevel@tonic-gate return (fmd_log_set_errno(lp, errno));
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate return (0);
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate static const char *const _fmd_errs[] = {
7110Sstevel@tonic-gate "client requires newer version of libfmd_log", /* EFDL_VERSION */
7120Sstevel@tonic-gate "required memory allocation failed", /* EFDL_NOMEM */
7130Sstevel@tonic-gate "log header did not contain required field", /* EFDL_BADHDR */
7140Sstevel@tonic-gate "log record did not contain protocol class", /* EFDL_NOCLASS */
7150Sstevel@tonic-gate "log record has invalid catalog tag", /* EFDL_BADTAG */
7160Sstevel@tonic-gate "log record has invalid cross-reference group", /* EFDL_BADREF */
7170Sstevel@tonic-gate "log record has invalid cross-reference dev_t", /* EFDL_BADDEV */
7180Sstevel@tonic-gate "log record was not of expected type", /* EFDL_EXACCT + OK */
7190Sstevel@tonic-gate "log access system call failed", /* EXR_SYSCALL_FAIL */
7200Sstevel@tonic-gate "log file corruption detected", /* EXR_CORRUPT_FILE */
7210Sstevel@tonic-gate "end-of-file reached", /* EXR_EOF */
7220Sstevel@tonic-gate "log file does not have appropriate creator", /* EXR_NO_CREATOR */
7230Sstevel@tonic-gate "invalid unpack buffer specified", /* EXR_INVALID_BUF */
7240Sstevel@tonic-gate "invalid exacct operation for log file", /* EXR_NOTSUPP */
7250Sstevel@tonic-gate "log file requires newer version of libexacct", /* EXR_UNKN_VERSION */
7260Sstevel@tonic-gate "invalid object buffer specified", /* EXR_INVALID_OBJ */
7270Sstevel@tonic-gate };
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate static const int _fmd_nerr = sizeof (_fmd_errs) / sizeof (_fmd_errs[0]);
7300Sstevel@tonic-gate
7310Sstevel@tonic-gate /*ARGSUSED*/
7320Sstevel@tonic-gate const char *
fmd_log_errmsg(fmd_log_t * lp,int err)7330Sstevel@tonic-gate fmd_log_errmsg(fmd_log_t *lp, int err)
7340Sstevel@tonic-gate {
7350Sstevel@tonic-gate const char *msg;
7360Sstevel@tonic-gate
7371193Smws if (err >= EFDL_BASE && err - EFDL_BASE < _fmd_nerr)
7380Sstevel@tonic-gate msg = _fmd_errs[err - EFDL_BASE];
7390Sstevel@tonic-gate else
7400Sstevel@tonic-gate msg = strerror(err);
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate return (msg ? msg : "unknown error");
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate int
fmd_log_errno(fmd_log_t * lp)7460Sstevel@tonic-gate fmd_log_errno(fmd_log_t *lp)
7470Sstevel@tonic-gate {
7480Sstevel@tonic-gate return (lp->log_errno);
7490Sstevel@tonic-gate }
750