1 /* $OpenBSD: fuser.c,v 1.3 2013/10/22 16:40:28 guenther 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/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 68 match(struct filearg *fa, struct kinfo_file *kf) 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 /* 80 * Examine kinfo_file struct and record the details if they 81 * match a watched file. 82 */ 83 void 84 fuser_check(struct kinfo_file *kf) 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; 117 case KERN_FILE_TEXT: 118 fu->flags |= F_TEXT; 119 break; 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 { 136 struct passwd *pwd; 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"); 146 147 if (fu->flags & F_TEXT) 148 fprintf(stderr, "t"); 149 150 if (uflg) { 151 pwd = getpwuid(fu->uid); 152 if (pwd != NULL) 153 fprintf(stderr, "(%s)", pwd->pw_name); 154 else 155 fprintf(stderr, "(%d)", fu->uid); 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 } 183