xref: /dragonfly/lib/libkvm/kvm_file.c (revision 7b1120e5)
1 /*-
2  * Copyright (c) 1989, 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)kvm_file.c	8.1 (Berkeley) 6/4/93
30  * $FreeBSD: src/lib/libkvm/kvm_file.c,v 1.11 2000/02/18 16:39:00 peter Exp $
31  */
32 
33 /*
34  * File list interface for kvm.
35  */
36 
37 #include <sys/user.h>	/* MUST BE FIRST */
38 #include <sys/param.h>
39 #include <sys/proc.h>
40 #define _KERNEL
41 #include <sys/file.h>
42 #undef _KERNEL
43 #include <sys/stat.h>
44 #include <sys/ioctl.h>
45 #include <sys/kinfo.h>
46 #include <nlist.h>
47 
48 #include <vm/vm.h>
49 #include <vm/vm_param.h>
50 #include <vm/swap_pager.h>
51 
52 #include <sys/sysctl.h>
53 
54 #include <limits.h>
55 #include <ndbm.h>
56 #include <paths.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 
61 #include "kvm.h"
62 #include "kvm_private.h"
63 
64 #define KREAD(kd, addr, obj) \
65 	(kvm_read(kd, addr, obj, sizeof(*obj)) != sizeof(*obj))
66 
67 /* XXX copied from sys/kern/subr_kcore.c */
68 static void
69 kcore_make_file(struct kinfo_file *ufile, struct file *kfile,
70     pid_t pid, uid_t owner, int n)
71 {
72 	bzero(ufile, sizeof(*ufile));
73 	ufile->f_size = sizeof(*ufile);
74 	ufile->f_pid = pid;
75 	ufile->f_uid = owner;
76 
77 	ufile->f_fd = n;
78 	ufile->f_file = kfile;
79 	ufile->f_data = kfile->f_data;
80 	ufile->f_type = kfile->f_type;
81 	ufile->f_count = kfile->f_count;
82 	ufile->f_msgcount = kfile->f_msgcount;
83 	ufile->f_offset = kfile->f_offset;
84 	ufile->f_flag = kfile->f_flag;
85 }
86 
87 /*
88  * Get file structures.
89  */
90 static int
91 kvm_deadfiles(kvm_t *kd, struct kinfo_proc *kproc, int kproc_cnt, int nfiles)
92 {
93 	struct kinfo_file *kinfo_file = (struct kinfo_file *)kd->argspc;
94 	struct fdnode *fd_files;
95 	size_t size;
96 	int i, fd_nfiles, found = 0;
97 
98 	fd_nfiles = NDFILE;
99 	fd_files = malloc(fd_nfiles * sizeof(struct fdnode));
100 	if (fd_files == NULL) {
101 		_kvm_err(kd, kd->program, "alloc fd_files failed");
102 		return 0;
103 	}
104 
105 	for (i = 0; i < kproc_cnt; ++i) {
106 		const struct kinfo_proc *kp = &kproc[i];
107 		struct filedesc fdp;
108 		int n, f;
109 
110 		if (kp->kp_fd == 0)
111 			continue;
112 		if (KREAD(kd, kp->kp_fd, &fdp)) {
113 			_kvm_err(kd, kd->program, "can't read fdp");
114 			free(fd_files);
115 			return 0;
116 		}
117 		if (fdp.fd_files == NULL)
118 			continue;
119 
120 		if (fdp.fd_nfiles > fd_nfiles) {
121 			struct fdnode *new_fd_files;
122 
123 			fd_nfiles = fdp.fd_nfiles;
124 			new_fd_files =
125 			    malloc(fd_nfiles * sizeof(struct fdnode));
126 			free(fd_files);
127 			if (new_fd_files == NULL) {
128 				_kvm_err(kd, kd->program,
129 				    "realloc fd_files failed");
130 				return 0;
131 			}
132 			fd_files = new_fd_files;
133 		}
134 		n = fdp.fd_nfiles * sizeof(struct fdnode);
135 
136 		if (kvm_read(kd, (uintptr_t)fdp.fd_files, fd_files, n) != n) {
137 			_kvm_err(kd, kd->program, "can't read fd_files");
138 			free(fd_files);
139 			return 0;
140 		}
141 		for (f = 0; f < fdp.fd_nfiles; ++f) {
142 			struct file kf;
143 
144 			if (fd_files[f].fp == NULL)
145 				continue;
146 			if (KREAD(kd, (uintptr_t)fd_files[f].fp, &kf)) {
147 				_kvm_err(kd, kd->program, "can't read file");
148 				free(fd_files);
149 				return 0;
150 			}
151 
152 			kcore_make_file(kinfo_file, &kf,
153 			    kp->kp_pid, kp->kp_uid, f);
154 			kinfo_file++;
155 			found++;
156 
157 			if (found == nfiles) {
158 				nfiles *= 2;
159 				size = nfiles * sizeof(struct kinfo_file);
160 
161 				kd->argspc = _kvm_realloc(kd, kd->argspc, size);
162 				if (kd->argspc == NULL) {
163 					free(fd_files);
164 					return 0;
165 				}
166 				kd->arglen = size;
167 
168 				kinfo_file = (struct kinfo_file *)kd->argspc;
169 				kinfo_file += found;
170 			}
171 		}
172 	}
173 	free(fd_files);
174 	return found;
175 }
176 
177 struct kinfo_file *
178 kvm_getfiles(kvm_t *kd, int op __unused, int arg __unused, int *cnt)
179 {
180 	int nfiles;
181 	size_t size;
182 
183 	if (kvm_ishost(kd)) {
184 		int mib[2], st;
185 
186 		size = 0;
187 		mib[0] = CTL_KERN;
188 		mib[1] = KERN_FILE;
189 		st = sysctl(mib, 2, NULL, &size, NULL, 0);
190 		if (st == -1) {
191 			_kvm_syserr(kd, kd->program, "sysctl KERN_FILE failed");
192 			return NULL;
193 		}
194 		if (kd->argspc == NULL)
195 			kd->argspc = _kvm_malloc(kd, size);
196 		else if (kd->arglen < (ssize_t)size)
197 			kd->argspc = _kvm_realloc(kd, kd->argspc, size);
198 		if (kd->argspc == NULL)
199 			return NULL;
200 		kd->arglen = size;
201 		st = sysctl(mib, 2, kd->argspc, &size, NULL, 0);
202 		if (st == -1 || size % sizeof(struct kinfo_file) != 0) {
203 			_kvm_syserr(kd, kd->program, "sysctl KERN_FILE failed");
204 			return NULL;
205 		}
206 		nfiles = size / sizeof(struct kinfo_file);
207 	} else {
208 		struct kinfo_proc *kproc0, *kproc;
209 		int kproc_cnt, kproc_len;
210 		struct nlist nl[2];
211 
212 		/*
213 		 * Get all processes and save them in kproc.
214 		 */
215 		kproc0 = kvm_getprocs(kd, KERN_PROC_ALL, 0, &kproc_cnt);
216 		if (kproc0 == NULL)
217 			return NULL;
218 		kproc_len = kproc_cnt * sizeof(struct kinfo_proc);
219 		kproc = malloc(kproc_len);
220 		if (kproc == NULL) {
221 			_kvm_syserr(kd, kd->program,
222 			    "malloc kinfo_proc failed");
223 			return NULL;
224 		}
225 		memcpy(kproc, kproc0, kproc_len);
226 
227 		/*
228 		 * Get the # of files
229 		 */
230 		memset(nl, 0, sizeof(nl));
231 		nl[0].n_name = "_nfiles";
232 		if (kvm_nlist(kd, nl) != 0) {
233 			_kvm_err(kd, kd->program, "%s: no such symbol",
234 			    nl[0].n_name);
235 			free(kproc);
236 			return NULL;
237 		}
238 		if (KREAD(kd, nl[0].n_value, &nfiles)) {
239 			_kvm_err(kd, kd->program, "can't read nfiles");
240 			free(kproc);
241 			return NULL;
242 		}
243 
244 		/*
245 		 * stdio/stderr/stdout are normally duplicated
246 		 * across all processes.
247 		 */
248 		nfiles += (kproc_cnt * 3);
249 		size = nfiles * sizeof(struct kinfo_file);
250 		if (kd->argspc == NULL)
251 			kd->argspc = _kvm_malloc(kd, size);
252 		else if (kd->arglen < (ssize_t)size)
253 			kd->argspc = _kvm_realloc(kd, kd->argspc, size);
254 		if (kd->argspc == NULL) {
255 			free(kproc);
256 			return NULL;
257 		}
258 		kd->arglen = size;
259 
260 		nfiles = kvm_deadfiles(kd, kproc, kproc_cnt, nfiles);
261 		free(kproc);
262 
263 		if (nfiles == 0)
264 			return NULL;
265 	}
266 	*cnt = nfiles;
267 	return (struct kinfo_file *)(kd->argspc);
268 }
269