/
githubmirror
/
lsof
Обзор
Документация
Войти
/
githubmirror
/
lsof
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
4.95.0
dialects/freebsd/dproc.c
723 строки
16 KB
Masatake YAMATO
Use LSOF_ERROR as the exit status reported when an error occurs
18 апр 2022, 08:54
18 апр 2022, 08:54
34fab02
Код
Авторство
О чём код?
/* * dproc.c - FreeBSD process access functions for lsof */ /* * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * 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 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 and Purdue * University must appear in documentation 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 1994 Purdue Research Foundation.\nAll rights reserved.\n"; #endif #include "lsof.h" /* * This is not an exact version but it should not matter. At worst there * is a small version window where this lsof does not compile on older * -CURRENT. */ #if __FreeBSD_version >= 1300081 #define HAS_PWD #endif _PROTOTYPE(static void enter_vn_text,(KA_T va, int *n)); _PROTOTYPE(static void get_kernel_access,(void)); _PROTOTYPE(static void process_text,(KA_T vm)); /* * Local static values */ static MALLOC_S Nv = 0; /* allocated Vp[] entries */ static KA_T *Vp = NULL; /* vnode address cache */ /* * enter_vn_text() - enter a vnode text reference */ static void enter_vn_text(va, n) KA_T va; /* vnode address */ int *n; /* Vp[] entries in use */ { int i; /* * Ignore the request if the vnode has already been entered. */ for (i = 0; i < *n; i++) { if (va == Vp[i]) return; } /* * Save the text file information. */ alloc_lfile(" txt", -1); Cfp = (struct file *)NULL; process_node(va); if (Lf->sf) link_lfile(); if (i >= Nv) { /* * Allocate space for remembering the vnode. */ Nv += 10; if (!Vp) Vp=(KA_T *)malloc((MALLOC_S)(sizeof(struct vnode *)*10)); else Vp=(KA_T *)realloc((MALLOC_P *)Vp,(MALLOC_S)(Nv*sizeof(KA_T))); if (!Vp) { (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n", Pn, Lp->pid); Error(); } } /* * Remember the vnode. */ Vp[*n] = va; (*n)++; } /* * gather_proc_info() -- gather process information */ void gather_proc_info() { 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 */ struct filedesc fd; #if defined(PWDDESC_KVM_LOAD_PWD) struct pwddesc pd; #endif /* defined(PWDDESC_KVM_LOAD_PWD) */ int i, nf; MALLOC_S nb; #if defined(HAS_FILEDESCENT) typedef struct filedescent ofb_t; #else /* !defined(HAS_FILEDESCENT) */ typedef struct file* ofb_t; #endif /* defined(HAS_FILEDESCENT) */ #if defined(HAS_FDESCENTTBL) struct fdescenttbl fdt; KA_T fa; #endif /* defined(HAS_FDESCENTTBL) */ #if defined(HAS_PWD) struct pwd pwd; KA_T pwd_addr; #endif /* defined(HAS_FDESCENTTBL) */ struct vnode *cdir; struct vnode *rdir; struct vnode *jdir; static ofb_t *ofb = NULL; static int ofbb = 0; int pgid, pid; int ppid = 0; short pss, sf; int px; int tid; /* thread (task) ID */ uid_t uid; struct kinfo_proc *p; #if defined(HASFSTRUCT) && !defined(HAS_FILEDESCENT) static char *pof = (char *)NULL; static int pofb = 0; #endif /* defined(HASFSTRUCT) && !defiled(HAS_FILEDESCENT) */ /* * 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; } /* * Read the process table. */ # if !defined(KERN_PROC_PROC) #define KERN_PROC_PROC KERN_PROC_ALL # endif /* !defined(KERN_PROC_PROC) */ if ((P = kvm_getprocs(Kd, Ftask ? KERN_PROC_ALL : KERN_PROC_PROC, 0, &Np)) == NULL) { (void) fprintf(stderr, "%s: can't read process table: %s\n", Pn, kvm_geterr(Kd) ); Error(); } /* * Examine proc structures and their associated information. */ for (p = P, px = 0; px < Np; p++, px++) { if (p->P_STAT == 0 || p->P_STAT == SZOMB) continue; pgid = p->P_PGID; uid = p->ki_uid; #if defined(HASPPID) ppid = p->P_PPID; #endif /* defined(HASPPID) */ #if defined(HASTASKS) /* * See if process,including its tasks, is excluded. */ tid = Ftask ? (int)p->ki_tid : 0; if (is_proc_excl(p->P_PID, pgid, (UID_ARG)uid, &pss, &sf, tid)) continue; #else /* !defined(HASTASKS) */ /* * See if process is excluded. */ if (is_proc_excl(p->P_PID, pgid, (UID_ARG)uid, &pss, &sf)) continue; #endif /* defined(HASTASKS) */ /* * Read file structure pointers. */ if (!p->P_FD || kread((KA_T)p->P_FD, (char *)&fd, sizeof(fd))) continue; #if defined(HAS_FDESCENTTBL) if (!fd.fd_files || kread((KA_T)fd.fd_files, (char *)&fdt, sizeof(fdt))) continue; if (!fd.fd_refcnt) continue; #else /* !defined(HAS_FDESCENTTBL) */ if (!fd.fd_refcnt || fd.fd_lastfile > fd.fd_nfiles) continue; #endif /* defined(HAS_FDESCENTTBL) */ #if defined(HAS_PWD) cdir = rdir = jdir = NULL; #if defined(PWDDESC_KVM_LOAD_PWD) pwd_addr = (KA_T)PWDDESC_KVM_LOAD_PWD(&pd); #else /* defined(PWDDESC_KVM_LOAD_PWD) */ pwd_addr = (KA_T)FILEDESC_KVM_LOAD_PWD(&fd); #endif /* defined(PWDDESC_KVM_LOAD_PWD) */ if (pwd_addr != 0) { if (!kread(pwd_addr, (char *)&pwd, sizeof(pwd))) { cdir = pwd.pwd_cdir; rdir = pwd.pwd_rdir; jdir = pwd.pwd_jdir; } } #else cdir = fd.fd_cdir; rdir = fd.fd_rdir; jdir = fd.fd_jdir; #endif /* * Allocate a local process structure. */ if (is_cmd_excl(p->P_COMM, &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; } alloc_lproc(p->P_PID, pgid, ppid, (UID_ARG)uid, p->P_COMM, (int)pss, (int)sf); Plf = (struct lfile *)NULL; #if defined(HASTASKS) /* * Save the task (thread) ID. */ Lp->tid = tid; #endif /* defined(HASTASKS) */ #if defined(P_ADDR) /* * Save the kernel proc struct address, if P_ADDR is defined. */ Kpa = (KA_T)p->P_ADDR; #endif /* defined(P_ADDR) */ /* * Save current working directory information. */ if (!ckscko && cdir) { alloc_lfile(CWD, -1); Cfp = (struct file *)NULL; process_node((KA_T)cdir); if (Lf->sf) link_lfile(); } /* * Save root directory information. */ if (!ckscko && rdir) { alloc_lfile(RTD, -1); Cfp = (struct file *)NULL; process_node((KA_T)rdir); if (Lf->sf) link_lfile(); } /* * Save jail directory information. */ if (!ckscko && jdir) { alloc_lfile("jld", -1); Cfp = (struct file *)NULL; process_node((KA_T)jdir); if (Lf->sf) link_lfile(); } /* * Save information on the text file. */ if (!ckscko && p->P_VMSPACE) process_text((KA_T)p->P_VMSPACE); /* * Read open file structure pointers. */ #if defined(HAS_FDESCENTTBL) if ((nf = fdt.fdt_nfiles) <= 0) continue; #else /* !defined(HAS_FDESCENTTBL) */ if (!fd.fd_ofiles || (nf = fd.fd_nfiles) <= 0) continue; #endif /* defined(HAS_FDESCENTTBL) */ nb = (MALLOC_S)(sizeof(ofb_t) * nf); if (nb > ofbb) { if (!ofb) ofb = (ofb_t *)malloc(nb); else ofb = (ofb_t *)realloc((MALLOC_P *)ofb, nb); if (!ofb) { (void) fprintf(stderr, "%s: PID %d, no file * space\n", Pn, p->P_PID); Error(); } ofbb = nb; } #if defined(HAS_FDESCENTTBL) fa = (KA_T)fd.fd_files + (KA_T)offsetof(struct fdescenttbl, fdt_ofiles); if (kread(fa, (char *)ofb, nb)) continue; #else /* !defined(HAS_FDESCENTTBL) */ if (kread((KA_T)fd.fd_ofiles, (char *)ofb, nb)) continue; #endif /* defined(HAS_FDESCENTTBL) */ #if defined(HASFSTRUCT) && !defined(HAS_FILEDESCENT) if (Fsv & FSV_FG) { nb = (MALLOC_S)(sizeof(char) * nf); if (nb > pofb) { if (!pof) pof = (char *)malloc(nb); else pof = (char *)realloc((MALLOC_P *)pof, nb); if (!pof) { (void) fprintf(stderr, "%s: PID %d, no file flag space\n", Pn, p->P_PID); Error(); } pofb = nb; } if (!fd.fd_ofileflags || kread((KA_T)fd.fd_ofileflags, pof, nb)) zeromem(pof, nb); } #endif /* defined(HASFSTRUCT) && !defined(HAS_FILEDESCENT) */ /* * Save information on file descriptors. */ for (i = 0; i < nf; i++) { #if defined(HAS_FILEDESCENT) if ((Cfp = ofb[i].fde_file)) #else /* !defined(HAS_FILEDESCENT) */ if ((Cfp = ofb[i])) #endif /* defined(HAS_FILEDESCENT) */ { alloc_lfile(NULL, i); process_file((KA_T)Cfp); if (Lf->sf) { #if defined(HASFSTRUCT) if (Fsv & FSV_FG) # if defined(HAS_FILEDESCENT) Lf->pof = (long)ofb[i].fde_flags; # else /* !defined(HAS_FILEDESCENT) */ Lf->pof = (long)pof[i]; # endif /* defined(HAS_FILEDESCENT) */ #endif /* defined(HASFSTRUCT) */ link_lfile(); } } } /* * Unless threads (tasks) are being processed, examine results. */ if (!Ftask) { if (examine_lproc()) return; } } } /* * get_kernel_access() - get access to kernel memory */ static void get_kernel_access() { /* * Check kernel version. */ (void) ckkv("FreeBSD", LSOF_VSTR, (char *)NULL, (char *)NULL); /* * Set name list file path. */ if (!Nmlst) #if defined(N_UNIX) Nmlst = N_UNIX; #else /* !defined(N_UNIX) */ { if (!(Nmlst = get_nlist_path(1))) { (void) fprintf(stderr, "%s: can't get kernel name list path\n", Pn); Error(); } } #endif /* defined(N_UNIX) */ #if defined(WILLDROPGID) /* * If kernel memory isn't coming from KMEM, drop setgid permission * before attempting to open the (Memory) file. */ if (Memory) (void) dropgid(); #else /* !defined(WILLDROPGID) */ /* * See if the non-KMEM memory and the name list files are readable. */ if ((Memory && !is_readable(Memory, 1)) || (Nmlst && !is_readable(Nmlst, 1))) Error(); #endif /* defined(WILLDROPGID) */ /* * Open kernel memory access. */ if ((Kd = kvm_open(Nmlst, Memory, NULL, O_RDONLY, NULL)) == NULL) { (void) fprintf(stderr, "%s: kvm_open%s(execfile=%s, corefile=%s): %s\n", Pn, "", Nmlst ? Nmlst : "default", Memory ? Memory : #if defined(_PATH_MEM) _PATH_MEM, #else /* !defined(_PATH_MEM) */ "default", #endif /* defined(_PATH_MEM) */ strerror(errno)); Error(); } (void) build_Nl(Drive_Nl); if (kvm_nlist(Kd, Nl) < 0) { (void) fprintf(stderr, "%s: can't read namelist from %s\n", Pn, Nmlst); Error(); } #if defined(X_BADFILEOPS) /* * Get kernel's badfileops address (for process_file()). */ if (get_Nl_value(X_BADFILEOPS, (struct drive_Nl *)NULL, &X_bfopsa) < 0 || !X_bfopsa) { X_bfopsa = (KA_T)0; } #endif /* defined(X_BADFILEOPS) */ #if defined(WILLDROPGID) /* * Drop setgid permission, if necessary. */ if (!Memory) (void) dropgid(); #endif /* defined(WILLDROPGID) */ } #if !defined(N_UNIX) /* * get_nlist_path() - get kernel name list path */ char * get_nlist_path(ap) int ap; /* on success, return an allocated path * string pointer if 1; return a * constant character pointer if 0; * return NULL if failure */ { const char *bf; static char *bfc; MALLOC_S bfl; /* * Get bootfile name. */ if ((bf = getbootfile())) { if (!ap) return(""); bfl = (MALLOC_S)(strlen(bf) + 1); if (!(bfc = (char *)malloc(bfl))) { (void) fprintf(stderr, "%s: can't allocate %d bytes for boot file path: %s\n", Pn, (int)bfl, bf); Error(); } (void) snpf(bfc, bfl, "%s", bf); return(bfc); } return((char *)NULL); } #endif /* !defined(N_UNIX) */ /* * initialize() - perform all initialization */ void initialize() { get_kernel_access(); } /* * kread() - read from kernel memory */ int kread(addr, buf, len) KA_T addr; /* kernel memory address */ char *buf; /* buffer to receive data */ READLEN_T len; /* length to read */ { int br; br = kvm_read(Kd, (u_long)addr, buf, len); return((br == len) ? 0 : 1); } static int vm_map_reader(void *token, vm_map_entry_t addr, vm_map_entry_t dest) { return (kread((KA_T)addr, (char *)dest, sizeof(*dest))); } #if __FreeBSD_version < 1300060 typedef int vm_map_entry_reader(void *token, vm_map_entry_t addr, vm_map_entry_t dest); static inline vm_map_entry_t vm_map_entry_read_succ(void *token, struct vm_map_entry *const clone, vm_map_entry_reader reader) { vm_map_entry_t next; next = clone->next; if (!reader(token, next, clone)) return (NULL); return (next); } #endif /* __FreeBSD_version < 1300060 */ /* * process_text() - process text information */ void process_text(vm) KA_T vm; /* vm space pointer */ { int i, j; KA_T ka; int n = 0; struct vm_map_entry vmme, *e; struct vm_object vmo; struct vmspace vmsp; /* * Read the vmspace structure for the process. */ if (kread(vm, (char *)&vmsp, sizeof(vmsp))) return; /* * Read the vm_map structure. Search its vm_map_entry structure list. */ vmme = vmsp.vm_map.header; e = &vmme; for (i = 0; i < vmsp.vm_map.nentries; i++) { /* * Read the next vm_map_entry. */ if (!vm_map_entry_read_succ(NULL, e, vm_map_reader)) return; #if defined(MAP_ENTRY_IS_A_MAP) if (e->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP)) #else /* !defined(MAP_ENTRY_IS_A_MAP) */ if (e->is_a_map || e->is_sub_map) #endif /* defined(MAP_ENTRY_IS_A_MAP) */ continue; /* * Read the map entry's object and the object's shadow. * Look for: a PG_VNODE pager handle (FreeBSD < 2.2); * an OBJT_VNODE object type (FreeBSD >= 2.2). */ for (j = 0, ka = (KA_T)e->object.vm_object; j < 2 && ka; j++, ka = (KA_T)vmo.backing_object ) { if (kread(ka, (char *)&vmo, sizeof(vmo))) break; if (vmo.type != OBJT_VNODE || vmo.handle == (void *)NULL) continue; (void) (enter_vn_text((KA_T)vmo.handle, &n)); } } }