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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/fm/protocol.h>
27 #include <sys/types.h>
28 #include <sys/mkdev.h>
39 #include <fmd_log_impl.h>
42 #define CAT_FMA_RGROUP (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_RFMA)
43 #define CAT_FMA_GROUP (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_FMA)
45 #define CAT_FMA_LABEL (EXT_STRING | EXC_DEFAULT | EXD_FMA_LABEL)
46 #define CAT_FMA_VERSION (EXT_STRING | EXC_DEFAULT | EXD_FMA_VERSION)
47 #define CAT_FMA_OSREL (EXT_STRING | EXC_DEFAULT | EXD_FMA_OSREL)
48 #define CAT_FMA_OSVER (EXT_STRING | EXC_DEFAULT | EXD_FMA_OSVER)
49 #define CAT_FMA_PLAT (EXT_STRING | EXC_DEFAULT | EXD_FMA_PLAT)
50 #define CAT_FMA_UUID (EXT_STRING | EXC_DEFAULT | EXD_FMA_UUID)
51 #define CAT_FMA_TODSEC (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_TODSEC)
52 #define CAT_FMA_TODNSEC (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_TODNSEC)
53 #define CAT_FMA_NVLIST (EXT_RAW | EXC_DEFAULT | EXD_FMA_NVLIST)
54 #define CAT_FMA_MAJOR (EXT_UINT32 | EXC_DEFAULT | EXD_FMA_MAJOR)
55 #define CAT_FMA_MINOR (EXT_UINT32 | EXC_DEFAULT | EXD_FMA_MINOR)
56 #define CAT_FMA_INODE (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_INODE)
57 #define CAT_FMA_OFFSET (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_OFFSET)
59 static int fmd_log_load_record(fmd_log_t
*, uint_t
, fmd_log_record_t
*);
60 static void fmd_log_free_record(fmd_log_record_t
*);
61 static int fmd_log_load_xrefs(fmd_log_t
*, uint_t
, fmd_log_record_t
*);
63 static const char FMD_CREATOR
[] = "fmd";
66 * fmd_log_set_errno is used as a utility function throughout the library. It
67 * sets both lp->log_errno and errno to the specified value. If the current
68 * error is EFDL_EXACCT, we store it internally as that value plus ea_error().
69 * If no ea_error() is present, we assume EFDL_BADTAG (catalog tag mismatch).
72 fmd_log_set_errno(fmd_log_t
*lp
, int err
)
74 if (err
== EFDL_EXACCT
&& ea_error() != EXR_OK
)
75 lp
->log_errno
= EFDL_EXACCT
+ ea_error();
76 else if (err
== EFDL_EXACCT
)
77 lp
->log_errno
= EFDL_BADTAG
;
81 errno
= lp
->log_errno
;
87 fmd_log_dprintf(fmd_log_t
*lp
, const char *format
, ...)
91 if (lp
->log_flags
& FMD_LF_DEBUG
) {
92 (void) fputs("fmd_log DEBUG: ", stderr
);
94 (void) vfprintf(stderr
, format
, ap
);
100 * fmd_log_load_record() is used to load the exacct object at the current file
101 * location into the specified fmd_log_record structure. Once the caller has
102 * made use of this information, it can clean up using fmd_log_free_record().
105 fmd_log_load_record(fmd_log_t
*lp
, uint_t iflags
, fmd_log_record_t
*rp
)
107 ea_object_t
*grp
, *obj
;
111 if (iflags
& FMD_LOG_XITER_OFFS
) {
112 ea_clear(&lp
->log_ea
);
113 off
= lseek64(lp
->log_fd
, 0, SEEK_CUR
);
116 if ((grp
= ea_get_object_tree(&lp
->log_ea
, 1)) == NULL
)
117 return (fmd_log_set_errno(lp
, EFDL_EXACCT
));
119 if (grp
->eo_catalog
!= CAT_FMA_RGROUP
&&
120 grp
->eo_catalog
!= CAT_FMA_GROUP
) {
121 fmd_log_dprintf(lp
, "bad catalog tag 0x%x\n", grp
->eo_catalog
);
122 ea_free_object(grp
, EUP_ALLOC
);
123 return (fmd_log_set_errno(lp
, EFDL_EXACCT
));
126 bzero(rp
, sizeof (fmd_log_record_t
));
129 if (iflags
& FMD_LOG_XITER_OFFS
)
132 for (obj
= grp
->eo_group
.eg_objs
; obj
!= NULL
; obj
= obj
->eo_next
) {
133 switch (obj
->eo_catalog
) {
135 if ((err
= nvlist_unpack(obj
->eo_item
.ei_raw
,
136 obj
->eo_item
.ei_size
, &rp
->rec_nvl
, 0)) != 0) {
137 fmd_log_free_record(rp
);
138 return (fmd_log_set_errno(lp
, err
));
143 rp
->rec_sec
= obj
->eo_item
.ei_uint64
;
146 case CAT_FMA_TODNSEC
:
147 rp
->rec_nsec
= obj
->eo_item
.ei_uint64
;
151 rp
->rec_nrefs
+= obj
->eo_group
.eg_nobjs
;
156 if (rp
->rec_nvl
== NULL
|| nvlist_lookup_string(rp
->rec_nvl
,
157 FM_CLASS
, (char **)&rp
->rec_class
) != 0) {
158 fmd_log_free_record(rp
);
159 return (fmd_log_set_errno(lp
, EFDL_NOCLASS
));
162 if (rp
->rec_nrefs
!= 0 && fmd_log_load_xrefs(lp
, iflags
, rp
) != 0) {
163 err
= errno
; /* errno is set for us */
164 fmd_log_free_record(rp
);
165 return (fmd_log_set_errno(lp
, err
));
172 * fmd_log_free_record frees memory associated with the specified record. If
173 * cross-references are contained in this record, we proceed recursively.
176 fmd_log_free_record(fmd_log_record_t
*rp
)
180 if (rp
->rec_xrefs
!= NULL
) {
181 for (i
= 0; i
< rp
->rec_nrefs
; i
++)
182 fmd_log_free_record(&rp
->rec_xrefs
[i
]);
186 nvlist_free(rp
->rec_nvl
);
187 ea_free_object(rp
->rec_grp
, EUP_ALLOC
);
191 * fmd_log_load_xref loads the cross-reference represented by the specified
192 * exacct group 'grp' into the next empty slot in rp->rec_xrefs. This function
193 * is called repeatedly by fmd_log_load_xrefs() for each embedded reference.
196 fmd_log_load_xref(fmd_log_t
*lp
, uint_t iflags
,
197 fmd_log_record_t
*rp
, ea_object_t
*grp
)
203 off64_t off
= (off64_t
)-1L;
204 major_t maj
= (major_t
)-1L;
205 minor_t min
= (minor_t
)-1L;
206 ino64_t ino
= (ino64_t
)-1L;
209 for (obj
= grp
->eo_group
.eg_objs
; obj
!= NULL
; obj
= obj
->eo_next
) {
210 switch (obj
->eo_catalog
) {
212 maj
= obj
->eo_item
.ei_uint32
;
215 min
= obj
->eo_item
.ei_uint32
;
218 ino
= obj
->eo_item
.ei_uint64
;
221 off
= obj
->eo_item
.ei_uint64
;
224 uuid
= obj
->eo_item
.ei_string
;
229 if (off
== (off64_t
)-1L || (uuid
== NULL
&& (ino
== (ino64_t
)-1L ||
230 maj
== (major_t
)-1L || min
== (minor_t
)-1L)))
231 return (fmd_log_set_errno(lp
, EFDL_BADREF
));
233 if (uuid
== NULL
&& (dev
= makedev(maj
, min
)) == NODEV
)
234 return (fmd_log_set_errno(lp
, EFDL_BADDEV
));
237 * Search our xref list for matching (dev_t, ino64_t) or (uuid).
238 * If we can't find one, return silently without
239 * doing anything. We expect log xrefs to be broken whenever log
240 * files are trimmed or removed; their only purpose is to help us
241 * debug diagnosis engine algorithms.
243 for (xlp
= lp
->log_xrefs
; xlp
!= NULL
; xlp
= xlp
->log_xnext
) {
245 if (xlp
->log_stat
.st_ino
== ino
&&
246 xlp
->log_stat
.st_dev
== dev
)
248 } else if (xlp
->log_uuid
!= NULL
&&
249 strcmp(xlp
->log_uuid
, uuid
) == 0)
255 fmd_log_dprintf(lp
, "broken xref dev=%lx ino=%llx\n",
256 (ulong_t
)dev
, (u_longlong_t
)ino
);
258 fmd_log_dprintf(lp
, "broken xref uuid=%s\n", uuid
);
263 xlp
->log_flags
&= ~FMD_LF_START
;
264 ea_clear(&xlp
->log_ea
);
265 (void) lseek64(xlp
->log_fd
, off
, SEEK_SET
);
267 return (fmd_log_load_record(xlp
,
268 iflags
, &rp
->rec_xrefs
[rp
->rec_nrefs
++]));
272 * fmd_log_load_xrdir is called by fmd_log_load_xrefs when the FMD_LF_XREFS bit
273 * is not yet set, indicating we haven't looked for cross-referenced files. We
274 * open the directory associated with the specified log file and attempt to
275 * perform an fmd_log_open() on every file found there (i.e. /var/fm/fmd). If
276 * we are successful, the files are chained on to lp->log_xrefs, where the
277 * fmd_log_load_xref() function can find them by comparing dev/ino to log_stat.
280 fmd_log_load_xrdir(fmd_log_t
*lp
)
283 char dirbuf
[PATH_MAX
], path
[PATH_MAX
], *dirpath
;
288 lp
->log_flags
|= FMD_LF_XREFS
;
289 (void) strlcpy(dirbuf
, lp
->log_path
, sizeof (dirbuf
));
290 dirpath
= dirname(dirbuf
);
292 if ((dirp
= opendir(dirpath
)) == NULL
)
293 return; /* failed to open directory; just skip it */
295 while ((dp
= readdir(dirp
)) != NULL
) {
296 if (dp
->d_name
[0] == '.')
297 continue; /* skip "." and ".." and hidden files */
299 (void) snprintf(path
, sizeof (path
),
300 "%s/%s", dirpath
, dp
->d_name
);
302 if (strcmp(path
, lp
->log_path
) != 0 &&
303 stat(path
, &statbuf
) != -1 &&
304 (statbuf
.st_mode
& S_IFMT
) == S_IFREG
&&
305 (xlp
= fmd_log_open(lp
->log_abi
, path
, NULL
)) != NULL
) {
306 fmd_log_dprintf(lp
, "%s loaded %s for xrefs\n",
307 lp
->log_path
, xlp
->log_path
);
308 xlp
->log_xnext
= lp
->log_xrefs
;
315 * fmd_log_load_xrefs iterates again over the record's exacct group and for
316 * each cross-reference (embedded CAT_FMA_GROUP), attempts to fill in the
317 * corresponding xref. rp->rec_nrefs is reset to the number of valid items
318 * in the finished rp->rec_xrefs array; see fmd_log_load_xref() for more info.
321 fmd_log_load_xrefs(fmd_log_t
*lp
, uint_t iflags
, fmd_log_record_t
*rp
)
323 size_t size
= sizeof (fmd_log_record_t
) * rp
->rec_nrefs
;
324 ea_object_t
*rgrp
= rp
->rec_grp
;
325 ea_object_t
*grp
, *obj
;
327 if (!(iflags
& FMD_LOG_XITER_REFS
))
328 return (0); /* do not load any xrefs */
330 if (!(lp
->log_flags
& FMD_LF_XREFS
))
331 fmd_log_load_xrdir(lp
);
333 if ((rp
->rec_xrefs
= malloc(size
)) == NULL
)
334 return (fmd_log_set_errno(lp
, EFDL_NOMEM
));
336 bzero(rp
->rec_xrefs
, size
);
340 * Make a second pass through the record group to locate and process
341 * each cross-reference sub-group. The structure of the groups is
342 * as follows (left-hand-side symbols named after the variables used):
344 * rgrp := CAT_FMA_TODSEC CAT_FMA_TODNSEC CAT_FMA_NVLIST grp*
345 * grp := obj* (i.e. zero or more groups of xref items)
346 * obj := CAT_FMA_MAJOR CAT_FMA_MINOR CAT_FMA_INODE CAT_FMA_OFFSET
348 * For each xref 'obj', we call fmd_log_load_xref() to parse the four
349 * xref members and then load the specified record into rp->rec_xrefs.
351 for (grp
= rgrp
->eo_group
.eg_objs
; grp
!= NULL
; grp
= grp
->eo_next
) {
352 if (grp
->eo_catalog
!= CAT_FMA_GROUP
)
353 continue; /* ignore anything that isn't a group */
355 for (obj
= grp
->eo_group
.eg_objs
;
356 obj
!= NULL
; obj
= obj
->eo_next
) {
357 if (fmd_log_load_xref(lp
, iflags
, rp
, obj
) != 0)
358 return (-1); /* errno is set for us */
366 fmd_log_open_err(fmd_log_t
*lp
, int *errp
, int err
)
369 *errp
= err
== EFDL_EXACCT
? EFDL_EXACCT
+ ea_error() : err
;
378 fmd_log_open(int abi
, const char *name
, int *errp
)
380 ea_object_t
*grp
, *obj
;
384 if (abi
> FMD_LOG_VERSION
)
385 return (fmd_log_open_err(NULL
, errp
, EFDL_VERSION
));
387 if ((lp
= malloc(sizeof (fmd_log_t
))) == NULL
)
388 return (fmd_log_open_err(NULL
, errp
, EFDL_NOMEM
));
390 bzero(lp
, sizeof (fmd_log_t
));
392 if ((lp
->log_path
= strdup(name
)) == NULL
)
393 return (fmd_log_open_err(lp
, errp
, EFDL_NOMEM
));
395 if ((lp
->log_fd
= open64(name
, O_RDONLY
)) == -1 ||
396 fstat64(lp
->log_fd
, &lp
->log_stat
) == -1 ||
397 (fd
= dup(lp
->log_fd
)) == -1)
398 return (fmd_log_open_err(lp
, errp
, errno
));
400 if (ea_fdopen(&lp
->log_ea
, fd
, FMD_CREATOR
,
401 EO_VALID_HDR
| EO_HEAD
, O_RDONLY
) == -1) {
403 return (fmd_log_open_err(lp
, errp
, EFDL_EXACCT
));
407 lp
->log_flags
|= FMD_LF_EAOPEN
;
408 if (getenv("FMD_LOG_DEBUG") != NULL
)
409 lp
->log_flags
|= FMD_LF_DEBUG
;
412 * Read the first group of log meta-data: the write-once read-only
413 * file header. We read all records in this group, ignoring all but
414 * the VERSION and LABEL, which are required and must be verified.
416 if ((grp
= ea_get_object_tree(&lp
->log_ea
, 1)) == NULL
)
417 return (fmd_log_open_err(lp
, errp
, EFDL_EXACCT
));
419 if (grp
->eo_catalog
!= CAT_FMA_GROUP
) {
420 ea_free_object(grp
, EUP_ALLOC
);
421 return (fmd_log_open_err(lp
, errp
, EFDL_EXACCT
));
424 for (obj
= grp
->eo_group
.eg_objs
; obj
!= NULL
; obj
= obj
->eo_next
) {
425 switch (obj
->eo_catalog
) {
426 case CAT_FMA_VERSION
:
427 lp
->log_version
= strdup(obj
->eo_item
.ei_string
);
428 if (lp
->log_version
== NULL
) {
429 ea_free_object(grp
, EUP_ALLOC
);
430 return (fmd_log_open_err(lp
, errp
, EFDL_NOMEM
));
434 lp
->log_label
= strdup(obj
->eo_item
.ei_string
);
435 if (lp
->log_label
== NULL
) {
436 ea_free_object(grp
, EUP_ALLOC
);
437 return (fmd_log_open_err(lp
, errp
, EFDL_NOMEM
));
441 lp
->log_osrelease
= strdup(obj
->eo_item
.ei_string
);
442 if (lp
->log_osrelease
== NULL
) {
443 ea_free_object(grp
, EUP_ALLOC
);
444 return (fmd_log_open_err(lp
, errp
, EFDL_NOMEM
));
448 lp
->log_osversion
= strdup(obj
->eo_item
.ei_string
);
449 if (lp
->log_osversion
== NULL
) {
450 ea_free_object(grp
, EUP_ALLOC
);
451 return (fmd_log_open_err(lp
, errp
, EFDL_NOMEM
));
455 lp
->log_platform
= strdup(obj
->eo_item
.ei_string
);
456 if (lp
->log_platform
== NULL
) {
457 ea_free_object(grp
, EUP_ALLOC
);
458 return (fmd_log_open_err(lp
, errp
, EFDL_NOMEM
));
462 lp
->log_uuid
= strdup(obj
->eo_item
.ei_string
);
463 if (lp
->log_uuid
== NULL
) {
464 ea_free_object(grp
, EUP_ALLOC
);
465 return (fmd_log_open_err(lp
, errp
, EFDL_NOMEM
));
471 ea_free_object(grp
, EUP_ALLOC
);
473 if (lp
->log_version
== NULL
|| lp
->log_label
== NULL
)
474 return (fmd_log_open_err(lp
, errp
, EFDL_BADHDR
));
477 * Read the second group of log meta-data: the table of contents. At
478 * present there are no records libfmd_log needs in here, so we just
479 * skip over this entire group so that fmd_log_xiter() starts after it.
481 if ((grp
= ea_get_object_tree(&lp
->log_ea
, 1)) == NULL
)
482 return (fmd_log_open_err(lp
, errp
, EFDL_EXACCT
));
484 if (grp
->eo_catalog
!= CAT_FMA_GROUP
) {
485 ea_free_object(grp
, EUP_ALLOC
);
486 return (fmd_log_open_err(lp
, errp
, EFDL_EXACCT
));
489 ea_free_object(grp
, EUP_ALLOC
);
490 lp
->log_flags
|= FMD_LF_START
;
492 fmd_log_dprintf(lp
, "open log %s dev=%lx ino=%llx\n", lp
->log_path
,
493 (ulong_t
)lp
->log_stat
.st_dev
, (u_longlong_t
)lp
->log_stat
.st_ino
);
499 fmd_log_close(fmd_log_t
*lp
)
501 fmd_log_t
*xlp
, *nlp
;
504 return; /* permit null lp to simply caller code */
506 for (xlp
= lp
->log_xrefs
; xlp
!= NULL
; xlp
= nlp
) {
507 nlp
= xlp
->log_xnext
;
511 if (lp
->log_flags
& FMD_LF_EAOPEN
)
512 (void) ea_close(&lp
->log_ea
);
515 (void) close(lp
->log_fd
);
518 free(lp
->log_version
);
520 free(lp
->log_osrelease
);
521 free(lp
->log_osversion
);
522 free(lp
->log_platform
);
529 fmd_log_label(fmd_log_t
*lp
)
531 return (lp
->log_label
);
535 fmd_log_header(fmd_log_t
*lp
, fmd_log_header_t
*hp
)
537 const char *creator
= ea_get_creator(&lp
->log_ea
);
538 const char *hostname
= ea_get_hostname(&lp
->log_ea
);
540 hp
->log_creator
= creator
? creator
: "";
541 hp
->log_hostname
= hostname
? hostname
: "";
542 hp
->log_label
= lp
->log_label
? lp
->log_label
: "";
543 hp
->log_version
= lp
->log_version
? lp
->log_version
: "";
544 hp
->log_osrelease
= lp
->log_osrelease
? lp
->log_osrelease
: "";
545 hp
->log_osversion
= lp
->log_osversion
? lp
->log_osversion
: "";
546 hp
->log_platform
= lp
->log_platform
? lp
->log_platform
: "";
548 hp
->log_uuid
= lp
->log_uuid
? lp
->log_uuid
: "";
552 * Note: this will be verrrry slow for big files. If this function becomes
553 * important, we'll need to add a function to libexacct to let us rewind.
554 * Currently libexacct has no notion of seeking other than record-at-a-time.
557 fmd_log_rewind(fmd_log_t
*lp
)
559 ea_object_t obj
, *grp
;
561 if (!(lp
->log_flags
& FMD_LF_START
)) {
562 while (ea_previous_object(&lp
->log_ea
, &obj
) != EO_ERROR
)
563 continue; /* rewind until beginning of file */
565 if ((grp
= ea_get_object_tree(&lp
->log_ea
, 1)) == NULL
)
566 return (fmd_log_set_errno(lp
, EFDL_EXACCT
));
568 ea_free_object(grp
, EUP_ALLOC
); /* hdr group */
570 if ((grp
= ea_get_object_tree(&lp
->log_ea
, 1)) == NULL
)
571 return (fmd_log_set_errno(lp
, EFDL_EXACCT
));
573 ea_free_object(grp
, EUP_ALLOC
); /* toc group */
575 lp
->log_flags
|= FMD_LF_START
;
582 fmd_log_xiter_filter(fmd_log_t
*lp
, const fmd_log_record_t
*rp
,
583 uint_t fac
, const fmd_log_filtvec_t
*fav
)
587 for (i
= 0; i
< fac
; i
++) {
588 for (j
= 0; j
< fav
[i
].filt_argc
; j
++) {
589 if (fav
[i
].filt_argv
[j
].filt_func(lp
, rp
,
590 fav
[i
].filt_argv
[j
].filt_arg
) != 0)
591 break; /* logical OR of this class is true */
594 if (j
== fav
[i
].filt_argc
)
595 return (0); /* logical AND of filter is false */
598 return (1); /* logical AND of filter is true */
602 fmd_log_xiter_filtcmp(const void *lp
, const void *rp
)
604 return ((intptr_t)((fmd_log_filter_t
*)lp
)->filt_func
-
605 (intptr_t)((fmd_log_filter_t
*)rp
)->filt_func
);
609 fmd_log_filter(fmd_log_t
*lp
, uint_t fc
, fmd_log_filter_t
*fv
,
610 const fmd_log_record_t
*rp
)
612 fmd_log_filtvec_t
*fav
= alloca(fc
* sizeof (fmd_log_filtvec_t
));
616 * If a filter array was provided, create an array of filtvec structs
617 * to perform logical AND/OR processing. See fmd_log_xiter(), below.
619 bzero(fav
, fc
* sizeof (fmd_log_filtvec_t
));
620 qsort(fv
, fc
, sizeof (fmd_log_filter_t
), fmd_log_xiter_filtcmp
);
622 for (i
= 0; i
< fc
; i
++) {
623 if (i
== 0 || fv
[i
].filt_func
!= fv
[i
- 1].filt_func
)
624 fav
[fac
++].filt_argv
= &fv
[i
];
625 fav
[fac
- 1].filt_argc
++;
628 return (fmd_log_xiter_filter(lp
, rp
, fac
, fav
));
632 fmd_log_xiter(fmd_log_t
*lp
, uint_t flag
, uint_t fc
, fmd_log_filter_t
*fv
,
633 fmd_log_rec_f
*rfunc
, fmd_log_err_f
*efunc
, void *private, ulong_t
*rcntp
)
635 fmd_log_record_t rec
;
636 fmd_log_filtvec_t
*fav
= NULL
;
641 if (flag
& ~FMD_LOG_XITER_MASK
)
642 return (fmd_log_set_errno(lp
, EINVAL
));
645 * If a filter array was provided, create an array of filtvec structs
646 * where each filtvec holds a pointer to an equivalent list of filters,
647 * as determined by their filt_func. We sort the input array by func,
648 * and then fill in the filtvec struct array. We can then compute the
649 * logical OR of equivalent filters by iterating over filt_argv, and
650 * we can compute the logical AND of 'fv' by iterating over filt_argc.
653 if ((fav
= calloc(fc
, sizeof (fmd_log_filtvec_t
))) == NULL
)
654 return (fmd_log_set_errno(lp
, EFDL_NOMEM
));
656 qsort(fv
, fc
, sizeof (fmd_log_filter_t
), fmd_log_xiter_filtcmp
);
658 for (i
= 0; i
< fc
; i
++) {
659 if (i
== 0 || fv
[i
].filt_func
!= fv
[i
- 1].filt_func
)
660 fav
[fac
++].filt_argv
= &fv
[i
];
661 fav
[fac
- 1].filt_argc
++;
665 lp
->log_flags
&= ~FMD_LF_START
;
666 ea_clear(&lp
->log_ea
);
669 if (fmd_log_load_record(lp
, flag
, &rec
) != 0) {
670 if (lp
->log_errno
== EFDL_EXACCT
+ EXR_EOF
)
671 break; /* end-of-file reached */
672 rv
= efunc
? efunc(lp
, private) : -1;
675 if (fc
== 0 || fmd_log_xiter_filter(lp
, &rec
, fac
, fav
))
676 rv
= rfunc(lp
, &rec
, private);
678 fmd_log_free_record(&rec
);
693 fmd_log_iter(fmd_log_t
*lp
, fmd_log_rec_f
*rfunc
, void *private)
695 return (fmd_log_xiter(lp
, 0, 0, NULL
, rfunc
, NULL
, private, NULL
));
699 fmd_log_seek(fmd_log_t
*lp
, off64_t off
)
701 lp
->log_flags
&= ~FMD_LF_START
;
702 ea_clear(&lp
->log_ea
);
704 if (lseek64(lp
->log_fd
, off
, SEEK_SET
) != off
)
705 return (fmd_log_set_errno(lp
, errno
));
710 static const char *const _fmd_errs
[] = {
711 "client requires newer version of libfmd_log", /* EFDL_VERSION */
712 "required memory allocation failed", /* EFDL_NOMEM */
713 "log header did not contain required field", /* EFDL_BADHDR */
714 "log record did not contain protocol class", /* EFDL_NOCLASS */
715 "log record has invalid catalog tag", /* EFDL_BADTAG */
716 "log record has invalid cross-reference group", /* EFDL_BADREF */
717 "log record has invalid cross-reference dev_t", /* EFDL_BADDEV */
718 "log record was not of expected type", /* EFDL_EXACCT + OK */
719 "log access system call failed", /* EXR_SYSCALL_FAIL */
720 "log file corruption detected", /* EXR_CORRUPT_FILE */
721 "end-of-file reached", /* EXR_EOF */
722 "log file does not have appropriate creator", /* EXR_NO_CREATOR */
723 "invalid unpack buffer specified", /* EXR_INVALID_BUF */
724 "invalid exacct operation for log file", /* EXR_NOTSUPP */
725 "log file requires newer version of libexacct", /* EXR_UNKN_VERSION */
726 "invalid object buffer specified", /* EXR_INVALID_OBJ */
729 static const int _fmd_nerr
= sizeof (_fmd_errs
) / sizeof (_fmd_errs
[0]);
733 fmd_log_errmsg(fmd_log_t
*lp
, int err
)
737 if (err
>= EFDL_BASE
&& err
- EFDL_BASE
< _fmd_nerr
)
738 msg
= _fmd_errs
[err
- EFDL_BASE
];
742 return (msg
? msg
: "unknown error");
746 fmd_log_errno(fmd_log_t
*lp
)
748 return (lp
->log_errno
);