1 /* $OpenBSD: fuser.c,v 1.4 2014/07/10 14:25:29 deraadt Exp $ */ 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/param.h> 45 #include <sys/queue.h> 46 #include <sys/stat.h> 47 #include <sys/sysctl.h> 48 #define _KERNEL /* for DTYPE_VNODE */ 49 #include <sys/ucred.h> 50 #include <sys/file.h> 51 #undef _KERNEL 52 53 #include <err.h> 54 #include <fcntl.h> 55 #include <pwd.h> 56 #include <signal.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 #include "fstat.h" 63 64 /* 65 * Returns 1 if the file watched (fa) is equivalent 66 * to a file held by a process (kf), else 0. 67 */ 68 static int 69 match(struct filearg *fa, struct kinfo_file *kf) 70 { 71 if (fa->dev == kf->va_fsid) { 72 if (cflg) 73 return (1); 74 if (fa->ino == kf->va_fileid) 75 return (1); 76 } 77 return (0); 78 } 79 80 /* 81 * Examine kinfo_file struct and record the details if they 82 * match a watched file. 83 */ 84 void 85 fuser_check(struct kinfo_file *kf) 86 { 87 struct filearg *fa; 88 struct fuser *fu; 89 90 if (kf->f_type != DTYPE_VNODE) 91 return; 92 93 SLIST_FOREACH(fa, &fileargs, next) { 94 if (!match(fa, kf)) 95 continue; 96 97 /* 98 * This assumes that kinfo_files2 returns all files 99 * associated with a process in a contiguous block. 100 */ 101 if (TAILQ_EMPTY(&fa->fusers) || kf->p_pid != 102 (fu = TAILQ_LAST(&fa->fusers, fuserhead))->pid) { 103 fu = malloc(sizeof(*fu)); 104 if (fu == NULL) 105 err(1, NULL); 106 fu->pid = kf->p_pid; 107 fu->uid = kf->p_uid; 108 fu->flags = 0; 109 TAILQ_INSERT_TAIL(&fa->fusers, fu, tq); 110 } 111 switch (kf->fd_fd) { 112 case KERN_FILE_CDIR: 113 fu->flags |= F_CWD; 114 break; 115 case KERN_FILE_RDIR: 116 fu->flags |= F_ROOT; 117 break; 118 case KERN_FILE_TEXT: 119 fu->flags |= F_TEXT; 120 break; 121 case KERN_FILE_TRACE: 122 /* ignore */ 123 break; 124 default: 125 fu->flags |= F_OPEN; 126 break; 127 } 128 } 129 } 130 131 /* 132 * Print out the specfics for a given file/filesystem 133 */ 134 static void 135 printfu(struct fuser *fu) 136 { 137 struct passwd *pwd; 138 139 printf("%d", fu->pid); 140 fflush(stdout); 141 142 if (fu->flags & F_CWD) 143 fprintf(stderr, "c"); 144 145 if (fu->flags & F_ROOT) 146 fprintf(stderr, "r"); 147 148 if (fu->flags & F_TEXT) 149 fprintf(stderr, "t"); 150 151 if (uflg) { 152 pwd = getpwuid(fu->uid); 153 if (pwd != NULL) 154 fprintf(stderr, "(%s)", pwd->pw_name); 155 else 156 fprintf(stderr, "(%d)", fu->uid); 157 } 158 159 putchar(' '); 160 } 161 162 /* 163 * For each file, print matching process info and optionally send a signal. 164 */ 165 void 166 fuser_run(void) 167 { 168 struct filearg *fa; 169 struct fuser *fu; 170 pid_t mypid = getpid(); 171 172 SLIST_FOREACH(fa, &fileargs, next) { 173 fprintf(stderr, "%s: ", fa->name); 174 TAILQ_FOREACH(fu, &fa->fusers, tq) { 175 printfu(fu); 176 if (sflg && fu->pid != mypid) { 177 kill(fu->pid, signo); 178 } 179 } 180 fflush(stdout); 181 fprintf(stderr, "\n"); 182 } 183 } 184