1/*	$NetBSD: kvm_file.c,v 1.27 2010/09/19 02:07:00 jym Exp $	*/
2
3/*-
4 * Copyright (c) 1989, 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#if defined(LIBC_SCCS) && !defined(lint)
34#if 0
35static char sccsid[] = "@(#)kvm_file.c	8.1 (Berkeley) 6/4/93";
36#else
37__RCSID("$NetBSD: kvm_file.c,v 1.27 2010/09/19 02:07:00 jym Exp $");
38#endif
39#endif /* LIBC_SCCS and not lint */
40
41/*
42 * File list interface for kvm.  pstat, fstat and netstat are
43 * users of this code, so we've factored it out into a separate module.
44 * Thus, we keep this grunge out of the other kvm applications (i.e.,
45 * most other applications are interested only in open/close/read/nlist).
46 */
47
48#define _KERNEL
49#include <sys/types.h>
50#undef _KERNEL
51#include <sys/param.h>
52#include <sys/user.h>
53#include <sys/lwp.h>
54#include <sys/proc.h>
55#include <sys/exec.h>
56#define _KERNEL
57#include <sys/file.h>
58#undef _KERNEL
59#include <sys/stat.h>
60#include <sys/ioctl.h>
61#include <nlist.h>
62#include <kvm.h>
63
64#include <uvm/uvm_extern.h>
65
66#include <sys/sysctl.h>
67
68#include <limits.h>
69#include <ndbm.h>
70#include <paths.h>
71#include <string.h>
72
73#include "kvm_private.h"
74
75static int
76kvm_deadfiles(kvm_t *, int, int, long, int);
77
78/*
79 * Get file structures.
80 */
81/*ARGSUSED*/
82static int
83kvm_deadfiles(kvm_t *kd, int op, int arg, long ofhead, int numfiles)
84{
85	size_t buflen = kd->argspc_len, n = 0;
86	struct file *fp;
87	struct filelist fhead;
88	char *where = kd->argspc;
89
90	/*
91	 * first copyout filehead
92	 */
93	if (buflen < sizeof(fhead) ||
94	    KREAD(kd, (u_long)ofhead, &fhead)) {
95		_kvm_err(kd, kd->program, "can't read filehead");
96		return (0);
97	}
98	buflen -= sizeof(fhead);
99	where += sizeof(fhead);
100	(void)memcpy(kd->argspc, &fhead, sizeof(fhead));
101
102	/*
103	 * followed by an array of file structures
104	 */
105	for (fp = fhead.lh_first; fp != 0; fp = fp->f_list.le_next) {
106		if (buflen > sizeof(struct file)) {
107			if (KREAD(kd, (u_long)fp,
108			    ((struct file *)(void *)where))) {
109				_kvm_err(kd, kd->program, "can't read kfp");
110				return (0);
111			}
112			buflen -= sizeof(struct file);
113			fp = (struct file *)(void *)where;
114			where += sizeof(struct file);
115			n++;
116		}
117	}
118	if (n != numfiles) {
119		_kvm_err(kd, kd->program, "inconsistent nfiles");
120		return (0);
121	}
122	return (numfiles);
123}
124
125char *
126kvm_getfiles(kvm_t *kd, int op, int arg, int *cnt)
127{
128	size_t size;
129	int mib[2], st;
130	int numfiles;
131	struct file *fp, *fplim;
132	struct filelist fhead;
133
134	if (ISSYSCTL(kd)) {
135		size = 0;
136		mib[0] = CTL_KERN;
137		mib[1] = KERN_FILE;
138		st = sysctl(mib, 2, NULL, &size, NULL, 0);
139		if (st == -1) {
140			_kvm_syserr(kd, kd->program, "kvm_getprocs");
141			return (0);
142		}
143		KVM_ALLOC(kd, argspc, size);
144		st = sysctl(mib, 2, kd->argspc, &size, NULL, 0);
145		if (st == -1 || size < sizeof(fhead)) {
146			_kvm_syserr(kd, kd->program, "kvm_getfiles");
147			return (0);
148		}
149		(void)memcpy(&fhead, kd->argspc, sizeof(fhead));
150		fp = (struct file *)(void *)(kd->argspc + sizeof(fhead));
151		fplim = (struct file *)(void *)(kd->argspc + size);
152		for (numfiles = 0; fhead.lh_first && (fp < fplim);
153		    numfiles++, fp++)
154			fhead.lh_first = fp->f_list.le_next;
155	} else {
156		struct nlist nl[3], *p;
157
158		nl[0].n_name = "_nfiles";
159		nl[1].n_name = "_filehead";
160		nl[2].n_name = 0;
161
162		if (kvm_nlist(kd, nl) != 0) {
163			for (p = nl; p->n_type != 0; ++p)
164				;
165			_kvm_err(kd, kd->program,
166				 "%s: no such symbol", p->n_name);
167			return (0);
168		}
169		if (KREAD(kd, nl[0].n_value, &numfiles)) {
170			_kvm_err(kd, kd->program, "can't read numfiles");
171			return (0);
172		}
173		size = sizeof(fhead) + (numfiles + 10) * sizeof(struct file);
174		KVM_ALLOC(kd, argspc, size);
175		numfiles = kvm_deadfiles(kd, op, arg, (long)nl[1].n_value,
176		    numfiles);
177		if (numfiles == 0)
178			return (0);
179	}
180	*cnt = numfiles;
181	return (kd->argspc);
182}
183