Annotation of src/sys/miscfs/procfs/procfs_vnops.c, Revision 1.123.2.4
1.123.2.4! yamt 1: /* $NetBSD: procfs_vnops.c,v 1.123.2.3 2007/02/26 09:11:31 yamt Exp $ */
1.123.2.3 yamt 2:
3: /*-
4: * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
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.123.2.4! yamt 115: __KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.123.2.3 2007/02/26 09:11:31 yamt 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.123.2.1 yamt 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.123.2.1 yamt 146: static int procfs_validfile_linux(struct lwp *, struct mount *);
1.117 yamt 147: static int procfs_root_readdir_callback(struct proc *, void *);
1.123.2.1 yamt 148: static struct vnode *procfs_dir(pfstype, struct lwp *, struct proc *,
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.123.2.1 yamt 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.123.2.2 yamt 165: { DT_DIR, N("."), PFSproc, NULL },
166: { DT_DIR, N(".."), PFSroot, NULL },
1.109 darcy 167: { DT_DIR, N("fd"), PFSfd, NULL },
1.123.2.2 yamt 168: { DT_REG, N("file"), PFSfile, procfs_validfile },
1.109 darcy 169: { DT_REG, N("mem"), PFSmem, NULL },
1.123.2.2 yamt 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.123.2.2 yamt 173: { DT_REG, N("stat"), PFSstat, procfs_validfile_linux },
1.109 darcy 174: { DT_REG, N("status"), PFSstatus, NULL },
1.123.2.2 yamt 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.123.2.2 yamt 178: { DT_REG, N("maps"), PFSmaps, procfs_validmap },
1.109 darcy 179: { DT_REG, N("cmdline"), PFScmdline, NULL },
1.123.2.2 yamt 180: { DT_REG, N("exe"), PFSexe, procfs_validfile },
1.123.2.1 yamt 181: { DT_LNK, N("cwd"), PFScwd, NULL },
182: { DT_LNK, N("root"), PFSchroot, NULL },
1.123.2.2 yamt 183: { DT_LNK, N("emul"), PFSemul, NULL },
1.123.2.4! yamt 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.123.2.2 yamt 203: { DT_REG, N("devices"), PFSdevices, procfs_validfile_linux },
1.123.2.4! yamt 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.123.2.1 yamt 211: int procfs_lookup(void *);
1.96 jdolecek 212: #define procfs_create genfs_eopnotsupp
213: #define procfs_mknod genfs_eopnotsupp
1.123.2.1 yamt 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.123.2.1 yamt 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.123.2.1 yamt 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.123.2.1 yamt 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.123.2.1 yamt 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.123.2.1 yamt 249: static int atoi(const char *, size_t);
1.37 christos 250:
251: /*
252: * procfs vnode operations.
253: */
1.123.2.1 yamt 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.123.2.1 yamt 315: kauth_cred_t a_cred;
316: struct lwp *a_l;
1.37 christos 317: } */ *ap = v;
1.21 mycroft 318: struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.123.2.1 yamt 319: struct lwp *l1;
320: struct proc *p2;
1.88 christos 321: int error;
1.50 thorpej 322:
1.123.2.3 yamt 323: if ((error = procfs_proc_lock(pfs->pfs_pid, &p2, ENOENT)) != 0)
324: return error;
1.9 cgd 325:
1.123.2.3 yamt 326: l1 = ap->a_l; /* tracer */
1.123.2.2 yamt 327:
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.123.2.3 yamt 333: mutex_enter(&p2->p_mutex);
1.123.2.2 yamt 334: error = kauth_authorize_process(l1->l_cred, KAUTH_PROCESS_CANPROCFS,
335: p2, pfs, KAUTH_ARG(M2K(ap->a_mode)), NULL);
1.123.2.3 yamt 336: mutex_exit(&p2->p_mutex);
1.123.2.2 yamt 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.123.2.3 yamt 345: ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) {
346: error = EBUSY;
347: break;
348: }
1.50 thorpej 349:
1.123.2.2 yamt 350: if (!proc_isunder(p2, l1))
351: return (EPERM);
1.1 pk 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.123.2.2 yamt 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.123.2.3 yamt 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.123.2.1 yamt 387: kauth_cred_t a_cred;
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.123.2.3 yamt 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.123.2.3 yamt 431: struct proc *p;
432: int error;
1.1 pk 433:
1.122 christos 434: VOP_UNLOCK(vp, 0);
1.123.2.3 yamt 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.123.2.3 yamt 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.123.2.1 yamt 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 *
563: procfs_dir(pfstype t, struct lwp *caller, struct proc *target,
564: char **bpp, char *path, int len)
565: {
566: struct vnode *vp, *rvp = caller->l_proc->p_cwdi->cwdi_rdir;
567: char *bp;
568:
1.123.2.3 yamt 569: LOCK_ASSERT(mutex_owned(&target->p_mutex));
570:
1.123.2.1 yamt 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.123.2.2 yamt 580: case PFSexe:
581: vp = target->p_textvp;
582: break;
1.123.2.1 yamt 583: default:
584: return (NULL);
585: }
586:
1.123.2.4! yamt 587: /*
! 588: * XXX: this horrible kludge avoids locking panics when
! 589: * attempting to lookup links that point to within procfs
! 590: */
! 591: if (vp != NULL && vp->v_tag == VT_PROCFS) {
! 592: if (bpp) {
! 593: *--bp = '/';
! 594: *bpp = bp;
! 595: }
! 596: return vp;
! 597: }
! 598:
1.123.2.1 yamt 599: if (rvp == NULL)
600: rvp = rootvnode;
1.123.2.3 yamt 601: mutex_exit(&target->p_mutex); /* XXXSMP */
1.123.2.1 yamt 602: if (vp == NULL || getcwd_common(vp, rvp, bp ? &bp : NULL, path,
603: len / 2, 0, caller) != 0) {
604: vp = NULL;
605: if (bpp) {
1.123.2.4! yamt 606: /*
! 607: if (t == PFSexe) {
! 608: snprintf(path, len, "%s/%d/file"
! 609: mp->mnt_stat.f_mntonname, pfs->pfs_pid);
! 610: } else */ {
! 611: bp = *bpp;
! 612: *--bp = '/';
! 613: }
1.123.2.1 yamt 614: }
615: }
1.123.2.3 yamt 616: mutex_enter(&target->p_mutex); /* XXXSMP */
1.123.2.1 yamt 617:
618: if (bpp)
619: *bpp = bp;
620:
621: return (vp);
622: }
623:
624: /*
1.9 cgd 625: * Invent attributes for pfsnode (vp) and store
626: * them in (vap).
627: * Directories lengths are returned as zero since
628: * any real length would require the genuine size
629: * to be computed, and nothing cares anyway.
630: *
631: * this is relatively minimal for procfs.
1.1 pk 632: */
1.37 christos 633: int
634: procfs_getattr(v)
635: void *v;
636: {
1.22 mycroft 637: struct vop_getattr_args /* {
638: struct vnode *a_vp;
639: struct vattr *a_vap;
1.123.2.1 yamt 640: kauth_cred_t a_cred;
641: struct lwp *a_l;
1.37 christos 642: } */ *ap = v;
1.21 mycroft 643: struct pfsnode *pfs = VTOPFS(ap->a_vp);
644: struct vattr *vap = ap->a_vap;
1.1 pk 645: struct proc *procp;
1.123.2.3 yamt 646: char *path;
1.9 cgd 647: int error;
1.1 pk 648:
1.21 mycroft 649: /* first check the process still exists */
650: switch (pfs->pfs_type) {
1.109 darcy 651: case PFSroot:
652: case PFScurproc:
653: case PFSself:
1.123.2.3 yamt 654: procp = NULL;
1.21 mycroft 655: break;
656:
657: default:
1.123.2.3 yamt 658: error = procfs_proc_lock(pfs->pfs_pid, &procp, ENOENT);
659: if (error != 0)
660: return (error);
661: break;
662: }
663:
664: switch (pfs->pfs_type) {
665: case PFScwd:
666: case PFSchroot:
667: case PFSexe:
668: MALLOC(path, char *, MAXPATHLEN + 4, M_TEMP,
669: M_WAITOK|M_CANFAIL);
670: if (path == NULL && procp != NULL) {
671: procfs_proc_unlock(procp);
672: return (ENOMEM);
673: }
674: break;
675:
676: default:
677: path = NULL;
1.46 mycroft 678: break;
1.21 mycroft 679: }
680:
1.123.2.1 yamt 681: if (procp != NULL) {
1.123.2.3 yamt 682: mutex_enter(&procp->p_mutex);
683: error = kauth_authorize_process(kauth_cred_get(),
684: KAUTH_PROCESS_CANSEE, procp, NULL, NULL, NULL);
685: mutex_exit(&procp->p_mutex);
686: if (error != 0) {
687: procfs_proc_unlock(procp);
688: if (path != NULL)
689: free(path, M_TEMP);
1.123.2.1 yamt 690: return (ENOENT);
1.123.2.3 yamt 691: }
1.123.2.1 yamt 692: }
693:
1.21 mycroft 694: error = 0;
695:
1.9 cgd 696: /* start by zeroing out the attributes */
1.1 pk 697: VATTR_NULL(vap);
1.9 cgd 698:
699: /* next do all the common fields */
1.21 mycroft 700: vap->va_type = ap->a_vp->v_type;
1.9 cgd 701: vap->va_mode = pfs->pfs_mode;
702: vap->va_fileid = pfs->pfs_fileno;
703: vap->va_flags = 0;
1.19 cgd 704: vap->va_blocksize = PAGE_SIZE;
1.9 cgd 705:
706: /*
1.123.2.1 yamt 707: * Make all times be current TOD.
1.90 simonb 708: *
1.9 cgd 709: * It would be possible to get the process start
1.123.2.1 yamt 710: * time from the p_stats structure, but there's
1.9 cgd 711: * no "file creation" time stamp anyway, and the
1.123.2.1 yamt 712: * p_stats structure is not addressable if u. gets
1.9 cgd 713: * swapped out for that process.
714: */
1.123.2.1 yamt 715: getnanotime(&vap->va_ctime);
1.9 cgd 716: vap->va_atime = vap->va_mtime = vap->va_ctime;
1.123.2.1 yamt 717: if (procp)
718: TIMEVAL_TO_TIMESPEC(&procp->p_stats->p_start,
719: &vap->va_birthtime);
720: else
721: getnanotime(&vap->va_birthtime);
1.9 cgd 722:
1.21 mycroft 723: switch (pfs->pfs_type) {
1.109 darcy 724: case PFSmem:
725: case PFSregs:
726: case PFSfpregs:
1.86 thorpej 727: #if defined(__HAVE_PROCFS_MACHDEP) && defined(PROCFS_MACHDEP_PROTECT_CASES)
728: PROCFS_MACHDEP_PROTECT_CASES
729: #endif
1.47 mycroft 730: /*
731: * If the process has exercised some setuid or setgid
732: * privilege, then rip away read/write permission so
733: * that only root can gain access.
734: */
1.123.2.3 yamt 735: if (procp->p_flag & PK_SUGID)
1.47 mycroft 736: vap->va_mode &= ~(S_IRUSR|S_IWUSR);
1.46 mycroft 737: /* FALLTHROUGH */
1.109 darcy 738: case PFSctl:
739: case PFSstatus:
740: case PFSstat:
741: case PFSnote:
742: case PFSnotepg:
743: case PFSmap:
744: case PFSmaps:
745: case PFScmdline:
1.123.2.2 yamt 746: case PFSemul:
1.123.2.4! yamt 747: case PFSstatm:
1.12 ws 748: vap->va_nlink = 1;
1.123.2.1 yamt 749: vap->va_uid = kauth_cred_geteuid(procp->p_cred);
750: vap->va_gid = kauth_cred_getegid(procp->p_cred);
1.21 mycroft 751: break;
1.109 darcy 752: case PFSmeminfo:
1.123.2.2 yamt 753: case PFSdevices:
1.109 darcy 754: case PFScpuinfo:
755: case PFSuptime:
1.114 jdolecek 756: case PFSmounts:
1.123.2.4! yamt 757: case PFScpustat:
! 758: case PFSloadavg:
1.76 fvdl 759: vap->va_nlink = 1;
760: vap->va_uid = vap->va_gid = 0;
761: break;
1.46 mycroft 762:
763: default:
1.37 christos 764: break;
1.12 ws 765: }
766:
1.9 cgd 767: /*
768: * now do the object specific fields
769: *
770: * The size could be set from struct reg, but it's hardly
771: * worth the trouble, and it puts some (potentially) machine
772: * dependent data into this machine-independent code. If it
773: * becomes important then this function should break out into
774: * a per-file stat function in the corresponding .c file.
775: */
1.1 pk 776:
1.9 cgd 777: switch (pfs->pfs_type) {
1.109 darcy 778: case PFSroot:
1.21 mycroft 779: /*
780: * Set nlink to 1 to tell fts(3) we don't actually know.
781: */
782: vap->va_nlink = 1;
783: vap->va_uid = 0;
784: vap->va_gid = 0;
1.46 mycroft 785: vap->va_bytes = vap->va_size = DEV_BSIZE;
1.21 mycroft 786: break;
787:
1.123.2.1 yamt 788: case PFSself:
1.109 darcy 789: case PFScurproc: {
1.123 christos 790: char bf[16]; /* should be enough */
1.21 mycroft 791: vap->va_nlink = 1;
792: vap->va_uid = 0;
793: vap->va_gid = 0;
1.46 mycroft 794: vap->va_bytes = vap->va_size =
1.123 christos 795: snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
1.9 cgd 796: break;
1.21 mycroft 797: }
1.9 cgd 798:
1.109 darcy 799: case PFSfd:
1.91 christos 800: if (pfs->pfs_fd != -1) {
801: struct file *fp;
1.98 jdolecek 802:
1.123.2.3 yamt 803: fp = fd_getfile(procp->p_fd, pfs->pfs_fd);
804: if (fp == NULL) {
805: error = EBADF;
806: break;
807: }
1.98 jdolecek 808: FILE_USE(fp);
1.91 christos 809: vap->va_nlink = 1;
1.123.2.1 yamt 810: vap->va_uid = kauth_cred_geteuid(fp->f_cred);
811: vap->va_gid = kauth_cred_getegid(fp->f_cred);
1.91 christos 812: switch (fp->f_type) {
813: case DTYPE_VNODE:
814: vap->va_bytes = vap->va_size =
815: ((struct vnode *)fp->f_data)->v_size;
816: break;
817: default:
818: vap->va_bytes = vap->va_size = 0;
819: break;
820: }
1.123.2.3 yamt 821: FILE_UNUSE(fp, curlwp);
1.91 christos 822: break;
823: }
824: /*FALLTHROUGH*/
1.109 darcy 825: case PFSproc:
1.9 cgd 826: vap->va_nlink = 2;
1.123.2.1 yamt 827: vap->va_uid = kauth_cred_geteuid(procp->p_cred);
828: vap->va_gid = kauth_cred_getegid(procp->p_cred);
1.46 mycroft 829: vap->va_bytes = vap->va_size = DEV_BSIZE;
1.21 mycroft 830: break;
831:
1.109 darcy 832: case PFSfile:
1.21 mycroft 833: error = EOPNOTSUPP;
1.9 cgd 834: break;
835:
1.109 darcy 836: case PFSmem:
1.9 cgd 837: vap->va_bytes = vap->va_size =
838: ctob(procp->p_vmspace->vm_tsize +
839: procp->p_vmspace->vm_dsize +
840: procp->p_vmspace->vm_ssize);
841: break;
842:
1.18 cgd 843: #if defined(PT_GETREGS) || defined(PT_SETREGS)
1.109 darcy 844: case PFSregs:
1.11 cgd 845: vap->va_bytes = vap->va_size = sizeof(struct reg);
1.18 cgd 846: break;
1.14 cgd 847: #endif
848:
1.18 cgd 849: #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
1.109 darcy 850: case PFSfpregs:
1.14 cgd 851: vap->va_bytes = vap->va_size = sizeof(struct fpreg);
1.18 cgd 852: break;
1.14 cgd 853: #endif
1.12 ws 854:
1.109 darcy 855: case PFSctl:
856: case PFSstatus:
857: case PFSstat:
858: case PFSnote:
859: case PFSnotepg:
860: case PFScmdline:
861: case PFSmeminfo:
1.123.2.2 yamt 862: case PFSdevices:
1.109 darcy 863: case PFScpuinfo:
864: case PFSuptime:
1.114 jdolecek 865: case PFSmounts:
1.123.2.4! yamt 866: case PFScpustat:
! 867: case PFSloadavg:
! 868: case PFSstatm:
1.46 mycroft 869: vap->va_bytes = vap->va_size = 0;
1.79 fvdl 870: break;
1.109 darcy 871: case PFSmap:
872: case PFSmaps:
1.79 fvdl 873: /*
874: * Advise a larger blocksize for the map files, so that
875: * they may be read in one pass.
876: */
1.80 fvdl 877: vap->va_blocksize = 4 * PAGE_SIZE;
1.83 chs 878: vap->va_bytes = vap->va_size = 0;
1.9 cgd 879: break;
1.86 thorpej 880:
1.123.2.1 yamt 881: case PFScwd:
1.123.2.2 yamt 882: case PFSchroot:
883: case PFSexe: {
1.123.2.3 yamt 884: char *bp;
1.123.2.1 yamt 885:
886: vap->va_nlink = 1;
887: vap->va_uid = 0;
888: vap->va_gid = 0;
889: bp = path + MAXPATHLEN;
890: *--bp = '\0';
1.123.2.3 yamt 891: mutex_enter(&procp->p_mutex);
1.123.2.1 yamt 892: (void)procfs_dir(pfs->pfs_type, curlwp, procp, &bp, path,
893: MAXPATHLEN);
1.123.2.3 yamt 894: mutex_exit(&procp->p_mutex);
1.123.2.1 yamt 895: vap->va_bytes = vap->va_size = strlen(bp);
896: break;
897: }
898:
1.123.2.2 yamt 899: case PFSemul:
900: vap->va_bytes = vap->va_size = strlen(procp->p_emul->e_name);
901: break;
902:
1.86 thorpej 903: #ifdef __HAVE_PROCFS_MACHDEP
904: PROCFS_MACHDEP_NODETYPE_CASES
905: error = procfs_machdep_getattr(ap->a_vp, vap, procp);
906: break;
907: #endif
1.1 pk 908:
1.9 cgd 909: default:
1.21 mycroft 910: panic("procfs_getattr");
1.1 pk 911: }
912:
1.123.2.3 yamt 913: if (procp != NULL)
914: procfs_proc_unlock(procp);
915: if (path != NULL)
916: free(path, M_TEMP);
917:
1.9 cgd 918: return (error);
1.1 pk 919: }
920:
1.37 christos 921: /*ARGSUSED*/
922: int
1.123.2.2 yamt 923: procfs_setattr(void *v)
1.5 pk 924: {
925: /*
1.9 cgd 926: * just fake out attribute setting
927: * it's not good to generate an error
928: * return, otherwise things like creat()
929: * will fail when they try to set the
930: * file length to 0. worse, this means
931: * that echo $note > /proc/$pid/note will fail.
1.5 pk 932: */
933:
1.9 cgd 934: return (0);
1.5 pk 935: }
936:
1.9 cgd 937: /*
938: * implement access checking.
939: *
940: * actually, the check for super-user is slightly
941: * broken since it will allow read access to write-only
942: * objects. this doesn't cause any particular trouble
943: * but does mean that the i/o entry points need to check
944: * that the operation really does make sense.
945: */
1.37 christos 946: int
947: procfs_access(v)
948: void *v;
949: {
1.22 mycroft 950: struct vop_access_args /* {
951: struct vnode *a_vp;
952: int a_mode;
1.123.2.1 yamt 953: kauth_cred_t a_cred;
954: struct lwp *a_l;
1.37 christos 955: } */ *ap = v;
1.31 mycroft 956: struct vattr va;
1.1 pk 957: int error;
958:
1.123.2.1 yamt 959: if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_l)) != 0)
1.1 pk 960: return (error);
1.9 cgd 961:
1.49 mycroft 962: return (vaccess(va.va_type, va.va_mode,
963: va.va_uid, va.va_gid, ap->a_mode, ap->a_cred));
1.1 pk 964: }
965:
966: /*
1.9 cgd 967: * lookup. this is incredibly complicated in the
968: * general case, however for most pseudo-filesystems
969: * very little needs to be done.
970: *
1.62 wrstuden 971: * Locking isn't hard here, just poorly documented.
972: *
1.121 perry 973: * If we're looking up ".", just vref the parent & return it.
1.62 wrstuden 974: *
975: * If we're looking up "..", unlock the parent, and lock "..". If everything
976: * went ok, and we're on the last component and the caller requested the
977: * parent locked, try to re-lock the parent. We do this to prevent lock
978: * races.
979: *
980: * For anything else, get the needed node. Then unlock the parent if not
981: * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the
982: * parent in the .. case).
983: *
984: * We try to exit with the parent locked in error cases.
1.9 cgd 985: */
1.37 christos 986: int
987: procfs_lookup(v)
988: void *v;
989: {
1.22 mycroft 990: struct vop_lookup_args /* {
991: struct vnode * a_dvp;
992: struct vnode ** a_vpp;
993: struct componentname * a_cnp;
1.37 christos 994: } */ *ap = v;
1.21 mycroft 995: struct componentname *cnp = ap->a_cnp;
996: struct vnode **vpp = ap->a_vpp;
997: struct vnode *dvp = ap->a_dvp;
1.45 cgd 998: const char *pname = cnp->cn_nameptr;
1.78 jdolecek 999: const struct proc_target *pt = NULL;
1.32 mycroft 1000: struct vnode *fvp;
1.123.2.3 yamt 1001: pid_t pid, vnpid;
1.9 cgd 1002: struct pfsnode *pfs;
1.76 fvdl 1003: struct proc *p = NULL;
1.123.2.1 yamt 1004: struct lwp *l = NULL;
1.123.2.3 yamt 1005: int i, error;
1006: pfstype type;
1.1 pk 1007:
1.32 mycroft 1008: *vpp = NULL;
1009:
1010: if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
1011: return (EROFS);
1012:
1.21 mycroft 1013: if (cnp->cn_namelen == 1 && *pname == '.') {
1014: *vpp = dvp;
1.9 cgd 1015: VREF(dvp);
1016: return (0);
1017: }
1.1 pk 1018:
1.9 cgd 1019: pfs = VTOPFS(dvp);
1020: switch (pfs->pfs_type) {
1.109 darcy 1021: case PFSroot:
1.62 wrstuden 1022: /*
1023: * Shouldn't get here with .. in the root node.
1024: */
1.121 perry 1025: if (cnp->cn_flags & ISDOTDOT)
1.9 cgd 1026: return (EIO);
1027:
1.76 fvdl 1028: for (i = 0; i < nproc_root_targets; i++) {
1029: pt = &proc_root_targets[i];
1.123.2.3 yamt 1030: /*
1031: * check for node match. proc is always NULL here,
1032: * so call pt_valid with constant NULL lwp.
1033: */
1.76 fvdl 1034: if (cnp->cn_namelen == pt->pt_namlen &&
1035: memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1036: (pt->pt_valid == NULL ||
1.123.2.3 yamt 1037: (*pt->pt_valid)(NULL, dvp->v_mount)))
1.76 fvdl 1038: break;
1039: }
1040:
1041: if (i != nproc_root_targets) {
1042: error = procfs_allocvp(dvp->v_mount, vpp, 0,
1.123.2.3 yamt 1043: pt->pt_pfstype, -1, NULL);
1.76 fvdl 1044: return (error);
1045: }
1046:
1.123.2.3 yamt 1047: if (CNEQ(cnp, "curproc", 7)) {
1048: pid = curproc->p_pid;
1049: vnpid = 0;
1050: type = PFScurproc;
1051: } else if (CNEQ(cnp, "self", 4)) {
1052: pid = curproc->p_pid;
1053: vnpid = 0;
1054: type = PFSself;
1055: } else {
1056: pid = (pid_t)atoi(pname, cnp->cn_namelen);
1057: vnpid = pid;
1058: type = PFSproc;
1059: }
1.9 cgd 1060:
1.123.2.3 yamt 1061: if (procfs_proc_lock(pid, &p, ESRCH) != 0)
1.32 mycroft 1062: break;
1.123.2.3 yamt 1063: error = procfs_allocvp(dvp->v_mount, vpp, vnpid, type, -1, p);
1064: procfs_proc_unlock(p);
1.62 wrstuden 1065: return (error);
1.9 cgd 1066:
1.109 darcy 1067: case PFSproc:
1.62 wrstuden 1068: /*
1069: * do the .. dance. We unlock the directory, and then
1070: * get the root dir. That will automatically return ..
1071: * locked. Then if the caller wanted dvp locked, we
1072: * re-lock.
1073: */
1074: if (cnp->cn_flags & ISDOTDOT) {
1075: VOP_UNLOCK(dvp, 0);
1.105 thorpej 1076: error = procfs_root(dvp->v_mount, vpp);
1.123.2.2 yamt 1077: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.62 wrstuden 1078: return (error);
1079: }
1.1 pk 1080:
1.123.2.3 yamt 1081: if (procfs_proc_lock(pfs->pfs_pid, &p, ESRCH) != 0)
1.32 mycroft 1082: break;
1083:
1084: for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
1.123.2.3 yamt 1085: struct lwp *plwp;
1086: int found;
1087:
1088: mutex_enter(&p->p_smutex);
1089: plwp = proc_representative_lwp(p, NULL, 1);
1090: lwp_addref(plwp);
1091: mutex_exit(&p->p_smutex);
1092: found = cnp->cn_namelen == pt->pt_namlen &&
1.56 perry 1093: memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1.123.2.3 yamt 1094: (pt->pt_valid == NULL
1095: || (*pt->pt_valid)(plwp, dvp->v_mount));
1096: lwp_delref(plwp);
1097: if (found)
1098: break;
1099: }
1100: if (i == nproc_targets) {
1101: procfs_proc_unlock(p);
1102: break;
1.9 cgd 1103: }
1.109 darcy 1104: if (pt->pt_pfstype == PFSfile) {
1.75 chs 1105: fvp = p->p_textvp;
1.23 mycroft 1106: /* We already checked that it exists. */
1.32 mycroft 1107: VREF(fvp);
1.53 fvdl 1108: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
1.32 mycroft 1109: *vpp = fvp;
1.123.2.3 yamt 1110: procfs_proc_unlock(p);
1.21 mycroft 1111: return (0);
1112: }
1.1 pk 1113:
1.62 wrstuden 1114: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.123.2.3 yamt 1115: pt->pt_pfstype, -1, p);
1116: procfs_proc_unlock(p);
1.62 wrstuden 1117: return (error);
1.1 pk 1118:
1.109 darcy 1119: case PFSfd: {
1.91 christos 1120: int fd;
1121: struct file *fp;
1.123.2.3 yamt 1122:
1123: if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ENOENT)) != 0)
1124: return error;
1125:
1.91 christos 1126: /*
1127: * do the .. dance. We unlock the directory, and then
1128: * get the proc dir. That will automatically return ..
1.123.2.2 yamt 1129: * locked. Then re-lock the directory.
1.91 christos 1130: */
1131: if (cnp->cn_flags & ISDOTDOT) {
1132: VOP_UNLOCK(dvp, 0);
1133: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.123.2.3 yamt 1134: PFSproc, -1, p);
1.123.2.2 yamt 1135: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.123.2.3 yamt 1136: procfs_proc_unlock(p);
1.91 christos 1137: return (error);
1138: }
1139: fd = atoi(pname, cnp->cn_namelen);
1.123.2.3 yamt 1140:
1141: mutex_enter(&p->p_mutex);
1142: fp = fd_getfile(p->p_fd, fd);
1143: mutex_exit(&p->p_mutex);
1144: if (fp == NULL) {
1145: procfs_proc_unlock(p);
1.91 christos 1146: return ENOENT;
1.123.2.3 yamt 1147: }
1148:
1.99 jdolecek 1149: FILE_USE(fp);
1150:
1.91 christos 1151: switch (fp->f_type) {
1152: case DTYPE_VNODE:
1153: fvp = (struct vnode *)fp->f_data;
1.101 jdolecek 1154:
1155: /* Don't show directories */
1.102 christos 1156: if (fvp->v_type == VDIR)
1157: goto symlink;
1.101 jdolecek 1158:
1.91 christos 1159: VREF(fvp);
1.123.2.1 yamt 1160: FILE_UNUSE(fp, l);
1.121 perry 1161: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY |
1.92 christos 1162: (p == curproc ? LK_CANRECURSE : 0));
1.91 christos 1163: *vpp = fvp;
1164: error = 0;
1165: break;
1166: default:
1.102 christos 1167: symlink:
1.123.2.1 yamt 1168: FILE_UNUSE(fp, l);
1.91 christos 1169: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.123.2.3 yamt 1170: PFSfd, fd, p);
1.91 christos 1171: break;
1172: }
1.123.2.3 yamt 1173: procfs_proc_unlock(p);
1.91 christos 1174: return error;
1175: }
1.9 cgd 1176: default:
1177: return (ENOTDIR);
1.1 pk 1178: }
1.32 mycroft 1179:
1180: return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
1.1 pk 1181: }
1182:
1.18 cgd 1183: int
1.123.2.2 yamt 1184: procfs_validfile(struct lwp *l, struct mount *mp)
1.18 cgd 1185: {
1.123.2.2 yamt 1186: return l != NULL && l->l_proc != NULL && l->l_proc->p_textvp != NULL;
1.74 tv 1187: }
1.21 mycroft 1188:
1.74 tv 1189: static int
1.123.2.1 yamt 1190: procfs_validfile_linux(l, mp)
1191: struct lwp *l;
1.76 fvdl 1192: struct mount *mp;
1.74 tv 1193: {
1.76 fvdl 1194: int flags;
1195:
1196: flags = VFSTOPROC(mp)->pmnt_flags;
1.123.2.2 yamt 1197: return (flags & PROCFSMNT_LINUXCOMPAT) &&
1198: (l == NULL || l->l_proc == NULL || procfs_validfile(l, mp));
1.18 cgd 1199: }
1200:
1.117 yamt 1201: struct procfs_root_readdir_ctx {
1202: struct uio *uiop;
1203: off_t *cookies;
1204: int ncookies;
1.120 yamt 1205: off_t off;
1206: off_t startoff;
1.117 yamt 1207: int error;
1208: };
1209:
1210: static int
1211: procfs_root_readdir_callback(struct proc *p, void *arg)
1212: {
1213: struct procfs_root_readdir_ctx *ctxp = arg;
1214: struct dirent d;
1215: struct uio *uiop;
1216: int error;
1217:
1218: uiop = ctxp->uiop;
1219: if (uiop->uio_resid < UIO_MX)
1220: return -1; /* no space */
1221:
1.120 yamt 1222: if (ctxp->off < ctxp->startoff) {
1223: ctxp->off++;
1.117 yamt 1224: return 0;
1225: }
1226:
1.123.2.1 yamt 1227: if (kauth_authorize_process(kauth_cred_get(),
1228: KAUTH_PROCESS_CANSEE, p, NULL, NULL, NULL) != 0)
1229: return 0;
1230:
1.117 yamt 1231: memset(&d, 0, UIO_MX);
1232: d.d_reclen = UIO_MX;
1233: d.d_fileno = PROCFS_FILENO(p->p_pid, PFSproc, -1);
1234: d.d_namlen = snprintf(d.d_name,
1235: UIO_MX - offsetof(struct dirent, d_name), "%ld", (long)p->p_pid);
1236: d.d_type = DT_DIR;
1237:
1.123.2.4! yamt 1238: mutex_exit(&proclist_lock);
1.117 yamt 1239: error = uiomove(&d, UIO_MX, uiop);
1.123.2.4! yamt 1240: mutex_enter(&proclist_lock);
1.117 yamt 1241: if (error) {
1242: ctxp->error = error;
1243: return -1;
1244: }
1245:
1246: ctxp->ncookies++;
1247: if (ctxp->cookies)
1.120 yamt 1248: *(ctxp->cookies)++ = ctxp->off + 1;
1249: ctxp->off++;
1.117 yamt 1250:
1251: return 0;
1252: }
1253:
1.9 cgd 1254: /*
1255: * readdir returns directory entries from pfsnode (vp).
1256: *
1257: * the strategy here with procfs is to generate a single
1.34 mycroft 1258: * directory entry at a time (struct dirent) and then
1.9 cgd 1259: * copy that out to userland using uiomove. a more efficent
1260: * though more complex implementation, would try to minimize
1261: * the number of calls to uiomove(). for procfs, this is
1262: * hardly worth the added code complexity.
1263: *
1264: * this should just be done through read()
1265: */
1.37 christos 1266: int
1267: procfs_readdir(v)
1268: void *v;
1269: {
1.22 mycroft 1270: struct vop_readdir_args /* {
1271: struct vnode *a_vp;
1272: struct uio *a_uio;
1.123.2.1 yamt 1273: kauth_cred_t a_cred;
1.22 mycroft 1274: int *a_eofflag;
1.53 fvdl 1275: off_t **a_cookies;
1276: int *a_ncookies;
1.37 christos 1277: } */ *ap = v;
1.21 mycroft 1278: struct uio *uio = ap->a_uio;
1.34 mycroft 1279: struct dirent d;
1.9 cgd 1280: struct pfsnode *pfs;
1.68 sommerfe 1281: off_t i;
1.9 cgd 1282: int error;
1.53 fvdl 1283: off_t *cookies = NULL;
1.117 yamt 1284: int ncookies;
1.76 fvdl 1285: struct vnode *vp;
1.78 jdolecek 1286: const struct proc_target *pt;
1.117 yamt 1287: struct procfs_root_readdir_ctx ctx;
1.123.2.3 yamt 1288: struct lwp *l;
1.9 cgd 1289:
1.76 fvdl 1290: vp = ap->a_vp;
1291: pfs = VTOPFS(vp);
1.1 pk 1292:
1.9 cgd 1293: if (uio->uio_resid < UIO_MX)
1294: return (EINVAL);
1.35 mycroft 1295: if (uio->uio_offset < 0)
1.1 pk 1296: return (EINVAL);
1297:
1.9 cgd 1298: error = 0;
1.35 mycroft 1299: i = uio->uio_offset;
1.113 jrf 1300: memset(&d, 0, UIO_MX);
1.34 mycroft 1301: d.d_reclen = UIO_MX;
1.53 fvdl 1302: ncookies = uio->uio_resid / UIO_MX;
1.9 cgd 1303:
1304: switch (pfs->pfs_type) {
1305: /*
1306: * this is for the process-specific sub-directories.
1307: * all that is needed to is copy out all the entries
1308: * from the procent[] table (top of this file).
1309: */
1.109 darcy 1310: case PFSproc: {
1.32 mycroft 1311: struct proc *p;
1.66 christos 1312:
1313: if (i >= nproc_targets)
1.67 sommerfe 1314: return 0;
1.9 cgd 1315:
1.123.2.3 yamt 1316: if (procfs_proc_lock(pfs->pfs_pid, &p, ESRCH) != 0)
1.32 mycroft 1317: break;
1318:
1.53 fvdl 1319: if (ap->a_ncookies) {
1320: ncookies = min(ncookies, (nproc_targets - i));
1.72 thorpej 1321: cookies = malloc(ncookies * sizeof (off_t),
1.53 fvdl 1322: M_TEMP, M_WAITOK);
1323: *ap->a_cookies = cookies;
1324: }
1325:
1.32 mycroft 1326: for (pt = &proc_targets[i];
1327: uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
1.123.2.3 yamt 1328: if (pt->pt_valid) {
1329: /* XXXSMP locking */
1330: mutex_enter(&p->p_smutex);
1331: l = proc_representative_lwp(p, NULL, 1);
1332: mutex_exit(&p->p_smutex);
1333: if ((*pt->pt_valid)(l, vp->v_mount) == 0)
1334: continue;
1335: }
1.121 perry 1336:
1.91 christos 1337: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1338: pt->pt_pfstype, -1);
1.34 mycroft 1339: d.d_namlen = pt->pt_namlen;
1.56 perry 1340: memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1.34 mycroft 1341: d.d_type = pt->pt_type;
1.15 ws 1342:
1.113 jrf 1343: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.9 cgd 1344: break;
1.53 fvdl 1345: if (cookies)
1.35 mycroft 1346: *cookies++ = i + 1;
1.6 ws 1347: }
1.9 cgd 1348:
1.123.2.3 yamt 1349: procfs_proc_unlock(p);
1.9 cgd 1350: break;
1.34 mycroft 1351: }
1.109 darcy 1352: case PFSfd: {
1.91 christos 1353: struct proc *p;
1354: struct filedesc *fdp;
1.111 jdolecek 1355: struct file *fp;
1.110 simonb 1356: int lim, nc = 0;
1.91 christos 1357:
1.123.2.3 yamt 1358: if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH)) != 0)
1359: return error;
1.91 christos 1360:
1.123.2.1 yamt 1361: if (kauth_authorize_process(kauth_cred_get(),
1.123.2.3 yamt 1362: KAUTH_PROCESS_CANSEE, p, NULL, NULL, NULL) != 0) {
1363: procfs_proc_unlock(p);
1.123.2.1 yamt 1364: return ESRCH;
1.123.2.3 yamt 1365: }
1.123.2.1 yamt 1366:
1.123.2.3 yamt 1367: fdp = p->p_fd; /* XXXSMP */
1.91 christos 1368:
1369: lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
1.123.2.3 yamt 1370: if (i >= lim) {
1371: procfs_proc_unlock(p);
1.91 christos 1372: return 0;
1.123.2.3 yamt 1373: }
1.91 christos 1374:
1375: if (ap->a_ncookies) {
1376: ncookies = min(ncookies, (fdp->fd_nfiles + 2 - i));
1377: cookies = malloc(ncookies * sizeof (off_t),
1378: M_TEMP, M_WAITOK);
1379: *ap->a_cookies = cookies;
1380: }
1381:
1382: for (; i < 2 && uio->uio_resid >= UIO_MX; i++) {
1383: pt = &proc_targets[i];
1384: d.d_namlen = pt->pt_namlen;
1385: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
1386: pt->pt_pfstype, -1);
1387: (void)memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1388: d.d_type = pt->pt_type;
1.113 jrf 1389: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.91 christos 1390: break;
1391: if (cookies)
1392: *cookies++ = i + 1;
1393: nc++;
1394: }
1395: if (error) {
1396: ncookies = nc;
1397: break;
1398: }
1399: for (; uio->uio_resid >= UIO_MX && i < fdp->fd_nfiles; i++) {
1.111 jdolecek 1400: /* check the descriptor exists */
1401: if ((fp = fd_getfile(fdp, i - 2)) == NULL)
1.100 jdolecek 1402: continue;
1.111 jdolecek 1403: simple_unlock(&fp->f_slock);
1404:
1.109 darcy 1405: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, PFSfd, i - 2);
1.91 christos 1406: d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
1.93 martin 1407: "%lld", (long long)(i - 2));
1.91 christos 1408: d.d_type = VREG;
1.113 jrf 1409: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.91 christos 1410: break;
1411: if (cookies)
1412: *cookies++ = i + 1;
1413: nc++;
1414: }
1415: ncookies = nc;
1.123.2.3 yamt 1416: procfs_proc_unlock(p);
1.91 christos 1417: break;
1418: }
1.9 cgd 1419:
1420: /*
1421: * this is for the root of the procfs filesystem
1.69 thorpej 1422: * what is needed are special entries for "curproc"
1423: * and "self" followed by an entry for each process
1.117 yamt 1424: * on allproc.
1.9 cgd 1425: */
1426:
1.109 darcy 1427: case PFSroot: {
1.117 yamt 1428: int nc = 0;
1.9 cgd 1429:
1.53 fvdl 1430: if (ap->a_ncookies) {
1431: /*
1432: * XXX Potentially allocating too much space here,
1433: * but I'm lazy. This loop needs some work.
1434: */
1.72 thorpej 1435: cookies = malloc(ncookies * sizeof (off_t),
1.53 fvdl 1436: M_TEMP, M_WAITOK);
1437: *ap->a_cookies = cookies;
1438: }
1.117 yamt 1439: error = 0;
1440: /* 0 ... 3 are static entries. */
1441: for (; i <= 3 && uio->uio_resid >= UIO_MX; i++) {
1.9 cgd 1442: switch (i) {
1.12 ws 1443: case 0: /* `.' */
1444: case 1: /* `..' */
1.109 darcy 1445: d.d_fileno = PROCFS_FILENO(0, PFSroot, -1);
1.34 mycroft 1446: d.d_namlen = i + 1;
1.56 perry 1447: memcpy(d.d_name, "..", d.d_namlen);
1.34 mycroft 1448: d.d_name[i + 1] = '\0';
1449: d.d_type = DT_DIR;
1.12 ws 1450: break;
1.21 mycroft 1451:
1.12 ws 1452: case 2:
1.109 darcy 1453: d.d_fileno = PROCFS_FILENO(0, PFScurproc, -1);
1.69 thorpej 1454: d.d_namlen = sizeof("curproc") - 1;
1455: memcpy(d.d_name, "curproc", sizeof("curproc"));
1456: d.d_type = DT_LNK;
1457: break;
1458:
1459: case 3:
1.109 darcy 1460: d.d_fileno = PROCFS_FILENO(0, PFSself, -1);
1.69 thorpej 1461: d.d_namlen = sizeof("self") - 1;
1462: memcpy(d.d_name, "self", sizeof("self"));
1.34 mycroft 1463: d.d_type = DT_LNK;
1.9 cgd 1464: break;
1.1 pk 1465: }
1.21 mycroft 1466:
1.113 jrf 1467: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.9 cgd 1468: break;
1.53 fvdl 1469: nc++;
1470: if (cookies)
1.35 mycroft 1471: *cookies++ = i + 1;
1.1 pk 1472: }
1.117 yamt 1473: /* 4 ... are process entries. */
1474: ctx.uiop = uio;
1475: ctx.error = 0;
1.120 yamt 1476: ctx.off = 4;
1477: ctx.startoff = i;
1.117 yamt 1478: ctx.cookies = cookies;
1479: ctx.ncookies = nc;
1480: proclist_foreach_call(&allproc,
1481: procfs_root_readdir_callback, &ctx);
1482: cookies = ctx.cookies;
1483: nc = ctx.ncookies;
1484: error = ctx.error;
1485: if (error)
1486: break;
1.76 fvdl 1487:
1.117 yamt 1488: /* misc entries. */
1.120 yamt 1489: if (i < ctx.off)
1490: i = ctx.off;
1491: if (i >= ctx.off + nproc_root_targets)
1.76 fvdl 1492: break;
1.120 yamt 1493: for (pt = &proc_root_targets[i - ctx.off];
1.117 yamt 1494: uio->uio_resid >= UIO_MX &&
1495: pt < &proc_root_targets[nproc_root_targets];
1496: pt++, i++) {
1.76 fvdl 1497: if (pt->pt_valid &&
1498: (*pt->pt_valid)(NULL, vp->v_mount) == 0)
1499: continue;
1.91 christos 1500: d.d_fileno = PROCFS_FILENO(0, pt->pt_pfstype, -1);
1.76 fvdl 1501: d.d_namlen = pt->pt_namlen;
1502: memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1503: d.d_type = pt->pt_type;
1504:
1.113 jrf 1505: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.76 fvdl 1506: break;
1507: nc++;
1508: if (cookies)
1509: *cookies++ = i + 1;
1510: }
1511:
1.53 fvdl 1512: ncookies = nc;
1.9 cgd 1513: break;
1.34 mycroft 1514: }
1.9 cgd 1515:
1516: default:
1517: error = ENOTDIR;
1518: break;
1.1 pk 1519: }
1.9 cgd 1520:
1.53 fvdl 1521: if (ap->a_ncookies) {
1522: if (error) {
1.54 fvdl 1523: if (cookies)
1.72 thorpej 1524: free(*ap->a_cookies, M_TEMP);
1.53 fvdl 1525: *ap->a_ncookies = 0;
1526: *ap->a_cookies = NULL;
1527: } else
1528: *ap->a_ncookies = ncookies;
1529: }
1.35 mycroft 1530: uio->uio_offset = i;
1.9 cgd 1531: return (error);
1.12 ws 1532: }
1533:
1534: /*
1.123.2.1 yamt 1535: * readlink reads the link of `curproc' and others
1.12 ws 1536: */
1.37 christos 1537: int
1538: procfs_readlink(v)
1539: void *v;
1.12 ws 1540: {
1.37 christos 1541: struct vop_readlink_args *ap = v;
1.123 christos 1542: char bf[16]; /* should be enough */
1543: char *bp = bf;
1.102 christos 1544: char *path = NULL;
1.12 ws 1545: int len;
1.102 christos 1546: int error = 0;
1547: struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.123.2.1 yamt 1548: struct proc *pown;
1.12 ws 1549:
1.109 darcy 1550: if (pfs->pfs_fileno == PROCFS_FILENO(0, PFScurproc, -1))
1.123 christos 1551: len = snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
1.109 darcy 1552: else if (pfs->pfs_fileno == PROCFS_FILENO(0, PFSself, -1))
1.123 christos 1553: len = snprintf(bf, sizeof(bf), "%s", "curproc");
1.123.2.2 yamt 1554: else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFScwd, -1) ||
1555: pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSchroot, -1) ||
1556: pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSexe, -1)) {
1.123.2.3 yamt 1557: if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
1558: return error;
1.123.2.1 yamt 1559: MALLOC(path, char *, MAXPATHLEN + 4, M_TEMP,
1560: M_WAITOK|M_CANFAIL);
1.123.2.3 yamt 1561: if (path == NULL) {
1562: procfs_proc_unlock(pown);
1.123.2.1 yamt 1563: return (ENOMEM);
1.123.2.3 yamt 1564: }
1.123.2.1 yamt 1565: bp = path + MAXPATHLEN;
1566: *--bp = '\0';
1.123.2.3 yamt 1567: mutex_enter(&pown->p_mutex);
1.123.2.2 yamt 1568: (void)procfs_dir(PROCFS_TYPE(pfs->pfs_fileno), curlwp, pown,
1569: &bp, path, MAXPATHLEN);
1.123.2.3 yamt 1570: mutex_exit(&pown->p_mutex);
1571: procfs_proc_unlock(pown);
1.123.2.1 yamt 1572: len = strlen(bp);
1.123.2.2 yamt 1573: } else {
1.102 christos 1574: struct file *fp;
1575: struct vnode *vxp, *vp;
1576:
1.123.2.3 yamt 1577: if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
1.102 christos 1578: return error;
1.123.2.4! yamt 1579:
1.123.2.3 yamt 1580: mutex_enter(&pown->p_mutex);
1581: fp = fd_getfile(pown->p_fd, pfs->pfs_fd);
1582: mutex_exit(&pown->p_mutex);
1.123.2.4! yamt 1583: if (fp == NULL) {
1.123.2.3 yamt 1584: procfs_proc_unlock(pown);
1.123.2.4! yamt 1585: return EBADF;
1.123.2.3 yamt 1586: }
1.123.2.4! yamt 1587:
1.102 christos 1588: FILE_USE(fp);
1589: switch (fp->f_type) {
1590: case DTYPE_VNODE:
1591: vxp = (struct vnode *)fp->f_data;
1592: if (vxp->v_type != VDIR) {
1.123.2.3 yamt 1593: FILE_UNUSE(fp, curlwp);
1594: error = EINVAL;
1595: break;
1.102 christos 1596: }
1597: if ((path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK))
1598: == NULL) {
1.123.2.3 yamt 1599: FILE_UNUSE(fp, curlwp);
1600: error = ENOMEM;
1601: break;
1.102 christos 1602: }
1603: bp = path + MAXPATHLEN;
1604: *--bp = '\0';
1.123.2.4! yamt 1605:
! 1606: /*
! 1607: * XXX: kludge to avoid locking against ourselves
! 1608: * in getcwd()
! 1609: */
! 1610: if (vxp->v_tag == VT_PROCFS) {
! 1611: *--bp = '/';
! 1612: } else {
! 1613: vp = curproc->p_cwdi->cwdi_rdir; /* XXXSMP */
! 1614: if (vp == NULL)
! 1615: vp = rootvnode;
! 1616: error = getcwd_common(vxp, vp, &bp, path,
! 1617: MAXPATHLEN / 2, 0, curlwp);
! 1618: }
1.123.2.3 yamt 1619: FILE_UNUSE(fp, curlwp);
1620: if (error)
1621: break;
1.102 christos 1622: len = strlen(bp);
1623: break;
1624:
1625: case DTYPE_MISC:
1.123 christos 1626: len = snprintf(bf, sizeof(bf), "%s", "[misc]");
1.102 christos 1627: break;
1628:
1629: case DTYPE_KQUEUE:
1.123 christos 1630: len = snprintf(bf, sizeof(bf), "%s", "[kqueue]");
1.102 christos 1631: break;
1632:
1633: default:
1.123.2.3 yamt 1634: error = EINVAL;
1635: break;
1636: }
1637: procfs_proc_unlock(pown);
1.102 christos 1638: }
1.12 ws 1639:
1.123.2.3 yamt 1640: if (error == 0)
1641: error = uiomove(bp, len, ap->a_uio);
1.102 christos 1642: if (path)
1643: free(path, M_TEMP);
1644: return error;
1.1 pk 1645: }
1646:
1647: /*
1.91 christos 1648: * convert decimal ascii to int
1.1 pk 1649: */
1.91 christos 1650: static int
1651: atoi(b, len)
1.9 cgd 1652: const char *b;
1.91 christos 1653: size_t len;
1.1 pk 1654: {
1.91 christos 1655: int p = 0;
1.1 pk 1656:
1657: while (len--) {
1.9 cgd 1658: char c = *b++;
1.1 pk 1659: if (c < '0' || c > '9')
1.91 christos 1660: return -1;
1.9 cgd 1661: p = 10 * p + (c - '0');
1.1 pk 1662: }
1.9 cgd 1663:
1.91 christos 1664: return p;
1.1 pk 1665: }
CVSweb <webmaster@jp.NetBSD.org>