File: [local] / src / usr.bin / fstat / fuser.c (download)
Revision 1.2, Sun Jul 19 12:56:19 2009 UTC (14 years, 10 months ago) by millert
Branch: MAIN
CVS Tags: OPENBSD_5_4_BASE, OPENBSD_5_4, OPENBSD_5_3_BASE, OPENBSD_5_3, OPENBSD_5_2_BASE, OPENBSD_5_2, OPENBSD_5_1_BASE, OPENBSD_5_1, OPENBSD_5_0_BASE, OPENBSD_5_0, OPENBSD_4_9_BASE, OPENBSD_4_9, OPENBSD_4_8_BASE, OPENBSD_4_8, OPENBSD_4_7_BASE, OPENBSD_4_7 Changes since 1.1: +7 -2 lines
Hook up "text" (executable) output and implement for fuser too.
Man page bits adapted from FreeBSD. OK miod@
|
/* $OpenBSD: fuser.c,v 1.2 2009/07/19 12:56:19 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_TEXT:
fu->flags |= F_TEXT;
break;
case KERN_FILE_TRACE:
/* 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 (fu->flags & F_TEXT)
fprintf(stderr, "t");
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");
}
}