diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2009-07-08 16:04:01 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2009-07-08 16:04:01 +0000 |
commit | db88960d516b2c5ac6c28f48ad6f552239017182 (patch) | |
tree | 2eb62c4b472e6eab4b3b59c0b4c498be8772e383 /usr.bin/fstat/fuser.c | |
parent | adaaa9d9490a77fc421f46a2b0f652b6d9c9199e (diff) |
Add POSIX-compliant fuser mode to fstat. Originally based on
a diff from Peter Werner but largely rewritten to use kinfo_file2.
OK deraadt@ with man fixes from jmc@ and sobrado@
Diffstat (limited to 'usr.bin/fstat/fuser.c')
-rw-r--r-- | usr.bin/fstat/fuser.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/usr.bin/fstat/fuser.c b/usr.bin/fstat/fuser.c new file mode 100644 index 00000000000..3f146373d72 --- /dev/null +++ b/usr.bin/fstat/fuser.c @@ -0,0 +1,177 @@ +/* $OpenBSD: fuser.c,v 1.1 2009/07/08 16:04:00 millert Exp $ */ + +/* + * Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Copyright (c) 2002 Peter Werner <peterw@ifost.org.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#define _KERNEL /* for DTYPE_VNODE */ +#include <sys/file.h> +#undef _KERNEL + +#include <err.h> +#include <fcntl.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "fstat.h" + +/* + * Returns 1 if the file watched (fa) is equivalent + * to a file held by a process (kf), else 0. + */ +static int +match(struct filearg *fa, struct kinfo_file2 *kf) +{ + if (fa->dev == kf->va_fsid) { + if (cflg) + return (1); + if (fa->ino == kf->va_fileid) + return (1); + } + return (0); +} + +/* + * Examine kinfo_file2 struct and record the details if they + * match a watched file. + */ +void +fuser_check(struct kinfo_file2 *kf) +{ + struct filearg *fa; + struct fuser *fu; + + if (kf->f_type != DTYPE_VNODE) + return; + + SLIST_FOREACH(fa, &fileargs, next) { + if (!match(fa, kf)) + continue; + + /* + * This assumes that kinfo_files2 returns all files + * associated with a process in a contiguous block. + */ + if (TAILQ_EMPTY(&fa->fusers) || kf->p_pid != + (fu = TAILQ_LAST(&fa->fusers, fuserhead))->pid) { + fu = malloc(sizeof(*fu)); + if (fu == NULL) + err(1, NULL); + fu->pid = kf->p_pid; + fu->uid = kf->p_uid; + fu->flags = 0; + TAILQ_INSERT_TAIL(&fa->fusers, fu, tq); + } + switch (kf->fd_fd) { + case KERN_FILE_CDIR: + fu->flags |= F_CWD; + break; + case KERN_FILE_RDIR: + fu->flags |= F_ROOT; + break; + case KERN_FILE_TRACE: + case KERN_FILE_TEXT: + /* ignore */ + break; + default: + fu->flags |= F_OPEN; + break; + } + } +} + +/* + * Print out the specfics for a given file/filesystem + */ +static void +printfu(struct fuser *fu) +{ + struct passwd *pwd; + + printf("%d", fu->pid); + fflush(stdout); + + if (fu->flags & F_CWD) + fprintf(stderr, "c"); + + if (fu->flags & F_ROOT) + fprintf(stderr, "r"); + + if (uflg) { + pwd = getpwuid(fu->uid); + if (pwd != NULL) + fprintf(stderr, "(%s)", pwd->pw_name); + else + fprintf(stderr, "(%d)", fu->uid); + } + + putchar(' '); +} + +/* + * For each file, print matching process info and optionally send a signal. + */ +void +fuser_run(void) +{ + struct filearg *fa; + struct fuser *fu; + pid_t mypid = getpid(); + + SLIST_FOREACH(fa, &fileargs, next) { + fprintf(stderr, "%s: ", fa->name); + TAILQ_FOREACH(fu, &fa->fusers, tq) { + printfu(fu); + if (sflg && fu->pid != mypid) { + kill(fu->pid, signo); + } + } + fflush(stdout); + fprintf(stderr, "\n"); + } +} |