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