version 1.67, 2009/06/15 04:19:59 |
version 1.68, 2009/07/08 16:04:00 |
|
|
*/ |
*/ |
|
|
#ifndef lint |
#ifndef lint |
static char copyright[] = |
static const char copyright[] = |
"@(#) Copyright (c) 1988, 1993\n\ |
"@(#) Copyright (c) 1988, 1993\n\ |
The Regents of the University of California. All rights reserved.\n"; |
The Regents of the University of California. All rights reserved.\n"; |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
#ifndef lint |
#ifndef lint |
/*static char sccsid[] = "from: @(#)fstat.c 8.1 (Berkeley) 6/6/93";*/ |
/*static const char sccsid[] = "from: @(#)fstat.c 8.1 (Berkeley) 6/6/93";*/ |
static char *rcsid = "$OpenBSD$"; |
static const char rcsid[] = "$OpenBSD$"; |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
|
#include <sys/queue.h> |
|
#include <sys/mount.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <sys/vnode.h> |
#include <sys/vnode.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
|
|
#include <limits.h> |
#include <limits.h> |
#include <nlist.h> |
#include <nlist.h> |
#include <pwd.h> |
#include <pwd.h> |
|
#include <signal.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdint.h> |
#include <stdint.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
|
#include <unistd.h> |
#include <unistd.h> |
#include <err.h> |
#include <err.h> |
|
|
typedef struct devs { |
#include "fstat.h" |
struct devs *next; |
|
long fsid; |
|
ino_t ino; |
|
char *name; |
|
} DEVS; |
|
DEVS *devs; |
|
|
|
|
struct fileargs fileargs = SLIST_HEAD_INITIALIZER(fileargs); |
|
|
int fsflg; /* show files on same filesystem as file(s) argument */ |
int fsflg; /* show files on same filesystem as file(s) argument */ |
int pflg; /* show files open by a particular pid */ |
int pflg; /* show files open by a particular pid */ |
int uflg; /* show files open by a particular (effective) user */ |
int uflg; /* show files open by a particular (effective) user */ |
|
|
int oflg; /* display file offset */ |
int oflg; /* display file offset */ |
int sflg; /* display file xfer/bytes counters */ |
int sflg; /* display file xfer/bytes counters */ |
int vflg; /* display errors in locating kernel data objects etc... */ |
int vflg; /* display errors in locating kernel data objects etc... */ |
|
int cflg; /* fuser only */ |
|
|
|
int fuser; /* 1 if we are fuser, 0 if we are fstat */ |
|
int signo; /* signal to send (fuser only) */ |
|
|
kvm_t *kd; |
kvm_t *kd; |
uid_t uid; |
uid_t uid; |
|
|
|
void fstat_dofile(struct kinfo_file2 *); |
void dofiles(struct kinfo_file2 *); |
void fstat_header(void); |
|
void fuser_dofile(struct kinfo_file2 *); |
void getinetproto(int); |
void getinetproto(int); |
void usage(void); |
void usage(void); |
int getfname(char *); |
int getfname(char *); |
|
|
void systracetrans(struct kinfo_file2 *); |
void systracetrans(struct kinfo_file2 *); |
void vtrans(struct kinfo_file2 *); |
void vtrans(struct kinfo_file2 *); |
const char *inet6_addrstr(struct in6_addr *); |
const char *inet6_addrstr(struct in6_addr *); |
|
int signame_to_signum(char *); |
|
|
int |
int |
main(int argc, char *argv[]) |
main(int argc, char *argv[]) |
|
|
struct passwd *passwd; |
struct passwd *passwd; |
struct kinfo_file2 *kf, *kflast; |
struct kinfo_file2 *kf, *kflast; |
int arg, ch, what; |
int arg, ch, what; |
char *memf, *nlistf; |
char *memf, *nlistf, *optstr; |
char buf[_POSIX2_LINE_MAX]; |
char buf[_POSIX2_LINE_MAX]; |
const char *errstr; |
const char *errstr; |
int cnt, flags; |
int cnt, flags; |
|
|
what = KERN_FILE_BYPID; |
what = KERN_FILE_BYPID; |
nlistf = memf = NULL; |
nlistf = memf = NULL; |
oflg = 0; |
oflg = 0; |
while ((ch = getopt(argc, argv, "fnop:su:vN:M:")) != -1) |
|
|
/* are we fstat(1) or fuser(1)? */ |
|
if (strcmp(__progname, "fuser") == 0) { |
|
fuser = 1; |
|
optstr = "cfks:uM:N:"; |
|
} else { |
|
fuser = 0; |
|
optstr = "fnop:su:vN:M:"; |
|
} |
|
|
|
/* |
|
* fuser and fstat share three flags: -f, -s and -u. In both cases |
|
* -f is a boolean, but for -u fstat wants an argument while fuser |
|
* does not and for -s fuser wants an argument whereas fstat does not. |
|
*/ |
|
while ((ch = getopt(argc, argv, optstr)) != -1) |
switch ((char)ch) { |
switch ((char)ch) { |
|
case 'c': |
|
if (fsflg) |
|
usage(); |
|
cflg = 1; |
|
break; |
case 'f': |
case 'f': |
|
if (cflg) |
|
usage(); |
fsflg = 1; |
fsflg = 1; |
break; |
break; |
|
case 'k': |
|
sflg = 1; |
|
signo = SIGKILL; |
|
break; |
case 'M': |
case 'M': |
memf = optarg; |
memf = optarg; |
break; |
break; |
|
|
break; |
break; |
case 's': |
case 's': |
sflg = 1; |
sflg = 1; |
|
if (fuser) { |
|
signo = signame_to_signum(optarg); |
|
if (signo == -1) { |
|
warnx("invalid signal %s", optarg); |
|
usage(); |
|
} |
|
} |
break; |
break; |
case 'u': |
case 'u': |
if (uflg++) |
if (uflg++) |
usage(); |
usage(); |
if (!(passwd = getpwnam(optarg))) |
if (!fuser) { |
errx(1, "%s: unknown uid", optarg); |
if (!(passwd = getpwnam(optarg))) |
what = KERN_FILE_BYUID; |
errx(1, "%s: unknown uid", optarg); |
arg = passwd->pw_uid; |
what = KERN_FILE_BYUID; |
|
arg = passwd->pw_uid; |
|
} |
break; |
break; |
case 'v': |
case 'v': |
vflg = 1; |
vflg = 1; |
|
|
if (getfname(*argv)) |
if (getfname(*argv)) |
checkfile = 1; |
checkfile = 1; |
} |
} |
if (!checkfile) /* file(s) specified, but none accessible */ |
/* file(s) specified, but none accessible */ |
|
if (!checkfile) |
exit(1); |
exit(1); |
} |
} else if (fuser) |
|
usage(); |
|
|
if (fsflg && !checkfile) { |
if (!fuser && fsflg && !checkfile) { |
/* -f with no files means use wd */ |
/* fstat -f with no files means use wd */ |
if (getfname(".") == 0) |
if (getfname(".") == 0) |
exit(1); |
exit(1); |
checkfile = 1; |
checkfile = 1; |
|
|
|
|
if ((kf = kvm_getfile2(kd, what, arg, sizeof(*kf), &cnt)) == NULL) |
if ((kf = kvm_getfile2(kd, what, arg, sizeof(*kf), &cnt)) == NULL) |
errx(1, "%s", kvm_geterr(kd)); |
errx(1, "%s", kvm_geterr(kd)); |
|
|
|
if (!fuser) |
|
fstat_header(); |
|
for (kflast = &kf[cnt]; kf < kflast; ++kf) { |
|
if (fuser) |
|
fuser_check(kf); |
|
else |
|
fstat_dofile(kf); |
|
} |
|
if (fuser) |
|
fuser_run(); |
|
|
|
exit(0); |
|
} |
|
|
|
void |
|
fstat_header(void) |
|
{ |
if (nflg) |
if (nflg) |
printf("%s", |
printf("%s", |
"USER CMD PID FD DEV INUM MODE R/W SZ|DV"); |
"USER CMD PID FD DEV INUM MODE R/W SZ|DV"); |
|
|
if (sflg) |
if (sflg) |
printf(" XFERS KBYTES"); |
printf(" XFERS KBYTES"); |
putchar('\n'); |
putchar('\n'); |
|
|
for (kflast = &kf[cnt]; kf < kflast; ++kf) |
|
dofiles(kf); |
|
exit(0); |
|
} |
} |
|
|
char *Uname, *Comm; |
char *Uname, *Comm; |
|
|
* print open files attributed to this process |
* print open files attributed to this process |
*/ |
*/ |
void |
void |
dofiles(struct kinfo_file2 *kf) |
fstat_dofile(struct kinfo_file2 *kf) |
{ |
{ |
|
|
Uname = user_from_uid(kf->p_uid, 0); |
Uname = user_from_uid(kf->p_uid, 0); |
|
|
|
|
if (checkfile) { |
if (checkfile) { |
int fsmatch = 0; |
int fsmatch = 0; |
DEVS *d; |
struct filearg *fa; |
|
|
if (badtype) |
if (badtype) |
return; |
return; |
for (d = devs; d != NULL; d = d->next) { |
SLIST_FOREACH(fa, &fileargs, next) { |
if (d->fsid == kf->va_fsid) { |
if (fa->dev == kf->va_fsid) { |
fsmatch = 1; |
fsmatch = 1; |
if (d->ino == kf->va_fileid) { |
if (fa->ino == kf->va_fileid) { |
filename = d->name; |
filename = fa->name; |
break; |
break; |
} |
} |
} |
} |
|
|
memcpy(&faddr, kf->inp_faddru, sizeof(faddr)); |
memcpy(&faddr, kf->inp_faddru, sizeof(faddr)); |
getinetproto(kf->so_protocol); |
getinetproto(kf->so_protocol); |
if (kf->so_protocol == IPPROTO_TCP) { |
if (kf->so_protocol == IPPROTO_TCP) { |
printf(" %p", kf->inp_ppcb); |
printf(" %p", (void *)(uintptr_t)kf->inp_ppcb); |
printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" : |
printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" : |
inet_ntoa(laddr), ntohs(kf->inp_lport)); |
inet_ntoa(laddr), ntohs(kf->inp_lport)); |
if (kf->inp_fport) { |
if (kf->inp_fport) { |
|
|
inet_ntoa(faddr), ntohs(kf->inp_fport)); |
inet_ntoa(faddr), ntohs(kf->inp_fport)); |
} |
} |
} else if (kf->so_pcb) |
} else if (kf->so_pcb) |
printf(" %p", kf->so_pcb); |
printf(" %p", (void *)(uintptr_t)kf->so_pcb); |
break; |
break; |
#ifdef INET6 |
#ifdef INET6 |
case AF_INET6: |
case AF_INET6: |
|
|
memcpy(&faddr6, kf->inp_faddru, sizeof(faddr6)); |
memcpy(&faddr6, kf->inp_faddru, sizeof(faddr6)); |
getinetproto(kf->so_protocol); |
getinetproto(kf->so_protocol); |
if (kf->so_protocol == IPPROTO_TCP) { |
if (kf->so_protocol == IPPROTO_TCP) { |
printf(" %p", kf->inp_ppcb); |
printf(" %p", (void *)(uintptr_t)kf->inp_ppcb); |
snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", |
snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", |
inet6_addrstr(&laddr6)); |
inet6_addrstr(&laddr6)); |
printf(" %s:%d", |
printf(" %s:%d", |
|
|
xaddrbuf, ntohs(kf->inp_fport)); |
xaddrbuf, ntohs(kf->inp_fport)); |
} |
} |
} else if (kf->so_pcb) |
} else if (kf->so_pcb) |
printf(" %p", kf->so_pcb); |
printf(" %p", (void *)(uintptr_t)kf->so_pcb); |
break; |
break; |
#endif |
#endif |
case AF_UNIX: |
case AF_UNIX: |
/* print address of pcb and connected pcb */ |
/* print address of pcb and connected pcb */ |
printf("* unix %s", stype); |
printf("* unix %s", stype); |
if (kf->so_pcb) { |
if (kf->so_pcb) { |
printf(" %p", kf->so_pcb); |
printf(" %p", (void *)(uintptr_t)kf->so_pcb); |
if (kf->unp_conn) { |
if (kf->unp_conn) { |
char shoconn[4], *cp; |
char shoconn[4], *cp; |
|
|
|
|
int |
int |
getfname(char *filename) |
getfname(char *filename) |
{ |
{ |
struct stat statbuf; |
static struct statfs *mntbuf; |
DEVS *cur; |
static int nmounts; |
|
int i; |
|
struct stat sb; |
|
struct filearg *cur; |
|
|
if (stat(filename, &statbuf)) { |
if (stat(filename, &sb)) { |
warn("%s", filename); |
warn("%s", filename); |
return(0); |
return (0); |
} |
} |
if ((cur = malloc(sizeof(DEVS))) == NULL) |
|
err(1, "malloc"); |
|
cur->next = devs; |
|
devs = cur; |
|
|
|
cur->ino = statbuf.st_ino; |
/* |
cur->fsid = statbuf.st_dev & 0xffff; |
* POSIX specifies "For block special devices, all processes using any |
|
* file on that device are listed". However the -f flag description |
|
* states "The report shall be only for the named files", so we only |
|
* look up a block device if the -f flag has not be specified. |
|
*/ |
|
if (fuser && !fsflg && S_ISBLK(sb.st_mode)) { |
|
if (mntbuf == NULL) { |
|
nmounts = getmntinfo(&mntbuf, MNT_NOWAIT); |
|
if (nmounts == -1) |
|
err(1, "getmntinfo"); |
|
} |
|
for (i = 0; i < nmounts; i++) { |
|
if (!strcmp(mntbuf[i].f_mntfromname, filename)) { |
|
if (stat(mntbuf[i].f_mntonname, &sb) == -1) { |
|
warn("%s", filename); |
|
return (0); |
|
} |
|
cflg = 1; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if ((cur = malloc(sizeof(*cur))) == NULL) |
|
err(1, NULL); |
|
|
|
cur->ino = sb.st_ino; |
|
cur->dev = sb.st_dev & 0xffff; |
cur->name = filename; |
cur->name = filename; |
return(1); |
TAILQ_INIT(&cur->fusers); |
|
SLIST_INSERT_HEAD(&fileargs, cur, next); |
|
return (1); |
} |
} |
|
|
|
int |
|
signame_to_signum(char *sig) |
|
{ |
|
int n; |
|
const char *errstr = NULL; |
|
|
|
if (isdigit((unsigned char)*sig)) { |
|
n = strtonum(sig, 0, NSIG - 1, &errstr); |
|
return (errstr ? -1 : n); |
|
} |
|
if (!strncasecmp(sig, "sig", 3)) |
|
sig += 3; |
|
for (n = 1; n < NSIG; n++) { |
|
if (!strcasecmp(sys_signame[n], sig)) |
|
return (n); |
|
} |
|
return (-1); |
|
} |
|
|
void |
void |
usage(void) |
usage(void) |
{ |
{ |
fprintf(stderr, "usage: fstat [-fnosv] [-M core] [-N system] " |
if (fuser) { |
"[-p pid] [-u user] [file ...]\n"); |
fprintf(stderr, "usage: fuser [-cfku] [-M core] " |
|
"[-N system] [-s signal] file ...\n"); |
|
} else { |
|
fprintf(stderr, "usage: fstat [-fnosv] [-M core] [-N system] " |
|
"[-p pid] [-u user] [file ...]\n"); |
|
} |
exit(1); |
exit(1); |
} |
} |