/
githubmirror
/
lsof
Обзор
Документация
Войти
/
githubmirror
/
lsof
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/dialects/darwin/dproc.c
777 строк
25 KB
Jiajie Chen
Move static variables to lsof_context in Darwin dproc.c
31 мар 2026, 14:25
31 мар 2026, 14:25
5c3045e
Код
Авторство
О чём код?
/* * dproc.c -- Darwin process access functions for libproc-based lsof */ /* * Portions Copyright 2005-2007 Apple Inc. All rights reserved. * * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue * University. * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors, nor Apple Inc. nor Purdue University are * responsible for any consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either * by explicit claim or by omission. Credit to the authors, Apple * Inc. and Purdue University must appear in documentation and sources. * and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #ifndef lint static char copyright[] = "@(#) Copyright 2005-2007 Apple Inc. and Purdue " "Research Foundation.\nAll rights reserved.\n"; #endif #include "common.h" /* * Local definitions */ #define PIDS_INCR (sizeof(int) * 32) /* PID space increment */ #define VIPS_INCR 16 /* Vips space increment */ #if DARWINV >= 900 # define THREADS_INCR (sizeof(uint64_t) * 32) /* Threads space increment */ #endif /* DARWINV>=900 */ #if defined(PROC_PIDLISTFILEPORTS) # define FILEPORTS_INCR \ (sizeof(struct proc_fileportinfo) * 32) /* Fileports space increment \ */ #endif /* PROC_PIDLISTFILEPORTS */ /* * Local function prototypes */ static void enter_vn_text(struct lsof_context *ctx, struct vnode_info_path *vip, int *n); static void process_fds(struct lsof_context *ctx, int pid, uint32_t n, int ckscko); static void process_text(struct lsof_context *ctx, int pid); #if DARWINV >= 900 static void process_threads(struct lsof_context *ctx, int pid, uint32_t n); #endif /* DARWINV>=900 */ #if defined(PROC_PIDLISTFILEPORTS) static void process_fileports(struct lsof_context *ctx, int pid, int ckscko); #endif /* PROC_PIDLISTFILEPORTS */ /* * enter_vn_text() -- enter vnode information text reference */ static void enter_vn_text(struct lsof_context *ctx, /* context */ struct vnode_info_path *vip, /* vnode info */ int *n) /* number of vips[] entries in use */ { int i; /* * Ignore the request if the vnode information has already been entered. */ for (i = 0; i < *n; i++) { if ((vip->vip_vi.vi_stat.vst_dev == Vips[i].dev) && (vip->vip_vi.vi_stat.vst_ino == Vips[i].ino)) { return; } } /* * Save the text file information. */ alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1); Cfp = (struct file *)NULL; (void)enter_vnode_info(ctx, vip); if (Lf->sf) link_lfile(ctx); /* * Record the entry of the vnode information. */ if (i >= NVips) { /* * Allocate space for recording the vnode information. */ if (grow_array((void **)&Vips, &NVips, sizeof(struct darwin_vips_info), VIPS_INCR)) { (void)fprintf(stderr, "%s: PID %d: no text recording space\n", Pn, Lp->pid); Error(ctx); } } /* * Record the vnode information. */ Vips[*n].dev = vip->vip_vi.vi_stat.vst_dev; Vips[*n].ino = vip->vip_vi.vi_stat.vst_ino; (*n)++; } /* * gather_proc_info() -- gather process information */ void gather_proc_info(struct lsof_context *ctx) { short cckreg; /* conditional status of regular file * checking: * 0 = unconditionally check * 1 = conditionally check */ short ckscko; /* socket file only checking status: * 0 = none * 1 = check only socket files, * including TCP and UDP * streams with eXPORT data, * where supported */ int cre, cres, ef, i, nb, np, pid; short pss, sf; struct proc_taskallinfo tai; struct proc_vnodepathinfo vpi; /* * Define socket and regular file conditional processing flags. * * If only socket files have been selected, or socket files have been * selected, ANDed with other selection options, enable the skipping of * regular files. * * If socket files and some process options have been selected, enable * conditional skipping of regular file; i.e., regular files will be skipped * unless they belong to a process selected by one of the specified options. */ if (Selflags & SELNW) { /* * Some network files selection options have been specified. */ if (Fand || !(Selflags & ~SELNW)) { /* * Selection ANDing or only network file options have been * specified, so set unconditional skipping of regular files * and socket file only checking. */ cckreg = 0; ckscko = 1; } else { /* * If ORed file selection options have been specified, or no * ORed process selection options have been specified, enable * unconditional file checking and clear socket file only * checking. * * If only ORed process selection options have been specified, * enable conditional file skipping and socket file only checking. */ if ((Selflags & SELFILE) || !(Selflags & SelProc)) cckreg = ckscko = 0; else cckreg = ckscko = 1; } } else { /* * No network file selection options were specified. Enable * unconditional file checking and clear socket file only checking. */ cckreg = ckscko = 0; } /* * Determine how many bytes are needed to contain the PIDs on the system; * make sure sufficient buffer space is allocated to hold them (and a few * extra); then read the list of PIDs. */ if ((nb = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0)) <= 0) { (void)fprintf(stderr, "%s: can't get PID byte count: %s\n", Pn, strerror(errno)); Error(ctx); } if (nb > NbPids) { while (nb > NbPids) { NbPids += PIDS_INCR; } if (!Pids) Pids = (int *)malloc((MALLOC_S)NbPids); else Pids = (int *)realloc((MALLOC_P *)Pids, (MALLOC_S)NbPids); if (!Pids) { (void)fprintf(stderr, "%s: can't allocate space for %d PIDs\n", Pn, (int)(NbPids / sizeof(int *))); Error(ctx); } } /* * Get the list of PIDs. */ for (ef = 0; !ef;) { if ((nb = proc_listpids(PROC_ALL_PIDS, 0, Pids, NbPids)) <= 0) { (void)fprintf(stderr, "%s: can't get list of PIDs: %s\n", Pn, strerror(errno)); Error(ctx); } if ((nb + sizeof(int)) < NbPids) { /* * There is room in the buffer for at least one more PID. */ np = nb / sizeof(int); ef = 1; } else { /* * The PID buffer must be enlarged. */ NbPids += PIDS_INCR; Pids = (int *)realloc((MALLOC_P *)Pids, (MALLOC_S)NbPids); if (!Pids) { (void)fprintf(stderr, "%s: can't allocate space for %d PIDs\n", Pn, (int)(NbPids / sizeof(int *))); Error(ctx); } } } /* * Loop through the identified processes. */ for (i = 0; i < np; i++) { if (!(pid = Pids[i])) continue; nb = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &tai, sizeof(tai)); if (nb <= 0) { if ((errno == EPERM) || (errno == ESRCH)) continue; if (!Fwarn) { (void)fprintf(stderr, "%s: PID %d information error: %s\n", Pn, pid, strerror(errno)); } continue; } else if (nb < sizeof(tai)) { (void)fprintf(stderr, "%s: PID %d: proc_pidinfo(PROC_PIDTASKALLINFO);\n", Pn, pid); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(tai), nb); Error(ctx); } /* * Check for process or command exclusion. */ if (is_proc_excl(ctx, (int)pid, (int)tai.pbsd.pbi_pgid, (UID_ARG)tai.pbsd.pbi_uid, &pss, &sf)) { continue; } tai.pbsd.pbi_comm[sizeof(tai.pbsd.pbi_comm) - 1] = '\0'; if (is_cmd_excl(ctx, tai.pbsd.pbi_comm, &pss, &sf)) continue; if (tai.pbsd.pbi_name[0]) { tai.pbsd.pbi_name[sizeof(tai.pbsd.pbi_name) - 1] = '\0'; if (is_cmd_excl(ctx, tai.pbsd.pbi_name, &pss, &sf)) continue; } if (cckreg) { /* * If conditional checking of regular files is enabled, enable * socket file only checking, based on the process' selection * status. */ ckscko = (sf & SelProc) ? 0 : 1; } /* * Get root and current directory information. */ if (!ckscko) { nb = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi)); if (nb <= 0) { cre = errno; cres = 1; } else if (nb < sizeof(vpi)) { (void)fprintf( stderr, "%s: PID %d: proc_pidinfo(PROC_PIDVNODEPATHINFO);\n", Pn, pid); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(vpi), nb); Error(ctx); } else cres = 0; } /* * Allocate local process space. * * Caveat: pbi_name can be changed by setprogname(3), while pbi_comm * cannot. Should we allow empty pbi_name here? */ alloc_lproc(ctx, (int)pid, (int)tai.pbsd.pbi_pgid, (int)tai.pbsd.pbi_ppid, (UID_ARG)tai.pbsd.pbi_uid, (tai.pbsd.pbi_name[0] != '\0') ? tai.pbsd.pbi_name : tai.pbsd.pbi_comm, (int)pss, (int)sf); Plf = (struct lfile *)NULL; /* * Save current working directory information. */ if (!ckscko) { if (cres || vpi.pvi_cdir.vip_path[0]) { alloc_lfile(ctx, LSOF_FD_CWD, -1); Cfp = (struct file *)NULL; if (cres) { /* * If the CWD|RTD information access error is ESRCH, * ignore it; otherwise report the error's message in the * CWD's NAME column. */ if (cre != ESRCH) { (void)snpf(Namech, Namechl, "%s|%s info error: %s", CWD + 1, RTD + 1, strerror(cre)); Namech[Namechl - 1] = '\0'; enter_nm(ctx, Namech); if (Lf->sf) link_lfile(ctx); } } else { (void)enter_vnode_info(ctx, &vpi.pvi_cdir); if (Lf->sf) link_lfile(ctx); } } } /* * Save root directory information. */ if (!ckscko) { if (!cres && vpi.pvi_rdir.vip_path[0]) { alloc_lfile(ctx, LSOF_FD_ROOT_DIR, -1); Cfp = (struct file *)NULL; (void)enter_vnode_info(ctx, &vpi.pvi_rdir); if (Lf->sf) link_lfile(ctx); } } #if DARWINV >= 900 /* * Check for per-thread current working directories */ if (!ckscko) { if (tai.pbsd.pbi_flags & PROC_FLAG_THCWD) { (void)process_threads(ctx, pid, tai.ptinfo.pti_threadnum); } } #endif /* DARWINV>=900 */ /* * Print text file information. */ if (!ckscko) (void)process_text(ctx, pid); #if defined(PROC_PIDLISTFILEPORTS) /* * Loop through the fileports */ (void)process_fileports(ctx, pid, ckscko); #endif /* PROC_PIDLISTFILEPORTS */ /* * Loop through the file descriptors. */ (void)process_fds(ctx, pid, tai.pbsd.pbi_nfiles, ckscko); /* * Examine results. */ if (examine_lproc(ctx)) return; } } /* * initialize() -- perform all initialization */ void initialize(struct lsof_context *ctx) {} /* * process_fds() -- process file descriptors */ static void process_fds(struct lsof_context *ctx, /* context */ int pid, /* PID of interest */ uint32_t n, /* max FDs */ int ckscko) /* check socket files only */ { int i, isock, nb, nf; struct proc_fdinfo *fdp; /* * Make sure an FD buffer has been allocated. */ if (!Fds) { NbFds = sizeof(struct proc_fdinfo) * n; Fds = (struct proc_fdinfo *)malloc((MALLOC_S)NbFds); } else if (NbFds < sizeof(struct proc_fdinfo) * n) { /* * More proc_fdinfo space is required. Allocate it. */ NbFds = sizeof(struct proc_fdinfo) * n; Fds = (struct proc_fdinfo *)realloc((MALLOC_P *)Fds, (MALLOC_S)NbFds); } if (!Fds) { (void)fprintf(stderr, "%s: PID %d: can't allocate space for %d FDs\n", Pn, pid, (int)(NbFds / sizeof(struct proc_fdinfo))); Error(ctx); } /* * Get FD information for the process. */ nb = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, Fds, NbFds); if (nb <= 0) { if (errno == ESRCH) { /* * Quit if no FD information is available for the process. */ return; } /* * Make a dummy file entry with an error message in its NAME column. */ alloc_lfile(ctx, LSOF_FD_ERROR, -1); (void)snpf(Namech, Namechl, "FD info error: %s", strerror(errno)); Namech[Namechl - 1] = '\0'; enter_nm(ctx, Namech); if (Lf->sf) link_lfile(ctx); return; } nf = (int)(nb / sizeof(struct proc_fdinfo)); /* * Loop through the file descriptors. */ for (i = 0; i < nf; i++) { fdp = &Fds[i]; alloc_lfile(ctx, LSOF_FD_NUMERIC, (int)fdp->proc_fd); /* * Process the file by its type. */ isock = 0; switch (fdp->proc_fdtype) { case PROX_FDTYPE_ATALK: if (!ckscko) (void)process_atalk(ctx, pid, fdp->proc_fd); break; case PROX_FDTYPE_FSEVENTS: if (!ckscko) (void)process_fsevents(ctx, pid, fdp->proc_fd); break; case PROX_FDTYPE_KQUEUE: if (!ckscko) (void)process_kqueue(ctx, pid, fdp->proc_fd); break; case PROX_FDTYPE_PIPE: if (!ckscko) (void)process_pipe(ctx, pid, fdp->proc_fd); break; case PROX_FDTYPE_PSEM: if (!ckscko) (void)process_psem(ctx, pid, fdp->proc_fd); break; case PROX_FDTYPE_SOCKET: (void)process_socket(ctx, pid, fdp->proc_fd); isock = 1; break; case PROX_FDTYPE_PSHM: (void)process_pshm(ctx, pid, fdp->proc_fd); break; case PROX_FDTYPE_VNODE: (void)process_vnode(ctx, pid, fdp->proc_fd); break; case PROX_FDTYPE_NETPOLICY: (void)process_netpolicy(ctx, pid, fdp->proc_fd); break; default: (void)snpf(Namech, Namechl - 1, "unknown file type: %d", fdp->proc_fdtype); Namech[Namechl - 1] = '\0'; (void)enter_nm(ctx, Namech); break; } if (Lf->sf) { if (!ckscko || isock) link_lfile(ctx); } } } #if defined(PROC_PIDLISTFILEPORTS) /* * process_fileports() -- process fileports */ static void process_fileports(struct lsof_context *ctx, /* context */ int pid, /* PID of interest */ int ckscko) /* check socket files only */ { int ef, i, isock, nb = 0, nf; struct proc_fileportinfo *fpi; /* * Get fileport information for the process. */ for (ef = 0; !ef;) { nb = proc_pidinfo(pid, PROC_PIDLISTFILEPORTS, 0, Fps, NbFps); if (nb == 0) { /* * Quit if no fileport information */ return; } else if (nb < 0) { if (errno == ESRCH) { /* * Quit if no fileport information is available for the process. */ return; } /* * Make a dummy file entry with an error message in its NAME column. */ alloc_lfile(ctx, LSOF_FD_ERROR, -1); (void)snpf(Namech, Namechl, "FILEPORT info error: %s", strerror(errno)); Namech[Namechl - 1] = '\0'; enter_nm(ctx, Namech); if (Lf->sf) link_lfile(ctx); } if ((nb + sizeof(struct proc_fileportinfo)) < NbFps) { /* * There is room in the buffer for at least one more fileport. */ ef = 1; } else { if (Fps && ((nb = proc_pidinfo(pid, PROC_PIDLISTFILEPORTS, 0, NULL, 0)) <= 0)) { (void)fprintf(stderr, "%s: can't get fileport byte count: %s\n", Pn, strerror(errno)); Error(ctx); } /* * The fileport buffer must be enlarged. */ while (nb > NbFps) { NbFps += FILEPORTS_INCR; } if (!Fps) Fps = (struct proc_fileportinfo *)malloc((MALLOC_S)NbFps); else Fps = (struct proc_fileportinfo *)realloc((MALLOC_P *)Fps, (MALLOC_S)NbFps); } } /* * Loop through the fileports. */ nf = (int)(nb / sizeof(struct proc_fileportinfo)); for (i = 0; i < nf; i++) { fpi = &Fps[i]; /* * fileport reported as "fp." with "(fileport=0xXXXX)" in the Name * column */ alloc_lfile(ctx, LSOF_FD_FILEPORT, -1); Lf->fileport = fpi->proc_fileport; /* * Process the file by its type. */ isock = 0; switch (fpi->proc_fdtype) { case PROX_FDTYPE_PIPE: if (!ckscko) (void)process_fileport_pipe(ctx, pid, fpi->proc_fileport); break; case PROX_FDTYPE_SOCKET: (void)process_fileport_socket(ctx, pid, fpi->proc_fileport); isock = 1; break; case PROX_FDTYPE_PSHM: (void)process_fileport_pshm(ctx, pid, fpi->proc_fileport); break; case PROX_FDTYPE_VNODE: (void)process_fileport_vnode(ctx, pid, fpi->proc_fileport); break; default: (void)snpf(Namech, Namechl - 1, "unknown file type: %d", fpi->proc_fileport); Namech[Namechl - 1] = '\0'; (void)enter_nm(ctx, Namech); break; } if (Lf->sf) { if (!ckscko || isock) link_lfile(ctx); } } } #endif /* PROC_PIDLISTFILEPORTS */ /* * process_text() -- process text information */ static void process_text(struct lsof_context *ctx, /* context */ int pid) /* PID */ { uint64_t a; int i, n, nb; struct proc_regionwithpathinfo rwpi; for (a = (uint64_t)0, i = n = 0; i < 10000; i++) { nb = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO, a, &rwpi, sizeof(rwpi)); if (nb <= 0) { if ((errno == ESRCH) || (errno == EINVAL)) { /* * Quit if no more text information is available for the * process. */ return; } /* * Warn about all other errors via a NAME column message. */ alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1); Cfp = (struct file *)NULL; (void)snpf(Namech, Namechl, "region info error: %s", strerror(errno)); Namech[Namechl - 1] = '\0'; enter_nm(ctx, Namech); if (Lf->sf) link_lfile(ctx); return; } else if (nb < sizeof(rwpi)) { (void)fprintf(stderr, "%s: PID %d: proc_pidinfo(PROC_PIDREGIONPATHINFO);\n", Pn, pid); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(rwpi), nb); Error(ctx); } if (rwpi.prp_vip.vip_path[0]) enter_vn_text(ctx, &rwpi.prp_vip, &n); a = rwpi.prp_prinfo.pri_address + rwpi.prp_prinfo.pri_size; } } #if DARWINV >= 900 /* * process_threads() -- process thread information */ # define TWD \ " twd" /* per-thread current working directory \ * fd name */ static void process_threads(struct lsof_context *ctx, /* context */ int pid, /* PID */ uint32_t n) /* number of threads */ { int i, nb, nt; /* * Make sure a thread buffer has been allocated. */ n += 10; if (n > NbThreads) { while (n > NbThreads) { NbThreads += THREADS_INCR; } if (!Threads) Threads = (uint64_t *)malloc((MALLOC_S)NbThreads); else Threads = (uint64_t *)realloc((MALLOC_P *)Threads, (MALLOC_S)NbThreads); if (!Threads) { (void)fprintf(stderr, "%s: can't allocate space for %d Threads\n", Pn, (int)(NbThreads / sizeof(int *))); Error(ctx); } } /* * Get thread information for the process. */ nb = proc_pidinfo(pid, PROC_PIDLISTTHREADS, 0, Threads, NbThreads); if (nb <= 0) { if (errno == ESRCH) { /* * Quit if no thread information is available for the * process. */ return; } } nt = (int)(nb / sizeof(uint64_t)); /* * Loop through the threads. */ for (i = 0; i < nt; i++) { uint64_t t; struct proc_threadwithpathinfo tpi; t = Threads[i]; nb = proc_pidinfo(pid, PROC_PIDTHREADPATHINFO, t, &tpi, sizeof(tpi)); if (nb <= 0) { if ((errno == ESRCH) || (errno == EINVAL)) { /* * Quit if no more thread information is available for the * process. */ return; } /* * Warn about all other errors via a NAME column message. */ alloc_lfile(ctx, LSOF_FD_TASK_CWD, -1); Cfp = (struct file *)NULL; (void)snpf(Namech, Namechl, "thread info error: %s", strerror(errno)); Namech[Namechl - 1] = '\0'; enter_nm(ctx, Namech); if (Lf->sf) link_lfile(ctx); return; } else if (nb < sizeof(tpi)) { (void)fprintf(stderr, "%s: PID %d: proc_pidinfo(PROC_PIDTHREADPATHINFO);\n", Pn, pid); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(tpi), nb); Error(ctx); } if (tpi.pvip.vip_path[0]) { alloc_lfile(ctx, LSOF_FD_TASK_CWD, -1); Cfp = (struct file *)NULL; (void)enter_vnode_info(ctx, &tpi.pvip); if (Lf->sf) link_lfile(ctx); } } } #endif /* DARWINV>=900 */