1 /* $OpenBSD: ktrstruct.c,v 1.29 2020/12/21 07:47:37 otto Exp $ */ 2 3 /*- 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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 <sys/types.h> 33 #include <sys/resource.h> 34 #include <sys/socket.h> 35 #include <sys/select.h> 36 #include <sys/stat.h> 37 #include <sys/time.h> 38 #include <sys/event.h> 39 #include <sys/un.h> 40 #include <sys/fcntl.h> 41 #include <ufs/ufs/quota.h> 42 #include <netinet/in.h> 43 #include <arpa/inet.h> 44 45 #include <ctype.h> 46 #include <err.h> 47 #include <limits.h> 48 #include <netdb.h> 49 #include <poll.h> 50 #include <signal.h> 51 #include <stddef.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <stdint.h> 55 #include <string.h> 56 #include <grp.h> 57 #include <pwd.h> 58 #include <unistd.h> 59 #include <vis.h> 60 61 #include "kdump.h" 62 #include "kdump_subr.h" 63 64 #define TIME_FORMAT "%b %e %T %Y" 65 66 static void 67 ktrsockaddr(struct sockaddr *sa) 68 { 69 /* 70 * TODO: Support additional address families 71 * #include <netmpls/mpls.h> 72 * struct sockaddr_mpls *mpls; 73 */ 74 75 /* 76 * note: ktrstruct() has already verified that sa points to a 77 * buffer at least sizeof(struct sockaddr) bytes long and exactly 78 * sa->sa_len bytes long. 79 */ 80 printf("struct sockaddr { "); 81 sockfamilyname(sa->sa_family); 82 printf(", "); 83 84 #define check_sockaddr_len(n) \ 85 if (sa_##n->s##n##_len < sizeof(struct sockaddr_##n)) { \ 86 printf("invalid"); \ 87 break; \ 88 } 89 90 switch(sa->sa_family) { 91 case AF_INET: { 92 struct sockaddr_in *sa_in; 93 char addr[INET_ADDRSTRLEN]; 94 95 sa_in = (struct sockaddr_in *)sa; 96 check_sockaddr_len(in); 97 inet_ntop(AF_INET, &sa_in->sin_addr, addr, sizeof addr); 98 printf("%s:%u", addr, ntohs(sa_in->sin_port)); 99 break; 100 } 101 case AF_INET6: { 102 struct sockaddr_in6 *sa_in6; 103 char addr[INET6_ADDRSTRLEN], scope[12] = { 0 }; 104 105 sa_in6 = (struct sockaddr_in6 *)sa; 106 check_sockaddr_len(in6); 107 inet_ntop(AF_INET6, &sa_in6->sin6_addr, addr, sizeof addr); 108 if (sa_in6->sin6_scope_id) 109 snprintf(scope, sizeof(scope), "%%%u", 110 sa_in6->sin6_scope_id); 111 printf("[%s%s]:%u", addr, scope, htons(sa_in6->sin6_port)); 112 break; 113 } 114 case AF_UNIX: { 115 struct sockaddr_un *sa_un; 116 char path[4 * sizeof(sa_un->sun_path) + 1]; 117 size_t len; 118 119 sa_un = (struct sockaddr_un *)sa; 120 len = sa_un->sun_len; 121 if (len <= offsetof(struct sockaddr_un, sun_path)) { 122 printf("invalid"); 123 break; 124 } 125 len -= offsetof(struct sockaddr_un, sun_path); 126 if (len > sizeof(sa_un->sun_path)) { 127 printf("too long"); 128 break; 129 } 130 /* format, stopping at first NUL */ 131 len = strnlen(sa_un->sun_path, len); 132 strvisx(path, sa_un->sun_path, len, 133 VIS_CSTYLE | VIS_DQ | VIS_TAB | VIS_NL); 134 printf("\"%s\"", path); 135 break; 136 } 137 default: 138 printf("unknown address family"); 139 } 140 printf(" }\n"); 141 } 142 143 static void 144 print_time(time_t t, int relative, int have_subsec) 145 { 146 char timestr[PATH_MAX + 4]; 147 struct tm *tm; 148 149 if (t < 0 && have_subsec) { 150 /* negative times with non-zero subsecs require care */ 151 printf("-%jd", -(intmax_t)(t + 1)); 152 } else 153 printf("%jd", (intmax_t)t); 154 155 /* 1970s times are probably relative */ 156 if (!relative && t > (10 * 365 * 24 * 3600)) { 157 tm = localtime(&t); 158 if (tm != NULL) { 159 (void)strftime(timestr, sizeof(timestr), TIME_FORMAT, 160 tm); 161 printf("<\"%s\">", timestr); 162 } 163 } 164 } 165 166 static void 167 print_timespec(const struct timespec *tsp, int relative) 168 { 169 if (tsp->tv_nsec == UTIME_NOW) 170 printf("UTIME_NOW"); 171 else if (tsp->tv_nsec == UTIME_OMIT) 172 printf("UTIME_OMIT"); 173 else { 174 print_time(tsp->tv_sec, relative, tsp->tv_nsec); 175 if (tsp->tv_nsec != 0) 176 printf(".%09ld", tsp->tv_sec >= 0 ? tsp->tv_nsec : 177 1000000000 - tsp->tv_nsec); 178 } 179 } 180 181 void 182 uidname(int uid) 183 { 184 const char *name; 185 186 if (uid == -1) 187 printf("-1"); 188 else { 189 printf("%u<", (unsigned)uid); 190 if (uid > UID_MAX || (name = user_from_uid(uid, 1)) == NULL) 191 printf("unknown>"); 192 else 193 printf("\"%s\">", name); 194 } 195 } 196 197 void 198 gidname(int gid) 199 { 200 const char *name; 201 202 if (gid == -1) 203 printf("-1"); 204 else { 205 printf("%u<", (unsigned)gid); 206 if (gid > GID_MAX || (name = group_from_gid(gid, 1)) == NULL) 207 printf("unknown>"); 208 else 209 printf("\"%s\">", name); 210 } 211 } 212 213 static void 214 ktrstat(const struct stat *statp) 215 { 216 char mode[12]; 217 218 /* 219 * note: ktrstruct() has already verified that statp points to a 220 * buffer exactly sizeof(struct stat) bytes long. 221 */ 222 printf("struct stat { "); 223 strmode(statp->st_mode, mode); 224 printf("dev=%d, ino=%llu, mode=%s, nlink=%u, uid=", 225 statp->st_dev, (unsigned long long)statp->st_ino, 226 mode, statp->st_nlink); 227 uidname(statp->st_uid); 228 printf(", gid="); 229 gidname(statp->st_gid); 230 printf(", rdev=%d, ", statp->st_rdev); 231 printf("atime="); 232 print_timespec(&statp->st_atim, 0); 233 printf(", mtime="); 234 print_timespec(&statp->st_mtim, 0); 235 printf(", ctime="); 236 print_timespec(&statp->st_ctim, 0); 237 printf(", size=%lld, blocks=%lld, blksize=%d, flags=0x%x, gen=0x%x", 238 statp->st_size, statp->st_blocks, statp->st_blksize, 239 statp->st_flags, statp->st_gen); 240 printf(" }\n"); 241 } 242 243 static void 244 ktrtimespec(const struct timespec *tsp, int relative) 245 { 246 printf("struct timespec { "); 247 print_timespec(tsp, relative); 248 printf(" }\n"); 249 } 250 251 static void 252 print_timeval(const struct timeval *tvp, int relative) 253 { 254 print_time(tvp->tv_sec, relative, tvp->tv_usec); 255 if (tvp->tv_usec != 0) 256 printf(".%06ld", tvp->tv_sec >= 0 ? tvp->tv_usec : 257 1000000 - tvp->tv_usec); 258 } 259 260 static void 261 ktrtimeval(const struct timeval *tvp, int relative) 262 { 263 printf("struct timeval { "); 264 print_timeval(tvp, relative); 265 printf(" }\n"); 266 } 267 268 static void 269 ktrsigaction(const struct sigaction *sa) 270 { 271 /* 272 * note: ktrstruct() has already verified that sa points to a 273 * buffer exactly sizeof(struct sigaction) bytes long. 274 */ 275 /* 276 * Fuck! Comparison of function pointers on hppa assumes you can 277 * dereference them if they're plabels! Cast everything to void * 278 * to suppress that extra logic; sorry folks, the address we report 279 * here might not match what you see in your executable... 280 */ 281 printf("struct sigaction { "); 282 if ((void *)sa->sa_handler == (void *)SIG_DFL) 283 printf("handler=SIG_DFL"); 284 else if ((void *)sa->sa_handler == (void *)SIG_IGN) 285 printf("handler=SIG_IGN"); 286 else if (sa->sa_flags & SA_SIGINFO) 287 printf("sigaction=%p", (void *)sa->sa_sigaction); 288 else 289 printf("handler=%p", (void *)sa->sa_handler); 290 printf(", mask="); 291 sigset(sa->sa_mask); 292 printf(", flags="); 293 sigactionflagname(sa->sa_flags); 294 printf(" }\n"); 295 } 296 297 static void 298 print_rlim(rlim_t lim) 299 { 300 if (lim == RLIM_INFINITY) 301 printf("infinite"); 302 else 303 printf("%llu", (unsigned long long)lim); 304 } 305 306 static void 307 ktrrlimit(const struct rlimit *limp) 308 { 309 printf("struct rlimit { "); 310 printf("cur="); 311 print_rlim(limp->rlim_cur); 312 printf(", max="); 313 print_rlim(limp->rlim_max); 314 printf(" }\n"); 315 } 316 317 static void 318 ktrtfork(const struct __tfork *tf) 319 { 320 printf("struct __tfork { tcb=%p, tid=%p, stack=%p }\n", 321 tf->tf_tcb, (void *)tf->tf_tid, tf->tf_stack); 322 } 323 324 static void 325 ktrfds(const char *data, size_t count) 326 { 327 size_t i; 328 int fd; 329 330 printf("int"); 331 if (count > 1) 332 printf(" [%zu] { ", count); 333 for (i = 0; i < count; i++) { 334 memcpy(&fd, &data[i * sizeof(fd)], sizeof(fd)); 335 printf("%d%s", fd, i < count - 1 ? ", " : ""); 336 } 337 if (count > 1) 338 printf(" }"); 339 printf("\n"); 340 } 341 342 static void 343 ktrfdset(struct fd_set *fds, int len) 344 { 345 int nfds, i, start = -1; 346 char sep = ' '; 347 348 nfds = len * NBBY; 349 printf("struct fd_set {"); 350 for (i = 0; i <= nfds; i++) 351 if (i != nfds && FD_ISSET(i, fds)) { 352 if (start == -1) 353 start = i; 354 } else if (start != -1) { 355 putchar(sep); 356 if (start == i - 1) 357 printf("%d", start); 358 else if (start == i - 2) 359 printf("%d,%d", start, i - 1); 360 else 361 printf("%d-%d", start, i - 1); 362 sep = ','; 363 start = -1; 364 } 365 366 printf(" }\n"); 367 } 368 369 static void 370 ktrrusage(const struct rusage *rup) 371 { 372 printf("struct rusage { utime="); 373 print_timeval(&rup->ru_utime, 1); 374 printf(", stime="); 375 print_timeval(&rup->ru_stime, 1); 376 printf(", maxrss=%ld, ixrss=%ld, idrss=%ld, isrss=%ld," 377 " minflt=%ld, majflt=%ld, nswap=%ld, inblock=%ld," 378 " oublock=%ld, msgsnd=%ld, msgrcv=%ld, nsignals=%ld," 379 " nvcsw=%ld, nivcsw=%ld }\n", 380 rup->ru_maxrss, rup->ru_ixrss, rup->ru_idrss, rup->ru_isrss, 381 rup->ru_minflt, rup->ru_majflt, rup->ru_nswap, rup->ru_inblock, 382 rup->ru_oublock, rup->ru_msgsnd, rup->ru_msgrcv, rup->ru_nsignals, 383 rup->ru_nvcsw, rup->ru_nivcsw); 384 } 385 386 static void 387 ktrquota(const struct dqblk *quota) 388 { 389 printf("struct dqblk { bhardlimit=%u, bsoftlimit=%u, curblocks=%u," 390 " ihardlimit=%u, isoftlimit=%u, curinodes=%u, btime=", 391 quota->dqb_bhardlimit, quota->dqb_bsoftlimit, 392 quota->dqb_curblocks, quota->dqb_ihardlimit, 393 quota->dqb_isoftlimit, quota->dqb_curinodes); 394 print_time(quota->dqb_btime, 0, 0); 395 printf(", itime="); 396 print_time(quota->dqb_itime, 0, 0); 397 printf(" }\n"); 398 } 399 400 static void 401 ktrmsghdr(const struct msghdr *msg) 402 { 403 printf("struct msghdr { name=%p, namelen=%u, iov=%p, iovlen=%u," 404 " control=%p, controllen=%u, flags=", 405 msg->msg_name, msg->msg_namelen, msg->msg_iov, msg->msg_iovlen, 406 msg->msg_control, msg->msg_controllen); 407 sendrecvflagsname(msg->msg_flags); 408 printf(" }\n"); 409 } 410 411 static void 412 ktriovec(const char *data, int count) 413 { 414 struct iovec iov; 415 int i; 416 417 printf("struct iovec"); 418 if (count > 1) 419 printf(" [%d]", count); 420 for (i = 0; i < count; i++) { 421 memcpy(&iov, data, sizeof(iov)); 422 data += sizeof(iov); 423 printf(" { base=%p, len=%lu }", iov.iov_base, iov.iov_len); 424 } 425 printf("\n"); 426 } 427 428 static void 429 ktrevent(const char *data, int count) 430 { 431 struct kevent kev; 432 int i; 433 434 printf("struct kevent"); 435 if (count > 1) 436 printf(" [%d]", count); 437 for (i = 0; i < count; i++) { 438 memcpy(&kev, data, sizeof(kev)); 439 data += sizeof(kev); 440 printf(" { ident=%lu, filter=", kev.ident); 441 evfiltername(kev.filter); 442 printf(", flags="); 443 evflagsname(kev.flags); 444 printf(", fflags="); 445 evfflagsname(kev.filter, kev.fflags); 446 printf(", data=%llu", kev.data); 447 if ((kev.flags & EV_ERROR) && fancy) { 448 printf("<\"%s\">", strerror(kev.data)); 449 } 450 printf(", udata=%p }", kev.udata); 451 } 452 printf("\n"); 453 } 454 455 static void 456 ktrpollfd(const char *data, int count) 457 { 458 struct pollfd pfd; 459 int i; 460 461 printf("struct pollfd"); 462 if (count > 1) 463 printf(" [%d]", count); 464 for (i = 0; i < count; i++) { 465 memcpy(&pfd, data, sizeof(pfd)); 466 data += sizeof(pfd); 467 printf(" { fd=%d, events=", pfd.fd); 468 pollfdeventname(pfd.events); 469 printf(", revents="); 470 pollfdeventname(pfd.revents); 471 printf(" }"); 472 } 473 printf("\n"); 474 } 475 476 static void 477 ktrcmsghdr(char *data, socklen_t len) 478 { 479 struct msghdr msg; 480 struct cmsghdr *cmsg; 481 int i, count, *fds; 482 483 msg.msg_control = data; 484 msg.msg_controllen = len; 485 486 /* count the control messages */ 487 count = 0; 488 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 489 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 490 count++; 491 } 492 493 printf("struct cmsghdr"); 494 if (count > 1) 495 printf(" [%d]", count); 496 497 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 498 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 499 printf(" { len=%u, level=", cmsg->cmsg_len); 500 if (cmsg->cmsg_level == SOL_SOCKET) { 501 printf("SOL_SOCKET, type="); 502 switch (cmsg->cmsg_type) { 503 case SCM_RIGHTS: 504 printf("SCM_RIGHTS, data="); 505 fds = (int *)CMSG_DATA(cmsg); 506 for (i = 0; 507 cmsg->cmsg_len > CMSG_LEN(sizeof(int) * i) 508 && (char *)fds + (i + 1) * sizeof(int) <= 509 data + len; 510 i++) { 511 printf("%s%d", i ? "," : "", fds[i]); 512 } 513 break; 514 case SCM_TIMESTAMP: 515 default: 516 printf("%d", cmsg->cmsg_type); 517 break; 518 } 519 } else { 520 struct protoent *p = getprotobynumber(cmsg->cmsg_level); 521 522 printf("%u<%s>, type=%d", cmsg->cmsg_level, 523 p != NULL ? p->p_name : "unknown", cmsg->cmsg_type); 524 } 525 printf(" }"); 526 } 527 printf("\n"); 528 } 529 530 static void 531 ktrflock(const struct flock *fl) 532 { 533 printf("struct flock { start=%lld, len=%lld, pid=%d, type=", 534 fl->l_start, fl->l_len, fl->l_pid); 535 flocktypename(fl->l_type); 536 printf(", whence="); 537 whencename(fl->l_whence); 538 printf(" }\n"); 539 } 540 541 void 542 ktrstruct(char *buf, size_t buflen) 543 { 544 char *name, *data; 545 size_t namelen, datalen; 546 int i; 547 548 for (name = buf, namelen = 0; namelen < buflen && name[namelen] != '\0'; 549 ++namelen) 550 /* nothing */; 551 if (namelen == buflen) 552 goto invalid; 553 if (name[namelen] != '\0') 554 goto invalid; 555 data = buf + namelen + 1; 556 datalen = buflen - namelen - 1; 557 558 /* sanity check */ 559 for (i = 0; i < namelen; ++i) 560 if (!isalpha((unsigned char)name[i])) 561 goto invalid; 562 if (strcmp(name, "stat") == 0) { 563 struct stat sb; 564 565 if (datalen != sizeof(struct stat)) 566 goto invalid; 567 memcpy(&sb, data, datalen); 568 ktrstat(&sb); 569 } else if (strcmp(name, "sockaddr") == 0) { 570 struct sockaddr_storage ss; 571 572 if (datalen > sizeof(ss)) 573 goto invalid; 574 if (datalen < offsetof(struct sockaddr_storage, ss_len) + 575 sizeof(ss.ss_len)) 576 goto invalid; 577 memcpy(&ss, data, datalen); 578 if ((ss.ss_family != AF_UNIX && 579 datalen < sizeof(struct sockaddr)) || datalen != ss.ss_len) 580 goto invalid; 581 ktrsockaddr((struct sockaddr *)&ss); 582 } else if (strcmp(name, "abstimespec") == 0 || 583 strcmp(name, "reltimespec") == 0) { 584 struct timespec ts; 585 586 if (datalen != sizeof(ts)) 587 goto invalid; 588 memcpy(&ts, data, datalen); 589 ktrtimespec(&ts, name[0] == 'r'); 590 } else if (strcmp(name, "abstimeval") == 0 || 591 strcmp(name, "reltimeval") == 0) { 592 struct timeval tv; 593 594 if (datalen != sizeof(tv)) 595 goto invalid; 596 memcpy(&tv, data, datalen); 597 ktrtimeval(&tv, name[0] == 'r'); 598 } else if (strcmp(name, "sigaction") == 0) { 599 struct sigaction sa; 600 601 if (datalen != sizeof(sa)) 602 goto invalid; 603 memcpy(&sa, data, datalen); 604 ktrsigaction(&sa); 605 } else if (strcmp(name, "rlimit") == 0) { 606 struct rlimit lim; 607 608 if (datalen != sizeof(lim)) 609 goto invalid; 610 memcpy(&lim, data, datalen); 611 ktrrlimit(&lim); 612 } else if (strcmp(name, "rusage") == 0) { 613 struct rusage ru; 614 615 if (datalen != sizeof(ru)) 616 goto invalid; 617 memcpy(&ru, data, datalen); 618 ktrrusage(&ru); 619 } else if (strcmp(name, "tfork") == 0) { 620 struct __tfork tf; 621 622 if (datalen != sizeof(tf)) 623 goto invalid; 624 memcpy(&tf, data, datalen); 625 ktrtfork(&tf); 626 } else if (strcmp(name, "fds") == 0) { 627 if (datalen % sizeof(int)) 628 goto invalid; 629 ktrfds(data, datalen / sizeof(int)); 630 } else if (strcmp(name, "fdset") == 0) { 631 struct fd_set *fds; 632 633 if ((fds = malloc(datalen)) == NULL) 634 err(1, "malloc"); 635 memcpy(fds, data, datalen); 636 ktrfdset(fds, datalen); 637 free(fds); 638 } else if (strcmp(name, "quota") == 0) { 639 struct dqblk quota; 640 641 if (datalen != sizeof(quota)) 642 goto invalid; 643 memcpy("a, data, datalen); 644 ktrquota("a); 645 } else if (strcmp(name, "msghdr") == 0) { 646 struct msghdr msg; 647 648 if (datalen != sizeof(msg)) 649 goto invalid; 650 memcpy(&msg, data, datalen); 651 ktrmsghdr(&msg); 652 } else if (strcmp(name, "iovec") == 0) { 653 if (datalen % sizeof(struct iovec)) 654 goto invalid; 655 ktriovec(data, datalen / sizeof(struct iovec)); 656 } else if (strcmp(name, "kevent") == 0) { 657 if (datalen % sizeof(struct kevent)) 658 goto invalid; 659 ktrevent(data, datalen / sizeof(struct kevent)); 660 } else if (strcmp(name, "pollfd") == 0) { 661 if (datalen % sizeof(struct pollfd)) 662 goto invalid; 663 ktrpollfd(data, datalen / sizeof(struct pollfd)); 664 } else if (strcmp(name, "cmsghdr") == 0) { 665 char *cmsg; 666 667 if (datalen == 0) 668 goto invalid; 669 670 if ((cmsg = malloc(datalen)) == NULL) 671 err(1, "malloc"); 672 memcpy(cmsg, data, datalen); 673 ktrcmsghdr(cmsg, datalen); 674 free(cmsg); 675 } else if (strcmp(name, "pledgereq") == 0) { 676 printf("promise="); 677 showbufc(basecol + sizeof("promise=") - 1, 678 (unsigned char *)data, datalen, VIS_DQ | VIS_TAB | VIS_NL); 679 } else if (strcmp(name, "pledgeexecreq") == 0) { 680 printf("execpromise="); 681 showbufc(basecol + sizeof("execpromise=") - 1, 682 (unsigned char *)data, datalen, VIS_DQ | VIS_TAB | VIS_NL); 683 } else if (strcmp(name, "unveil") == 0) { 684 printf("flags="); 685 showbufc(basecol + sizeof("flags=") - 1, 686 (unsigned char *)data, datalen, VIS_DQ | VIS_TAB | VIS_NL); 687 } else if (strcmp(name, "flock") == 0) { 688 struct flock fl; 689 690 if (datalen != sizeof(fl)) 691 goto invalid; 692 memcpy(&fl, data, datalen); 693 ktrflock(&fl); 694 } else { 695 printf("unknown structure %s\n", name); 696 } 697 return; 698 invalid: 699 printf("invalid record\n"); 700 } 701