Annotation of src/sys/miscfs/procfs/procfs_vnops.c, Revision 1.157
1.157 ! agc 1: /* $NetBSD: procfs_vnops.c,v 1.156 2007/04/04 10:50:42 rmind Exp $ */
1.145 ad 2:
3: /*-
1.147 ad 4: * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
1.145 ad 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Andrew Doran.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
1.24 cgd 38:
1.1 pk 39: /*
1.53 fvdl 40: * Copyright (c) 1993, 1995
1.21 mycroft 41: * The Regents of the University of California. All rights reserved.
1.2 pk 42: *
1.9 cgd 43: * This code is derived from software contributed to Berkeley by
44: * Jan-Simon Pendry.
45: *
1.2 pk 46: * Redistribution and use in source and binary forms, with or without
47: * modification, are permitted provided that the following conditions
48: * are met:
49: * 1. Redistributions of source code must retain the above copyright
50: * notice, this list of conditions and the following disclaimer.
51: * 2. Redistributions in binary form must reproduce the above copyright
52: * notice, this list of conditions and the following disclaimer in the
53: * documentation and/or other materials provided with the distribution.
1.107 agc 54: * 3. Neither the name of the University nor the names of its contributors
55: * may be used to endorse or promote products derived from this software
56: * without specific prior written permission.
57: *
58: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68: * SUCH DAMAGE.
69: *
70: * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95
71: */
72:
73: /*
74: * Copyright (c) 1993 Jan-Simon Pendry
75: *
76: * This code is derived from software contributed to Berkeley by
77: * Jan-Simon Pendry.
78: *
79: * Redistribution and use in source and binary forms, with or without
80: * modification, are permitted provided that the following conditions
81: * are met:
82: * 1. Redistributions of source code must retain the above copyright
83: * notice, this list of conditions and the following disclaimer.
84: * 2. Redistributions in binary form must reproduce the above copyright
85: * notice, this list of conditions and the following disclaimer in the
86: * documentation and/or other materials provided with the distribution.
1.2 pk 87: * 3. All advertising materials mentioning features or use of this software
88: * must display the following acknowledgement:
1.9 cgd 89: * This product includes software developed by the University of
90: * California, Berkeley and its contributors.
91: * 4. Neither the name of the University nor the names of its contributors
92: * may be used to endorse or promote products derived from this software
93: * without specific prior written permission.
94: *
95: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
96: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
97: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
98: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
99: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
100: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
101: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
102: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
103: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
104: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
105: * SUCH DAMAGE.
1.2 pk 106: *
1.53 fvdl 107: * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95
1.2 pk 108: */
109:
110: /*
1.9 cgd 111: * procfs vnode interface
1.1 pk 112: */
1.85 lukem 113:
114: #include <sys/cdefs.h>
1.157 ! agc 115: __KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.156 2007/04/04 10:50:42 rmind Exp $");
1.1 pk 116:
1.8 mycroft 117: #include <sys/param.h>
118: #include <sys/systm.h>
119: #include <sys/time.h>
120: #include <sys/kernel.h>
121: #include <sys/file.h>
1.91 christos 122: #include <sys/filedesc.h>
1.8 mycroft 123: #include <sys/proc.h>
124: #include <sys/vnode.h>
125: #include <sys/namei.h>
1.9 cgd 126: #include <sys/malloc.h>
1.76 fvdl 127: #include <sys/mount.h>
1.21 mycroft 128: #include <sys/dirent.h>
1.8 mycroft 129: #include <sys/resourcevar.h>
1.48 mycroft 130: #include <sys/stat.h>
1.89 thorpej 131: #include <sys/ptrace.h>
1.130 elad 132: #include <sys/kauth.h>
1.48 mycroft 133:
1.71 mrg 134: #include <uvm/uvm_extern.h> /* for PAGE_SIZE */
1.48 mycroft 135:
1.21 mycroft 136: #include <machine/reg.h>
1.41 mycroft 137:
138: #include <miscfs/genfs/genfs.h>
1.9 cgd 139: #include <miscfs/procfs/procfs.h>
1.11 cgd 140:
1.9 cgd 141: /*
142: * Vnode Operations.
143: *
144: */
1.1 pk 145:
1.128 christos 146: static int procfs_validfile_linux(struct lwp *, struct mount *);
1.117 yamt 147: static int procfs_root_readdir_callback(struct proc *, void *);
1.128 christos 148: static struct vnode *procfs_dir(pfstype, struct lwp *, struct proc *,
1.126 atatat 149: char **, char *, int);
1.74 tv 150:
1.1 pk 151: /*
1.9 cgd 152: * This is a list of the valid names in the
153: * process-specific sub-directories. It is
154: * used in procfs_lookup and procfs_readdir
155: */
1.97 jdolecek 156: static const struct proc_target {
1.32 mycroft 157: u_char pt_type;
158: u_char pt_namlen;
1.97 jdolecek 159: const char *pt_name;
1.32 mycroft 160: pfstype pt_pfstype;
1.128 christos 161: int (*pt_valid)(struct lwp *, struct mount *);
1.32 mycroft 162: } proc_targets[] = {
1.9 cgd 163: #define N(s) sizeof(s)-1, s
1.32 mycroft 164: /* name type validp */
1.136 christos 165: { DT_DIR, N("."), PFSproc, NULL },
166: { DT_DIR, N(".."), PFSroot, NULL },
1.109 darcy 167: { DT_DIR, N("fd"), PFSfd, NULL },
1.136 christos 168: { DT_REG, N("file"), PFSfile, procfs_validfile },
1.109 darcy 169: { DT_REG, N("mem"), PFSmem, NULL },
1.136 christos 170: { DT_REG, N("regs"), PFSregs, procfs_validregs },
1.109 darcy 171: { DT_REG, N("fpregs"), PFSfpregs, procfs_validfpregs },
172: { DT_REG, N("ctl"), PFSctl, NULL },
1.136 christos 173: { DT_REG, N("stat"), PFSstat, procfs_validfile_linux },
1.109 darcy 174: { DT_REG, N("status"), PFSstatus, NULL },
1.136 christos 175: { DT_REG, N("note"), PFSnote, NULL },
1.109 darcy 176: { DT_REG, N("notepg"), PFSnotepg, NULL },
177: { DT_REG, N("map"), PFSmap, procfs_validmap },
1.136 christos 178: { DT_REG, N("maps"), PFSmaps, procfs_validmap },
1.109 darcy 179: { DT_REG, N("cmdline"), PFScmdline, NULL },
1.139 skrll 180: { DT_REG, N("exe"), PFSexe, procfs_validfile },
1.126 atatat 181: { DT_LNK, N("cwd"), PFScwd, NULL },
182: { DT_LNK, N("root"), PFSchroot, NULL },
1.137 christos 183: { DT_LNK, N("emul"), PFSemul, NULL },
1.157 ! agc 184: { DT_REG, N("statm"), PFSstatm, procfs_validfile_linux },
1.86 thorpej 185: #ifdef __HAVE_PROCFS_MACHDEP
186: PROCFS_MACHDEP_NODETYPE_DEFNS
187: #endif
1.9 cgd 188: #undef N
1.1 pk 189: };
1.97 jdolecek 190: static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
1.1 pk 191:
1.76 fvdl 192: /*
193: * List of files in the root directory. Note: the validate function will
194: * be called with p == NULL for these ones.
195: */
1.97 jdolecek 196: static const struct proc_target proc_root_targets[] = {
1.76 fvdl 197: #define N(s) sizeof(s)-1, s
198: /* name type validp */
1.109 darcy 199: { DT_REG, N("meminfo"), PFSmeminfo, procfs_validfile_linux },
200: { DT_REG, N("cpuinfo"), PFScpuinfo, procfs_validfile_linux },
201: { DT_REG, N("uptime"), PFSuptime, procfs_validfile_linux },
1.114 jdolecek 202: { DT_REG, N("mounts"), PFSmounts, procfs_validfile_linux },
1.134 manu 203: { DT_REG, N("devices"), PFSdevices, procfs_validfile_linux },
1.157 ! agc 204: { DT_REG, N("stat"), PFScpustat, procfs_validfile_linux },
! 205: { DT_REG, N("loadavg"), PFSloadavg, procfs_validfile_linux },
1.76 fvdl 206: #undef N
207: };
1.97 jdolecek 208: static const int nproc_root_targets =
1.76 fvdl 209: sizeof(proc_root_targets) / sizeof(proc_root_targets[0]);
210:
1.124 xtraeme 211: int procfs_lookup(void *);
1.96 jdolecek 212: #define procfs_create genfs_eopnotsupp
213: #define procfs_mknod genfs_eopnotsupp
1.124 xtraeme 214: int procfs_open(void *);
215: int procfs_close(void *);
216: int procfs_access(void *);
217: int procfs_getattr(void *);
218: int procfs_setattr(void *);
1.37 christos 219: #define procfs_read procfs_rw
220: #define procfs_write procfs_rw
1.65 wrstuden 221: #define procfs_fcntl genfs_fcntl
1.57 matthias 222: #define procfs_ioctl genfs_enoioctl
1.42 mycroft 223: #define procfs_poll genfs_poll
1.53 fvdl 224: #define procfs_revoke genfs_revoke
1.41 mycroft 225: #define procfs_fsync genfs_nullop
226: #define procfs_seek genfs_nullop
1.96 jdolecek 227: #define procfs_remove genfs_eopnotsupp
1.124 xtraeme 228: int procfs_link(void *);
1.96 jdolecek 229: #define procfs_rename genfs_eopnotsupp
230: #define procfs_mkdir genfs_eopnotsupp
231: #define procfs_rmdir genfs_eopnotsupp
1.124 xtraeme 232: int procfs_symlink(void *);
233: int procfs_readdir(void *);
234: int procfs_readlink(void *);
1.41 mycroft 235: #define procfs_abortop genfs_abortop
1.124 xtraeme 236: int procfs_inactive(void *);
237: int procfs_reclaim(void *);
1.62 wrstuden 238: #define procfs_lock genfs_lock
239: #define procfs_unlock genfs_unlock
1.82 chs 240: #define procfs_bmap genfs_badop
1.41 mycroft 241: #define procfs_strategy genfs_badop
1.124 xtraeme 242: int procfs_print(void *);
243: int procfs_pathconf(void *);
1.62 wrstuden 244: #define procfs_islocked genfs_islocked
1.58 kleink 245: #define procfs_advlock genfs_einval
1.41 mycroft 246: #define procfs_bwrite genfs_eopnotsupp
1.87 chs 247: #define procfs_putpages genfs_null_putpages
1.37 christos 248:
1.124 xtraeme 249: static int atoi(const char *, size_t);
1.37 christos 250:
251: /*
252: * procfs vnode operations.
253: */
1.124 xtraeme 254: int (**procfs_vnodeop_p)(void *);
1.77 jdolecek 255: const struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
1.37 christos 256: { &vop_default_desc, vn_default_error },
257: { &vop_lookup_desc, procfs_lookup }, /* lookup */
258: { &vop_create_desc, procfs_create }, /* create */
259: { &vop_mknod_desc, procfs_mknod }, /* mknod */
260: { &vop_open_desc, procfs_open }, /* open */
261: { &vop_close_desc, procfs_close }, /* close */
262: { &vop_access_desc, procfs_access }, /* access */
263: { &vop_getattr_desc, procfs_getattr }, /* getattr */
264: { &vop_setattr_desc, procfs_setattr }, /* setattr */
265: { &vop_read_desc, procfs_read }, /* read */
266: { &vop_write_desc, procfs_write }, /* write */
1.65 wrstuden 267: { &vop_fcntl_desc, procfs_fcntl }, /* fcntl */
1.37 christos 268: { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */
1.42 mycroft 269: { &vop_poll_desc, procfs_poll }, /* poll */
1.53 fvdl 270: { &vop_revoke_desc, procfs_revoke }, /* revoke */
1.37 christos 271: { &vop_fsync_desc, procfs_fsync }, /* fsync */
272: { &vop_seek_desc, procfs_seek }, /* seek */
273: { &vop_remove_desc, procfs_remove }, /* remove */
274: { &vop_link_desc, procfs_link }, /* link */
275: { &vop_rename_desc, procfs_rename }, /* rename */
276: { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */
277: { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */
278: { &vop_symlink_desc, procfs_symlink }, /* symlink */
279: { &vop_readdir_desc, procfs_readdir }, /* readdir */
280: { &vop_readlink_desc, procfs_readlink }, /* readlink */
281: { &vop_abortop_desc, procfs_abortop }, /* abortop */
282: { &vop_inactive_desc, procfs_inactive }, /* inactive */
283: { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */
284: { &vop_lock_desc, procfs_lock }, /* lock */
285: { &vop_unlock_desc, procfs_unlock }, /* unlock */
286: { &vop_bmap_desc, procfs_bmap }, /* bmap */
287: { &vop_strategy_desc, procfs_strategy }, /* strategy */
288: { &vop_print_desc, procfs_print }, /* print */
289: { &vop_islocked_desc, procfs_islocked }, /* islocked */
290: { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */
291: { &vop_advlock_desc, procfs_advlock }, /* advlock */
1.87 chs 292: { &vop_putpages_desc, procfs_putpages }, /* putpages */
1.82 chs 293: { NULL, NULL }
1.37 christos 294: };
1.77 jdolecek 295: const struct vnodeopv_desc procfs_vnodeop_opv_desc =
1.37 christos 296: { &procfs_vnodeop_p, procfs_vnodeop_entries };
297: /*
1.9 cgd 298: * set things up for doing i/o on
299: * the pfsnode (vp). (vp) is locked
300: * on entry, and should be left locked
301: * on exit.
1.1 pk 302: *
1.9 cgd 303: * for procfs we don't need to do anything
304: * in particular for i/o. all that is done
305: * is to support exclusive open on process
306: * memory images.
1.1 pk 307: */
1.37 christos 308: int
309: procfs_open(v)
310: void *v;
311: {
1.22 mycroft 312: struct vop_open_args /* {
313: struct vnode *a_vp;
314: int a_mode;
1.130 elad 315: kauth_cred_t a_cred;
1.128 christos 316: struct lwp *a_l;
1.37 christos 317: } */ *ap = v;
1.21 mycroft 318: struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.128 christos 319: struct lwp *l1;
320: struct proc *p2;
1.88 christos 321: int error;
1.50 thorpej 322:
1.145 ad 323: if ((error = procfs_proc_lock(pfs->pfs_pid, &p2, ENOENT)) != 0)
324: return error;
325:
1.128 christos 326: l1 = ap->a_l; /* tracer */
1.140 elad 327:
1.144 elad 328: #define M2K(m) (((m) & FREAD) && ((m) & FWRITE) ? \
329: KAUTH_REQ_PROCESS_CANPROCFS_RW : \
330: (m) & FWRITE ? KAUTH_REQ_PROCESS_CANPROCFS_WRITE : \
331: KAUTH_REQ_PROCESS_CANPROCFS_READ)
332:
1.145 ad 333: mutex_enter(&p2->p_mutex);
1.144 elad 334: error = kauth_authorize_process(l1->l_cred, KAUTH_PROCESS_CANPROCFS,
335: p2, pfs, KAUTH_ARG(M2K(ap->a_mode)), NULL);
1.145 ad 336: mutex_exit(&p2->p_mutex);
1.144 elad 337: if (error)
338: return (error);
339:
340: #undef M2K
341:
1.9 cgd 342: switch (pfs->pfs_type) {
1.109 darcy 343: case PFSmem:
1.37 christos 344: if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
1.145 ad 345: ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) {
346: error = EBUSY;
347: break;
348: }
1.50 thorpej 349:
1.141 elad 350: if (!proc_isunder(p2, l1))
351: return (EPERM);
352:
1.21 mycroft 353: if (ap->a_mode & FWRITE)
354: pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
1.1 pk 355:
1.144 elad 356: break;
357:
358: case PFSregs:
359: case PFSfpregs:
360: if (!proc_isunder(p2, l1))
361: return (EPERM);
362:
363: break;
1.1 pk 364:
1.9 cgd 365: default:
366: break;
367: }
1.1 pk 368:
1.145 ad 369: procfs_proc_unlock(p2);
370: return (error);
1.1 pk 371: }
372:
373: /*
1.9 cgd 374: * close the pfsnode (vp) after doing i/o.
375: * (vp) is not locked on entry or exit.
376: *
377: * nothing to do for procfs other than undo
378: * any exclusive open flag (see _open above).
1.1 pk 379: */
1.37 christos 380: int
381: procfs_close(v)
382: void *v;
383: {
1.22 mycroft 384: struct vop_close_args /* {
385: struct vnode *a_vp;
386: int a_fflag;
1.130 elad 387: kauth_cred_t a_cred;
1.128 christos 388: struct lwp *a_l;
1.37 christos 389: } */ *ap = v;
1.21 mycroft 390: struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.1 pk 391:
1.9 cgd 392: switch (pfs->pfs_type) {
1.109 darcy 393: case PFSmem:
1.21 mycroft 394: if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
1.9 cgd 395: pfs->pfs_flags &= ~(FWRITE|O_EXCL);
396: break;
1.46 mycroft 397:
398: default:
1.37 christos 399: break;
1.9 cgd 400: }
1.1 pk 401:
402: return (0);
403: }
404:
405: /*
1.9 cgd 406: * _inactive is called when the pfsnode
407: * is vrele'd and the reference count goes
408: * to zero. (vp) will be on the vnode free
409: * list, so to get it back vget() must be
410: * used.
411: *
412: * for procfs, check if the process is still
413: * alive and if it isn't then just throw away
414: * the vnode by calling vgone(). this may
415: * be overkill and a waste of time since the
416: * chances are that the process will still be
1.145 ad 417: * there.
1.9 cgd 418: *
1.62 wrstuden 419: * (vp) is locked on entry, but must be unlocked on exit.
1.1 pk 420: */
1.37 christos 421: int
422: procfs_inactive(v)
423: void *v;
424: {
1.22 mycroft 425: struct vop_inactive_args /* {
426: struct vnode *a_vp;
1.53 fvdl 427: struct proc *a_p;
1.37 christos 428: } */ *ap = v;
1.122 christos 429: struct vnode *vp = ap->a_vp;
430: struct pfsnode *pfs = VTOPFS(vp);
1.145 ad 431: struct proc *p;
432: int error;
1.1 pk 433:
1.122 christos 434: VOP_UNLOCK(vp, 0);
1.145 ad 435:
436: error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH);
437: if (error != 0 && (vp->v_flag & VXLOCK) == 0)
1.122 christos 438: vgone(vp);
1.145 ad 439: else
440: procfs_proc_unlock(p);
1.5 pk 441:
1.9 cgd 442: return (0);
1.1 pk 443: }
444:
445: /*
1.9 cgd 446: * _reclaim is called when getnewvnode()
447: * wants to make use of an entry on the vnode
448: * free list. at this time the filesystem needs
449: * to free any private data and remove the node
450: * from any private lists.
1.1 pk 451: */
1.37 christos 452: int
453: procfs_reclaim(v)
454: void *v;
455: {
1.22 mycroft 456: struct vop_reclaim_args /* {
457: struct vnode *a_vp;
1.37 christos 458: } */ *ap = v;
1.21 mycroft 459:
460: return (procfs_freevp(ap->a_vp));
461: }
462:
463: /*
464: * Return POSIX pathconf information applicable to special devices.
465: */
1.37 christos 466: int
467: procfs_pathconf(v)
468: void *v;
469: {
1.21 mycroft 470: struct vop_pathconf_args /* {
471: struct vnode *a_vp;
472: int a_name;
1.26 cgd 473: register_t *a_retval;
1.37 christos 474: } */ *ap = v;
1.1 pk 475:
1.21 mycroft 476: switch (ap->a_name) {
477: case _PC_LINK_MAX:
478: *ap->a_retval = LINK_MAX;
479: return (0);
480: case _PC_MAX_CANON:
481: *ap->a_retval = MAX_CANON;
482: return (0);
483: case _PC_MAX_INPUT:
484: *ap->a_retval = MAX_INPUT;
485: return (0);
486: case _PC_PIPE_BUF:
487: *ap->a_retval = PIPE_BUF;
488: return (0);
489: case _PC_CHOWN_RESTRICTED:
490: *ap->a_retval = 1;
491: return (0);
492: case _PC_VDISABLE:
493: *ap->a_retval = _POSIX_VDISABLE;
1.55 kleink 494: return (0);
495: case _PC_SYNC_IO:
496: *ap->a_retval = 1;
1.21 mycroft 497: return (0);
498: default:
499: return (EINVAL);
500: }
501: /* NOTREACHED */
1.1 pk 502: }
503:
504: /*
1.9 cgd 505: * _print is used for debugging.
506: * just print a readable description
507: * of (vp).
1.1 pk 508: */
1.37 christos 509: int
510: procfs_print(v)
511: void *v;
512: {
1.22 mycroft 513: struct vop_print_args /* {
514: struct vnode *a_vp;
1.37 christos 515: } */ *ap = v;
1.21 mycroft 516: struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.5 pk 517:
1.44 christos 518: printf("tag VT_PROCFS, type %d, pid %d, mode %x, flags %lx\n",
1.21 mycroft 519: pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
1.37 christos 520: return 0;
1.36 mycroft 521: }
522:
523: int
1.121 perry 524: procfs_link(v)
1.37 christos 525: void *v;
526: {
1.36 mycroft 527: struct vop_link_args /* {
528: struct vnode *a_dvp;
1.121 perry 529: struct vnode *a_vp;
1.36 mycroft 530: struct componentname *a_cnp;
1.37 christos 531: } */ *ap = v;
1.121 perry 532:
1.36 mycroft 533: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
534: vput(ap->a_dvp);
535: return (EROFS);
536: }
537:
538: int
1.37 christos 539: procfs_symlink(v)
540: void *v;
541: {
1.36 mycroft 542: struct vop_symlink_args /* {
543: struct vnode *a_dvp;
544: struct vnode **a_vpp;
545: struct componentname *a_cnp;
546: struct vattr *a_vap;
547: char *a_target;
1.37 christos 548: } */ *ap = v;
1.121 perry 549:
1.36 mycroft 550: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
551: vput(ap->a_dvp);
552: return (EROFS);
1.1 pk 553: }
554:
555: /*
1.126 atatat 556: * Works out the path to (and vnode of) the target process's current
557: * working directory or chroot. If the caller is in a chroot and
558: * can't "reach" the target's cwd or root (or some other error
559: * occurs), a "/" is returned for the path and a NULL pointer is
560: * returned for the vnode.
561: */
562: static struct vnode *
1.128 christos 563: procfs_dir(pfstype t, struct lwp *caller, struct proc *target,
1.126 atatat 564: char **bpp, char *path, int len)
565: {
1.128 christos 566: struct vnode *vp, *rvp = caller->l_proc->p_cwdi->cwdi_rdir;
1.126 atatat 567: char *bp;
568:
1.145 ad 569: LOCK_ASSERT(mutex_owned(&target->p_mutex));
570:
1.126 atatat 571: bp = bpp ? *bpp : NULL;
572:
573: switch (t) {
574: case PFScwd:
575: vp = target->p_cwdi->cwdi_cdir;
576: break;
577: case PFSchroot:
578: vp = target->p_cwdi->cwdi_rdir;
579: break;
1.136 christos 580: case PFSexe:
581: vp = target->p_textvp;
582: break;
1.126 atatat 583: default:
584: return (NULL);
585: }
586:
587: if (rvp == NULL)
588: rvp = rootvnode;
1.145 ad 589: mutex_exit(&target->p_mutex); /* XXXSMP */
1.126 atatat 590: if (vp == NULL || getcwd_common(vp, rvp, bp ? &bp : NULL, path,
591: len / 2, 0, caller) != 0) {
592: vp = NULL;
593: if (bpp) {
1.153 christos 594: /*
595: if (t == PFSexe) {
596: snprintf(path, len, "%s/%d/file"
597: mp->mnt_stat.f_mntonname, pfs->pfs_pid);
598: } else */ {
599: bp = *bpp;
600: *--bp = '/';
601: }
1.126 atatat 602: }
603: }
1.145 ad 604: mutex_enter(&target->p_mutex); /* XXXSMP */
1.126 atatat 605:
606: if (bpp)
607: *bpp = bp;
608:
609: return (vp);
610: }
611:
612: /*
1.9 cgd 613: * Invent attributes for pfsnode (vp) and store
614: * them in (vap).
615: * Directories lengths are returned as zero since
616: * any real length would require the genuine size
617: * to be computed, and nothing cares anyway.
618: *
619: * this is relatively minimal for procfs.
1.1 pk 620: */
1.37 christos 621: int
622: procfs_getattr(v)
623: void *v;
624: {
1.22 mycroft 625: struct vop_getattr_args /* {
626: struct vnode *a_vp;
627: struct vattr *a_vap;
1.130 elad 628: kauth_cred_t a_cred;
1.128 christos 629: struct lwp *a_l;
1.37 christos 630: } */ *ap = v;
1.21 mycroft 631: struct pfsnode *pfs = VTOPFS(ap->a_vp);
632: struct vattr *vap = ap->a_vap;
1.1 pk 633: struct proc *procp;
1.145 ad 634: char *path;
1.9 cgd 635: int error;
1.1 pk 636:
1.21 mycroft 637: /* first check the process still exists */
638: switch (pfs->pfs_type) {
1.109 darcy 639: case PFSroot:
640: case PFScurproc:
641: case PFSself:
1.145 ad 642: procp = NULL;
643: break;
644:
645: default:
646: error = procfs_proc_lock(pfs->pfs_pid, &procp, ENOENT);
647: if (error != 0)
648: return (error);
649: break;
650: }
651:
652: switch (pfs->pfs_type) {
653: case PFScwd:
654: case PFSchroot:
655: case PFSexe:
656: MALLOC(path, char *, MAXPATHLEN + 4, M_TEMP,
657: M_WAITOK|M_CANFAIL);
1.146 ad 658: if (path == NULL && procp != NULL) {
1.145 ad 659: procfs_proc_unlock(procp);
660: return (ENOMEM);
661: }
1.21 mycroft 662: break;
663:
664: default:
1.145 ad 665: path = NULL;
1.46 mycroft 666: break;
1.21 mycroft 667: }
668:
1.125 elad 669: if (procp != NULL) {
1.145 ad 670: mutex_enter(&procp->p_mutex);
1.146 ad 671: error = kauth_authorize_process(kauth_cred_get(),
672: KAUTH_PROCESS_CANSEE, procp, NULL, NULL, NULL);
673: mutex_exit(&procp->p_mutex);
674: if (error != 0) {
1.145 ad 675: procfs_proc_unlock(procp);
676: if (path != NULL)
677: free(path, M_TEMP);
1.125 elad 678: return (ENOENT);
1.145 ad 679: }
1.125 elad 680: }
681:
1.21 mycroft 682: error = 0;
683:
1.9 cgd 684: /* start by zeroing out the attributes */
1.1 pk 685: VATTR_NULL(vap);
1.9 cgd 686:
687: /* next do all the common fields */
1.21 mycroft 688: vap->va_type = ap->a_vp->v_type;
1.9 cgd 689: vap->va_mode = pfs->pfs_mode;
690: vap->va_fileid = pfs->pfs_fileno;
691: vap->va_flags = 0;
1.19 cgd 692: vap->va_blocksize = PAGE_SIZE;
1.9 cgd 693:
694: /*
1.131 kardel 695: * Make all times be current TOD.
1.90 simonb 696: *
1.9 cgd 697: * It would be possible to get the process start
1.126 atatat 698: * time from the p_stats structure, but there's
1.9 cgd 699: * no "file creation" time stamp anyway, and the
1.126 atatat 700: * p_stats structure is not addressable if u. gets
1.9 cgd 701: * swapped out for that process.
702: */
1.131 kardel 703: getnanotime(&vap->va_ctime);
1.9 cgd 704: vap->va_atime = vap->va_mtime = vap->va_ctime;
1.126 atatat 705: if (procp)
706: TIMEVAL_TO_TIMESPEC(&procp->p_stats->p_start,
707: &vap->va_birthtime);
708: else
1.131 kardel 709: getnanotime(&vap->va_birthtime);
1.9 cgd 710:
1.21 mycroft 711: switch (pfs->pfs_type) {
1.109 darcy 712: case PFSmem:
713: case PFSregs:
714: case PFSfpregs:
1.86 thorpej 715: #if defined(__HAVE_PROCFS_MACHDEP) && defined(PROCFS_MACHDEP_PROTECT_CASES)
716: PROCFS_MACHDEP_PROTECT_CASES
717: #endif
1.47 mycroft 718: /*
719: * If the process has exercised some setuid or setgid
720: * privilege, then rip away read/write permission so
721: * that only root can gain access.
722: */
1.149 pavel 723: if (procp->p_flag & PK_SUGID)
1.47 mycroft 724: vap->va_mode &= ~(S_IRUSR|S_IWUSR);
1.46 mycroft 725: /* FALLTHROUGH */
1.109 darcy 726: case PFSctl:
727: case PFSstatus:
728: case PFSstat:
729: case PFSnote:
730: case PFSnotepg:
731: case PFSmap:
732: case PFSmaps:
733: case PFScmdline:
1.137 christos 734: case PFSemul:
1.157 ! agc 735: case PFSstatm:
1.12 ws 736: vap->va_nlink = 1;
1.130 elad 737: vap->va_uid = kauth_cred_geteuid(procp->p_cred);
738: vap->va_gid = kauth_cred_getegid(procp->p_cred);
1.21 mycroft 739: break;
1.109 darcy 740: case PFSmeminfo:
1.134 manu 741: case PFSdevices:
1.109 darcy 742: case PFScpuinfo:
743: case PFSuptime:
1.114 jdolecek 744: case PFSmounts:
1.157 ! agc 745: case PFScpustat:
! 746: case PFSloadavg:
1.76 fvdl 747: vap->va_nlink = 1;
748: vap->va_uid = vap->va_gid = 0;
749: break;
1.46 mycroft 750:
751: default:
1.37 christos 752: break;
1.12 ws 753: }
754:
1.9 cgd 755: /*
756: * now do the object specific fields
757: *
758: * The size could be set from struct reg, but it's hardly
759: * worth the trouble, and it puts some (potentially) machine
760: * dependent data into this machine-independent code. If it
761: * becomes important then this function should break out into
762: * a per-file stat function in the corresponding .c file.
763: */
1.1 pk 764:
1.9 cgd 765: switch (pfs->pfs_type) {
1.109 darcy 766: case PFSroot:
1.21 mycroft 767: /*
768: * Set nlink to 1 to tell fts(3) we don't actually know.
769: */
770: vap->va_nlink = 1;
771: vap->va_uid = 0;
772: vap->va_gid = 0;
1.46 mycroft 773: vap->va_bytes = vap->va_size = DEV_BSIZE;
1.21 mycroft 774: break;
775:
1.129 christos 776: case PFSself:
1.109 darcy 777: case PFScurproc: {
1.123 christos 778: char bf[16]; /* should be enough */
1.21 mycroft 779: vap->va_nlink = 1;
780: vap->va_uid = 0;
781: vap->va_gid = 0;
1.46 mycroft 782: vap->va_bytes = vap->va_size =
1.123 christos 783: snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
1.9 cgd 784: break;
1.21 mycroft 785: }
1.9 cgd 786:
1.109 darcy 787: case PFSfd:
1.91 christos 788: if (pfs->pfs_fd != -1) {
789: struct file *fp;
1.98 jdolecek 790:
1.145 ad 791: fp = fd_getfile(procp->p_fd, pfs->pfs_fd);
792: if (fp == NULL) {
793: error = EBADF;
794: break;
795: }
1.98 jdolecek 796: FILE_USE(fp);
1.91 christos 797: vap->va_nlink = 1;
1.130 elad 798: vap->va_uid = kauth_cred_geteuid(fp->f_cred);
799: vap->va_gid = kauth_cred_getegid(fp->f_cred);
1.91 christos 800: switch (fp->f_type) {
801: case DTYPE_VNODE:
802: vap->va_bytes = vap->va_size =
803: ((struct vnode *)fp->f_data)->v_size;
804: break;
805: default:
806: vap->va_bytes = vap->va_size = 0;
807: break;
808: }
1.145 ad 809: FILE_UNUSE(fp, curlwp);
1.91 christos 810: break;
811: }
812: /*FALLTHROUGH*/
1.109 darcy 813: case PFSproc:
1.9 cgd 814: vap->va_nlink = 2;
1.130 elad 815: vap->va_uid = kauth_cred_geteuid(procp->p_cred);
816: vap->va_gid = kauth_cred_getegid(procp->p_cred);
1.46 mycroft 817: vap->va_bytes = vap->va_size = DEV_BSIZE;
1.21 mycroft 818: break;
819:
1.109 darcy 820: case PFSfile:
1.21 mycroft 821: error = EOPNOTSUPP;
1.9 cgd 822: break;
823:
1.109 darcy 824: case PFSmem:
1.9 cgd 825: vap->va_bytes = vap->va_size =
826: ctob(procp->p_vmspace->vm_tsize +
827: procp->p_vmspace->vm_dsize +
828: procp->p_vmspace->vm_ssize);
829: break;
830:
1.18 cgd 831: #if defined(PT_GETREGS) || defined(PT_SETREGS)
1.109 darcy 832: case PFSregs:
1.11 cgd 833: vap->va_bytes = vap->va_size = sizeof(struct reg);
1.18 cgd 834: break;
1.14 cgd 835: #endif
836:
1.18 cgd 837: #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
1.109 darcy 838: case PFSfpregs:
1.14 cgd 839: vap->va_bytes = vap->va_size = sizeof(struct fpreg);
1.18 cgd 840: break;
1.14 cgd 841: #endif
1.12 ws 842:
1.109 darcy 843: case PFSctl:
844: case PFSstatus:
845: case PFSstat:
846: case PFSnote:
847: case PFSnotepg:
848: case PFScmdline:
849: case PFSmeminfo:
1.134 manu 850: case PFSdevices:
1.109 darcy 851: case PFScpuinfo:
852: case PFSuptime:
1.114 jdolecek 853: case PFSmounts:
1.157 ! agc 854: case PFScpustat:
! 855: case PFSloadavg:
! 856: case PFSstatm:
1.46 mycroft 857: vap->va_bytes = vap->va_size = 0;
1.79 fvdl 858: break;
1.109 darcy 859: case PFSmap:
860: case PFSmaps:
1.79 fvdl 861: /*
862: * Advise a larger blocksize for the map files, so that
863: * they may be read in one pass.
864: */
1.80 fvdl 865: vap->va_blocksize = 4 * PAGE_SIZE;
1.83 chs 866: vap->va_bytes = vap->va_size = 0;
1.9 cgd 867: break;
1.86 thorpej 868:
1.126 atatat 869: case PFScwd:
1.136 christos 870: case PFSchroot:
871: case PFSexe: {
1.145 ad 872: char *bp;
1.126 atatat 873:
874: vap->va_nlink = 1;
875: vap->va_uid = 0;
876: vap->va_gid = 0;
877: bp = path + MAXPATHLEN;
878: *--bp = '\0';
1.147 ad 879: mutex_enter(&procp->p_mutex);
1.128 christos 880: (void)procfs_dir(pfs->pfs_type, curlwp, procp, &bp, path,
1.126 atatat 881: MAXPATHLEN);
1.147 ad 882: mutex_exit(&procp->p_mutex);
1.126 atatat 883: vap->va_bytes = vap->va_size = strlen(bp);
884: break;
885: }
886:
1.137 christos 887: case PFSemul:
888: vap->va_bytes = vap->va_size = strlen(procp->p_emul->e_name);
889: break;
890:
1.86 thorpej 891: #ifdef __HAVE_PROCFS_MACHDEP
892: PROCFS_MACHDEP_NODETYPE_CASES
893: error = procfs_machdep_getattr(ap->a_vp, vap, procp);
894: break;
895: #endif
1.1 pk 896:
1.9 cgd 897: default:
1.21 mycroft 898: panic("procfs_getattr");
1.1 pk 899: }
900:
1.146 ad 901: if (procp != NULL)
1.145 ad 902: procfs_proc_unlock(procp);
903: if (path != NULL)
904: free(path, M_TEMP);
905:
1.9 cgd 906: return (error);
1.1 pk 907: }
908:
1.37 christos 909: /*ARGSUSED*/
910: int
1.138 christos 911: procfs_setattr(void *v)
1.5 pk 912: {
913: /*
1.9 cgd 914: * just fake out attribute setting
915: * it's not good to generate an error
916: * return, otherwise things like creat()
917: * will fail when they try to set the
918: * file length to 0. worse, this means
919: * that echo $note > /proc/$pid/note will fail.
1.5 pk 920: */
921:
1.9 cgd 922: return (0);
1.5 pk 923: }
924:
1.9 cgd 925: /*
926: * implement access checking.
927: *
928: * actually, the check for super-user is slightly
929: * broken since it will allow read access to write-only
930: * objects. this doesn't cause any particular trouble
931: * but does mean that the i/o entry points need to check
932: * that the operation really does make sense.
933: */
1.37 christos 934: int
935: procfs_access(v)
936: void *v;
937: {
1.22 mycroft 938: struct vop_access_args /* {
939: struct vnode *a_vp;
940: int a_mode;
1.130 elad 941: kauth_cred_t a_cred;
1.128 christos 942: struct lwp *a_l;
1.37 christos 943: } */ *ap = v;
1.31 mycroft 944: struct vattr va;
1.1 pk 945: int error;
946:
1.128 christos 947: if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_l)) != 0)
1.1 pk 948: return (error);
1.9 cgd 949:
1.49 mycroft 950: return (vaccess(va.va_type, va.va_mode,
951: va.va_uid, va.va_gid, ap->a_mode, ap->a_cred));
1.1 pk 952: }
953:
954: /*
1.9 cgd 955: * lookup. this is incredibly complicated in the
956: * general case, however for most pseudo-filesystems
957: * very little needs to be done.
958: *
1.62 wrstuden 959: * Locking isn't hard here, just poorly documented.
960: *
1.121 perry 961: * If we're looking up ".", just vref the parent & return it.
1.62 wrstuden 962: *
963: * If we're looking up "..", unlock the parent, and lock "..". If everything
964: * went ok, and we're on the last component and the caller requested the
965: * parent locked, try to re-lock the parent. We do this to prevent lock
966: * races.
967: *
968: * For anything else, get the needed node. Then unlock the parent if not
969: * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the
970: * parent in the .. case).
971: *
972: * We try to exit with the parent locked in error cases.
1.9 cgd 973: */
1.37 christos 974: int
975: procfs_lookup(v)
976: void *v;
977: {
1.22 mycroft 978: struct vop_lookup_args /* {
979: struct vnode * a_dvp;
980: struct vnode ** a_vpp;
981: struct componentname * a_cnp;
1.37 christos 982: } */ *ap = v;
1.21 mycroft 983: struct componentname *cnp = ap->a_cnp;
984: struct vnode **vpp = ap->a_vpp;
985: struct vnode *dvp = ap->a_dvp;
1.45 cgd 986: const char *pname = cnp->cn_nameptr;
1.78 jdolecek 987: const struct proc_target *pt = NULL;
1.32 mycroft 988: struct vnode *fvp;
1.146 ad 989: pid_t pid, vnpid;
1.9 cgd 990: struct pfsnode *pfs;
1.76 fvdl 991: struct proc *p = NULL;
1.128 christos 992: struct lwp *l = NULL;
1.146 ad 993: int i, error;
994: pfstype type;
1.1 pk 995:
1.32 mycroft 996: *vpp = NULL;
997:
998: if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
999: return (EROFS);
1000:
1.21 mycroft 1001: if (cnp->cn_namelen == 1 && *pname == '.') {
1002: *vpp = dvp;
1.9 cgd 1003: VREF(dvp);
1004: return (0);
1005: }
1.1 pk 1006:
1.9 cgd 1007: pfs = VTOPFS(dvp);
1008: switch (pfs->pfs_type) {
1.109 darcy 1009: case PFSroot:
1.62 wrstuden 1010: /*
1011: * Shouldn't get here with .. in the root node.
1012: */
1.121 perry 1013: if (cnp->cn_flags & ISDOTDOT)
1.9 cgd 1014: return (EIO);
1015:
1.76 fvdl 1016: for (i = 0; i < nproc_root_targets; i++) {
1017: pt = &proc_root_targets[i];
1.150 pooka 1018: /*
1019: * check for node match. proc is always NULL here,
1020: * so call pt_valid with constant NULL lwp.
1021: */
1.76 fvdl 1022: if (cnp->cn_namelen == pt->pt_namlen &&
1023: memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1.150 pooka 1024: (pt->pt_valid == NULL ||
1025: (*pt->pt_valid)(NULL, dvp->v_mount)))
1.76 fvdl 1026: break;
1027: }
1028:
1029: if (i != nproc_root_targets) {
1030: error = procfs_allocvp(dvp->v_mount, vpp, 0,
1.145 ad 1031: pt->pt_pfstype, -1, NULL);
1.76 fvdl 1032: return (error);
1033: }
1034:
1.146 ad 1035: if (CNEQ(cnp, "curproc", 7)) {
1036: pid = curproc->p_pid;
1037: vnpid = 0;
1038: type = PFScurproc;
1039: } else if (CNEQ(cnp, "self", 4)) {
1040: pid = curproc->p_pid;
1041: vnpid = 0;
1042: type = PFSself;
1043: } else {
1044: pid = (pid_t)atoi(pname, cnp->cn_namelen);
1045: vnpid = pid;
1046: type = PFSproc;
1047: }
1.9 cgd 1048:
1.145 ad 1049: if (procfs_proc_lock(pid, &p, ESRCH) != 0)
1.32 mycroft 1050: break;
1.146 ad 1051: error = procfs_allocvp(dvp->v_mount, vpp, vnpid, type, -1, p);
1.145 ad 1052: procfs_proc_unlock(p);
1.62 wrstuden 1053: return (error);
1.9 cgd 1054:
1.109 darcy 1055: case PFSproc:
1.62 wrstuden 1056: /*
1057: * do the .. dance. We unlock the directory, and then
1058: * get the root dir. That will automatically return ..
1059: * locked. Then if the caller wanted dvp locked, we
1060: * re-lock.
1061: */
1062: if (cnp->cn_flags & ISDOTDOT) {
1063: VOP_UNLOCK(dvp, 0);
1.105 thorpej 1064: error = procfs_root(dvp->v_mount, vpp);
1.143 chs 1065: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.62 wrstuden 1066: return (error);
1067: }
1.1 pk 1068:
1.145 ad 1069: if (procfs_proc_lock(pfs->pfs_pid, &p, ESRCH) != 0)
1.32 mycroft 1070: break;
1071:
1072: for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
1.151 pooka 1073: struct lwp *plwp;
1074: int found;
1075:
1076: mutex_enter(&p->p_smutex);
1077: plwp = proc_representative_lwp(p, NULL, 1);
1078: lwp_addref(plwp);
1079: mutex_exit(&p->p_smutex);
1080: found = cnp->cn_namelen == pt->pt_namlen &&
1.56 perry 1081: memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1.151 pooka 1082: (pt->pt_valid == NULL
1083: || (*pt->pt_valid)(plwp, dvp->v_mount));
1084: lwp_delref(plwp);
1085: if (found)
1.145 ad 1086: break;
1.9 cgd 1087: }
1.146 ad 1088: if (i == nproc_targets) {
1089: procfs_proc_unlock(p);
1.145 ad 1090: break;
1.146 ad 1091: }
1.109 darcy 1092: if (pt->pt_pfstype == PFSfile) {
1.75 chs 1093: fvp = p->p_textvp;
1.23 mycroft 1094: /* We already checked that it exists. */
1.32 mycroft 1095: VREF(fvp);
1.53 fvdl 1096: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
1.32 mycroft 1097: *vpp = fvp;
1.146 ad 1098: procfs_proc_unlock(p);
1.21 mycroft 1099: return (0);
1100: }
1.1 pk 1101:
1.62 wrstuden 1102: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.145 ad 1103: pt->pt_pfstype, -1, p);
1104: procfs_proc_unlock(p);
1.62 wrstuden 1105: return (error);
1.1 pk 1106:
1.109 darcy 1107: case PFSfd: {
1.91 christos 1108: int fd;
1109: struct file *fp;
1.145 ad 1110:
1111: if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ENOENT)) != 0)
1112: return error;
1113:
1.91 christos 1114: /*
1115: * do the .. dance. We unlock the directory, and then
1116: * get the proc dir. That will automatically return ..
1.143 chs 1117: * locked. Then re-lock the directory.
1.91 christos 1118: */
1119: if (cnp->cn_flags & ISDOTDOT) {
1120: VOP_UNLOCK(dvp, 0);
1121: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.145 ad 1122: PFSproc, -1, p);
1.146 ad 1123: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.145 ad 1124: procfs_proc_unlock(p);
1.91 christos 1125: return (error);
1126: }
1127: fd = atoi(pname, cnp->cn_namelen);
1.145 ad 1128:
1129: mutex_enter(&p->p_mutex);
1130: fp = fd_getfile(p->p_fd, fd);
1131: mutex_exit(&p->p_mutex);
1132: if (fp == NULL) {
1133: procfs_proc_unlock(p);
1.91 christos 1134: return ENOENT;
1.145 ad 1135: }
1136:
1.99 jdolecek 1137: FILE_USE(fp);
1138:
1.91 christos 1139: switch (fp->f_type) {
1140: case DTYPE_VNODE:
1141: fvp = (struct vnode *)fp->f_data;
1.101 jdolecek 1142:
1143: /* Don't show directories */
1.102 christos 1144: if (fvp->v_type == VDIR)
1145: goto symlink;
1.101 jdolecek 1146:
1.91 christos 1147: VREF(fvp);
1.128 christos 1148: FILE_UNUSE(fp, l);
1.121 perry 1149: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY |
1.92 christos 1150: (p == curproc ? LK_CANRECURSE : 0));
1.91 christos 1151: *vpp = fvp;
1152: error = 0;
1153: break;
1154: default:
1.102 christos 1155: symlink:
1.128 christos 1156: FILE_UNUSE(fp, l);
1.91 christos 1157: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.145 ad 1158: PFSfd, fd, p);
1.91 christos 1159: break;
1160: }
1.145 ad 1161: procfs_proc_unlock(p);
1.91 christos 1162: return error;
1163: }
1.9 cgd 1164: default:
1165: return (ENOTDIR);
1.1 pk 1166: }
1.32 mycroft 1167:
1168: return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
1.1 pk 1169: }
1170:
1.18 cgd 1171: int
1.138 christos 1172: procfs_validfile(struct lwp *l, struct mount *mp)
1.18 cgd 1173: {
1.136 christos 1174: return l != NULL && l->l_proc != NULL && l->l_proc->p_textvp != NULL;
1.74 tv 1175: }
1.21 mycroft 1176:
1.74 tv 1177: static int
1.128 christos 1178: procfs_validfile_linux(l, mp)
1179: struct lwp *l;
1.76 fvdl 1180: struct mount *mp;
1.74 tv 1181: {
1.76 fvdl 1182: int flags;
1183:
1184: flags = VFSTOPROC(mp)->pmnt_flags;
1.142 christos 1185: return (flags & PROCFSMNT_LINUXCOMPAT) &&
1186: (l == NULL || l->l_proc == NULL || procfs_validfile(l, mp));
1.18 cgd 1187: }
1188:
1.117 yamt 1189: struct procfs_root_readdir_ctx {
1190: struct uio *uiop;
1191: off_t *cookies;
1192: int ncookies;
1.120 yamt 1193: off_t off;
1194: off_t startoff;
1.117 yamt 1195: int error;
1196: };
1197:
1198: static int
1199: procfs_root_readdir_callback(struct proc *p, void *arg)
1200: {
1201: struct procfs_root_readdir_ctx *ctxp = arg;
1202: struct dirent d;
1203: struct uio *uiop;
1204: int error;
1205:
1206: uiop = ctxp->uiop;
1207: if (uiop->uio_resid < UIO_MX)
1208: return -1; /* no space */
1209:
1.120 yamt 1210: if (ctxp->off < ctxp->startoff) {
1211: ctxp->off++;
1.117 yamt 1212: return 0;
1213: }
1214:
1.133 yamt 1215: if (kauth_authorize_process(kauth_cred_get(),
1216: KAUTH_PROCESS_CANSEE, p, NULL, NULL, NULL) != 0)
1217: return 0;
1.125 elad 1218:
1.117 yamt 1219: memset(&d, 0, UIO_MX);
1220: d.d_reclen = UIO_MX;
1221: d.d_fileno = PROCFS_FILENO(p->p_pid, PFSproc, -1);
1222: d.d_namlen = snprintf(d.d_name,
1223: UIO_MX - offsetof(struct dirent, d_name), "%ld", (long)p->p_pid);
1224: d.d_type = DT_DIR;
1225:
1.154 ad 1226: mutex_exit(&proclist_lock);
1.117 yamt 1227: error = uiomove(&d, UIO_MX, uiop);
1.154 ad 1228: mutex_enter(&proclist_lock);
1.117 yamt 1229: if (error) {
1230: ctxp->error = error;
1231: return -1;
1232: }
1233:
1234: ctxp->ncookies++;
1235: if (ctxp->cookies)
1.120 yamt 1236: *(ctxp->cookies)++ = ctxp->off + 1;
1237: ctxp->off++;
1.117 yamt 1238:
1239: return 0;
1240: }
1241:
1.9 cgd 1242: /*
1243: * readdir returns directory entries from pfsnode (vp).
1244: *
1245: * the strategy here with procfs is to generate a single
1.34 mycroft 1246: * directory entry at a time (struct dirent) and then
1.9 cgd 1247: * copy that out to userland using uiomove. a more efficent
1248: * though more complex implementation, would try to minimize
1249: * the number of calls to uiomove(). for procfs, this is
1250: * hardly worth the added code complexity.
1251: *
1252: * this should just be done through read()
1253: */
1.37 christos 1254: int
1255: procfs_readdir(v)
1256: void *v;
1257: {
1.22 mycroft 1258: struct vop_readdir_args /* {
1259: struct vnode *a_vp;
1260: struct uio *a_uio;
1.130 elad 1261: kauth_cred_t a_cred;
1.22 mycroft 1262: int *a_eofflag;
1.53 fvdl 1263: off_t **a_cookies;
1264: int *a_ncookies;
1.37 christos 1265: } */ *ap = v;
1.21 mycroft 1266: struct uio *uio = ap->a_uio;
1.34 mycroft 1267: struct dirent d;
1.9 cgd 1268: struct pfsnode *pfs;
1.68 sommerfe 1269: off_t i;
1.9 cgd 1270: int error;
1.53 fvdl 1271: off_t *cookies = NULL;
1.117 yamt 1272: int ncookies;
1.76 fvdl 1273: struct vnode *vp;
1.78 jdolecek 1274: const struct proc_target *pt;
1.117 yamt 1275: struct procfs_root_readdir_ctx ctx;
1.145 ad 1276: struct lwp *l;
1.9 cgd 1277:
1.76 fvdl 1278: vp = ap->a_vp;
1279: pfs = VTOPFS(vp);
1.1 pk 1280:
1.9 cgd 1281: if (uio->uio_resid < UIO_MX)
1282: return (EINVAL);
1.35 mycroft 1283: if (uio->uio_offset < 0)
1.1 pk 1284: return (EINVAL);
1285:
1.9 cgd 1286: error = 0;
1.35 mycroft 1287: i = uio->uio_offset;
1.113 jrf 1288: memset(&d, 0, UIO_MX);
1.34 mycroft 1289: d.d_reclen = UIO_MX;
1.53 fvdl 1290: ncookies = uio->uio_resid / UIO_MX;
1.9 cgd 1291:
1292: switch (pfs->pfs_type) {
1293: /*
1294: * this is for the process-specific sub-directories.
1295: * all that is needed to is copy out all the entries
1296: * from the procent[] table (top of this file).
1297: */
1.109 darcy 1298: case PFSproc: {
1.32 mycroft 1299: struct proc *p;
1.66 christos 1300:
1301: if (i >= nproc_targets)
1.67 sommerfe 1302: return 0;
1.9 cgd 1303:
1.145 ad 1304: if (procfs_proc_lock(pfs->pfs_pid, &p, ESRCH) != 0)
1.32 mycroft 1305: break;
1306:
1.53 fvdl 1307: if (ap->a_ncookies) {
1308: ncookies = min(ncookies, (nproc_targets - i));
1.72 thorpej 1309: cookies = malloc(ncookies * sizeof (off_t),
1.53 fvdl 1310: M_TEMP, M_WAITOK);
1311: *ap->a_cookies = cookies;
1312: }
1313:
1.32 mycroft 1314: for (pt = &proc_targets[i];
1315: uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
1.145 ad 1316: if (pt->pt_valid) {
1317: /* XXXSMP locking */
1318: mutex_enter(&p->p_smutex);
1319: l = proc_representative_lwp(p, NULL, 1);
1320: mutex_exit(&p->p_smutex);
1321: if ((*pt->pt_valid)(l, vp->v_mount) == 0)
1322: continue;
1323: }
1.121 perry 1324:
1.91 christos 1325: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1326: pt->pt_pfstype, -1);
1.34 mycroft 1327: d.d_namlen = pt->pt_namlen;
1.56 perry 1328: memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1.34 mycroft 1329: d.d_type = pt->pt_type;
1.15 ws 1330:
1.113 jrf 1331: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.9 cgd 1332: break;
1.53 fvdl 1333: if (cookies)
1.35 mycroft 1334: *cookies++ = i + 1;
1.6 ws 1335: }
1.9 cgd 1336:
1.145 ad 1337: procfs_proc_unlock(p);
1.9 cgd 1338: break;
1.34 mycroft 1339: }
1.109 darcy 1340: case PFSfd: {
1.91 christos 1341: struct proc *p;
1342: struct filedesc *fdp;
1.111 jdolecek 1343: struct file *fp;
1.110 simonb 1344: int lim, nc = 0;
1.91 christos 1345:
1.145 ad 1346: if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH)) != 0)
1347: return error;
1.91 christos 1348:
1.133 yamt 1349: if (kauth_authorize_process(kauth_cred_get(),
1.145 ad 1350: KAUTH_PROCESS_CANSEE, p, NULL, NULL, NULL) != 0) {
1351: procfs_proc_unlock(p);
1.133 yamt 1352: return ESRCH;
1.145 ad 1353: }
1.125 elad 1354:
1.145 ad 1355: fdp = p->p_fd; /* XXXSMP */
1.91 christos 1356:
1357: lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
1.145 ad 1358: if (i >= lim) {
1359: procfs_proc_unlock(p);
1.91 christos 1360: return 0;
1.145 ad 1361: }
1.91 christos 1362:
1363: if (ap->a_ncookies) {
1364: ncookies = min(ncookies, (fdp->fd_nfiles + 2 - i));
1365: cookies = malloc(ncookies * sizeof (off_t),
1366: M_TEMP, M_WAITOK);
1367: *ap->a_cookies = cookies;
1368: }
1369:
1370: for (; i < 2 && uio->uio_resid >= UIO_MX; i++) {
1371: pt = &proc_targets[i];
1372: d.d_namlen = pt->pt_namlen;
1373: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1374: pt->pt_pfstype, -1);
1375: (void)memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1376: d.d_type = pt->pt_type;
1.113 jrf 1377: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.91 christos 1378: break;
1379: if (cookies)
1380: *cookies++ = i + 1;
1381: nc++;
1382: }
1383: if (error) {
1384: ncookies = nc;
1385: break;
1386: }
1387: for (; uio->uio_resid >= UIO_MX && i < fdp->fd_nfiles; i++) {
1.111 jdolecek 1388: /* check the descriptor exists */
1389: if ((fp = fd_getfile(fdp, i - 2)) == NULL)
1.100 jdolecek 1390: continue;
1.111 jdolecek 1391: simple_unlock(&fp->f_slock);
1392:
1.109 darcy 1393: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, PFSfd, i - 2);
1.91 christos 1394: d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
1.93 martin 1395: "%lld", (long long)(i - 2));
1.91 christos 1396: d.d_type = VREG;
1.113 jrf 1397: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.91 christos 1398: break;
1399: if (cookies)
1400: *cookies++ = i + 1;
1401: nc++;
1402: }
1403: ncookies = nc;
1.145 ad 1404: procfs_proc_unlock(p);
1.91 christos 1405: break;
1406: }
1.9 cgd 1407:
1408: /*
1409: * this is for the root of the procfs filesystem
1.69 thorpej 1410: * what is needed are special entries for "curproc"
1411: * and "self" followed by an entry for each process
1.117 yamt 1412: * on allproc.
1.9 cgd 1413: */
1414:
1.109 darcy 1415: case PFSroot: {
1.117 yamt 1416: int nc = 0;
1.9 cgd 1417:
1.53 fvdl 1418: if (ap->a_ncookies) {
1419: /*
1420: * XXX Potentially allocating too much space here,
1421: * but I'm lazy. This loop needs some work.
1422: */
1.72 thorpej 1423: cookies = malloc(ncookies * sizeof (off_t),
1.53 fvdl 1424: M_TEMP, M_WAITOK);
1425: *ap->a_cookies = cookies;
1426: }
1.117 yamt 1427: error = 0;
1428: /* 0 ... 3 are static entries. */
1429: for (; i <= 3 && uio->uio_resid >= UIO_MX; i++) {
1.9 cgd 1430: switch (i) {
1.12 ws 1431: case 0: /* `.' */
1432: case 1: /* `..' */
1.109 darcy 1433: d.d_fileno = PROCFS_FILENO(0, PFSroot, -1);
1.34 mycroft 1434: d.d_namlen = i + 1;
1.56 perry 1435: memcpy(d.d_name, "..", d.d_namlen);
1.34 mycroft 1436: d.d_name[i + 1] = '\0';
1437: d.d_type = DT_DIR;
1.12 ws 1438: break;
1.21 mycroft 1439:
1.12 ws 1440: case 2:
1.109 darcy 1441: d.d_fileno = PROCFS_FILENO(0, PFScurproc, -1);
1.69 thorpej 1442: d.d_namlen = sizeof("curproc") - 1;
1443: memcpy(d.d_name, "curproc", sizeof("curproc"));
1444: d.d_type = DT_LNK;
1445: break;
1446:
1447: case 3:
1.109 darcy 1448: d.d_fileno = PROCFS_FILENO(0, PFSself, -1);
1.69 thorpej 1449: d.d_namlen = sizeof("self") - 1;
1450: memcpy(d.d_name, "self", sizeof("self"));
1.34 mycroft 1451: d.d_type = DT_LNK;
1.9 cgd 1452: break;
1.1 pk 1453: }
1.21 mycroft 1454:
1.113 jrf 1455: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.9 cgd 1456: break;
1.53 fvdl 1457: nc++;
1458: if (cookies)
1.35 mycroft 1459: *cookies++ = i + 1;
1.1 pk 1460: }
1.117 yamt 1461: /* 4 ... are process entries. */
1462: ctx.uiop = uio;
1463: ctx.error = 0;
1.120 yamt 1464: ctx.off = 4;
1465: ctx.startoff = i;
1.117 yamt 1466: ctx.cookies = cookies;
1467: ctx.ncookies = nc;
1468: proclist_foreach_call(&allproc,
1469: procfs_root_readdir_callback, &ctx);
1470: cookies = ctx.cookies;
1471: nc = ctx.ncookies;
1472: error = ctx.error;
1473: if (error)
1474: break;
1.76 fvdl 1475:
1.117 yamt 1476: /* misc entries. */
1.120 yamt 1477: if (i < ctx.off)
1478: i = ctx.off;
1479: if (i >= ctx.off + nproc_root_targets)
1.76 fvdl 1480: break;
1.120 yamt 1481: for (pt = &proc_root_targets[i - ctx.off];
1.117 yamt 1482: uio->uio_resid >= UIO_MX &&
1483: pt < &proc_root_targets[nproc_root_targets];
1484: pt++, i++) {
1.76 fvdl 1485: if (pt->pt_valid &&
1486: (*pt->pt_valid)(NULL, vp->v_mount) == 0)
1487: continue;
1.91 christos 1488: d.d_fileno = PROCFS_FILENO(0, pt->pt_pfstype, -1);
1.76 fvdl 1489: d.d_namlen = pt->pt_namlen;
1490: memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1491: d.d_type = pt->pt_type;
1492:
1.113 jrf 1493: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.76 fvdl 1494: break;
1495: nc++;
1496: if (cookies)
1497: *cookies++ = i + 1;
1498: }
1499:
1.53 fvdl 1500: ncookies = nc;
1.9 cgd 1501: break;
1.34 mycroft 1502: }
1.9 cgd 1503:
1504: default:
1505: error = ENOTDIR;
1506: break;
1.1 pk 1507: }
1.9 cgd 1508:
1.53 fvdl 1509: if (ap->a_ncookies) {
1510: if (error) {
1.54 fvdl 1511: if (cookies)
1.72 thorpej 1512: free(*ap->a_cookies, M_TEMP);
1.53 fvdl 1513: *ap->a_ncookies = 0;
1514: *ap->a_cookies = NULL;
1515: } else
1516: *ap->a_ncookies = ncookies;
1517: }
1.35 mycroft 1518: uio->uio_offset = i;
1.9 cgd 1519: return (error);
1.12 ws 1520: }
1521:
1522: /*
1.126 atatat 1523: * readlink reads the link of `curproc' and others
1.12 ws 1524: */
1.37 christos 1525: int
1526: procfs_readlink(v)
1527: void *v;
1.12 ws 1528: {
1.37 christos 1529: struct vop_readlink_args *ap = v;
1.123 christos 1530: char bf[16]; /* should be enough */
1531: char *bp = bf;
1.102 christos 1532: char *path = NULL;
1.12 ws 1533: int len;
1.102 christos 1534: int error = 0;
1535: struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.126 atatat 1536: struct proc *pown;
1.12 ws 1537:
1.109 darcy 1538: if (pfs->pfs_fileno == PROCFS_FILENO(0, PFScurproc, -1))
1.123 christos 1539: len = snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
1.109 darcy 1540: else if (pfs->pfs_fileno == PROCFS_FILENO(0, PFSself, -1))
1.123 christos 1541: len = snprintf(bf, sizeof(bf), "%s", "curproc");
1.136 christos 1542: else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFScwd, -1) ||
1543: pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSchroot, -1) ||
1544: pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSexe, -1)) {
1.145 ad 1545: if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
1546: return error;
1.126 atatat 1547: MALLOC(path, char *, MAXPATHLEN + 4, M_TEMP,
1548: M_WAITOK|M_CANFAIL);
1.145 ad 1549: if (path == NULL) {
1550: procfs_proc_unlock(pown);
1.126 atatat 1551: return (ENOMEM);
1.145 ad 1552: }
1.126 atatat 1553: bp = path + MAXPATHLEN;
1554: *--bp = '\0';
1.145 ad 1555: mutex_enter(&pown->p_mutex);
1.136 christos 1556: (void)procfs_dir(PROCFS_TYPE(pfs->pfs_fileno), curlwp, pown,
1557: &bp, path, MAXPATHLEN);
1.145 ad 1558: mutex_exit(&pown->p_mutex);
1559: procfs_proc_unlock(pown);
1.126 atatat 1560: len = strlen(bp);
1.136 christos 1561: } else {
1.102 christos 1562: struct file *fp;
1563: struct vnode *vxp, *vp;
1564:
1.145 ad 1565: if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
1.102 christos 1566: return error;
1.155 rmind 1567:
1.145 ad 1568: mutex_enter(&pown->p_mutex);
1569: fp = fd_getfile(pown->p_fd, pfs->pfs_fd);
1570: mutex_exit(&pown->p_mutex);
1.156 rmind 1571: if (fp == NULL) {
1572: procfs_proc_unlock(pown);
1.155 rmind 1573: return EBADF;
1.156 rmind 1574: }
1.155 rmind 1575:
1.102 christos 1576: FILE_USE(fp);
1577: switch (fp->f_type) {
1578: case DTYPE_VNODE:
1579: vxp = (struct vnode *)fp->f_data;
1580: if (vxp->v_type != VDIR) {
1.145 ad 1581: FILE_UNUSE(fp, curlwp);
1582: error = EINVAL;
1583: break;
1.102 christos 1584: }
1585: if ((path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK))
1586: == NULL) {
1.145 ad 1587: FILE_UNUSE(fp, curlwp);
1588: error = ENOMEM;
1589: break;
1.102 christos 1590: }
1591: bp = path + MAXPATHLEN;
1592: *--bp = '\0';
1.145 ad 1593: vp = curproc->p_cwdi->cwdi_rdir; /* XXXSMP */
1.102 christos 1594: if (vp == NULL)
1595: vp = rootvnode;
1596: error = getcwd_common(vxp, vp, &bp, path,
1.128 christos 1597: MAXPATHLEN / 2, 0, curlwp);
1.145 ad 1598: FILE_UNUSE(fp, curlwp);
1599: if (error)
1600: break;
1.102 christos 1601: len = strlen(bp);
1602: break;
1603:
1604: case DTYPE_MISC:
1.123 christos 1605: len = snprintf(bf, sizeof(bf), "%s", "[misc]");
1.102 christos 1606: break;
1607:
1608: case DTYPE_KQUEUE:
1.123 christos 1609: len = snprintf(bf, sizeof(bf), "%s", "[kqueue]");
1.102 christos 1610: break;
1611:
1612: default:
1.145 ad 1613: error = EINVAL;
1614: break;
1615: }
1616: procfs_proc_unlock(pown);
1.102 christos 1617: }
1.12 ws 1618:
1.145 ad 1619: if (error == 0)
1620: error = uiomove(bp, len, ap->a_uio);
1.102 christos 1621: if (path)
1622: free(path, M_TEMP);
1623: return error;
1.1 pk 1624: }
1625:
1626: /*
1.91 christos 1627: * convert decimal ascii to int
1.1 pk 1628: */
1.91 christos 1629: static int
1630: atoi(b, len)
1.9 cgd 1631: const char *b;
1.91 christos 1632: size_t len;
1.1 pk 1633: {
1.91 christos 1634: int p = 0;
1.1 pk 1635:
1636: while (len--) {
1.9 cgd 1637: char c = *b++;
1.1 pk 1638: if (c < '0' || c > '9')
1.91 christos 1639: return -1;
1.9 cgd 1640: p = 10 * p + (c - '0');
1.1 pk 1641: }
1.9 cgd 1642:
1.91 christos 1643: return p;
1.1 pk 1644: }
CVSweb <webmaster@jp.NetBSD.org>