Annotation of src/sys/miscfs/procfs/procfs_vnops.c, Revision 1.161
1.161 ! ad 1: /* $NetBSD: procfs_vnops.c,v 1.160 2007/10/10 20:42:30 ad 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.161 ! ad 115: __KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.160 2007/10/10 20:42:30 ad 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.161 ! ad 148: static void 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.161 ! ad 337: if (error) {
! 338: procfs_proc_unlock(p2);
1.144 elad 339: return (error);
1.161 ! ad 340: }
1.144 elad 341:
342: #undef M2K
343:
1.9 cgd 344: switch (pfs->pfs_type) {
1.109 darcy 345: case PFSmem:
1.37 christos 346: if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
1.145 ad 347: ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) {
348: error = EBUSY;
349: break;
350: }
1.50 thorpej 351:
1.161 ! ad 352: if (!proc_isunder(p2, l1)) {
! 353: error = EPERM;
! 354: break;
! 355: }
1.141 elad 356:
1.21 mycroft 357: if (ap->a_mode & FWRITE)
358: pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
1.1 pk 359:
1.144 elad 360: break;
361:
362: case PFSregs:
363: case PFSfpregs:
1.161 ! ad 364: if (!proc_isunder(p2, l1)) {
! 365: error = EPERM;
! 366: break;
! 367: }
1.144 elad 368: break;
1.1 pk 369:
1.9 cgd 370: default:
371: break;
372: }
1.1 pk 373:
1.145 ad 374: procfs_proc_unlock(p2);
375: return (error);
1.1 pk 376: }
377:
378: /*
1.9 cgd 379: * close the pfsnode (vp) after doing i/o.
380: * (vp) is not locked on entry or exit.
381: *
382: * nothing to do for procfs other than undo
383: * any exclusive open flag (see _open above).
1.1 pk 384: */
1.37 christos 385: int
386: procfs_close(v)
387: void *v;
388: {
1.22 mycroft 389: struct vop_close_args /* {
390: struct vnode *a_vp;
391: int a_fflag;
1.130 elad 392: kauth_cred_t a_cred;
1.128 christos 393: struct lwp *a_l;
1.37 christos 394: } */ *ap = v;
1.21 mycroft 395: struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.1 pk 396:
1.9 cgd 397: switch (pfs->pfs_type) {
1.109 darcy 398: case PFSmem:
1.21 mycroft 399: if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
1.9 cgd 400: pfs->pfs_flags &= ~(FWRITE|O_EXCL);
401: break;
1.46 mycroft 402:
403: default:
1.37 christos 404: break;
1.9 cgd 405: }
1.1 pk 406:
407: return (0);
408: }
409:
410: /*
1.9 cgd 411: * _inactive is called when the pfsnode
412: * is vrele'd and the reference count goes
413: * to zero. (vp) will be on the vnode free
414: * list, so to get it back vget() must be
415: * used.
416: *
1.62 wrstuden 417: * (vp) is locked on entry, but must be unlocked on exit.
1.1 pk 418: */
1.37 christos 419: int
420: procfs_inactive(v)
421: void *v;
422: {
1.22 mycroft 423: struct vop_inactive_args /* {
424: struct vnode *a_vp;
1.161 ! ad 425: bool *a_recycle;
1.37 christos 426: } */ *ap = v;
1.122 christos 427: struct vnode *vp = ap->a_vp;
428: struct pfsnode *pfs = VTOPFS(vp);
1.161 ! ad 429: bool recycle;
! 430:
! 431: mutex_enter(&proclist_lock);
! 432: recycle = (p_find(pfs->pfs_pid, PFIND_LOCKED) == NULL);
! 433: mutex_exit(&proclist_lock);
1.1 pk 434:
1.122 christos 435: VOP_UNLOCK(vp, 0);
1.145 ad 436:
1.161 ! ad 437: if (recycle)
1.122 christos 438: vgone(vp);
1.5 pk 439:
1.9 cgd 440: return (0);
1.1 pk 441: }
442:
443: /*
1.9 cgd 444: * _reclaim is called when getnewvnode()
445: * wants to make use of an entry on the vnode
446: * free list. at this time the filesystem needs
447: * to free any private data and remove the node
448: * from any private lists.
1.1 pk 449: */
1.37 christos 450: int
451: procfs_reclaim(v)
452: void *v;
453: {
1.22 mycroft 454: struct vop_reclaim_args /* {
455: struct vnode *a_vp;
1.37 christos 456: } */ *ap = v;
1.21 mycroft 457:
458: return (procfs_freevp(ap->a_vp));
459: }
460:
461: /*
462: * Return POSIX pathconf information applicable to special devices.
463: */
1.37 christos 464: int
465: procfs_pathconf(v)
466: void *v;
467: {
1.21 mycroft 468: struct vop_pathconf_args /* {
469: struct vnode *a_vp;
470: int a_name;
1.26 cgd 471: register_t *a_retval;
1.37 christos 472: } */ *ap = v;
1.1 pk 473:
1.21 mycroft 474: switch (ap->a_name) {
475: case _PC_LINK_MAX:
476: *ap->a_retval = LINK_MAX;
477: return (0);
478: case _PC_MAX_CANON:
479: *ap->a_retval = MAX_CANON;
480: return (0);
481: case _PC_MAX_INPUT:
482: *ap->a_retval = MAX_INPUT;
483: return (0);
484: case _PC_PIPE_BUF:
485: *ap->a_retval = PIPE_BUF;
486: return (0);
487: case _PC_CHOWN_RESTRICTED:
488: *ap->a_retval = 1;
489: return (0);
490: case _PC_VDISABLE:
491: *ap->a_retval = _POSIX_VDISABLE;
1.55 kleink 492: return (0);
493: case _PC_SYNC_IO:
494: *ap->a_retval = 1;
1.21 mycroft 495: return (0);
496: default:
497: return (EINVAL);
498: }
499: /* NOTREACHED */
1.1 pk 500: }
501:
502: /*
1.9 cgd 503: * _print is used for debugging.
504: * just print a readable description
505: * of (vp).
1.1 pk 506: */
1.37 christos 507: int
508: procfs_print(v)
509: void *v;
510: {
1.22 mycroft 511: struct vop_print_args /* {
512: struct vnode *a_vp;
1.37 christos 513: } */ *ap = v;
1.21 mycroft 514: struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.5 pk 515:
1.44 christos 516: printf("tag VT_PROCFS, type %d, pid %d, mode %x, flags %lx\n",
1.21 mycroft 517: pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
1.37 christos 518: return 0;
1.36 mycroft 519: }
520:
521: int
1.121 perry 522: procfs_link(v)
1.37 christos 523: void *v;
524: {
1.36 mycroft 525: struct vop_link_args /* {
526: struct vnode *a_dvp;
1.121 perry 527: struct vnode *a_vp;
1.36 mycroft 528: struct componentname *a_cnp;
1.37 christos 529: } */ *ap = v;
1.121 perry 530:
1.36 mycroft 531: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
532: vput(ap->a_dvp);
533: return (EROFS);
534: }
535:
536: int
1.37 christos 537: procfs_symlink(v)
538: void *v;
539: {
1.36 mycroft 540: struct vop_symlink_args /* {
541: struct vnode *a_dvp;
542: struct vnode **a_vpp;
543: struct componentname *a_cnp;
544: struct vattr *a_vap;
545: char *a_target;
1.37 christos 546: } */ *ap = v;
1.121 perry 547:
1.36 mycroft 548: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
549: vput(ap->a_dvp);
550: return (EROFS);
1.1 pk 551: }
552:
553: /*
1.126 atatat 554: * Works out the path to (and vnode of) the target process's current
555: * working directory or chroot. If the caller is in a chroot and
556: * can't "reach" the target's cwd or root (or some other error
557: * occurs), a "/" is returned for the path and a NULL pointer is
558: * returned for the vnode.
559: */
1.161 ! ad 560: static void
1.128 christos 561: procfs_dir(pfstype t, struct lwp *caller, struct proc *target,
1.126 atatat 562: char **bpp, char *path, int len)
563: {
1.161 ! ad 564: struct cwdinfo *cwdi;
! 565: struct vnode *vp, *rvp;
1.126 atatat 566: char *bp;
567:
1.161 ! ad 568: cwdi = caller->l_proc->p_cwdi;
! 569: rw_enter(&cwdi->cwdi_lock, RW_READER);
1.145 ad 570:
1.161 ! ad 571: rvp = cwdi->cwdi_rdir;
1.126 atatat 572: bp = bpp ? *bpp : NULL;
573:
574: switch (t) {
575: case PFScwd:
576: vp = target->p_cwdi->cwdi_cdir;
577: break;
578: case PFSchroot:
579: vp = target->p_cwdi->cwdi_rdir;
580: break;
1.136 christos 581: case PFSexe:
582: vp = target->p_textvp;
583: break;
1.126 atatat 584: default:
1.161 ! ad 585: rw_exit(&cwdi->cwdi_lock);
! 586: return;
1.126 atatat 587: }
588:
1.158 pooka 589: /*
590: * XXX: this horrible kludge avoids locking panics when
591: * attempting to lookup links that point to within procfs
592: */
593: if (vp != NULL && vp->v_tag == VT_PROCFS) {
594: if (bpp) {
595: *--bp = '/';
596: *bpp = bp;
597: }
1.161 ! ad 598: rw_exit(&cwdi->cwdi_lock);
! 599: return;
1.158 pooka 600: }
601:
1.126 atatat 602: if (rvp == NULL)
603: rvp = rootvnode;
604: if (vp == NULL || getcwd_common(vp, rvp, bp ? &bp : NULL, path,
605: len / 2, 0, caller) != 0) {
606: vp = NULL;
607: if (bpp) {
1.153 christos 608: /*
609: if (t == PFSexe) {
610: snprintf(path, len, "%s/%d/file"
611: mp->mnt_stat.f_mntonname, pfs->pfs_pid);
612: } else */ {
613: bp = *bpp;
614: *--bp = '/';
615: }
1.126 atatat 616: }
617: }
618:
619: if (bpp)
620: *bpp = bp;
621:
1.161 ! ad 622: rw_exit(&cwdi->cwdi_lock);
1.126 atatat 623: }
624:
625: /*
1.9 cgd 626: * Invent attributes for pfsnode (vp) and store
627: * them in (vap).
628: * Directories lengths are returned as zero since
629: * any real length would require the genuine size
630: * to be computed, and nothing cares anyway.
631: *
632: * this is relatively minimal for procfs.
1.1 pk 633: */
1.37 christos 634: int
635: procfs_getattr(v)
636: void *v;
637: {
1.22 mycroft 638: struct vop_getattr_args /* {
639: struct vnode *a_vp;
640: struct vattr *a_vap;
1.130 elad 641: kauth_cred_t a_cred;
1.128 christos 642: struct lwp *a_l;
1.37 christos 643: } */ *ap = v;
1.21 mycroft 644: struct pfsnode *pfs = VTOPFS(ap->a_vp);
645: struct vattr *vap = ap->a_vap;
1.1 pk 646: struct proc *procp;
1.145 ad 647: char *path;
1.9 cgd 648: int error;
1.1 pk 649:
1.21 mycroft 650: /* first check the process still exists */
651: switch (pfs->pfs_type) {
1.109 darcy 652: case PFSroot:
653: case PFScurproc:
654: case PFSself:
1.145 ad 655: procp = NULL;
656: break;
657:
658: default:
659: error = procfs_proc_lock(pfs->pfs_pid, &procp, ENOENT);
660: if (error != 0)
661: return (error);
662: break;
663: }
664:
665: switch (pfs->pfs_type) {
666: case PFScwd:
667: case PFSchroot:
668: case PFSexe:
669: MALLOC(path, char *, MAXPATHLEN + 4, M_TEMP,
670: M_WAITOK|M_CANFAIL);
1.146 ad 671: if (path == NULL && procp != NULL) {
1.145 ad 672: procfs_proc_unlock(procp);
673: return (ENOMEM);
674: }
1.21 mycroft 675: break;
676:
677: default:
1.145 ad 678: path = NULL;
1.46 mycroft 679: break;
1.21 mycroft 680: }
681:
1.125 elad 682: if (procp != NULL) {
1.145 ad 683: mutex_enter(&procp->p_mutex);
1.146 ad 684: error = kauth_authorize_process(kauth_cred_get(),
685: KAUTH_PROCESS_CANSEE, procp, NULL, NULL, NULL);
686: mutex_exit(&procp->p_mutex);
687: if (error != 0) {
1.145 ad 688: procfs_proc_unlock(procp);
689: if (path != NULL)
690: free(path, M_TEMP);
1.125 elad 691: return (ENOENT);
1.145 ad 692: }
1.125 elad 693: }
694:
1.21 mycroft 695: error = 0;
696:
1.9 cgd 697: /* start by zeroing out the attributes */
1.1 pk 698: VATTR_NULL(vap);
1.9 cgd 699:
700: /* next do all the common fields */
1.21 mycroft 701: vap->va_type = ap->a_vp->v_type;
1.9 cgd 702: vap->va_mode = pfs->pfs_mode;
703: vap->va_fileid = pfs->pfs_fileno;
704: vap->va_flags = 0;
1.19 cgd 705: vap->va_blocksize = PAGE_SIZE;
1.9 cgd 706:
707: /*
1.131 kardel 708: * Make all times be current TOD.
1.90 simonb 709: *
1.9 cgd 710: * It would be possible to get the process start
1.126 atatat 711: * time from the p_stats structure, but there's
1.9 cgd 712: * no "file creation" time stamp anyway, and the
1.126 atatat 713: * p_stats structure is not addressable if u. gets
1.9 cgd 714: * swapped out for that process.
715: */
1.131 kardel 716: getnanotime(&vap->va_ctime);
1.9 cgd 717: vap->va_atime = vap->va_mtime = vap->va_ctime;
1.126 atatat 718: if (procp)
719: TIMEVAL_TO_TIMESPEC(&procp->p_stats->p_start,
720: &vap->va_birthtime);
721: else
1.131 kardel 722: getnanotime(&vap->va_birthtime);
1.9 cgd 723:
1.21 mycroft 724: switch (pfs->pfs_type) {
1.109 darcy 725: case PFSmem:
726: case PFSregs:
727: case PFSfpregs:
1.86 thorpej 728: #if defined(__HAVE_PROCFS_MACHDEP) && defined(PROCFS_MACHDEP_PROTECT_CASES)
729: PROCFS_MACHDEP_PROTECT_CASES
730: #endif
1.47 mycroft 731: /*
732: * If the process has exercised some setuid or setgid
733: * privilege, then rip away read/write permission so
734: * that only root can gain access.
735: */
1.149 pavel 736: if (procp->p_flag & PK_SUGID)
1.47 mycroft 737: vap->va_mode &= ~(S_IRUSR|S_IWUSR);
1.46 mycroft 738: /* FALLTHROUGH */
1.109 darcy 739: case PFSctl:
740: case PFSstatus:
741: case PFSstat:
742: case PFSnote:
743: case PFSnotepg:
744: case PFSmap:
745: case PFSmaps:
746: case PFScmdline:
1.137 christos 747: case PFSemul:
1.157 agc 748: case PFSstatm:
1.12 ws 749: vap->va_nlink = 1;
1.130 elad 750: vap->va_uid = kauth_cred_geteuid(procp->p_cred);
751: vap->va_gid = kauth_cred_getegid(procp->p_cred);
1.21 mycroft 752: break;
1.109 darcy 753: case PFSmeminfo:
1.134 manu 754: case PFSdevices:
1.109 darcy 755: case PFScpuinfo:
756: case PFSuptime:
1.114 jdolecek 757: case PFSmounts:
1.157 agc 758: case PFScpustat:
759: case PFSloadavg:
1.76 fvdl 760: vap->va_nlink = 1;
761: vap->va_uid = vap->va_gid = 0;
762: break;
1.46 mycroft 763:
764: default:
1.37 christos 765: break;
1.12 ws 766: }
767:
1.9 cgd 768: /*
769: * now do the object specific fields
770: *
771: * The size could be set from struct reg, but it's hardly
772: * worth the trouble, and it puts some (potentially) machine
773: * dependent data into this machine-independent code. If it
774: * becomes important then this function should break out into
775: * a per-file stat function in the corresponding .c file.
776: */
1.1 pk 777:
1.9 cgd 778: switch (pfs->pfs_type) {
1.109 darcy 779: case PFSroot:
1.21 mycroft 780: /*
781: * Set nlink to 1 to tell fts(3) we don't actually know.
782: */
783: vap->va_nlink = 1;
784: vap->va_uid = 0;
785: vap->va_gid = 0;
1.46 mycroft 786: vap->va_bytes = vap->va_size = DEV_BSIZE;
1.21 mycroft 787: break;
788:
1.129 christos 789: case PFSself:
1.109 darcy 790: case PFScurproc: {
1.123 christos 791: char bf[16]; /* should be enough */
1.21 mycroft 792: vap->va_nlink = 1;
793: vap->va_uid = 0;
794: vap->va_gid = 0;
1.46 mycroft 795: vap->va_bytes = vap->va_size =
1.123 christos 796: snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
1.9 cgd 797: break;
1.21 mycroft 798: }
1.9 cgd 799:
1.109 darcy 800: case PFSfd:
1.91 christos 801: if (pfs->pfs_fd != -1) {
802: struct file *fp;
1.98 jdolecek 803:
1.145 ad 804: fp = fd_getfile(procp->p_fd, pfs->pfs_fd);
805: if (fp == NULL) {
806: error = EBADF;
807: break;
808: }
1.98 jdolecek 809: FILE_USE(fp);
1.91 christos 810: vap->va_nlink = 1;
1.130 elad 811: vap->va_uid = kauth_cred_geteuid(fp->f_cred);
812: vap->va_gid = kauth_cred_getegid(fp->f_cred);
1.91 christos 813: switch (fp->f_type) {
814: case DTYPE_VNODE:
815: vap->va_bytes = vap->va_size =
816: ((struct vnode *)fp->f_data)->v_size;
817: break;
818: default:
819: vap->va_bytes = vap->va_size = 0;
820: break;
821: }
1.145 ad 822: FILE_UNUSE(fp, curlwp);
1.91 christos 823: break;
824: }
825: /*FALLTHROUGH*/
1.109 darcy 826: case PFSproc:
1.9 cgd 827: vap->va_nlink = 2;
1.130 elad 828: vap->va_uid = kauth_cred_geteuid(procp->p_cred);
829: vap->va_gid = kauth_cred_getegid(procp->p_cred);
1.46 mycroft 830: vap->va_bytes = vap->va_size = DEV_BSIZE;
1.21 mycroft 831: break;
832:
1.109 darcy 833: case PFSfile:
1.21 mycroft 834: error = EOPNOTSUPP;
1.9 cgd 835: break;
836:
1.109 darcy 837: case PFSmem:
1.9 cgd 838: vap->va_bytes = vap->va_size =
839: ctob(procp->p_vmspace->vm_tsize +
840: procp->p_vmspace->vm_dsize +
841: procp->p_vmspace->vm_ssize);
842: break;
843:
1.18 cgd 844: #if defined(PT_GETREGS) || defined(PT_SETREGS)
1.109 darcy 845: case PFSregs:
1.11 cgd 846: vap->va_bytes = vap->va_size = sizeof(struct reg);
1.18 cgd 847: break;
1.14 cgd 848: #endif
849:
1.18 cgd 850: #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
1.109 darcy 851: case PFSfpregs:
1.14 cgd 852: vap->va_bytes = vap->va_size = sizeof(struct fpreg);
1.18 cgd 853: break;
1.14 cgd 854: #endif
1.12 ws 855:
1.109 darcy 856: case PFSctl:
857: case PFSstatus:
858: case PFSstat:
859: case PFSnote:
860: case PFSnotepg:
861: case PFScmdline:
862: case PFSmeminfo:
1.134 manu 863: case PFSdevices:
1.109 darcy 864: case PFScpuinfo:
865: case PFSuptime:
1.114 jdolecek 866: case PFSmounts:
1.157 agc 867: case PFScpustat:
868: case PFSloadavg:
869: case PFSstatm:
1.46 mycroft 870: vap->va_bytes = vap->va_size = 0;
1.79 fvdl 871: break;
1.109 darcy 872: case PFSmap:
873: case PFSmaps:
1.79 fvdl 874: /*
875: * Advise a larger blocksize for the map files, so that
876: * they may be read in one pass.
877: */
1.80 fvdl 878: vap->va_blocksize = 4 * PAGE_SIZE;
1.83 chs 879: vap->va_bytes = vap->va_size = 0;
1.9 cgd 880: break;
1.86 thorpej 881:
1.126 atatat 882: case PFScwd:
1.136 christos 883: case PFSchroot:
884: case PFSexe: {
1.145 ad 885: char *bp;
1.126 atatat 886:
887: vap->va_nlink = 1;
888: vap->va_uid = 0;
889: vap->va_gid = 0;
890: bp = path + MAXPATHLEN;
891: *--bp = '\0';
1.161 ! ad 892: procfs_dir(pfs->pfs_type, curlwp, procp, &bp, path,
1.126 atatat 893: MAXPATHLEN);
894: vap->va_bytes = vap->va_size = strlen(bp);
895: break;
896: }
897:
1.137 christos 898: case PFSemul:
899: vap->va_bytes = vap->va_size = strlen(procp->p_emul->e_name);
900: break;
901:
1.86 thorpej 902: #ifdef __HAVE_PROCFS_MACHDEP
903: PROCFS_MACHDEP_NODETYPE_CASES
904: error = procfs_machdep_getattr(ap->a_vp, vap, procp);
905: break;
906: #endif
1.1 pk 907:
1.9 cgd 908: default:
1.21 mycroft 909: panic("procfs_getattr");
1.1 pk 910: }
911:
1.146 ad 912: if (procp != NULL)
1.145 ad 913: procfs_proc_unlock(procp);
914: if (path != NULL)
915: free(path, M_TEMP);
916:
1.9 cgd 917: return (error);
1.1 pk 918: }
919:
1.37 christos 920: /*ARGSUSED*/
921: int
1.138 christos 922: procfs_setattr(void *v)
1.5 pk 923: {
924: /*
1.9 cgd 925: * just fake out attribute setting
926: * it's not good to generate an error
927: * return, otherwise things like creat()
928: * will fail when they try to set the
929: * file length to 0. worse, this means
930: * that echo $note > /proc/$pid/note will fail.
1.5 pk 931: */
932:
1.9 cgd 933: return (0);
1.5 pk 934: }
935:
1.9 cgd 936: /*
937: * implement access checking.
938: *
939: * actually, the check for super-user is slightly
940: * broken since it will allow read access to write-only
941: * objects. this doesn't cause any particular trouble
942: * but does mean that the i/o entry points need to check
943: * that the operation really does make sense.
944: */
1.37 christos 945: int
946: procfs_access(v)
947: void *v;
948: {
1.22 mycroft 949: struct vop_access_args /* {
950: struct vnode *a_vp;
951: int a_mode;
1.130 elad 952: kauth_cred_t a_cred;
1.128 christos 953: struct lwp *a_l;
1.37 christos 954: } */ *ap = v;
1.31 mycroft 955: struct vattr va;
1.1 pk 956: int error;
957:
1.128 christos 958: if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_l)) != 0)
1.1 pk 959: return (error);
1.9 cgd 960:
1.49 mycroft 961: return (vaccess(va.va_type, va.va_mode,
962: va.va_uid, va.va_gid, ap->a_mode, ap->a_cred));
1.1 pk 963: }
964:
965: /*
1.9 cgd 966: * lookup. this is incredibly complicated in the
967: * general case, however for most pseudo-filesystems
968: * very little needs to be done.
969: *
1.62 wrstuden 970: * Locking isn't hard here, just poorly documented.
971: *
1.121 perry 972: * If we're looking up ".", just vref the parent & return it.
1.62 wrstuden 973: *
974: * If we're looking up "..", unlock the parent, and lock "..". If everything
975: * went ok, and we're on the last component and the caller requested the
976: * parent locked, try to re-lock the parent. We do this to prevent lock
977: * races.
978: *
979: * For anything else, get the needed node. Then unlock the parent if not
980: * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the
981: * parent in the .. case).
982: *
983: * We try to exit with the parent locked in error cases.
1.9 cgd 984: */
1.37 christos 985: int
986: procfs_lookup(v)
987: void *v;
988: {
1.22 mycroft 989: struct vop_lookup_args /* {
990: struct vnode * a_dvp;
991: struct vnode ** a_vpp;
992: struct componentname * a_cnp;
1.37 christos 993: } */ *ap = v;
1.21 mycroft 994: struct componentname *cnp = ap->a_cnp;
995: struct vnode **vpp = ap->a_vpp;
996: struct vnode *dvp = ap->a_dvp;
1.45 cgd 997: const char *pname = cnp->cn_nameptr;
1.78 jdolecek 998: const struct proc_target *pt = NULL;
1.32 mycroft 999: struct vnode *fvp;
1.146 ad 1000: pid_t pid, vnpid;
1.9 cgd 1001: struct pfsnode *pfs;
1.76 fvdl 1002: struct proc *p = NULL;
1.128 christos 1003: struct lwp *l = NULL;
1.146 ad 1004: int i, error;
1005: pfstype type;
1.1 pk 1006:
1.32 mycroft 1007: *vpp = NULL;
1008:
1009: if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
1010: return (EROFS);
1011:
1.21 mycroft 1012: if (cnp->cn_namelen == 1 && *pname == '.') {
1013: *vpp = dvp;
1.9 cgd 1014: VREF(dvp);
1015: return (0);
1016: }
1.1 pk 1017:
1.9 cgd 1018: pfs = VTOPFS(dvp);
1019: switch (pfs->pfs_type) {
1.109 darcy 1020: case PFSroot:
1.62 wrstuden 1021: /*
1022: * Shouldn't get here with .. in the root node.
1023: */
1.121 perry 1024: if (cnp->cn_flags & ISDOTDOT)
1.9 cgd 1025: return (EIO);
1026:
1.76 fvdl 1027: for (i = 0; i < nproc_root_targets; i++) {
1028: pt = &proc_root_targets[i];
1.150 pooka 1029: /*
1030: * check for node match. proc is always NULL here,
1031: * so call pt_valid with constant NULL lwp.
1032: */
1.76 fvdl 1033: if (cnp->cn_namelen == pt->pt_namlen &&
1034: memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1.150 pooka 1035: (pt->pt_valid == NULL ||
1036: (*pt->pt_valid)(NULL, dvp->v_mount)))
1.76 fvdl 1037: break;
1038: }
1039:
1040: if (i != nproc_root_targets) {
1041: error = procfs_allocvp(dvp->v_mount, vpp, 0,
1.145 ad 1042: pt->pt_pfstype, -1, NULL);
1.76 fvdl 1043: return (error);
1044: }
1045:
1.146 ad 1046: if (CNEQ(cnp, "curproc", 7)) {
1047: pid = curproc->p_pid;
1048: vnpid = 0;
1049: type = PFScurproc;
1050: } else if (CNEQ(cnp, "self", 4)) {
1051: pid = curproc->p_pid;
1052: vnpid = 0;
1053: type = PFSself;
1054: } else {
1055: pid = (pid_t)atoi(pname, cnp->cn_namelen);
1056: vnpid = pid;
1057: type = PFSproc;
1058: }
1.9 cgd 1059:
1.145 ad 1060: if (procfs_proc_lock(pid, &p, ESRCH) != 0)
1.32 mycroft 1061: break;
1.146 ad 1062: error = procfs_allocvp(dvp->v_mount, vpp, vnpid, type, -1, p);
1.145 ad 1063: procfs_proc_unlock(p);
1.62 wrstuden 1064: return (error);
1.9 cgd 1065:
1.109 darcy 1066: case PFSproc:
1.62 wrstuden 1067: /*
1068: * do the .. dance. We unlock the directory, and then
1069: * get the root dir. That will automatically return ..
1070: * locked. Then if the caller wanted dvp locked, we
1071: * re-lock.
1072: */
1073: if (cnp->cn_flags & ISDOTDOT) {
1074: VOP_UNLOCK(dvp, 0);
1.105 thorpej 1075: error = procfs_root(dvp->v_mount, vpp);
1.143 chs 1076: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.62 wrstuden 1077: return (error);
1078: }
1.1 pk 1079:
1.145 ad 1080: if (procfs_proc_lock(pfs->pfs_pid, &p, ESRCH) != 0)
1.32 mycroft 1081: break;
1082:
1083: for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
1.151 pooka 1084: struct lwp *plwp;
1085: int found;
1086:
1087: mutex_enter(&p->p_smutex);
1088: plwp = proc_representative_lwp(p, NULL, 1);
1089: lwp_addref(plwp);
1090: mutex_exit(&p->p_smutex);
1091: found = cnp->cn_namelen == pt->pt_namlen &&
1.56 perry 1092: memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1.151 pooka 1093: (pt->pt_valid == NULL
1094: || (*pt->pt_valid)(plwp, dvp->v_mount));
1095: lwp_delref(plwp);
1096: if (found)
1.145 ad 1097: break;
1.9 cgd 1098: }
1.146 ad 1099: if (i == nproc_targets) {
1100: procfs_proc_unlock(p);
1.145 ad 1101: break;
1.146 ad 1102: }
1.109 darcy 1103: if (pt->pt_pfstype == PFSfile) {
1.75 chs 1104: fvp = p->p_textvp;
1.23 mycroft 1105: /* We already checked that it exists. */
1.32 mycroft 1106: VREF(fvp);
1.161 ! ad 1107: procfs_proc_unlock(p);
1.53 fvdl 1108: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
1.32 mycroft 1109: *vpp = fvp;
1.21 mycroft 1110: return (0);
1111: }
1.1 pk 1112:
1.62 wrstuden 1113: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.145 ad 1114: pt->pt_pfstype, -1, p);
1115: procfs_proc_unlock(p);
1.62 wrstuden 1116: return (error);
1.1 pk 1117:
1.109 darcy 1118: case PFSfd: {
1.91 christos 1119: int fd;
1120: struct file *fp;
1.145 ad 1121:
1122: if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ENOENT)) != 0)
1123: return error;
1124:
1.91 christos 1125: /*
1126: * do the .. dance. We unlock the directory, and then
1127: * get the proc dir. That will automatically return ..
1.143 chs 1128: * locked. Then re-lock the directory.
1.91 christos 1129: */
1130: if (cnp->cn_flags & ISDOTDOT) {
1131: VOP_UNLOCK(dvp, 0);
1132: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.145 ad 1133: PFSproc, -1, p);
1.161 ! ad 1134: procfs_proc_unlock(p);
1.146 ad 1135: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.91 christos 1136: return (error);
1137: }
1138: fd = atoi(pname, cnp->cn_namelen);
1.145 ad 1139:
1140: fp = fd_getfile(p->p_fd, fd);
1141: if (fp == NULL) {
1142: procfs_proc_unlock(p);
1.91 christos 1143: return ENOENT;
1.145 ad 1144: }
1145:
1.99 jdolecek 1146: FILE_USE(fp);
1.161 ! ad 1147: fvp = (struct vnode *)fp->f_data;
1.99 jdolecek 1148:
1.161 ! ad 1149: /* Don't show directories */
! 1150: if (fp->f_type == DTYPE_VNODE && fvp->v_type != VDIR) {
1.91 christos 1151: VREF(fvp);
1.128 christos 1152: FILE_UNUSE(fp, l);
1.161 ! ad 1153: procfs_proc_unlock(p);
1.121 perry 1154: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY |
1.92 christos 1155: (p == curproc ? LK_CANRECURSE : 0));
1.91 christos 1156: *vpp = fvp;
1.161 ! ad 1157: return 0;
1.91 christos 1158: }
1.161 ! ad 1159:
! 1160: FILE_UNUSE(fp, l);
! 1161: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
! 1162: PFSfd, fd, p);
1.145 ad 1163: procfs_proc_unlock(p);
1.91 christos 1164: return error;
1165: }
1.9 cgd 1166: default:
1167: return (ENOTDIR);
1.1 pk 1168: }
1.32 mycroft 1169:
1170: return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
1.1 pk 1171: }
1172:
1.18 cgd 1173: int
1.138 christos 1174: procfs_validfile(struct lwp *l, struct mount *mp)
1.18 cgd 1175: {
1.136 christos 1176: return l != NULL && l->l_proc != NULL && l->l_proc->p_textvp != NULL;
1.74 tv 1177: }
1.21 mycroft 1178:
1.74 tv 1179: static int
1.128 christos 1180: procfs_validfile_linux(l, mp)
1181: struct lwp *l;
1.76 fvdl 1182: struct mount *mp;
1.74 tv 1183: {
1.76 fvdl 1184: int flags;
1185:
1186: flags = VFSTOPROC(mp)->pmnt_flags;
1.142 christos 1187: return (flags & PROCFSMNT_LINUXCOMPAT) &&
1188: (l == NULL || l->l_proc == NULL || procfs_validfile(l, mp));
1.18 cgd 1189: }
1190:
1.117 yamt 1191: struct procfs_root_readdir_ctx {
1192: struct uio *uiop;
1193: off_t *cookies;
1194: int ncookies;
1.120 yamt 1195: off_t off;
1196: off_t startoff;
1.117 yamt 1197: int error;
1198: };
1199:
1200: static int
1201: procfs_root_readdir_callback(struct proc *p, void *arg)
1202: {
1203: struct procfs_root_readdir_ctx *ctxp = arg;
1204: struct dirent d;
1205: struct uio *uiop;
1206: int error;
1207:
1208: uiop = ctxp->uiop;
1209: if (uiop->uio_resid < UIO_MX)
1210: return -1; /* no space */
1211:
1.120 yamt 1212: if (ctxp->off < ctxp->startoff) {
1213: ctxp->off++;
1.117 yamt 1214: return 0;
1215: }
1216:
1.133 yamt 1217: if (kauth_authorize_process(kauth_cred_get(),
1218: KAUTH_PROCESS_CANSEE, p, NULL, NULL, NULL) != 0)
1219: return 0;
1.125 elad 1220:
1.117 yamt 1221: memset(&d, 0, UIO_MX);
1222: d.d_reclen = UIO_MX;
1223: d.d_fileno = PROCFS_FILENO(p->p_pid, PFSproc, -1);
1224: d.d_namlen = snprintf(d.d_name,
1225: UIO_MX - offsetof(struct dirent, d_name), "%ld", (long)p->p_pid);
1226: d.d_type = DT_DIR;
1227:
1.154 ad 1228: mutex_exit(&proclist_lock);
1.117 yamt 1229: error = uiomove(&d, UIO_MX, uiop);
1.154 ad 1230: mutex_enter(&proclist_lock);
1.117 yamt 1231: if (error) {
1232: ctxp->error = error;
1233: return -1;
1234: }
1235:
1236: ctxp->ncookies++;
1237: if (ctxp->cookies)
1.120 yamt 1238: *(ctxp->cookies)++ = ctxp->off + 1;
1239: ctxp->off++;
1.117 yamt 1240:
1241: return 0;
1242: }
1243:
1.9 cgd 1244: /*
1245: * readdir returns directory entries from pfsnode (vp).
1246: *
1247: * the strategy here with procfs is to generate a single
1.34 mycroft 1248: * directory entry at a time (struct dirent) and then
1.9 cgd 1249: * copy that out to userland using uiomove. a more efficent
1250: * though more complex implementation, would try to minimize
1251: * the number of calls to uiomove(). for procfs, this is
1252: * hardly worth the added code complexity.
1253: *
1254: * this should just be done through read()
1255: */
1.37 christos 1256: int
1257: procfs_readdir(v)
1258: void *v;
1259: {
1.22 mycroft 1260: struct vop_readdir_args /* {
1261: struct vnode *a_vp;
1262: struct uio *a_uio;
1.130 elad 1263: kauth_cred_t a_cred;
1.22 mycroft 1264: int *a_eofflag;
1.53 fvdl 1265: off_t **a_cookies;
1266: int *a_ncookies;
1.37 christos 1267: } */ *ap = v;
1.21 mycroft 1268: struct uio *uio = ap->a_uio;
1.34 mycroft 1269: struct dirent d;
1.9 cgd 1270: struct pfsnode *pfs;
1.68 sommerfe 1271: off_t i;
1.9 cgd 1272: int error;
1.53 fvdl 1273: off_t *cookies = NULL;
1.117 yamt 1274: int ncookies;
1.76 fvdl 1275: struct vnode *vp;
1.78 jdolecek 1276: const struct proc_target *pt;
1.117 yamt 1277: struct procfs_root_readdir_ctx ctx;
1.145 ad 1278: struct lwp *l;
1.161 ! ad 1279: int nfd;
1.9 cgd 1280:
1.76 fvdl 1281: vp = ap->a_vp;
1282: pfs = VTOPFS(vp);
1.1 pk 1283:
1.9 cgd 1284: if (uio->uio_resid < UIO_MX)
1285: return (EINVAL);
1.35 mycroft 1286: if (uio->uio_offset < 0)
1.1 pk 1287: return (EINVAL);
1288:
1.9 cgd 1289: error = 0;
1.35 mycroft 1290: i = uio->uio_offset;
1.113 jrf 1291: memset(&d, 0, UIO_MX);
1.34 mycroft 1292: d.d_reclen = UIO_MX;
1.53 fvdl 1293: ncookies = uio->uio_resid / UIO_MX;
1.9 cgd 1294:
1295: switch (pfs->pfs_type) {
1296: /*
1297: * this is for the process-specific sub-directories.
1298: * all that is needed to is copy out all the entries
1299: * from the procent[] table (top of this file).
1300: */
1.109 darcy 1301: case PFSproc: {
1.32 mycroft 1302: struct proc *p;
1.66 christos 1303:
1304: if (i >= nproc_targets)
1.67 sommerfe 1305: return 0;
1.9 cgd 1306:
1.145 ad 1307: if (procfs_proc_lock(pfs->pfs_pid, &p, ESRCH) != 0)
1.32 mycroft 1308: break;
1309:
1.53 fvdl 1310: if (ap->a_ncookies) {
1311: ncookies = min(ncookies, (nproc_targets - i));
1.72 thorpej 1312: cookies = malloc(ncookies * sizeof (off_t),
1.53 fvdl 1313: M_TEMP, M_WAITOK);
1314: *ap->a_cookies = cookies;
1315: }
1316:
1.32 mycroft 1317: for (pt = &proc_targets[i];
1318: uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
1.145 ad 1319: if (pt->pt_valid) {
1.161 ! ad 1320: /* XXX LWP can disappear */
1.145 ad 1321: mutex_enter(&p->p_smutex);
1322: l = proc_representative_lwp(p, NULL, 1);
1323: mutex_exit(&p->p_smutex);
1324: if ((*pt->pt_valid)(l, vp->v_mount) == 0)
1325: continue;
1326: }
1.121 perry 1327:
1.91 christos 1328: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1329: pt->pt_pfstype, -1);
1.34 mycroft 1330: d.d_namlen = pt->pt_namlen;
1.56 perry 1331: memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1.34 mycroft 1332: d.d_type = pt->pt_type;
1.15 ws 1333:
1.113 jrf 1334: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.9 cgd 1335: break;
1.53 fvdl 1336: if (cookies)
1.35 mycroft 1337: *cookies++ = i + 1;
1.6 ws 1338: }
1.9 cgd 1339:
1.145 ad 1340: procfs_proc_unlock(p);
1.9 cgd 1341: break;
1.34 mycroft 1342: }
1.109 darcy 1343: case PFSfd: {
1.91 christos 1344: struct proc *p;
1345: struct filedesc *fdp;
1.111 jdolecek 1346: struct file *fp;
1.110 simonb 1347: int lim, nc = 0;
1.91 christos 1348:
1.145 ad 1349: if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH)) != 0)
1350: return error;
1.91 christos 1351:
1.133 yamt 1352: if (kauth_authorize_process(kauth_cred_get(),
1.145 ad 1353: KAUTH_PROCESS_CANSEE, p, NULL, NULL, NULL) != 0) {
1354: procfs_proc_unlock(p);
1.133 yamt 1355: return ESRCH;
1.145 ad 1356: }
1.125 elad 1357:
1.161 ! ad 1358: fdp = p->p_fd;
! 1359: nfd = fdp->fd_nfiles;
1.91 christos 1360:
1361: lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
1.145 ad 1362: if (i >= lim) {
1363: procfs_proc_unlock(p);
1.91 christos 1364: return 0;
1.145 ad 1365: }
1.91 christos 1366:
1367: if (ap->a_ncookies) {
1.161 ! ad 1368: ncookies = min(ncookies, (nfd + 2 - i));
1.91 christos 1369: cookies = malloc(ncookies * sizeof (off_t),
1370: M_TEMP, M_WAITOK);
1371: *ap->a_cookies = cookies;
1372: }
1373:
1374: for (; i < 2 && uio->uio_resid >= UIO_MX; i++) {
1375: pt = &proc_targets[i];
1376: d.d_namlen = pt->pt_namlen;
1377: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1378: pt->pt_pfstype, -1);
1379: (void)memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1380: d.d_type = pt->pt_type;
1.113 jrf 1381: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.91 christos 1382: break;
1383: if (cookies)
1384: *cookies++ = i + 1;
1385: nc++;
1386: }
1387: if (error) {
1388: ncookies = nc;
1389: break;
1390: }
1.161 ! ad 1391: for (; uio->uio_resid >= UIO_MX && i < nfd; i++) {
1.111 jdolecek 1392: /* check the descriptor exists */
1393: if ((fp = fd_getfile(fdp, i - 2)) == NULL)
1.100 jdolecek 1394: continue;
1.159 ad 1395: mutex_exit(&fp->f_lock);
1.111 jdolecek 1396:
1.109 darcy 1397: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, PFSfd, i - 2);
1.91 christos 1398: d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
1.93 martin 1399: "%lld", (long long)(i - 2));
1.91 christos 1400: d.d_type = VREG;
1.113 jrf 1401: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.91 christos 1402: break;
1403: if (cookies)
1404: *cookies++ = i + 1;
1405: nc++;
1406: }
1407: ncookies = nc;
1.145 ad 1408: procfs_proc_unlock(p);
1.91 christos 1409: break;
1410: }
1.9 cgd 1411:
1412: /*
1413: * this is for the root of the procfs filesystem
1.69 thorpej 1414: * what is needed are special entries for "curproc"
1415: * and "self" followed by an entry for each process
1.117 yamt 1416: * on allproc.
1.9 cgd 1417: */
1418:
1.109 darcy 1419: case PFSroot: {
1.117 yamt 1420: int nc = 0;
1.9 cgd 1421:
1.53 fvdl 1422: if (ap->a_ncookies) {
1423: /*
1424: * XXX Potentially allocating too much space here,
1425: * but I'm lazy. This loop needs some work.
1426: */
1.72 thorpej 1427: cookies = malloc(ncookies * sizeof (off_t),
1.53 fvdl 1428: M_TEMP, M_WAITOK);
1429: *ap->a_cookies = cookies;
1430: }
1.117 yamt 1431: error = 0;
1432: /* 0 ... 3 are static entries. */
1433: for (; i <= 3 && uio->uio_resid >= UIO_MX; i++) {
1.9 cgd 1434: switch (i) {
1.12 ws 1435: case 0: /* `.' */
1436: case 1: /* `..' */
1.109 darcy 1437: d.d_fileno = PROCFS_FILENO(0, PFSroot, -1);
1.34 mycroft 1438: d.d_namlen = i + 1;
1.56 perry 1439: memcpy(d.d_name, "..", d.d_namlen);
1.34 mycroft 1440: d.d_name[i + 1] = '\0';
1441: d.d_type = DT_DIR;
1.12 ws 1442: break;
1.21 mycroft 1443:
1.12 ws 1444: case 2:
1.109 darcy 1445: d.d_fileno = PROCFS_FILENO(0, PFScurproc, -1);
1.69 thorpej 1446: d.d_namlen = sizeof("curproc") - 1;
1447: memcpy(d.d_name, "curproc", sizeof("curproc"));
1448: d.d_type = DT_LNK;
1449: break;
1450:
1451: case 3:
1.109 darcy 1452: d.d_fileno = PROCFS_FILENO(0, PFSself, -1);
1.69 thorpej 1453: d.d_namlen = sizeof("self") - 1;
1454: memcpy(d.d_name, "self", sizeof("self"));
1.34 mycroft 1455: d.d_type = DT_LNK;
1.9 cgd 1456: break;
1.1 pk 1457: }
1.21 mycroft 1458:
1.113 jrf 1459: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.9 cgd 1460: break;
1.53 fvdl 1461: nc++;
1462: if (cookies)
1.35 mycroft 1463: *cookies++ = i + 1;
1.1 pk 1464: }
1.117 yamt 1465: /* 4 ... are process entries. */
1466: ctx.uiop = uio;
1467: ctx.error = 0;
1.120 yamt 1468: ctx.off = 4;
1469: ctx.startoff = i;
1.117 yamt 1470: ctx.cookies = cookies;
1471: ctx.ncookies = nc;
1472: proclist_foreach_call(&allproc,
1473: procfs_root_readdir_callback, &ctx);
1474: cookies = ctx.cookies;
1475: nc = ctx.ncookies;
1476: error = ctx.error;
1477: if (error)
1478: break;
1.76 fvdl 1479:
1.117 yamt 1480: /* misc entries. */
1.120 yamt 1481: if (i < ctx.off)
1482: i = ctx.off;
1483: if (i >= ctx.off + nproc_root_targets)
1.76 fvdl 1484: break;
1.120 yamt 1485: for (pt = &proc_root_targets[i - ctx.off];
1.117 yamt 1486: uio->uio_resid >= UIO_MX &&
1487: pt < &proc_root_targets[nproc_root_targets];
1488: pt++, i++) {
1.76 fvdl 1489: if (pt->pt_valid &&
1490: (*pt->pt_valid)(NULL, vp->v_mount) == 0)
1491: continue;
1.91 christos 1492: d.d_fileno = PROCFS_FILENO(0, pt->pt_pfstype, -1);
1.76 fvdl 1493: d.d_namlen = pt->pt_namlen;
1494: memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1495: d.d_type = pt->pt_type;
1496:
1.113 jrf 1497: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.76 fvdl 1498: break;
1499: nc++;
1500: if (cookies)
1501: *cookies++ = i + 1;
1502: }
1503:
1.53 fvdl 1504: ncookies = nc;
1.9 cgd 1505: break;
1.34 mycroft 1506: }
1.9 cgd 1507:
1508: default:
1509: error = ENOTDIR;
1510: break;
1.1 pk 1511: }
1.9 cgd 1512:
1.53 fvdl 1513: if (ap->a_ncookies) {
1514: if (error) {
1.54 fvdl 1515: if (cookies)
1.72 thorpej 1516: free(*ap->a_cookies, M_TEMP);
1.53 fvdl 1517: *ap->a_ncookies = 0;
1518: *ap->a_cookies = NULL;
1519: } else
1520: *ap->a_ncookies = ncookies;
1521: }
1.35 mycroft 1522: uio->uio_offset = i;
1.9 cgd 1523: return (error);
1.12 ws 1524: }
1525:
1526: /*
1.126 atatat 1527: * readlink reads the link of `curproc' and others
1.12 ws 1528: */
1.37 christos 1529: int
1530: procfs_readlink(v)
1531: void *v;
1.12 ws 1532: {
1.37 christos 1533: struct vop_readlink_args *ap = v;
1.123 christos 1534: char bf[16]; /* should be enough */
1535: char *bp = bf;
1.102 christos 1536: char *path = NULL;
1.161 ! ad 1537: int len = 0;
1.102 christos 1538: int error = 0;
1539: struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.126 atatat 1540: struct proc *pown;
1.12 ws 1541:
1.109 darcy 1542: if (pfs->pfs_fileno == PROCFS_FILENO(0, PFScurproc, -1))
1.123 christos 1543: len = snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
1.109 darcy 1544: else if (pfs->pfs_fileno == PROCFS_FILENO(0, PFSself, -1))
1.123 christos 1545: len = snprintf(bf, sizeof(bf), "%s", "curproc");
1.136 christos 1546: else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFScwd, -1) ||
1547: pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSchroot, -1) ||
1548: pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSexe, -1)) {
1.145 ad 1549: if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
1550: return error;
1.126 atatat 1551: MALLOC(path, char *, MAXPATHLEN + 4, M_TEMP,
1552: M_WAITOK|M_CANFAIL);
1.145 ad 1553: if (path == NULL) {
1554: procfs_proc_unlock(pown);
1.126 atatat 1555: return (ENOMEM);
1.145 ad 1556: }
1.126 atatat 1557: bp = path + MAXPATHLEN;
1558: *--bp = '\0';
1.161 ! ad 1559: procfs_dir(PROCFS_TYPE(pfs->pfs_fileno), curlwp, pown,
1.136 christos 1560: &bp, path, MAXPATHLEN);
1.145 ad 1561: procfs_proc_unlock(pown);
1.126 atatat 1562: len = strlen(bp);
1.136 christos 1563: } else {
1.102 christos 1564: struct file *fp;
1565: struct vnode *vxp, *vp;
1566:
1.145 ad 1567: if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
1.102 christos 1568: return error;
1.155 rmind 1569:
1.145 ad 1570: fp = fd_getfile(pown->p_fd, pfs->pfs_fd);
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.158 pooka 1593:
1594: /*
1595: * XXX: kludge to avoid locking against ourselves
1596: * in getcwd()
1597: */
1598: if (vxp->v_tag == VT_PROCFS) {
1599: *--bp = '/';
1600: } else {
1.161 ! ad 1601: rw_enter(&curproc->p_cwdi->cwdi_lock, RW_READER);
! 1602: vp = curproc->p_cwdi->cwdi_rdir;
1.158 pooka 1603: if (vp == NULL)
1604: vp = rootvnode;
1605: error = getcwd_common(vxp, vp, &bp, path,
1606: MAXPATHLEN / 2, 0, curlwp);
1.161 ! ad 1607: rw_exit(&curproc->p_cwdi->cwdi_lock);
1.158 pooka 1608: }
1.145 ad 1609: if (error)
1610: break;
1.102 christos 1611: len = strlen(bp);
1612: break;
1613:
1614: case DTYPE_MISC:
1.123 christos 1615: len = snprintf(bf, sizeof(bf), "%s", "[misc]");
1.102 christos 1616: break;
1617:
1618: case DTYPE_KQUEUE:
1.123 christos 1619: len = snprintf(bf, sizeof(bf), "%s", "[kqueue]");
1.102 christos 1620: break;
1621:
1622: default:
1.145 ad 1623: error = EINVAL;
1624: break;
1625: }
1.161 ! ad 1626: FILE_UNUSE(fp, curlwp);
1.145 ad 1627: procfs_proc_unlock(pown);
1.102 christos 1628: }
1.12 ws 1629:
1.145 ad 1630: if (error == 0)
1631: error = uiomove(bp, len, ap->a_uio);
1.102 christos 1632: if (path)
1633: free(path, M_TEMP);
1634: return error;
1.1 pk 1635: }
1636:
1637: /*
1.91 christos 1638: * convert decimal ascii to int
1.1 pk 1639: */
1.91 christos 1640: static int
1641: atoi(b, len)
1.9 cgd 1642: const char *b;
1.91 christos 1643: size_t len;
1.1 pk 1644: {
1.91 christos 1645: int p = 0;
1.1 pk 1646:
1647: while (len--) {
1.9 cgd 1648: char c = *b++;
1.1 pk 1649: if (c < '0' || c > '9')
1.91 christos 1650: return -1;
1.9 cgd 1651: p = 10 * p + (c - '0');
1.1 pk 1652: }
1.9 cgd 1653:
1.91 christos 1654: return p;
1.1 pk 1655: }
CVSweb <webmaster@jp.NetBSD.org>