|  |  | varnish-cache/lib/libvarnishapi/vsl.c | 
|---|
| 0 |  | /*- | 
| 1 |  |  * Copyright (c) 2006 Verdens Gang AS | 
| 2 |  |  * Copyright (c) 2006-2015 Varnish Software AS | 
| 3 |  |  * All rights reserved. | 
| 4 |  |  * | 
| 5 |  |  * Author: Poul-Henning Kamp <phk@phk.freebsd.dk> | 
| 6 |  |  * Author: Martin Blix Grydeland <martin@varnish-software.com> | 
| 7 |  |  * | 
| 8 |  |  * SPDX-License-Identifier: BSD-2-Clause | 
| 9 |  |  * | 
| 10 |  |  * Redistribution and use in source and binary forms, with or without | 
| 11 |  |  * modification, are permitted provided that the following conditions | 
| 12 |  |  * are met: | 
| 13 |  |  * 1. Redistributions of source code must retain the above copyright | 
| 14 |  |  *    notice, this list of conditions and the following disclaimer. | 
| 15 |  |  * 2. Redistributions in binary form must reproduce the above copyright | 
| 16 |  |  *    notice, this list of conditions and the following disclaimer in the | 
| 17 |  |  *    documentation and/or other materials provided with the distribution. | 
| 18 |  |  * | 
| 19 |  |  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 
| 20 |  |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
| 21 |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
| 22 |  |  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE | 
| 23 |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
| 24 |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
| 25 |  |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
| 26 |  |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
| 27 |  |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
| 28 |  |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
| 29 |  |  * SUCH DAMAGE. | 
| 30 |  |  */ | 
| 31 |  |  | 
| 32 |  | #include "config.h" | 
| 33 |  |  | 
| 34 |  | #include <stdarg.h> | 
| 35 |  | #include <stdint.h> | 
| 36 |  | #include <stdio.h> | 
| 37 |  |  | 
| 38 |  | #include "vdef.h" | 
| 39 |  | #include "vas.h" | 
| 40 |  | #include "miniobj.h" | 
| 41 |  |  | 
| 42 |  | #include "vbm.h" | 
| 43 |  | #include "vqueue.h" | 
| 44 |  | #include "vre.h" | 
| 45 |  | #include "vsb.h" | 
| 46 |  |  | 
| 47 |  | #include "vapi/vsl.h" | 
| 48 |  |  | 
| 49 |  | #include "vsl_api.h" | 
| 50 |  |  | 
| 51 |  | /*--------------------------------------------------------------------*/ | 
| 52 |  |  | 
| 53 |  | const char                      vsl_file_id[] = {'V', 'S', 'L', '2'}; | 
| 54 |  |  | 
| 55 |  | const char * const VSL_tags[SLT__MAX] = { | 
| 56 |  | #  define SLTM(foo,flags,sdesc,ldesc)       [SLT_##foo] = #foo, | 
| 57 |  | #  include "tbl/vsl_tags.h" | 
| 58 |  | }; | 
| 59 |  |  | 
| 60 |  | const unsigned VSL_tagflags[SLT__MAX] = { | 
| 61 |  | #  define SLTM(foo, flags, sdesc, ldesc)        [SLT_##foo] = flags, | 
| 62 |  | #  include "tbl/vsl_tags.h" | 
| 63 |  | #  undef SLTM | 
| 64 |  | }; | 
| 65 |  |  | 
| 66 |  | int | 
| 67 | 37662 | vsl_diag(struct VSL_data *vsl, const char *fmt, ...) | 
| 68 |  | { | 
| 69 |  |         va_list ap; | 
| 70 |  |  | 
| 71 | 37662 |         CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); | 
| 72 | 37662 |         AN(fmt); | 
| 73 |  |  | 
| 74 | 37662 |         if (vsl->diag == NULL) | 
| 75 | 37662 |                 vsl->diag = VSB_new_auto(); | 
| 76 | 37662 |         AN(vsl->diag); | 
| 77 | 37662 |         VSB_clear(vsl->diag); | 
| 78 | 37662 |         va_start(ap, fmt); | 
| 79 | 37662 |         VSB_vprintf(vsl->diag, fmt, ap); | 
| 80 | 37662 |         va_end(ap); | 
| 81 | 37662 |         AZ(VSB_finish(vsl->diag)); | 
| 82 | 37662 |         return (-1); | 
| 83 |  | } | 
| 84 |  |  | 
| 85 |  | struct VSL_data * | 
| 86 | 11312 | VSL_New(void) | 
| 87 |  | { | 
| 88 |  |         struct VSL_data *vsl; | 
| 89 |  |  | 
| 90 | 11312 |         ALLOC_OBJ(vsl, VSL_MAGIC); | 
| 91 | 11312 |         if (vsl == NULL) | 
| 92 | 0 |                 return (NULL); | 
| 93 |  |  | 
| 94 | 11312 |         vsl->L_opt = 1000; | 
| 95 | 11312 |         vsl->T_opt = 120.; | 
| 96 | 11312 |         vsl->vbm_select = vbit_new(SLT__MAX); | 
| 97 | 11312 |         vsl->vbm_suppress = vbit_new(SLT__MAX); | 
| 98 | 11312 |         VTAILQ_INIT(&vsl->vslf_select); | 
| 99 | 11312 |         VTAILQ_INIT(&vsl->vslf_suppress); | 
| 100 |  |  | 
| 101 | 11312 |         return (vsl); | 
| 102 | 11312 | } | 
| 103 |  |  | 
| 104 |  | static void | 
| 105 | 20336 | vsl_IX_free(vslf_list *filters) | 
| 106 |  | { | 
| 107 |  |         struct vslf *vslf; | 
| 108 |  |  | 
| 109 | 20368 |         while (!VTAILQ_EMPTY(filters)) { | 
| 110 | 32 |                 vslf = VTAILQ_FIRST(filters); | 
| 111 | 32 |                 CHECK_OBJ_NOTNULL(vslf, VSLF_MAGIC); | 
| 112 | 32 |                 VTAILQ_REMOVE(filters, vslf, list); | 
| 113 | 32 |                 if (vslf->tags) | 
| 114 | 0 |                         vbit_destroy(vslf->tags); | 
| 115 | 32 |                 AN(vslf->vre); | 
| 116 | 32 |                 VRE_free(&vslf->vre); | 
| 117 | 32 |                 AZ(vslf->vre); | 
| 118 | 32 |                 FREE_OBJ(vslf); | 
| 119 |  |         } | 
| 120 | 20336 | } | 
| 121 |  |  | 
| 122 |  | void | 
| 123 | 10168 | VSL_Delete(struct VSL_data *vsl) | 
| 124 |  | { | 
| 125 |  |  | 
| 126 | 10168 |         CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); | 
| 127 |  |  | 
| 128 | 10168 |         vbit_destroy(vsl->vbm_select); | 
| 129 | 10168 |         vbit_destroy(vsl->vbm_suppress); | 
| 130 | 10168 |         vsl_IX_free(&vsl->vslf_select); | 
| 131 | 10168 |         vsl_IX_free(&vsl->vslf_suppress); | 
| 132 | 10168 |         VSL_ResetError(vsl); | 
| 133 | 10168 |         FREE_OBJ(vsl); | 
| 134 | 10168 | } | 
| 135 |  |  | 
| 136 |  | const char * | 
| 137 | 37662 | VSL_Error(const struct VSL_data *vsl) | 
| 138 |  | { | 
| 139 |  |  | 
| 140 | 37662 |         CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); | 
| 141 |  |  | 
| 142 | 37662 |         if (vsl->diag == NULL) | 
| 143 | 0 |                 return (NULL); | 
| 144 |  |         else | 
| 145 | 37662 |                 return (VSB_data(vsl->diag)); | 
| 146 | 37662 | } | 
| 147 |  |  | 
| 148 |  | void | 
| 149 | 47406 | VSL_ResetError(struct VSL_data *vsl) | 
| 150 |  | { | 
| 151 |  |  | 
| 152 | 47406 |         CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); | 
| 153 |  |  | 
| 154 | 47406 |         if (vsl->diag == NULL) | 
| 155 | 10168 |                 return; | 
| 156 | 37238 |         VSB_destroy(&vsl->diag); | 
| 157 | 47406 | } | 
| 158 |  |  | 
| 159 |  | static int | 
| 160 | 416 | vsl_match_IX(struct VSL_data *vsl, const vslf_list *list, | 
| 161 |  |     const struct VSL_cursor *c) | 
| 162 |  | { | 
| 163 |  |         enum VSL_tag_e tag; | 
| 164 |  |         const char *cdata; | 
| 165 |  |         int len; | 
| 166 |  |         const struct vslf *vslf; | 
| 167 |  |  | 
| 168 | 416 |         (void)vsl; | 
| 169 | 416 |         tag = VSL_TAG(c->rec.ptr); | 
| 170 | 416 |         cdata = VSL_CDATA(c->rec.ptr); | 
| 171 | 416 |         len = VSL_LEN(c->rec.ptr); | 
| 172 |  |  | 
| 173 | 720 |         VTAILQ_FOREACH(vslf, list, list) { | 
| 174 | 416 |                 CHECK_OBJ_NOTNULL(vslf, VSLF_MAGIC); | 
| 175 | 416 |                 if (vslf->tags != NULL && !vbit_test(vslf->tags, tag)) | 
| 176 | 0 |                         continue; | 
| 177 | 416 |                 if (VRE_match(vslf->vre, cdata, len, 0, NULL) >= 0) | 
| 178 | 112 |                         return (1); | 
| 179 | 304 |         } | 
| 180 | 304 |         return (0); | 
| 181 | 416 | } | 
| 182 |  |  | 
| 183 |  | int | 
| 184 | 261116 | VSL_Match(struct VSL_data *vsl, const struct VSL_cursor *c) | 
| 185 |  | { | 
| 186 |  |         enum VSL_tag_e tag; | 
| 187 |  |  | 
| 188 | 261116 |         CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); | 
| 189 | 261116 |         if (c == NULL || c->rec.ptr == NULL) | 
| 190 | 18 |                 return (0); | 
| 191 | 261116 |         tag = VSL_TAG(c->rec.ptr); | 
| 192 | 261116 |         if (tag <= SLT__Bogus || tag >= SLT__Reserved) | 
| 193 | 12 |                 return (0); | 
| 194 | 261112 |         if (!vsl->c_opt || !vsl->b_opt) { | 
| 195 | 260843 |                 if (vsl->c_opt && !VSL_CLIENT(c->rec.ptr)) | 
| 196 | 784 |                         return (0); | 
| 197 | 260059 |                 if (vsl->b_opt && !VSL_BACKEND(c->rec.ptr)) | 
| 198 | 0 |                         return (0); | 
| 199 | 260059 |         } | 
| 200 | 260328 |         if (!VTAILQ_EMPTY(&vsl->vslf_select) && | 
| 201 | 48 |             vsl_match_IX(vsl, &vsl->vslf_select, c)) | 
| 202 | 16 |                 return (1); | 
| 203 | 260312 |         else if (vbit_test(vsl->vbm_select, tag)) | 
| 204 | 0 |                 return (1); | 
| 205 | 260312 |         else if (!VTAILQ_EMPTY(&vsl->vslf_suppress) && | 
| 206 | 368 |             vsl_match_IX(vsl, &vsl->vslf_suppress, c)) | 
| 207 | 96 |                 return (0); | 
| 208 | 260216 |         else if (vbit_test(vsl->vbm_suppress, tag)) | 
| 209 | 13080 |                 return (0); | 
| 210 |  |  | 
| 211 |  |         /* Default show */ | 
| 212 | 247136 |         return (1); | 
| 213 | 261112 | } | 
| 214 |  |  | 
| 215 |  | static const char * const VSL_transactions[VSL_t__MAX] = { | 
| 216 |  |         /*                 12345678901234 */ | 
| 217 |  |         [VSL_t_unknown] = "<< Unknown  >>", | 
| 218 |  |         [VSL_t_sess]    = "<< Session  >>", | 
| 219 |  |         [VSL_t_req]     = "<< Request  >>", | 
| 220 |  |         [VSL_t_bereq]   = "<< BeReq    >>", | 
| 221 |  |         [VSL_t_raw]     = "<< Record   >>", | 
| 222 |  | }; | 
| 223 |  |  | 
| 224 |  | #define VSL_PRINT(...)                                  \ | 
| 225 |  |         do {                                            \ | 
| 226 |  |                 if (0 > fprintf(__VA_ARGS__))           \ | 
| 227 |  |                         return (-5);                    \ | 
| 228 |  |         } while (0) | 
| 229 |  |  | 
| 230 |  | static int | 
| 231 | 646 | vsl_print_unsafe(FILE *fo, unsigned len, const char *data) | 
| 232 |  | { | 
| 233 |  |  | 
| 234 | 646 |         VSL_PRINT(fo, "\""); | 
| 235 | 39682 |         while (len-- > 0) { | 
| 236 | 39036 |                 if (*data >= ' ' && *data <= '~') | 
| 237 | 38390 |                         VSL_PRINT(fo, "%c", *data); | 
| 238 |  |                 else | 
| 239 | 646 |                         VSL_PRINT(fo, "%%%02x", (unsigned char)*data); | 
| 240 | 39036 |                 data++; | 
| 241 |  |         } | 
| 242 | 646 |         VSL_PRINT(fo, "\"\n"); | 
| 243 | 646 |         return (0); | 
| 244 | 646 | } | 
| 245 |  |  | 
| 246 |  |  | 
| 247 |  | static int | 
| 248 | 184 | vsl_print_binary(FILE *fo, unsigned len, const char *data) | 
| 249 |  | { | 
| 250 |  |  | 
| 251 | 184 |         VSL_PRINT(fo, "["); | 
| 252 | 4188 |         while (len-- > 0) { | 
| 253 | 4004 |                 VSL_PRINT(fo, "%02x", (unsigned char)*data); | 
| 254 | 4004 |                 data++; | 
| 255 |  |         } | 
| 256 | 184 |         VSL_PRINT(fo, "]\n"); | 
| 257 | 184 |         return (0); | 
| 258 | 184 | } | 
| 259 |  |  | 
| 260 |  | static int | 
| 261 | 4548 | vsl_print(const struct VSL_data *vsl, const struct VSL_cursor *c, void *fo, | 
| 262 |  |     int terse) | 
| 263 |  | { | 
| 264 |  |         enum VSL_tag_e tag; | 
| 265 |  |         uint64_t vxid; | 
| 266 |  |         unsigned len; | 
| 267 |  |         const char *data; | 
| 268 |  |         int type; | 
| 269 |  |  | 
| 270 | 4548 |         CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); | 
| 271 | 4548 |         if (c == NULL || c->rec.ptr == NULL) | 
| 272 | 0 |                 return (0); | 
| 273 | 4548 |         if (fo == NULL) | 
| 274 | 0 |                 fo = stdout; | 
| 275 | 4548 |         tag = VSL_TAG(c->rec.ptr); | 
| 276 | 4548 |         vxid = VSL_ID(c->rec.ptr); | 
| 277 | 4548 |         len = VSL_LEN(c->rec.ptr); | 
| 278 | 4548 |         type = VSL_CLIENT(c->rec.ptr) ? 'c' : VSL_BACKEND(c->rec.ptr) ? | 
| 279 |  |             'b' : '-'; | 
| 280 | 4548 |         data = VSL_CDATA(c->rec.ptr); | 
| 281 |  |  | 
| 282 | 4548 |         if (!terse) | 
| 283 | 3644 |                 VSL_PRINT(fo, "%10ju ", (uintmax_t)vxid); | 
| 284 | 4548 |         VSL_PRINT(fo, "%-14s ", VSL_tags[tag]); | 
| 285 | 4548 |         if (!terse) | 
| 286 | 3644 |                 VSL_PRINT(fo, "%c ", type); | 
| 287 |  |  | 
| 288 | 4548 |         if (VSL_tagflags[tag] & SLT_F_UNSAFE) | 
| 289 | 646 |                 (void)vsl_print_unsafe(fo, len, data); | 
| 290 | 3902 |         else if (VSL_tagflags[tag] & SLT_F_BINARY) | 
| 291 | 184 |                 (void)vsl_print_binary(fo, len, data); | 
| 292 |  |         else | 
| 293 | 3718 |                 VSL_PRINT(fo, "%.*s\n", (int)len, data); | 
| 294 |  |  | 
| 295 | 4548 |         return (0); | 
| 296 | 4548 | } | 
| 297 |  |  | 
| 298 |  | int | 
| 299 | 3644 | VSL_Print(const struct VSL_data *vsl, const struct VSL_cursor *c, void *fo) | 
| 300 |  | { | 
| 301 |  |  | 
| 302 | 3644 |         return (vsl_print(vsl, c, fo, 0)); | 
| 303 |  | } | 
| 304 |  |  | 
| 305 |  | int | 
| 306 | 904 | VSL_PrintTerse(const struct VSL_data *vsl, const struct VSL_cursor *c, void *fo) | 
| 307 |  | { | 
| 308 |  |  | 
| 309 | 904 |         return (vsl_print(vsl, c, fo, 1)); | 
| 310 |  | } | 
| 311 |  |  | 
| 312 |  | int | 
| 313 | 0 | VSL_PrintAll(struct VSL_data *vsl, const struct VSL_cursor *c, void *fo) | 
| 314 |  | { | 
| 315 |  |         int i; | 
| 316 |  |  | 
| 317 | 0 |         if (c == NULL) | 
| 318 | 0 |                 return (0); | 
| 319 | 0 |         while (1) { | 
| 320 | 0 |                 i = VSL_Next(c); | 
| 321 | 0 |                 if (i <= 0) | 
| 322 | 0 |                         return (i); | 
| 323 | 0 |                 if (!VSL_Match(vsl, c)) | 
| 324 | 0 |                         continue; | 
| 325 | 0 |                 i = VSL_Print(vsl, c, fo); | 
| 326 | 0 |                 if (i != 0) | 
| 327 | 0 |                         return (i); | 
| 328 |  |         } | 
| 329 | 0 | } | 
| 330 |  |  | 
| 331 |  | int v_matchproto_(VSLQ_dispatch_f) | 
| 332 | 6636 | VSL_PrintTransactions(struct VSL_data *vsl, struct VSL_transaction * const pt[], | 
| 333 |  |     void *fo) | 
| 334 |  | { | 
| 335 |  |         struct VSL_transaction *t; | 
| 336 |  |         int i; | 
| 337 | 6636 |         int delim = 0; | 
| 338 |  |         int verbose; | 
| 339 |  |  | 
| 340 | 6636 |         CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); | 
| 341 | 6636 |         if (fo == NULL) | 
| 342 | 5456 |                 fo = stdout; | 
| 343 | 6636 |         if (pt[0] == NULL) | 
| 344 | 0 |                 return (0); | 
| 345 |  |  | 
| 346 | 13320 |         for (t = pt[0]; t != NULL; t = *++pt) { | 
| 347 | 6684 |                 if (vsl->c_opt || vsl->b_opt) { | 
| 348 | 2952 |                         switch (t->type) { | 
| 349 |  |                         case VSL_t_req: | 
| 350 | 160 |                                 if (!vsl->c_opt) | 
| 351 | 0 |                                         continue; | 
| 352 | 160 |                                 if (t->reason == VSL_r_esi && !vsl->E_opt) | 
| 353 | 32 |                                         continue; | 
| 354 | 128 |                                 break; | 
| 355 |  |                         case VSL_t_bereq: | 
| 356 | 32 |                                 if (!vsl->b_opt) | 
| 357 | 16 |                                         continue; | 
| 358 | 16 |                                 break; | 
| 359 |  |                         case VSL_t_raw: | 
| 360 | 2736 |                                 break; | 
| 361 |  |                         default: | 
| 362 | 24 |                                 continue; | 
| 363 |  |                         } | 
| 364 | 2880 |                 } | 
| 365 |  |  | 
| 366 | 6612 |                 verbose = 0; | 
| 367 | 6612 |                 if (t->level == 0 || vsl->v_opt) | 
| 368 | 6420 |                         verbose = 1; | 
| 369 |  |  | 
| 370 | 6612 |                 if (t->level) { | 
| 371 |  |                         /* Print header */ | 
| 372 | 200 |                         if (t->level > 3) | 
| 373 | 0 |                                 VSL_PRINT(fo, "*%1.1d* ", t->level); | 
| 374 |  |                         else | 
| 375 | 200 |                                 VSL_PRINT(fo, "%-3.*s ", | 
| 376 |  |                                     (int)(t->level), "***"); | 
| 377 | 200 |                         VSL_PRINT(fo, "%*.s%-14s %*.s%-10ju\n", | 
| 378 |  |                             verbose ? 10 + 1 : 0, " ", | 
| 379 |  |                             VSL_transactions[t->type], | 
| 380 |  |                             verbose ? 1 + 1 : 0, " ", | 
| 381 |  |                             (uintmax_t)t->vxid); | 
| 382 | 200 |                         delim = 1; | 
| 383 | 200 |                 } | 
| 384 |  |  | 
| 385 | 11160 |                 while (1) { | 
| 386 |  |                         /* Print records */ | 
| 387 | 18952 |                         i = VSL_Next(t->c); | 
| 388 | 18952 |                         if (i < 0) | 
| 389 | 0 |                                 return (i); | 
| 390 | 18952 |                         if (i == 0) | 
| 391 | 6612 |                                 break; | 
| 392 | 12340 |                         if (!VSL_Match(vsl, t->c)) | 
| 393 | 7792 |                                 continue; | 
| 394 | 4548 |                         if (t->level > 3) | 
| 395 | 0 |                                 VSL_PRINT(fo, "-%1.1d- ", t->level); | 
| 396 | 4548 |                         else if (t->level) | 
| 397 | 912 |                                 VSL_PRINT(fo, "%-3.*s ", | 
| 398 |  |                                     (int)(t->level), "---"); | 
| 399 | 4548 |                         if (verbose) | 
| 400 | 3644 |                                 i = VSL_Print(vsl, t->c, fo); | 
| 401 |  |                         else | 
| 402 | 904 |                                 i = VSL_PrintTerse(vsl, t->c, fo); | 
| 403 | 4548 |                         if (i != 0) | 
| 404 | 0 |                                 return (i); | 
| 405 |  |                 } | 
| 406 | 6612 |         } | 
| 407 |  |  | 
| 408 | 6636 |         if (delim) | 
| 409 | 200 |                 VSL_PRINT(fo, "\n");; | 
| 410 |  |  | 
| 411 | 6636 |         return (0); | 
| 412 | 6636 | } | 
| 413 |  |  | 
| 414 |  | FILE* | 
| 415 | 32 | VSL_WriteOpen(struct VSL_data *vsl, const char *name, int append, int unbuf) | 
| 416 |  | { | 
| 417 |  |         FILE* f; | 
| 418 |  |  | 
| 419 | 32 |         if (!strcmp(name, "-")) | 
| 420 | 8 |                 f = stdout; | 
| 421 |  |         else | 
| 422 | 24 |                 f = fopen(name, append ? "a" : "w"); | 
| 423 | 32 |         if (f == NULL) { | 
| 424 | 8 |                 vsl_diag(vsl, "%s", strerror(errno)); | 
| 425 | 8 |                 return (NULL); | 
| 426 |  |         } | 
| 427 | 24 |         if (unbuf) | 
| 428 | 0 |                 setbuf(f, NULL); | 
| 429 | 24 |         if (ftell(f) == 0 || f == stdout) { | 
| 430 | 24 |                 if (fwrite(VSL_FILE_ID, 1, sizeof VSL_FILE_ID, f) != | 
| 431 |  |                     sizeof VSL_FILE_ID) { | 
| 432 | 0 |                         vsl_diag(vsl, "%s", strerror(errno)); | 
| 433 | 0 |                         (void)fclose(f); | 
| 434 | 0 |                         return (NULL); | 
| 435 |  |                 } | 
| 436 | 24 |         } | 
| 437 | 24 |         return (f); | 
| 438 | 32 | } | 
| 439 |  |  | 
| 440 |  | int | 
| 441 | 856 | VSL_Write(const struct VSL_data *vsl, const struct VSL_cursor *c, void *fo) | 
| 442 |  | { | 
| 443 |  |         size_t r; | 
| 444 |  |  | 
| 445 | 856 |         CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); | 
| 446 | 856 |         if (c == NULL || c->rec.ptr == NULL) | 
| 447 | 0 |                 return (0); | 
| 448 | 856 |         if (fo == NULL) | 
| 449 | 0 |                 fo = stdout; | 
| 450 | 1712 |         r = fwrite(c->rec.ptr, sizeof *c->rec.ptr, | 
| 451 | 856 |             VSL_NEXT(c->rec.ptr) - c->rec.ptr, fo); | 
| 452 | 856 |         if (r == 0) | 
| 453 | 0 |                 return (-5); | 
| 454 | 856 |         return (0); | 
| 455 | 856 | } | 
| 456 |  |  | 
| 457 |  | int | 
| 458 | 72 | VSL_WriteAll(struct VSL_data *vsl, const struct VSL_cursor *c, void *fo) | 
| 459 |  | { | 
| 460 |  |         int i; | 
| 461 |  |  | 
| 462 | 72 |         if (c == NULL) | 
| 463 | 0 |                 return (0); | 
| 464 | 928 |         while (1) { | 
| 465 | 2192 |                 i = VSL_Next(c); | 
| 466 | 2192 |                 if (i <= 0) | 
| 467 | 72 |                         return (i); | 
| 468 | 2120 |                 if (!VSL_Match(vsl, c)) | 
| 469 | 1264 |                         continue; | 
| 470 | 856 |                 i = VSL_Write(vsl, c, fo); | 
| 471 | 856 |                 if (i != 0) | 
| 472 | 0 |                         return (i); | 
| 473 |  |         } | 
| 474 | 72 | } | 
| 475 |  |  | 
| 476 |  | int v_matchproto_(VSLQ_dispatch_f) | 
| 477 | 72 | VSL_WriteTransactions(struct VSL_data *vsl, struct VSL_transaction * const pt[], | 
| 478 |  |     void *fo) | 
| 479 |  | { | 
| 480 |  |         struct VSL_transaction *t; | 
| 481 |  |         int i; | 
| 482 |  |  | 
| 483 | 72 |         if (pt == NULL) | 
| 484 | 0 |                 return (0); | 
| 485 | 144 |         for (i = 0, t = pt[0]; i == 0 && t != NULL; t = *++pt) | 
| 486 | 72 |                 i = VSL_WriteAll(vsl, t->c, fo); | 
| 487 | 72 |         return (i); | 
| 488 | 72 | } |