Annotation of src/usr.bin/fstat/fuser.c, Revision 1.7
1.7 ! millert 1: /* $OpenBSD: fuser.c,v 1.6 2015/01/16 06:40:08 deraadt Exp $ */
1.1 millert 2:
3: /*
4: * Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: /*
20: * Copyright (c) 2002 Peter Werner <peterw@ifost.org.au>
21: * All rights reserved.
22: *
23: * Redistribution and use in source and binary forms, with or without
24: * modification, are permitted provided that the following conditions
25: * are met:
26: *
27: * 1. Redistributions of source code must retain the above copyright
28: * notice, this list of conditions and the following disclaimer.
29: * 2. The name of the author may not be used to endorse or promote products
30: * derived from this software without specific prior written permission.
31: *
32: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
33: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
34: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
35: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
36: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
37: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
38: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
39: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
40: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42: */
43:
44: #include <sys/queue.h>
45: #include <sys/stat.h>
46: #include <sys/sysctl.h>
1.5 guenther 47: #include <sys/ucred.h>
1.1 millert 48: #define _KERNEL /* for DTYPE_VNODE */
49: #include <sys/file.h>
50: #undef _KERNEL
51:
52: #include <err.h>
53: #include <fcntl.h>
54: #include <pwd.h>
55: #include <signal.h>
56: #include <stdio.h>
57: #include <stdlib.h>
58: #include <string.h>
59: #include <unistd.h>
60:
61: #include "fstat.h"
62:
63: /*
64: * Returns 1 if the file watched (fa) is equivalent
65: * to a file held by a process (kf), else 0.
66: */
67: static int
1.3 guenther 68: match(struct filearg *fa, struct kinfo_file *kf)
1.1 millert 69: {
70: if (fa->dev == kf->va_fsid) {
71: if (cflg)
72: return (1);
73: if (fa->ino == kf->va_fileid)
74: return (1);
75: }
76: return (0);
77: }
78:
79: /*
1.3 guenther 80: * Examine kinfo_file struct and record the details if they
1.1 millert 81: * match a watched file.
82: */
83: void
1.3 guenther 84: fuser_check(struct kinfo_file *kf)
1.1 millert 85: {
86: struct filearg *fa;
87: struct fuser *fu;
88:
89: if (kf->f_type != DTYPE_VNODE)
90: return;
91:
92: SLIST_FOREACH(fa, &fileargs, next) {
93: if (!match(fa, kf))
94: continue;
95:
96: /*
97: * This assumes that kinfo_files2 returns all files
98: * associated with a process in a contiguous block.
99: */
100: if (TAILQ_EMPTY(&fa->fusers) || kf->p_pid !=
101: (fu = TAILQ_LAST(&fa->fusers, fuserhead))->pid) {
102: fu = malloc(sizeof(*fu));
103: if (fu == NULL)
104: err(1, NULL);
105: fu->pid = kf->p_pid;
106: fu->uid = kf->p_uid;
107: fu->flags = 0;
108: TAILQ_INSERT_TAIL(&fa->fusers, fu, tq);
109: }
110: switch (kf->fd_fd) {
111: case KERN_FILE_CDIR:
112: fu->flags |= F_CWD;
113: break;
114: case KERN_FILE_RDIR:
115: fu->flags |= F_ROOT;
116: break;
1.2 millert 117: case KERN_FILE_TEXT:
118: fu->flags |= F_TEXT;
119: break;
1.1 millert 120: case KERN_FILE_TRACE:
121: /* ignore */
122: break;
123: default:
124: fu->flags |= F_OPEN;
125: break;
126: }
127: }
128: }
129:
130: /*
131: * Print out the specfics for a given file/filesystem
132: */
133: static void
134: printfu(struct fuser *fu)
135: {
1.7 ! millert 136: const char *name;
1.1 millert 137:
138: printf("%d", fu->pid);
139: fflush(stdout);
140:
141: if (fu->flags & F_CWD)
142: fprintf(stderr, "c");
143:
144: if (fu->flags & F_ROOT)
145: fprintf(stderr, "r");
1.2 millert 146:
147: if (fu->flags & F_TEXT)
148: fprintf(stderr, "t");
1.1 millert 149:
150: if (uflg) {
1.7 ! millert 151: name = user_from_uid(fu->uid, 1);
! 152: if (name != NULL)
! 153: fprintf(stderr, "(%s)", name);
1.1 millert 154: else
1.7 ! millert 155: fprintf(stderr, "(%u)", fu->uid);
1.1 millert 156: }
157:
158: putchar(' ');
159: }
160:
161: /*
162: * For each file, print matching process info and optionally send a signal.
163: */
164: void
165: fuser_run(void)
166: {
167: struct filearg *fa;
168: struct fuser *fu;
169: pid_t mypid = getpid();
170:
171: SLIST_FOREACH(fa, &fileargs, next) {
172: fprintf(stderr, "%s: ", fa->name);
173: TAILQ_FOREACH(fu, &fa->fusers, tq) {
174: printfu(fu);
175: if (sflg && fu->pid != mypid) {
176: kill(fu->pid, signo);
177: }
178: }
179: fflush(stdout);
180: fprintf(stderr, "\n");
181: }
182: }