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