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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2024 Oxide Computer Co. 26 */ 27 28 #include <sys/fm/protocol.h> 29 30 #include <strings.h> 31 #include <libgen.h> 32 #include <regex.h> 33 #include <libnvpair.h> 34 35 #include <fmd_log_impl.h> 36 #include <fmd_log.h> 37 38 /*ARGSUSED*/ 39 int 40 fmd_log_filter_class(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) 41 { 42 nvlist_t **nva; 43 uint32_t i, size; 44 char *class; 45 46 if (gmatch(rp->rec_class, arg)) 47 return (1); 48 49 /* return false if the record doesn't contain valid fault list */ 50 if (! gmatch(rp->rec_class, FM_LIST_EVENT ".*") || 51 nvlist_lookup_uint32(rp->rec_nvl, FM_SUSPECT_FAULT_SZ, 52 &size) != 0 || size == 0 || 53 nvlist_lookup_nvlist_array(rp->rec_nvl, FM_SUSPECT_FAULT_LIST, 54 &nva, &size) != 0) 55 return (0); 56 57 /* return true if any fault in the list matches */ 58 for (i = 0; i < size; i++) { 59 if (nvlist_lookup_string(nva[i], FM_CLASS, &class) == 0 && 60 gmatch(class, arg)) 61 return (1); 62 } 63 64 return (0); 65 } 66 67 /*ARGSUSED*/ 68 int 69 fmd_log_filter_uuid(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) 70 { 71 char *uuid; 72 73 /* 74 * Note: the uuid filter matches *any* member whose name is 'uuid'. 75 * This permits us to match not only a list.suspect uuid but any 76 * other event that decides to embed uuids, too, using the same name. 77 */ 78 return (nvlist_lookup_string(rp->rec_nvl, 79 "uuid", &uuid) == 0 && strcmp(uuid, arg) == 0); 80 } 81 82 /*ARGSUSED*/ 83 int 84 fmd_log_filter_before(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) 85 { 86 uint64_t sec = ((struct timeval *)arg)->tv_sec; 87 uint64_t nsec = ((struct timeval *)arg)->tv_usec * (NANOSEC / MICROSEC); 88 return (rp->rec_sec == sec ? rp->rec_nsec <= nsec : rp->rec_sec <= sec); 89 } 90 91 /*ARGSUSED*/ 92 int 93 fmd_log_filter_after(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) 94 { 95 uint64_t sec = ((struct timeval *)arg)->tv_sec; 96 uint64_t nsec = ((struct timeval *)arg)->tv_usec * (NANOSEC / MICROSEC); 97 return (rp->rec_sec == sec ? rp->rec_nsec >= nsec : rp->rec_sec >= sec); 98 } 99 100 /*ARGSUSED*/ 101 int 102 fmd_log_filter_nv(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) 103 { 104 /* 105 * The nvarg_next member was added compatibly with the introduction of 106 * ABI version 3. Older consumers pass a smaller structure that does 107 * not contain this member, so we treat it as if it were always NULL. 108 */ 109 for (fmd_log_filter_nvarg_t *argt = (fmd_log_filter_nvarg_t *)arg; 110 argt != NULL; argt = (lp->log_abi < 3) ? NULL : argt->nvarg_next) { 111 char *name = argt->nvarg_name; 112 char *value = argt->nvarg_value; 113 regex_t *value_regex = argt->nvarg_value_regex; 114 nvpair_t *nvp; 115 int ai; 116 117 /* see if nvlist has named member */ 118 if (nvlist_lookup_nvpair_embedded_index(rp->rec_nvl, name, 119 &nvp, &ai, NULL) != 0) { 120 return (0); /* name filter failure */ 121 } 122 123 /* check value match for matching nvpair */ 124 if ((value != NULL) && 125 (nvpair_value_match_regex(nvp, ai, 126 value, value_regex, NULL) != 1)) { 127 return (0); /* value filter failure */ 128 } 129 } 130 131 return (1); /* name/value filter pass */ 132 } 133 134 /* 135 * This exists because filters are sorted and grouped based on the pointer to 136 * the filtering function, and we need fmdump to be able to maintain backward 137 * compatibility. fmdump distinguishes filter classes by the command-line 138 * option used to describe the filter. As for all library consumers, filters 139 * with the same evaluation function are considered to have the same class, and 140 * groups of filters of the SAME class are ORed together (i.e., match-any) while 141 * distinct classes are ANDed together, so that at least one of every class of 142 * filter must match in order for the record to pass through. The command-line 143 * syntax fmdump accepts for multiple name-value filter chains cannot be made 144 * compatible with the syntax it accepted for single name-value filters, 145 * requiring that a new command-line option be introduced for multi-name-value 146 * filter chains. Using a separate function thus allows fmdump to treat 147 * single-name-value and multi-name-value filters as belonging to different 148 * classes, maintaining backward compatibility with its existing command-line 149 * option syntax AND consistency with its documented treatment of filters of 150 * distinct classes. At the same time, because a single-name-value filter is 151 * merely a special case of a multi-name-value filter (each entry in the 152 * argument list is required to match the record in order for the record to pass 153 * the filter), the actual implementation of the two filter classes is 154 * identical. A consumer that, unlike fmdump, wants to treat these types of 155 * filters as belonging to a single class can therefore do so simply by using 156 * fmd_log_filter_nv() regardless of the number of name-value parameters in the 157 * argument chain, while those that want the fmdump behaviour should use that 158 * function only for filters with a single such parameter and this function for 159 * those with multiple. See fmdump(8). 160 */ 161 int 162 fmd_log_filter_nv_multi(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) 163 { 164 return (fmd_log_filter_nv(lp, rp, arg)); 165 } 166