1/* 2 * dproc.c -- Darwin process access functions for libproc-based lsof 3 */ 4 5 6/* 7 * Portions Copyright 2005-2007 Apple Inc. All rights reserved. 8 * 9 * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana 10 * 47907. All rights reserved. 11 * 12 * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue 13 * University. 14 * 15 * This software is not subject to any license of the American Telephone 16 * and Telegraph Company or the Regents of the University of California. 17 * 18 * Permission is granted to anyone to use this software for any purpose on 19 * any computer system, and to alter it and redistribute it freely, subject 20 * to the following restrictions: 21 * 22 * 1. Neither the authors, nor Apple Inc. nor Purdue University are 23 * responsible for any consequences of the use of this software. 24 * 25 * 2. The origin of this software must not be misrepresented, either 26 * by explicit claim or by omission. Credit to the authors, Apple 27 * Inc. and Purdue University must appear in documentation and sources. 28 * and sources. 29 * 30 * 3. Altered versions must be plainly marked as such, and must not be 31 * misrepresented as being the original software. 32 * 33 * 4. This notice may not be removed or altered. 34 */ 35 36 37#ifndef lint 38static char copyright[] = 39"@(#) Copyright 2005-2007 Apple Inc. and Purdue Research Foundation.\nAll rights reserved.\n"; 40static char *rcsid = "$Id: dproc.c,v 1.8 2012/04/10 16:41:04 abe Exp abe $"; 41#endif 42 43#include "lsof.h" 44 45 46/* 47 * Local definitions 48 */ 49 50#define PIDS_INCR (sizeof(int) * 32) /* PID space increment */ 51#define VIPS_INCR 16 /* Vips space increment */ 52 53#if DARWINV>=900 54#define THREADS_INCR (sizeof(uint64_t) * 32) /* Threads space increment */ 55#endif /* DARWINV>=900 */ 56 57#ifdef PROC_PIDLISTFILEPORTS 58#define FILEPORTS_INCR (sizeof(struct proc_fileportinfo) * 32) /* Fileports space increment */ 59#endif /* PROC_PIDLISTFILEPORTS */ 60 61/* 62 * Local static variables 63 */ 64 65static struct proc_fdinfo *Fds = (struct proc_fdinfo *)NULL; 66 /* FD buffer */ 67static int NbPids = 0; /* bytes allocated to Pids */ 68static int NbFds = 0; /* bytes allocated to FDs */ 69static int *Pids = (int *)NULL; /* PID buffer */ 70 71#if DARWINV>=900 72static int NbThreads = 0; /* Threads bytes allocated */ 73static uint64_t *Threads = (uint64_t *)NULL; /* Thread buffer */ 74#endif /* DARWINV>=900 */ 75 76#ifdef PROC_PIDLISTFILEPORTS 77static struct proc_fileportinfo *Fps = (struct proc_fileportinfo *)NULL; 78 /* fileport buffer */ 79static int NbFps = 0; /* bytes allocated to fileports */ 80#endif /* PROC_PIDLISTFILEPORTS */ 81 82/* 83 * Local structure definitions 84 */ 85 86static struct vips_info { 87 dev_t dev; 88 ino_t ino; 89} *Vips = (struct vips_info *)NULL; /* recorded vnodes */ 90static int NbVips = 0; /* bytes allocated to Vips */ 91static int NVips = 0; /* entries allocated to Vips */ 92 93 94/* 95 * Local function prototypes 96 */ 97_PROTOTYPE(static void enter_vn_text,(struct vnode_info_path *vip, int *n)); 98_PROTOTYPE(static void process_fds,(int pid, uint32_t n, int ckscko)); 99_PROTOTYPE(static void process_text,(int pid)); 100 101#if DARWINV>=900 102_PROTOTYPE(static void process_threads,(int pid, uint32_t n)); 103#endif /* DARWINV>=900 */ 104 105#ifdef PROC_PIDLISTFILEPORTS 106_PROTOTYPE(static void process_fileports,(int pid, int ckscko)); 107#endif /* PROC_PIDLISTFILEPORTS */ 108 109/* 110 * enter_vn_text() -- enter vnode information text reference 111 */ 112 113static void 114enter_vn_text(vip, n) 115 struct vnode_info_path *vip; /* vnode info */ 116 int *n; /* number of vips[] entries in use */ 117{ 118 int i; 119/* 120 * Ignore the request if the vnode information has already been entered. 121 */ 122 for (i = 0; i < *n; i++) { 123 if ((vip->vip_vi.vi_stat.vst_dev == Vips[i].dev) 124 && (vip->vip_vi.vi_stat.vst_ino == Vips[i].ino)) 125 { 126 return; 127 } 128 } 129/* 130 * Save the text file information. 131 */ 132 alloc_lfile(" txt", -1); 133 Cfp = (struct file *)NULL; 134 (void) enter_vnode_info(vip); 135 if (Lf->sf) 136 link_lfile(); 137/* 138 * Record the entry of the vnode information. 139 */ 140 if (i >= NVips) { 141 142 /* 143 * Allocate space for recording the vnode information. 144 */ 145 NVips += VIPS_INCR; 146 NbVips += (int)(VIPS_INCR * sizeof(struct vips_info)); 147 if (!Vips) 148 Vips = (struct vips_info *)malloc((MALLOC_S)NbVips); 149 else 150 Vips = (struct vips_info *)realloc((MALLOC_P *)Vips, 151 (MALLOC_S)NbVips); 152 if (!Vips) { 153 (void) fprintf(stderr, "%s: PID %d: no text recording space\n", 154 Pn, Lp->pid); 155 Exit(1); 156 } 157 } 158/* 159 * Record the vnode information. 160 */ 161 Vips[*n].dev = vip->vip_vi.vi_stat.vst_dev; 162 Vips[*n].ino = vip->vip_vi.vi_stat.vst_ino; 163 (*n)++; 164} 165 166 167/* 168 * gather_proc_info() -- gather process information 169 */ 170 171void 172gather_proc_info() 173{ 174 short cckreg; /* conditional status of regular file 175 * checking: 176 * 0 = unconditionally check 177 * 1 = conditionally check */ 178 short ckscko; /* socket file only checking status: 179 * 0 = none 180 * 1 = check only socket files, 181 * including TCP and UDP 182 * streams with eXPORT data, 183 * where supported */ 184 int cre, cres, ef, i, nb, np, pid; 185 short pss, sf; 186 struct proc_taskallinfo tai; 187 struct proc_vnodepathinfo vpi; 188/* 189 * Define socket and regular file conditional processing flags. 190 * 191 * If only socket files have been selected, or socket files have been 192 * selected, ANDed with other selection options, enable the skipping of 193 * regular files. 194 * 195 * If socket files and some process options have been selected, enable 196 * conditional skipping of regular file; i.e., regular files will be skipped 197 * unless they belong to a process selected by one of the specified options. 198 */ 199 if (Selflags & SELNW) { 200 201 /* 202 * Some network files selection options have been specified. 203 */ 204 if (Fand || !(Selflags & ~SELNW)) { 205 206 /* 207 * Selection ANDing or only network file options have been 208 * specified, so set unconditional skipping of regular files 209 * and socket file only checking. 210 */ 211 cckreg = 0; 212 ckscko = 1; 213 } else { 214 215 /* 216 * If ORed file selection options have been specified, or no 217 * ORed process selection options have been specified, enable 218 * unconditional file checking and clear socket file only 219 * checking. 220 * 221 * If only ORed process selection options have been specified, 222 * enable conditional file skipping and socket file only checking. 223 */ 224 if ((Selflags & SELFILE) || !(Selflags & SELPROC)) 225 cckreg = ckscko = 0; 226 else 227 cckreg = ckscko = 1; 228 } 229 } else { 230 231 /* 232 * No network file selection options were specified. Enable 233 * unconditional file checking and clear socket file only checking. 234 */ 235 cckreg = ckscko = 0; 236 } 237/* 238 * Determine how many bytes are needed to contain the PIDs on the system; 239 * make sure sufficient buffer space is allocated to hold them (and a few 240 * extra); then read the list of PIDs. 241 */ 242 if ((nb = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0)) <= 0) { 243 (void) fprintf(stderr, "%s: can't get PID byte count: %s\n", 244 Pn, strerror(errno)); 245 Exit(1); 246 } 247 if (nb > NbPids) { 248 while (nb > NbPids) { 249 NbPids += PIDS_INCR; 250 } 251 if (!Pids) 252 Pids = (int *)malloc((MALLOC_S)NbPids); 253 else 254 Pids = (int *)realloc((MALLOC_P *)Pids, (MALLOC_S)NbPids); 255 if (!Pids) { 256 (void) fprintf(stderr, 257 "%s: can't allocate space for %d PIDs\n", Pn, 258 (int)(NbPids / sizeof(int *))); 259 Exit(1); 260 } 261 } 262/* 263 * Get the list of PIDs. 264 */ 265 for (ef = 0; !ef;) { 266 if ((nb = proc_listpids(PROC_ALL_PIDS, 0, Pids, NbPids)) <= 0) { 267 (void) fprintf(stderr, "%s: can't get list of PIDs: %s\n", 268 Pn, strerror(errno)); 269 Exit(1); 270 } 271 272 if ((nb + sizeof(int)) < NbPids) { 273 274 /* 275 * There is room in the buffer for at least one more PID. 276 */ 277 np = nb / sizeof(int); 278 ef = 1; 279 } else { 280 281 /* 282 * The PID buffer must be enlarged. 283 */ 284 NbPids += PIDS_INCR; 285 Pids = (int *)realloc((MALLOC_P *)Pids, (MALLOC_S)NbPids); 286 if (!Pids) { 287 (void) fprintf(stderr, 288 "%s: can't allocate space for %d PIDs\n", Pn, 289 (int)(NbPids / sizeof(int *))); 290 Exit(1); 291 } 292 } 293 } 294/* 295 * Loop through the identified processes. 296 */ 297 for (i = 0; i < np; i++) { 298 if (!(pid = Pids[i])) 299 continue; 300 nb = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &tai, sizeof(tai)); 301 if (nb <= 0) { 302 if ((errno == EPERM) || (errno == ESRCH)) 303 continue; 304 if (!Fwarn) { 305 (void) fprintf(stderr, "%s: PID %d information error: %s\n", 306 Pn, pid, strerror(errno)); 307 } 308 continue; 309 } else if (nb < sizeof(tai)) { 310 (void) fprintf(stderr, 311 "%s: PID %d: proc_pidinfo(PROC_PIDTASKALLINFO);\n", 312 Pn, pid); 313 (void) fprintf(stderr, 314 " too few bytes; expected %ld, got %d\n", 315 sizeof(tai), nb); 316 Exit(1); 317 } 318 /* 319 * Check for process or command exclusion. 320 */ 321 if (is_proc_excl((int)pid, (int)tai.pbsd.pbi_pgid, 322 (UID_ARG)tai.pbsd.pbi_uid, &pss, &sf)) 323 { 324 continue; 325 } 326 tai.pbsd.pbi_comm[sizeof(tai.pbsd.pbi_comm) - 1] = '\0'; 327 if (is_cmd_excl(tai.pbsd.pbi_comm, &pss, &sf)) 328 continue; 329 if (tai.pbsd.pbi_name[0]) { 330 tai.pbsd.pbi_name[sizeof(tai.pbsd.pbi_name) - 1] = '\0'; 331 if (is_cmd_excl(tai.pbsd.pbi_name, &pss, &sf)) 332 continue; 333 } 334 if (cckreg) { 335 336 /* 337 * If conditional checking of regular files is enabled, enable 338 * socket file only checking, based on the process' selection 339 * status. 340 */ 341 ckscko = (sf & SELPROC) ? 0 : 1; 342 } 343 /* 344 * Get root and current directory information. 345 */ 346 if (!ckscko) { 347 nb = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, 348 sizeof(vpi)); 349 if (nb <= 0) { 350 cre = errno; 351 cres = 1; 352 } else if (nb < sizeof(vpi)) { 353 (void) fprintf(stderr, 354 "%s: PID %d: proc_pidinfo(PROC_PIDVNODEPATHINFO);\n", 355 Pn, pid); 356 (void) fprintf(stderr, 357 " too few bytes; expected %ld, got %d\n", 358 sizeof(vpi), nb); 359 Exit(1); 360 } else 361 cres = 0; 362 } 363 /* 364 * Allocate local process space. 365 */ 366 alloc_lproc((int)pid, (int)tai.pbsd.pbi_pgid, 367 (int)tai.pbsd.pbi_ppid, (UID_ARG)tai.pbsd.pbi_uid, 368 (tai.pbsd.pbi_name[0] != '\0') ? tai.pbsd.pbi_name 369 : tai.pbsd.pbi_comm, 370 (int)pss, (int)sf); 371 Plf = (struct lfile *)NULL; 372 /* 373 * Save current working directory information. 374 */ 375 if (!ckscko) { 376 if (cres || vpi.pvi_cdir.vip_path[0]) { 377 alloc_lfile(CWD, -1); 378 Cfp = (struct file *)NULL; 379 if (cres) { 380 381 /* 382 * If the CWD|RTD information access error is ESRCH, 383 * ignore it; otherwise report the error's message in the 384 * CWD's NAME column. 385 */ 386 if (cre != ESRCH) { 387 (void) snpf(Namech, Namechl, "%s|%s info error: %s", 388 CWD + 1, RTD + 1, strerror(cre)); 389 Namech[Namechl - 1] = '\0'; 390 enter_nm(Namech); 391 if (Lf->sf) 392 link_lfile(); 393 } 394 } else { 395 (void) enter_vnode_info(&vpi.pvi_cdir); 396 if (Lf->sf) 397 link_lfile(); 398 } 399 } 400 } 401 /* 402 * Save root directory information. 403 */ 404 if (!ckscko) { 405 if (!cres && vpi.pvi_rdir.vip_path[0]) { 406 alloc_lfile(RTD, -1); 407 Cfp = (struct file *)NULL; 408 (void) enter_vnode_info(&vpi.pvi_rdir); 409 if (Lf->sf) 410 link_lfile(); 411 } 412 } 413 414#if DARWINV>=900 415 /* 416 * Check for per-thread current working directories 417 */ 418 if (!ckscko) { 419 if (tai.pbsd.pbi_flags & PROC_FLAG_THCWD) { 420 (void) process_threads(pid, tai.ptinfo.pti_threadnum); 421 } 422 } 423#endif /* DARWINV>=900 */ 424 425 /* 426 * Print text file information. 427 */ 428 if (!ckscko) 429 (void) process_text(pid); 430 431#ifdef PROC_PIDLISTFILEPORTS 432 /* 433 * Loop through the fileports 434 */ 435 (void) process_fileports(pid, ckscko); 436#endif /* PROC_PIDLISTFILEPORTS */ 437 438 /* 439 * Loop through the file descriptors. 440 */ 441 (void) process_fds(pid, tai.pbsd.pbi_nfiles, ckscko); 442 /* 443 * Examine results. 444 */ 445 if (examine_lproc()) 446 return; 447 } 448} 449 450 451/* 452 * initialize() -- perform all initialization 453 */ 454 455void 456initialize() 457{ 458} 459 460 461/* 462 * process_fds() -- process file descriptors 463 */ 464 465static void 466process_fds(pid, n, ckscko) 467 int pid; /* PID of interest */ 468 uint32_t n; /* max FDs */ 469 int ckscko; /* check socket files only */ 470{ 471 int i, isock, nb, nf; 472 struct proc_fdinfo *fdp; 473/* 474 * Make sure an FD buffer has been allocated. 475 */ 476 if (!Fds) { 477 NbFds = sizeof(struct proc_fdinfo) * n; 478 Fds = (struct proc_fdinfo *)malloc((MALLOC_S)NbFds); 479 } else if (NbFds < sizeof(struct proc_fdinfo) * n) { 480 481 /* 482 * More proc_fdinfo space is required. Allocate it. 483 */ 484 NbFds = sizeof(struct proc_fdinfo) * n; 485 Fds = (struct proc_fdinfo *)realloc((MALLOC_P *)Fds, 486 (MALLOC_S)NbFds); 487 } 488 if (!Fds) { 489 (void) fprintf(stderr, 490 "%s: PID %d: can't allocate space for %d FDs\n", 491 Pn, pid, (int)(NbFds / sizeof(struct proc_fdinfo))); 492 Exit(1); 493 } 494/* 495 * Get FD information for the process. 496 */ 497 nb = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, Fds, NbFds); 498 if (nb <= 0) { 499 if (errno == ESRCH) { 500 501 /* 502 * Quit if no FD information is available for the process. 503 */ 504 return; 505 } 506 /* 507 * Make a dummy file entry with an error message in its NAME column. 508 */ 509 alloc_lfile(" err", -1); 510 (void) snpf(Namech, Namechl, "FD info error: %s", strerror(errno)); 511 Namech[Namechl - 1] = '\0'; 512 enter_nm(Namech); 513 if (Lf->sf) 514 link_lfile(); 515 return; 516 } 517 nf = (int)(nb / sizeof(struct proc_fdinfo)); 518/* 519 * Loop through the file descriptors. 520 */ 521 for (i = 0; i < nf; i++) { 522 fdp = &Fds[i]; 523 alloc_lfile(NULL, (int)fdp->proc_fd); 524 /* 525 * Process the file by its type. 526 */ 527 isock = 0; 528 switch (fdp->proc_fdtype) { 529 case PROX_FDTYPE_ATALK: 530 if (!ckscko) 531 (void) process_atalk(pid, fdp->proc_fd); 532 break; 533 case PROX_FDTYPE_FSEVENTS: 534 if (!ckscko) 535 (void) process_fsevents(pid, fdp->proc_fd); 536 break; 537 case PROX_FDTYPE_KQUEUE: 538 if (!ckscko) 539 (void) process_kqueue(pid, fdp->proc_fd); 540 break; 541 case PROX_FDTYPE_PIPE: 542 if (!ckscko) 543 (void) process_pipe(pid, fdp->proc_fd); 544 break; 545 case PROX_FDTYPE_PSEM: 546 if (!ckscko) 547 (void) process_psem(pid, fdp->proc_fd); 548 break; 549 case PROX_FDTYPE_SOCKET: 550 (void) process_socket(pid, fdp->proc_fd); 551 isock = 1; 552 break; 553 case PROX_FDTYPE_PSHM: 554 (void) process_pshm(pid, fdp->proc_fd); 555 break; 556 case PROX_FDTYPE_VNODE: 557 (void) process_vnode(pid, fdp->proc_fd); 558 break; 559 default: 560 (void) snpf(Namech, Namechl - 1, "unknown file type: %d", 561 fdp->proc_fdtype); 562 Namech[Namechl - 1] = '\0'; 563 (void) enter_nm(Namech); 564 break; 565 } 566 if (Lf->sf) { 567 if (!ckscko || isock) 568 link_lfile(); 569 } 570 } 571} 572 573 574#ifdef PROC_PIDLISTFILEPORTS 575/* 576 * process_fileports() -- process fileports 577 */ 578 579static void 580process_fileports(pid, ckscko) 581 int pid; /* PID of interest */ 582 int ckscko; /* check socket files only */ 583{ 584 int ef, i, isock, nb = 0, nf; 585 struct proc_fileportinfo *fpi; 586 587/* 588 * Get fileport information for the process. 589 */ 590 for (ef = 0; !ef;) { 591 nb = proc_pidinfo(pid, PROC_PIDLISTFILEPORTS, 0, Fps, NbFps); 592 if (nb == 0) { 593 594 /* 595 * Quit if no fileport information 596 */ 597 return; 598 } else if (nb < 0) { 599 if (errno == ESRCH) { 600 601 /* 602 * Quit if no fileport information is available for the process. 603 */ 604 return; 605 } 606 /* 607 * Make a dummy file entry with an error message in its NAME column. 608 */ 609 alloc_lfile(" err", -1); 610 (void) snpf(Namech, Namechl, "FILEPORT info error: %s", strerror(errno)); 611 Namech[Namechl - 1] = '\0'; 612 enter_nm(Namech); 613 if (Lf->sf) 614 link_lfile(); 615 } 616 617 if ((nb + sizeof(struct proc_fileportinfo)) < NbFps) { 618 619 /* 620 * There is room in the buffer for at least one more fileport. 621 */ 622 ef = 1; 623 } else { 624 if (Fps && ((nb = proc_pidinfo(pid, PROC_PIDLISTFILEPORTS, 0, NULL, 0)) <= 0)) { 625 (void) fprintf(stderr, "%s: can't get fileport byte count: %s\n", 626 Pn, strerror(errno)); 627 Exit(1); 628 } 629 630 /* 631 * The fileport buffer must be enlarged. 632 */ 633 while (nb > NbFps) { 634 NbFps += FILEPORTS_INCR; 635 } 636 if (!Fps) 637 Fps = (struct proc_fileportinfo *)malloc((MALLOC_S)NbFps); 638 else 639 Fps = (struct proc_fileportinfo *)realloc((MALLOC_P *)Fps, (MALLOC_S)NbFps); 640 } 641 } 642 643/* 644 * Loop through the fileports. 645 */ 646 nf = (int)(nb / sizeof(struct proc_fileportinfo)); 647 for (i = 0; i < nf; i++) { 648 fpi = &Fps[i]; 649 /* 650 * fileport reported as "fp." with "(fileport=0xXXXX)" in the Name column 651 */ 652 alloc_lfile(" fp.", -1); 653 Lf->fileport = fpi->proc_fileport; 654 /* 655 * Process the file by its type. 656 */ 657 isock = 0; 658 switch (fpi->proc_fdtype) { 659 case PROX_FDTYPE_PIPE: 660 if (!ckscko) 661 (void) process_fileport_pipe(pid, fpi->proc_fileport); 662 break; 663 case PROX_FDTYPE_SOCKET: 664 (void) process_fileport_socket(pid, fpi->proc_fileport); 665 isock = 1; 666 break; 667 case PROX_FDTYPE_PSHM: 668 (void) process_fileport_pshm(pid, fpi->proc_fileport); 669 break; 670 case PROX_FDTYPE_VNODE: 671 (void) process_fileport_vnode(pid, fpi->proc_fileport); 672 break; 673 default: 674 (void) snpf(Namech, Namechl - 1, "unknown file type: %d", 675 fpi->proc_fileport); 676 Namech[Namechl - 1] = '\0'; 677 (void) enter_nm(Namech); 678 break; 679 } 680 if (Lf->sf) { 681 if (!ckscko || isock) 682 link_lfile(); 683 } 684 } 685} 686#endif /* PROC_PIDLISTFILEPORTS */ 687 688 689/* 690 * process_text() -- process text information 691 */ 692 693static void 694process_text(pid) 695 int pid; /* PID */ 696{ 697 uint64_t a; 698 int i, n, nb; 699 struct proc_regionwithpathinfo rwpi; 700 701 for (a = (uint64_t)0, i = n = 0; i < 10000; i++) { 702 nb = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO, a, &rwpi, 703 sizeof(rwpi)); 704 if (nb <= 0) { 705 if ((errno == ESRCH) || (errno == EINVAL)) { 706 707 /* 708 * Quit if no more text information is available for the 709 * process. 710 */ 711 return; 712 } 713 /* 714 * Warn about all other errors via a NAME column message. 715 */ 716 alloc_lfile(" txt", -1); 717 Cfp = (struct file *)NULL; 718 (void) snpf(Namech, Namechl, 719 "region info error: %s", strerror(errno)); 720 Namech[Namechl - 1] = '\0'; 721 enter_nm(Namech); 722 if (Lf->sf) 723 link_lfile(); 724 return; 725 } else if (nb < sizeof(rwpi)) { 726 (void) fprintf(stderr, 727 "%s: PID %d: proc_pidinfo(PROC_PIDREGIONPATHINFO);\n", 728 Pn, pid); 729 (void) fprintf(stderr, 730 " too few bytes; expected %ld, got %d\n", 731 sizeof(rwpi), nb); 732 Exit(1); 733 } 734 if (rwpi.prp_vip.vip_path[0]) 735 enter_vn_text(&rwpi.prp_vip, &n); 736 a = rwpi.prp_prinfo.pri_address + rwpi.prp_prinfo.pri_size; 737 } 738} 739 740 741#if DARWINV>=900 742/* 743 * process_threads() -- process thread information 744 */ 745 746#define TWD " twd" /* per-thread current working directory 747 * fd name */ 748 749static void 750process_threads(pid, n) 751 int pid; /* PID */ 752 uint32_t n; /* number of threads */ 753{ 754 int i, nb, nt; 755/* 756 * Make sure a thread buffer has been allocated. 757 */ 758 n += 10; 759 if (n > NbThreads) { 760 while (n > NbThreads) { 761 NbThreads += THREADS_INCR; 762 } 763 if (!Threads) 764 Threads = (uint64_t *)malloc((MALLOC_S)NbThreads); 765 else 766 Threads = (uint64_t *)realloc((MALLOC_P *)Threads, 767 (MALLOC_S)NbThreads); 768 if (!Threads) { 769 (void) fprintf(stderr, 770 "%s: can't allocate space for %d Threads\n", Pn, 771 (int)(NbThreads / sizeof(int *))); 772 Exit(1); 773 } 774 } 775/* 776 * Get thread information for the process. 777 */ 778 nb = proc_pidinfo(pid, PROC_PIDLISTTHREADS, 0, Threads, NbThreads); 779 if (nb <= 0) { 780 if (errno == ESRCH) { 781 782 /* 783 * Quit if no thread information is available for the 784 * process. 785 */ 786 return; 787 } 788 } 789 nt = (int)(nb / sizeof(uint64_t)); 790/* 791 * Loop through the threads. 792 */ 793 for (i = 0; i < nt; i++) { 794 uint64_t t; 795 struct proc_threadwithpathinfo tpi; 796 797 t = Threads[i]; 798 nb = proc_pidinfo(pid, PROC_PIDTHREADPATHINFO, t, &tpi, 799 sizeof(tpi)); 800 if (nb <= 0) { 801 if ((errno == ESRCH) || (errno == EINVAL)) { 802 803 /* 804 * Quit if no more thread information is available for the 805 * process. 806 */ 807 return; 808 } 809 /* 810 * Warn about all other errors via a NAME column message. 811 */ 812 alloc_lfile(TWD, -1); 813 Cfp = (struct file *)NULL; 814 (void) snpf(Namech, Namechl, 815 "thread info error: %s", strerror(errno)); 816 Namech[Namechl - 1] = '\0'; 817 enter_nm(Namech); 818 if (Lf->sf) 819 link_lfile(); 820 return; 821 } else if (nb < sizeof(tpi)) { 822 (void) fprintf(stderr, 823 "%s: PID %d: proc_pidinfo(PROC_PIDTHREADPATHINFO);\n", 824 Pn, pid); 825 (void) fprintf(stderr, 826 " too few bytes; expected %ld, got %d\n", 827 sizeof(tpi), nb); 828 Exit(1); 829 } 830 if (tpi.pvip.vip_path[0]) { 831 alloc_lfile(TWD, -1); 832 Cfp = (struct file *)NULL; 833 (void) enter_vnode_info(&tpi.pvip); 834 if (Lf->sf) 835 link_lfile(); 836 } 837 } 838} 839#endif /* DARWINV>=900 */ 840