procfs_vnops.c revision 1.1 1 /*
2 * %W% (Erasmus) %G% - pk (at) cs.few.eur.nl
3 */
4
5 #include "param.h"
6 #include "systm.h"
7 #include "time.h"
8 #include "kernel.h"
9 #include "ioctl.h"
10 #include "file.h"
11 #include "proc.h"
12 #include "buf.h"
13 #include "vnode.h"
14 #include "namei.h"
15 #include "resourcevar.h"
16 #include "vm/vm.h"
17 #include "kinfo.h"
18 #include "kinfo_proc.h"
19
20 #include "procfs.h"
21 #include "pfsnode.h"
22
23 #include "machine/vmparam.h"
24
25 /*
26 * procfs vnode operations.
27 */
28 struct vnodeops pfs_vnodeops = {
29 pfs_lookup, /* lookup */
30 pfs_create, /* create */
31 pfs_mknod, /* mknod */
32 pfs_open, /* open */
33 pfs_close, /* close */
34 pfs_access, /* access */
35 pfs_getattr, /* getattr */
36 pfs_setattr, /* setattr */
37 pfs_read, /* read */
38 pfs_write, /* write */
39 pfs_ioctl, /* ioctl */
40 pfs_select, /* select */
41 pfs_mmap, /* mmap */
42 pfs_fsync, /* fsync */
43 pfs_seek, /* seek */
44 pfs_remove, /* remove */
45 pfs_link, /* link */
46 pfs_rename, /* rename */
47 pfs_mkdir, /* mkdir */
48 pfs_rmdir, /* rmdir */
49 pfs_symlink, /* symlink */
50 pfs_readdir, /* readdir */
51 pfs_readlink, /* readlink */
52 pfs_abortop, /* abortop */
53 pfs_inactive, /* inactive */
54 pfs_reclaim, /* reclaim */
55 pfs_lock, /* lock */
56 pfs_unlock, /* unlock */
57 pfs_bmap, /* bmap */
58 pfs_strategy, /* strategy */
59 pfs_print, /* print */
60 pfs_islocked, /* islocked */
61 pfs_advlock, /* advlock */
62 };
63
64 /*
65 * Vnode Operations.
66 *
67 */
68 /* ARGSUSED */
69 int
70 pfs_open(vp, mode, cred, p)
71 register struct vnode *vp;
72 int mode;
73 struct ucred *cred;
74 struct proc *p;
75 {
76 struct pfsnode *pfsp = VTOPFS(vp);
77
78 #ifdef DEBUG
79 if (pfs_debug)
80 printf("pfs_open: vp 0x%x, proc %d\n", vp, p->p_pid);
81 #endif
82
83 if ((pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0) == NULL)
84 return ESRCH;
85
86 if ( (pfsp->flags & FWRITE) && (mode & O_EXCL) ||
87 (pfsp->flags & O_EXCL) && (mode & FWRITE) )
88 return EBUSY;
89
90
91 if (mode & FWRITE)
92 pfsp->flags = (mode & (FWRITE|O_EXCL));
93 return 0;
94 }
95
96 /*
97 * /proc filesystem close routine
98 */
99 /* ARGSUSED */
100 int
101 pfs_close(vp, flag, cred, p)
102 register struct vnode *vp;
103 int flag;
104 struct ucred *cred;
105 struct proc *p;
106 {
107 struct pfsnode *pfsp = VTOPFS(vp);
108
109 #ifdef DEBUG
110 if (pfs_debug)
111 printf("pfs_close: vp 0x%x proc %d\n", vp, p->p_pid);
112 #endif
113 if ((flag & FWRITE) && (pfsp->flags & O_EXCL))
114 pfsp->flags &= ~(FWRITE|O_EXCL);
115
116 return (0);
117 }
118
119 /*
120 * Ioctl operation.
121 */
122 /* ARGSUSED */
123 int
124 pfs_ioctl(vp, com, data, fflag, cred, p)
125 struct vnode *vp;
126 int com;
127 caddr_t data;
128 int fflag;
129 struct ucred *cred;
130 struct proc *p;
131 {
132 int error = 0;
133 struct proc *procp;
134 struct pfsnode *pfsp = VTOPFS(vp);
135
136 procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
137 if (!procp)
138 return ESRCH;
139
140 switch (com) {
141
142 case PIOCGPINFO: {
143 int copysize = sizeof(struct kinfo_proc), needed;
144 kinfo_doproc(KINFO_PROC_PID, data, ©size,
145 pfsp->pfs_pid, &needed);
146 break;
147 }
148
149 #ifdef notyet /* Changes to proc.h needed */
150 case PIOCGSIGSET:
151 procp->p_psigset = *(sigset_t *)data;
152 break;
153
154 case PIOCSSIGSET:
155 *(sigset_t *)data = procp->p_psigset;
156 break;
157
158 case PIOCGFLTSET:
159 procp->p_pfltset = *(sigflt_t *)data;
160 break;
161
162 case PIOCSFLTSET:
163 *(fltset_t *)data = procp->p_pfltset;
164 break;
165 #endif
166
167 case PIOCGMAPFD:
168 error = pfs_vmfd(procp, pfsp, (struct vmfd *)data, p);
169 break;
170
171 case PIOCGNMAP:
172 *(int *)data = pfs_vm_nentries(procp, pfsp);
173 break;
174
175 case PIOCGMAP:
176 error = pfs_vmmap(procp, pfsp, *(struct procmap *)data);
177 break;
178
179 default:
180 error = EIO;
181 break;
182 }
183 return error;
184 }
185
186 /*
187 * Pass I/O requests to the memory filesystem process.
188 */
189 int
190 pfs_strategy(bp)
191 register struct buf *bp;
192 {
193 struct vnode *vp;
194 struct proc *p = curproc; /* XXX */
195
196 return (0);
197 }
198
199 /*
200 * This is a noop, simply returning what one has been given.
201 */
202 int
203 pfs_bmap(vp, bn, vpp, bnp)
204 struct vnode *vp;
205 daddr_t bn;
206 struct vnode **vpp;
207 daddr_t *bnp;
208 {
209
210 if (vpp != NULL)
211 *vpp = vp;
212 if (bnp != NULL)
213 *bnp = bn;
214 return (0);
215 }
216
217 /*
218 * /proc filesystem inactive routine
219 */
220 /* ARGSUSED */
221 int
222 pfs_inactive(vp, p)
223 struct vnode *vp;
224 struct proc *p;
225 {
226 struct pfsnode *pfsp = VTOPFS(vp);
227
228 #if 0
229 if ((pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0) && vp->v_usecount == 0)
230 vgone(vp);
231 #endif
232 if (vp->v_usecount == 0)
233 vgone(vp);
234 return 0;
235 }
236
237 /*
238 * /proc filesystem reclaim routine
239 */
240 /* ARGSUSED */
241 int
242 pfs_reclaim(vp)
243 struct vnode *vp;
244 {
245 struct pfsnode **pp, *pfsp = VTOPFS(vp);
246
247 for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) {
248 if (*pp == pfsp) {
249 *pp = pfsp->pfs_next;
250 break;
251 }
252 }
253 return 0;
254 }
255
256 /*
257 * Print out the contents of an pfsnode.
258 */
259 void
260 pfs_print(vp)
261 struct vnode *vp;
262 {
263 return;
264 }
265
266 /*
267 * /proc bad operation
268 */
269 int
270 pfs_badop()
271 {
272 printf("pfs_badop called\n");
273 return EIO;
274 }
275
276 #if 0 /* Moved to pfs_subr.c */
277 /*
278 * Vnode op for reading/writing.
279 */
280 /* ARGSUSED */
281 int
282 pfs_doio(vp, uio, ioflag, cred)
283 struct vnode *vp;
284 register struct uio *uio;
285 int ioflag;
286 struct ucred *cred;
287 {
288 struct pfsnode *pfsp = VTOPFS(vp);
289 struct proc *procp;
290 int error = 0;
291 long n, off;
292 caddr_t kva;
293
294 #ifdef DEBUG
295 if (pfs_debug)
296 printf("pfs_doio(%s): vp 0x%x, proc %x\n",
297 uio->uio_rw==UIO_READ?"R":"W", vp, uio->uio_procp);
298 #endif
299
300 #ifdef DIAGNOSTIC
301 if (vp->v_type != VPROC)
302 panic("pfs_doio vtype");
303 #endif
304 procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
305 if (!procp)
306 return ESRCH;
307
308 if (uio->uio_resid == 0)
309 return (0);
310 if (uio->uio_offset < 0)
311 return (EINVAL);
312
313 do { /* One page at a time */
314 off = uio->uio_offset - trunc_page(uio->uio_offset);
315 n = MIN(PAGE_SIZE-off, uio->uio_resid);
316
317 /* Map page into kernel space */
318 error = pfs_map(procp, &kva, uio->uio_rw, uio->uio_offset);
319 if (error)
320 return error;
321
322 error = uiomove(kva + off, (int)n, uio);
323 pfs_unmap(procp, kva);
324
325 } while (error == 0 && uio->uio_resid > 0);
326
327 return (error);
328 }
329 #endif
330
331 /*
332 * Make up some attributes for a process file
333 */
334 int
335 pfs_getattr (vp, vap, cred, p)
336 struct vnode *vp;
337 struct vattr *vap;
338 struct ucred *cred;
339 struct proc *p;
340 {
341 struct pfsnode *pfsp = VTOPFS(vp);
342 struct proc *procp;
343
344 VATTR_NULL(vap);
345 vap->va_type = vp->v_type;
346
347 if (vp->v_flag & VROOT) {
348 vap->va_mode = 0755;
349 vap->va_nlink = 2;
350 vap->va_size =
351 roundup((2+nprocs)*sizeof(struct pfsdent), DIRBLKSIZ);
352 vap->va_size_rsv = 0;
353 vap->va_uid = 0;
354 vap->va_gid = 0;
355 vap->va_atime = vap->va_mtime = vap->va_ctime = time; /*XXX*/
356 return 0;
357 }
358
359 procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
360 if (!procp)
361 return ESRCH;
362
363 vap->va_mode = 0700;
364 vap->va_nlink = 1;
365 vap->va_size = ctob( procp->p_vmspace->vm_tsize +
366 procp->p_vmspace->vm_dsize +
367 procp->p_vmspace->vm_ssize);
368 vap->va_size_rsv = 0;
369 vap->va_blocksize = page_size;
370 vap->va_uid = procp->p_ucred->cr_uid;
371 vap->va_gid = procp->p_ucred->cr_gid;
372 if (vap->va_uid != procp->p_cred->p_ruid)
373 vap->va_mode |= VSUID;
374 if (vap->va_gid != procp->p_cred->p_rgid)
375 vap->va_mode |= VSGID;
376 if (procp->p_flag & SLOAD) {
377 vap->va_atime = vap->va_mtime = vap->va_ctime =
378 procp->p_stats->p_start;
379 }
380
381 return 0;
382 }
383
384 int
385 pfs_access (vp, mode, cred, p)
386 struct vnode *vp;
387 int mode;
388 struct ucred *cred;
389 struct proc *p;
390 {
391 register struct vattr *vap;
392 register gid_t *gp;
393 struct vattr vattr;
394 register int i;
395 int error;
396
397 /*
398 * If you're the super-user,
399 * you always get access.
400 */
401 if (cred->cr_uid == 0)
402 return (0);
403 vap = &vattr;
404 if (error = pfs_getattr(vp, vap, cred, p))
405 return (error);
406 /*
407 * Access check is based on only one of owner, group, public.
408 * If not owner, then check group. If not a member of the
409 * group, then check public access.
410 */
411 if (cred->cr_uid != vap->va_uid) {
412 mode >>= 3;
413 gp = cred->cr_groups;
414 for (i = 0; i < cred->cr_ngroups; i++, gp++)
415 if (vap->va_gid == *gp)
416 goto found;
417 mode >>= 3;
418 found:
419 ;
420 }
421 if ((vap->va_mode & mode) != 0)
422 return (0);
423 return (EACCES);
424 }
425
426 /*
427 * /proc lookup
428 */
429 int
430 pfs_lookup(vp, ndp, p)
431 register struct vnode *vp;
432 register struct nameidata *ndp;
433 struct proc *p;
434 {
435 int lockparent, wantparent, flag, error = 0;
436 pid_t pid;
437 struct vnode *nvp;
438 struct pfsnode *pfsp;
439 struct proc *procp;
440
441 #ifdef DEBUG
442 if (pfs_debug)
443 printf("pfs_lookup: vp 0x%x name %s proc %d\n",
444 vp, ndp->ni_ptr, p->p_pid);
445 #endif
446
447 ndp->ni_dvp = vp;
448 ndp->ni_vp = NULL;
449 if (vp->v_type != VDIR)
450 return (ENOTDIR);
451
452 lockparent = ndp->ni_nameiop & LOCKPARENT;
453 flag = ndp->ni_nameiop & OPMASK;
454 wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
455 if (flag != LOOKUP)
456 return EACCES;
457 if (ndp->ni_isdotdot) {
458 /* Should not happen */
459 printf("pfs_lookup: vp 0x%x: dotdot\n", vp);
460 return EIO;
461 }
462 if (ndp->ni_namelen == 1 && *ndp->ni_ptr == '.') {
463 VREF(vp);
464 ndp->ni_vp = vp;
465 return 0;
466 }
467
468 pid = (pid_t)atoi(ndp->ni_ptr, ndp->ni_namelen);
469 if (pid == (pid_t)-1)
470 return ENOENT;
471
472 if ((procp = pid?pfind(pid):&proc0) == NULL)
473 return ENOENT;
474
475 for (pfsp = pfshead; pfsp != NULL; pfsp = pfsp->pfs_next) {
476 if (pfsp->pfs_pid == pid)
477 break;
478 }
479
480 if (pfsp == NULL) {
481 struct pfsnode **pp;
482 error = getnewvnode(VT_PROCFS, vp->v_mount, &pfs_vnodeops, &nvp);
483 if (error)
484 return error;
485
486 nvp->v_type = VPROC;
487 pfsp = VTOPFS(nvp);
488 pfsp->pfs_pid = pid;
489 pfsp->pfs_vnode = nvp;
490 for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next);
491 *pp = pfsp;
492
493 }
494 ndp->ni_vp = pfsp->pfs_vnode;
495
496 return (error);
497 }
498
499 int
500 pfs_readdir(vp, uio, cred, eofflagp)
501 struct vnode *vp;
502 register struct uio *uio;
503 struct ucred *cred;
504 int *eofflagp;
505 {
506 int error = 0;
507 int count, lost, pcnt, skipcnt, doingzomb = 0;
508 struct proc *p;
509 struct pfsdent dent;
510
511 #ifdef DEBUG
512 if (pfs_debug)
513 printf("pfs_readdir: vp 0x%x proc %d\n",
514 vp, uio->uio_procp->p_pid);
515 #endif
516 count = uio->uio_resid;
517 count &= ~(DIRBLKSIZ - 1);
518 lost = uio->uio_resid - count;
519 if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
520 return (EINVAL);
521 uio->uio_resid = count;
522 uio->uio_iov->iov_len = count;
523 *eofflagp = 1;
524 skipcnt = uio->uio_offset / sizeof(struct pfsdent);
525
526 count = 0;
527 if (skipcnt == 0) {
528 /* Fake "." and ".." entries? */
529 #if 1
530 dent.d_fileno = 2; /* XXX - Filesystem root */
531 dent.d_reclen = sizeof(struct pfsdent);
532
533 dent.d_namlen = 1;
534 dent.d_nam[0] = '.';
535 dent.d_nam[1] = '\0';
536 error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio);
537 if (error)
538 return error;
539
540 dent.d_fileno = 2;
541 dent.d_namlen = 2;
542 dent.d_nam[1] = '.';
543 dent.d_nam[2] = '\0';
544 error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio);
545 if (error)
546 return error;
547 #endif
548 count += 2*dent.d_reclen;
549 }
550
551 p = allproc;
552 for (pcnt = 0; p && uio->uio_resid; pcnt++) {
553 if (pcnt < skipcnt) {
554 p = p->p_nxt;
555 if (p == NULL && doingzomb == 0) {
556 doingzomb = 1;
557 p = zombproc;
558 }
559 continue;
560 }
561 *eofflagp = 0;
562
563 /* "inode" is process slot (actually position on list) */
564 dent.d_fileno = (unsigned long)(pcnt+1);
565 dent.d_namlen = itos((unsigned int)p->p_pid, dent.d_nam);
566 dent.d_nam[dent.d_namlen] = '\0';
567
568 p = p->p_nxt;
569 if (p == NULL && doingzomb == 0) {
570 doingzomb = 1;
571 p = zombproc;
572 }
573 if (p == NULL) {
574 /* Extend 'reclen' to end of block */;
575 dent.d_reclen = DIRBLKSIZ - (count & (DIRBLKSIZ - 1));
576 } else
577 dent.d_reclen = sizeof(struct pfsdent);
578 count += dent.d_reclen;
579 error = uiomove((char *)&dent, dent.d_reclen, uio);
580 if (error)
581 break;
582 }
583 if (count == 0)
584 *eofflagp = 1;
585
586 uio->uio_resid += lost;
587 return error;
588 }
589
590 /*
591 * convert n to decimal representation in character array b
592 * return number of decimal digits produced.
593 */
594 int
595 itos(n, b)
596 unsigned int n;
597 char *b;
598 {
599 #define BASE 10
600 int m = (n<BASE)?0:itos(n/BASE, b);
601
602 *(b+m) = "0123456789abcdef"[n%BASE];
603 return m+1;
604 }
605
606 /*
607 * convert decimal ascii representation in b of length len to integer
608 */
609 int
610 atoi(b, len)
611 char *b;
612 unsigned int len;
613 {
614 int n = 0;
615
616 while (len--) {
617 register char c = *b++;
618 if (c < '0' || c > '9')
619 return -1;
620 n = 10 * n + (c - '0');
621 }
622 return n;
623 }
624