merge in vnodes
[unix-history] / usr / src / sys / kern / kern_ktrace.c
CommitLineData
2d68027d
MT
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
c4ec2128 17 * @(#)kern_ktrace.c 1.4 (Berkeley) %G%
2d68027d
MT
18 */
19
20#ifdef KTRACE
21
22#include "param.h"
2d68027d 23#include "user.h"
2d68027d 24#include "proc.h"
c4ec2128
KM
25#include "file.h"
26#include "vnode.h"
2d68027d
MT
27#include "ktrace.h"
28#include "malloc.h"
29
f73d8bd6 30#include "syscalls.c"
2d68027d
MT
31
32extern int nsysent;
33extern char *syscallnames[];
34
f73d8bd6
MT
35int ktrace_nocheck = 1;
36
2d68027d
MT
37struct ktr_header *
38ktrgetheader(type)
39{
40 register struct ktr_header *kth;
41
42 MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
43 M_TEMP, M_WAITOK);
2d68027d 44 kth->ktr_type = type;
f73d8bd6 45 microtime(&kth->ktr_time);
2d68027d
MT
46 kth->ktr_pid = u.u_procp->p_pid;
47 bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN);
2d68027d
MT
48 return (kth);
49}
50
c4ec2128
KM
51ktrsyscall(vp, code, narg)
52 struct vnode *vp;
2d68027d
MT
53{
54 struct ktr_header *kth = ktrgetheader(KTR_SYSCALL);
55 struct ktr_syscall *ktp;
56 register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
57 int *argp, i;
58
f73d8bd6 59 if (kth == NULL)
2d68027d 60 return;
2d68027d 61 MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
2d68027d
MT
62 ktp->ktr_code = code;
63 ktp->ktr_narg = narg;
64 argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
65 for (i = 0; i < narg; i++)
66 *argp++ = u.u_arg[i];
67 kth->ktr_buf = (caddr_t)ktp;
68 kth->ktr_len = len;
c4ec2128 69 ktrwrite(vp, kth);
2d68027d
MT
70 FREE(ktp, M_TEMP);
71 FREE(kth, M_TEMP);
72}
73
c4ec2128
KM
74ktrsysret(vp, code)
75 struct vnode *vp;
2d68027d
MT
76{
77 struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
78 struct ktr_sysret *ktp;
79
f73d8bd6 80 if (kth == NULL)
2d68027d 81 return;
2d68027d
MT
82 MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret),
83 M_TEMP , M_WAITOK);
2d68027d
MT
84 ktp->ktr_code = code;
85 ktp->ktr_eosys = u.u_eosys;
86 ktp->ktr_error = u.u_error;
87 ktp->ktr_retval = u.u_r.r_val1; /* what about val2 ? */
88
89 kth->ktr_buf = (caddr_t)ktp;
90 kth->ktr_len = sizeof(struct ktr_sysret);
91
c4ec2128 92 ktrwrite(vp, kth);
2d68027d
MT
93 FREE(ktp, M_TEMP);
94 FREE(kth, M_TEMP);
95}
96
c4ec2128
KM
97ktrnamei(vp, path)
98 struct vnode *vp;
2d68027d
MT
99 char *path;
100{
101 struct ktr_header *kth = ktrgetheader(KTR_NAMEI);
102
f73d8bd6 103 if (kth == NULL)
2d68027d 104 return;
2d68027d
MT
105 kth->ktr_len = strlen(path);
106 kth->ktr_buf = path;
107
c4ec2128 108 ktrwrite(vp, kth);
2d68027d
MT
109 FREE(kth, M_TEMP);
110}
111
c4ec2128
KM
112ktrgenio(vp, fd, rw, iov, len)
113 struct vnode *vp;
f73d8bd6
MT
114 enum uio_rw rw;
115 register struct iovec *iov;
116{
117 struct ktr_header *kth = ktrgetheader(KTR_GENIO);
118 register struct ktr_genio *ktp;
119 register caddr_t cp;
120 register int resid = len, cnt;
121
122 if (kth == NULL || u.u_error)
123 return;
124 MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
125 M_TEMP, M_WAITOK);
f73d8bd6
MT
126 ktp->ktr_fd = fd;
127 ktp->ktr_rw = rw;
128 cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
129 while (resid > 0) {
130 if ((cnt = iov->iov_len) > resid)
131 cnt = resid;
132 if (copyin(iov->iov_base, cp, cnt))
133 goto done;
134 cp += cnt;
135 resid -= cnt;
136 iov++;
137 }
138 kth->ktr_buf = (caddr_t)ktp;
139 kth->ktr_len = sizeof (struct ktr_genio) + len;
140
c4ec2128 141 ktrwrite(vp, kth);
f73d8bd6
MT
142done:
143 FREE(kth, M_TEMP);
144 FREE(ktp, M_TEMP);
145}
146
2d68027d
MT
147/*
148 * ktrace system call
149 */
150ktrace()
151{
2d68027d
MT
152 register struct a {
153 char *fname;
154 int ops;
155 int facs;
f73d8bd6 156 int pid;
2d68027d 157 } *uap = (struct a *)u.u_ap;
c4ec2128 158 register struct vnode *vp = NULL;
2d68027d
MT
159 register struct nameidata *ndp = &u.u_nd;
160 register struct proc *p;
161 struct pgrp *pg;
162 register int ops = uap->ops&0x3;
163 register int facs = uap->facs;
f73d8bd6 164 register int ret = 0;
2d68027d
MT
165
166 /*
167 * Until security implications are thought through,
f73d8bd6 168 * limit tracing to root (unless ktrace_nocheck is set).
2d68027d 169 */
849cbd39 170 if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag)))
2d68027d 171 return;
2d68027d
MT
172 if (ops != KTROP_CLEAR) {
173 /*
174 * an operation which requires a file argument.
175 */
2d68027d
MT
176 ndp->ni_segflg = UIO_USERSPACE;
177 ndp->ni_dirp = uap->fname;
c4ec2128 178 if (u.u_error = vn_open(ndp, FREAD|FWRITE, 0))
2d68027d 179 return;
c4ec2128
KM
180 vp = ndp->ni_vp;
181 if (vp->v_type != VREG) {
2d68027d 182 u.u_error = EACCES;
c4ec2128 183 vrele(vp);
2d68027d
MT
184 return;
185 }
2d68027d
MT
186 }
187 /*
188 * Clear all uses of the tracefile
189 */
190 if (ops == KTROP_CLEARFILE) {
191 for (p = allproc; p != NULL; p = p->p_nxt) {
c4ec2128 192 if (p->p_tracep == vp) {
2d68027d
MT
193 p->p_flag &= ~SKTR;
194 p->p_tracep = NULL;
195 p->p_traceflag = 0;
c4ec2128 196 vrele(vp);
2d68027d
MT
197 }
198 }
199 goto done;
200 }
201
202 /*
203 * need something to (un)trace
204 */
205 if (!facs) {
206 u.u_error = EINVAL;
207 goto done;
208 }
209
210 if (uap->pid < 0) {
211 pg = pgfind(-uap->pid);
212 if (pg == NULL) {
213 u.u_error = ESRCH;
214 goto done;
215 }
216 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
217 if (uap->ops&KTROP_INHERITFLAG)
c4ec2128 218 ret |= ktrsetchildren(p, ops, facs, vp);
2d68027d 219 else
c4ec2128 220 ret |= ktrops(p, ops, facs, vp);
2d68027d
MT
221
222 } else {
223 p = pfind(uap->pid);
224 if (p == NULL) {
225 u.u_error = ESRCH;
226 goto done;
227 }
228 if (uap->ops&KTROP_INHERITFLAG)
c4ec2128 229 ret |= ktrsetchildren(p, ops, facs, vp);
2d68027d 230 else
c4ec2128 231 ret |= ktrops(p, ops, facs, vp);
2d68027d 232 }
f73d8bd6
MT
233 if (!ret)
234 u.u_error = EPERM;
2d68027d 235done:
c4ec2128
KM
236 if (vp != NULL)
237 vrele(vp);
2d68027d
MT
238}
239
c4ec2128 240ktrops(p, ops, facs, vp)
2d68027d 241 struct proc *p;
c4ec2128 242 struct vnode *vp;
2d68027d 243{
f73d8bd6
MT
244
245 if (u.u_uid && u.u_uid != p->p_uid)
246 return 0;
2d68027d 247 if (ops == KTROP_SET) {
c4ec2128 248 if (p->p_tracep != vp) {
2d68027d
MT
249 /*
250 * if trace file already in use, relinquish
251 */
252 if (p->p_tracep != NULL)
c4ec2128
KM
253 vrele(p->p_tracep);
254 if (vp->v_count == 0)
255 panic("ktrace: bad vnode");
256 p->p_tracep = vp;
2d68027d
MT
257 }
258 p->p_traceflag |= facs;
259 } else {
260 /* KTROP_CLEAR */
261 if ((p->p_traceflag &= ~facs) == 0) {
262 if (p->p_tracep != NULL) {
c4ec2128 263 vrele(p->p_tracep);
2d68027d
MT
264 p->p_tracep = NULL;
265 }
f73d8bd6 266 p->p_flag &= ~SKTR;
2d68027d
MT
267 }
268 }
f73d8bd6
MT
269
270 return 1;
2d68027d 271}
f73d8bd6 272
c4ec2128 273ktrsetchildren(top, ops, facs, vp)
2d68027d 274 struct proc *top;
c4ec2128 275 struct vnode *vp;
2d68027d
MT
276{
277 register struct proc *p;
278 register int ndx;
f73d8bd6 279 register int ret = 0;
2d68027d
MT
280
281 p = top;
282 for (;;) {
c4ec2128 283 if ((ret |= ktrops(p, ops, facs, vp)) && ops == KTROP_SET)
2d68027d 284 p->p_flag |= SKTR;
2d68027d
MT
285 /*
286 * If this process has children, descend to them next,
287 * otherwise do any siblings, and if done with this level,
288 * follow back up the tree (but not past top).
289 */
290 if (p->p_cptr)
291 p = p->p_cptr;
292 else if (p == top)
f73d8bd6 293 return ret;
2d68027d
MT
294 else if (p->p_osptr)
295 p = p->p_osptr;
296 else for (;;) {
297 p = p->p_pptr;
298 if (p == top)
f73d8bd6 299 return ret;
2d68027d
MT
300 if (p->p_osptr) {
301 p = p->p_osptr;
302 break;
303 }
304 }
305 }
f73d8bd6 306 /*NOTREACHED*/
2d68027d
MT
307}
308
c4ec2128
KM
309ktrwrite(vp, kth)
310 struct vnode *vp;
311 register struct ktr_header *kth;
2d68027d 312{
c4ec2128
KM
313 struct uio auio;
314 struct iovec aiov[2];
315 int offset, error;
316
317 if (vp == NULL)
f73d8bd6 318 return;
c4ec2128
KM
319 auio.uio_iov = &aiov[0];
320 auio.uio_offset = 0;
321 auio.uio_segflg = UIO_SYSSPACE;
322 auio.uio_rw = UIO_WRITE;
323 aiov[0].iov_base = (caddr_t)kth;
324 aiov[0].iov_len = sizeof(struct ktr_header);
325 auio.uio_resid = sizeof(struct ktr_header);
326 auio.uio_iovcnt = 1;
2d68027d 327 if (kth->ktr_len > 0) {
c4ec2128
KM
328 auio.uio_iovcnt++;
329 aiov[1].iov_base = kth->ktr_buf;
330 aiov[1].iov_len = kth->ktr_len;
331 auio.uio_resid += kth->ktr_len;
2d68027d 332 }
c4ec2128 333 error = VOP_WRITE(vp, &auio, &offset, IO_UNIT|IO_APPEND, u.u_cred);
2d68027d 334}
2d68027d 335#endif