1 /* $NetBSD: procfs_vnops.c,v 1.113 2004/04/29 16:10:55 jrf Exp $ */ 2 3 /* 4 * Copyright (c) 1993, 1995 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 35 */ 36 37 /* 38 * Copyright (c) 1993 Jan-Simon Pendry 39 * 40 * This code is derived from software contributed to Berkeley by 41 * Jan-Simon Pendry. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 72 */ 73 74 /* 75 * procfs vnode interface 76 */ 77 78 #include <sys/cdefs.h> 79 __KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.113 2004/04/29 16:10:55 jrf Exp $"); 80 81 #include <sys/param.h> 82 #include <sys/systm.h> 83 #include <sys/time.h> 84 #include <sys/kernel.h> 85 #include <sys/file.h> 86 #include <sys/filedesc.h> 87 #include <sys/proc.h> 88 #include <sys/vnode.h> 89 #include <sys/namei.h> 90 #include <sys/malloc.h> 91 #include <sys/mount.h> 92 #include <sys/dirent.h> 93 #include <sys/resourcevar.h> 94 #include <sys/stat.h> 95 #include <sys/ptrace.h> 96 97 #include <uvm/uvm_extern.h> /* for PAGE_SIZE */ 98 99 #include <machine/reg.h> 100 101 #include <miscfs/genfs/genfs.h> 102 #include <miscfs/procfs/procfs.h> 103 104 /* 105 * Vnode Operations. 106 * 107 */ 108 109 static int procfs_validfile_linux __P((struct proc *, struct mount *)); 110 111 /* 112 * This is a list of the valid names in the 113 * process-specific sub-directories. It is 114 * used in procfs_lookup and procfs_readdir 115 */ 116 static const struct proc_target { 117 u_char pt_type; 118 u_char pt_namlen; 119 const char *pt_name; 120 pfstype pt_pfstype; 121 int (*pt_valid) __P((struct proc *, struct mount *)); 122 } proc_targets[] = { 123 #define N(s) sizeof(s)-1, s 124 /* name type validp */ 125 { DT_DIR, N("."), PFSproc, NULL }, 126 { DT_DIR, N(".."), PFSroot, NULL }, 127 { DT_DIR, N("fd"), PFSfd, NULL }, 128 { DT_REG, N("file"), PFSfile, procfs_validfile }, 129 { DT_REG, N("mem"), PFSmem, NULL }, 130 { DT_REG, N("regs"), PFSregs, procfs_validregs }, 131 { DT_REG, N("fpregs"), PFSfpregs, procfs_validfpregs }, 132 { DT_REG, N("ctl"), PFSctl, NULL }, 133 { DT_REG, N("stat"), PFSstat, procfs_validfile_linux }, 134 { DT_REG, N("status"), PFSstatus, NULL }, 135 { DT_REG, N("note"), PFSnote, NULL }, 136 { DT_REG, N("notepg"), PFSnotepg, NULL }, 137 { DT_REG, N("map"), PFSmap, procfs_validmap }, 138 { DT_REG, N("maps"), PFSmaps, procfs_validmap }, 139 { DT_REG, N("cmdline"), PFScmdline, NULL }, 140 { DT_REG, N("exe"), PFSfile, procfs_validfile_linux }, 141 #ifdef __HAVE_PROCFS_MACHDEP 142 PROCFS_MACHDEP_NODETYPE_DEFNS 143 #endif 144 #undef N 145 }; 146 static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]); 147 148 /* 149 * List of files in the root directory. Note: the validate function will 150 * be called with p == NULL for these ones. 151 */ 152 static const struct proc_target proc_root_targets[] = { 153 #define N(s) sizeof(s)-1, s 154 /* name type validp */ 155 { DT_REG, N("meminfo"), PFSmeminfo, procfs_validfile_linux }, 156 { DT_REG, N("cpuinfo"), PFScpuinfo, procfs_validfile_linux }, 157 { DT_REG, N("uptime"), PFSuptime, procfs_validfile_linux }, 158 #undef N 159 }; 160 static const int nproc_root_targets = 161 sizeof(proc_root_targets) / sizeof(proc_root_targets[0]); 162 163 int procfs_lookup __P((void *)); 164 #define procfs_create genfs_eopnotsupp 165 #define procfs_mknod genfs_eopnotsupp 166 int procfs_open __P((void *)); 167 int procfs_close __P((void *)); 168 int procfs_access __P((void *)); 169 int procfs_getattr __P((void *)); 170 int procfs_setattr __P((void *)); 171 #define procfs_read procfs_rw 172 #define procfs_write procfs_rw 173 #define procfs_fcntl genfs_fcntl 174 #define procfs_ioctl genfs_enoioctl 175 #define procfs_poll genfs_poll 176 #define procfs_revoke genfs_revoke 177 #define procfs_fsync genfs_nullop 178 #define procfs_seek genfs_nullop 179 #define procfs_remove genfs_eopnotsupp 180 int procfs_link __P((void *)); 181 #define procfs_rename genfs_eopnotsupp 182 #define procfs_mkdir genfs_eopnotsupp 183 #define procfs_rmdir genfs_eopnotsupp 184 int procfs_symlink __P((void *)); 185 int procfs_readdir __P((void *)); 186 int procfs_readlink __P((void *)); 187 #define procfs_abortop genfs_abortop 188 int procfs_inactive __P((void *)); 189 int procfs_reclaim __P((void *)); 190 #define procfs_lock genfs_lock 191 #define procfs_unlock genfs_unlock 192 #define procfs_bmap genfs_badop 193 #define procfs_strategy genfs_badop 194 int procfs_print __P((void *)); 195 int procfs_pathconf __P((void *)); 196 #define procfs_islocked genfs_islocked 197 #define procfs_advlock genfs_einval 198 #define procfs_blkatoff genfs_eopnotsupp 199 #define procfs_valloc genfs_eopnotsupp 200 #define procfs_vfree genfs_nullop 201 #define procfs_truncate genfs_eopnotsupp 202 #define procfs_update genfs_nullop 203 #define procfs_bwrite genfs_eopnotsupp 204 #define procfs_putpages genfs_null_putpages 205 206 static int atoi __P((const char *, size_t)); 207 208 /* 209 * procfs vnode operations. 210 */ 211 int (**procfs_vnodeop_p) __P((void *)); 212 const struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 213 { &vop_default_desc, vn_default_error }, 214 { &vop_lookup_desc, procfs_lookup }, /* lookup */ 215 { &vop_create_desc, procfs_create }, /* create */ 216 { &vop_mknod_desc, procfs_mknod }, /* mknod */ 217 { &vop_open_desc, procfs_open }, /* open */ 218 { &vop_close_desc, procfs_close }, /* close */ 219 { &vop_access_desc, procfs_access }, /* access */ 220 { &vop_getattr_desc, procfs_getattr }, /* getattr */ 221 { &vop_setattr_desc, procfs_setattr }, /* setattr */ 222 { &vop_read_desc, procfs_read }, /* read */ 223 { &vop_write_desc, procfs_write }, /* write */ 224 { &vop_fcntl_desc, procfs_fcntl }, /* fcntl */ 225 { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 226 { &vop_poll_desc, procfs_poll }, /* poll */ 227 { &vop_revoke_desc, procfs_revoke }, /* revoke */ 228 { &vop_fsync_desc, procfs_fsync }, /* fsync */ 229 { &vop_seek_desc, procfs_seek }, /* seek */ 230 { &vop_remove_desc, procfs_remove }, /* remove */ 231 { &vop_link_desc, procfs_link }, /* link */ 232 { &vop_rename_desc, procfs_rename }, /* rename */ 233 { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 234 { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 235 { &vop_symlink_desc, procfs_symlink }, /* symlink */ 236 { &vop_readdir_desc, procfs_readdir }, /* readdir */ 237 { &vop_readlink_desc, procfs_readlink }, /* readlink */ 238 { &vop_abortop_desc, procfs_abortop }, /* abortop */ 239 { &vop_inactive_desc, procfs_inactive }, /* inactive */ 240 { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 241 { &vop_lock_desc, procfs_lock }, /* lock */ 242 { &vop_unlock_desc, procfs_unlock }, /* unlock */ 243 { &vop_bmap_desc, procfs_bmap }, /* bmap */ 244 { &vop_strategy_desc, procfs_strategy }, /* strategy */ 245 { &vop_print_desc, procfs_print }, /* print */ 246 { &vop_islocked_desc, procfs_islocked }, /* islocked */ 247 { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 248 { &vop_advlock_desc, procfs_advlock }, /* advlock */ 249 { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 250 { &vop_valloc_desc, procfs_valloc }, /* valloc */ 251 { &vop_vfree_desc, procfs_vfree }, /* vfree */ 252 { &vop_truncate_desc, procfs_truncate }, /* truncate */ 253 { &vop_update_desc, procfs_update }, /* update */ 254 { &vop_putpages_desc, procfs_putpages }, /* putpages */ 255 { NULL, NULL } 256 }; 257 const struct vnodeopv_desc procfs_vnodeop_opv_desc = 258 { &procfs_vnodeop_p, procfs_vnodeop_entries }; 259 /* 260 * set things up for doing i/o on 261 * the pfsnode (vp). (vp) is locked 262 * on entry, and should be left locked 263 * on exit. 264 * 265 * for procfs we don't need to do anything 266 * in particular for i/o. all that is done 267 * is to support exclusive open on process 268 * memory images. 269 */ 270 int 271 procfs_open(v) 272 void *v; 273 { 274 struct vop_open_args /* { 275 struct vnode *a_vp; 276 int a_mode; 277 struct ucred *a_cred; 278 struct proc *a_p; 279 } */ *ap = v; 280 struct pfsnode *pfs = VTOPFS(ap->a_vp); 281 struct proc *p1, *p2; 282 int error; 283 284 p1 = ap->a_p; /* tracer */ 285 p2 = PFIND(pfs->pfs_pid); /* traced */ 286 287 if (p2 == NULL) 288 return (ENOENT); /* was ESRCH, jsp */ 289 290 switch (pfs->pfs_type) { 291 case PFSmem: 292 if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) || 293 ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) 294 return (EBUSY); 295 296 if ((error = process_checkioperm(p1, p2)) != 0) 297 return (error); 298 299 if (ap->a_mode & FWRITE) 300 pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); 301 302 return (0); 303 304 default: 305 break; 306 } 307 308 return (0); 309 } 310 311 /* 312 * close the pfsnode (vp) after doing i/o. 313 * (vp) is not locked on entry or exit. 314 * 315 * nothing to do for procfs other than undo 316 * any exclusive open flag (see _open above). 317 */ 318 int 319 procfs_close(v) 320 void *v; 321 { 322 struct vop_close_args /* { 323 struct vnode *a_vp; 324 int a_fflag; 325 struct ucred *a_cred; 326 struct proc *a_p; 327 } */ *ap = v; 328 struct pfsnode *pfs = VTOPFS(ap->a_vp); 329 330 switch (pfs->pfs_type) { 331 case PFSmem: 332 if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) 333 pfs->pfs_flags &= ~(FWRITE|O_EXCL); 334 break; 335 336 default: 337 break; 338 } 339 340 return (0); 341 } 342 343 /* 344 * _inactive is called when the pfsnode 345 * is vrele'd and the reference count goes 346 * to zero. (vp) will be on the vnode free 347 * list, so to get it back vget() must be 348 * used. 349 * 350 * for procfs, check if the process is still 351 * alive and if it isn't then just throw away 352 * the vnode by calling vgone(). this may 353 * be overkill and a waste of time since the 354 * chances are that the process will still be 355 * there and PFIND is not free. 356 * 357 * (vp) is locked on entry, but must be unlocked on exit. 358 */ 359 int 360 procfs_inactive(v) 361 void *v; 362 { 363 struct vop_inactive_args /* { 364 struct vnode *a_vp; 365 struct proc *a_p; 366 } */ *ap = v; 367 struct pfsnode *pfs = VTOPFS(ap->a_vp); 368 369 VOP_UNLOCK(ap->a_vp, 0); 370 if (PFIND(pfs->pfs_pid) == NULL) 371 vgone(ap->a_vp); 372 373 return (0); 374 } 375 376 /* 377 * _reclaim is called when getnewvnode() 378 * wants to make use of an entry on the vnode 379 * free list. at this time the filesystem needs 380 * to free any private data and remove the node 381 * from any private lists. 382 */ 383 int 384 procfs_reclaim(v) 385 void *v; 386 { 387 struct vop_reclaim_args /* { 388 struct vnode *a_vp; 389 } */ *ap = v; 390 391 return (procfs_freevp(ap->a_vp)); 392 } 393 394 /* 395 * Return POSIX pathconf information applicable to special devices. 396 */ 397 int 398 procfs_pathconf(v) 399 void *v; 400 { 401 struct vop_pathconf_args /* { 402 struct vnode *a_vp; 403 int a_name; 404 register_t *a_retval; 405 } */ *ap = v; 406 407 switch (ap->a_name) { 408 case _PC_LINK_MAX: 409 *ap->a_retval = LINK_MAX; 410 return (0); 411 case _PC_MAX_CANON: 412 *ap->a_retval = MAX_CANON; 413 return (0); 414 case _PC_MAX_INPUT: 415 *ap->a_retval = MAX_INPUT; 416 return (0); 417 case _PC_PIPE_BUF: 418 *ap->a_retval = PIPE_BUF; 419 return (0); 420 case _PC_CHOWN_RESTRICTED: 421 *ap->a_retval = 1; 422 return (0); 423 case _PC_VDISABLE: 424 *ap->a_retval = _POSIX_VDISABLE; 425 return (0); 426 case _PC_SYNC_IO: 427 *ap->a_retval = 1; 428 return (0); 429 default: 430 return (EINVAL); 431 } 432 /* NOTREACHED */ 433 } 434 435 /* 436 * _print is used for debugging. 437 * just print a readable description 438 * of (vp). 439 */ 440 int 441 procfs_print(v) 442 void *v; 443 { 444 struct vop_print_args /* { 445 struct vnode *a_vp; 446 } */ *ap = v; 447 struct pfsnode *pfs = VTOPFS(ap->a_vp); 448 449 printf("tag VT_PROCFS, type %d, pid %d, mode %x, flags %lx\n", 450 pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); 451 return 0; 452 } 453 454 int 455 procfs_link(v) 456 void *v; 457 { 458 struct vop_link_args /* { 459 struct vnode *a_dvp; 460 struct vnode *a_vp; 461 struct componentname *a_cnp; 462 } */ *ap = v; 463 464 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 465 vput(ap->a_dvp); 466 return (EROFS); 467 } 468 469 int 470 procfs_symlink(v) 471 void *v; 472 { 473 struct vop_symlink_args /* { 474 struct vnode *a_dvp; 475 struct vnode **a_vpp; 476 struct componentname *a_cnp; 477 struct vattr *a_vap; 478 char *a_target; 479 } */ *ap = v; 480 481 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 482 vput(ap->a_dvp); 483 return (EROFS); 484 } 485 486 /* 487 * Invent attributes for pfsnode (vp) and store 488 * them in (vap). 489 * Directories lengths are returned as zero since 490 * any real length would require the genuine size 491 * to be computed, and nothing cares anyway. 492 * 493 * this is relatively minimal for procfs. 494 */ 495 int 496 procfs_getattr(v) 497 void *v; 498 { 499 struct vop_getattr_args /* { 500 struct vnode *a_vp; 501 struct vattr *a_vap; 502 struct ucred *a_cred; 503 struct proc *a_p; 504 } */ *ap = v; 505 struct pfsnode *pfs = VTOPFS(ap->a_vp); 506 struct vattr *vap = ap->a_vap; 507 struct proc *procp; 508 int error; 509 510 /* first check the process still exists */ 511 switch (pfs->pfs_type) { 512 case PFSroot: 513 case PFScurproc: 514 case PFSself: 515 procp = 0; 516 break; 517 518 default: 519 procp = PFIND(pfs->pfs_pid); 520 if (procp == NULL) 521 return (ENOENT); 522 break; 523 } 524 525 error = 0; 526 527 /* start by zeroing out the attributes */ 528 VATTR_NULL(vap); 529 530 /* next do all the common fields */ 531 vap->va_type = ap->a_vp->v_type; 532 vap->va_mode = pfs->pfs_mode; 533 vap->va_fileid = pfs->pfs_fileno; 534 vap->va_flags = 0; 535 vap->va_blocksize = PAGE_SIZE; 536 537 /* 538 * Make all times be current TOD. Avoid microtime(9), it's slow. 539 * We don't guard the read from time(9) with splclock(9) since we 540 * don't actually need to be THAT sure the access is atomic. 541 * 542 * It would be possible to get the process start 543 * time from the p_stat structure, but there's 544 * no "file creation" time stamp anyway, and the 545 * p_stat structure is not addressible if u. gets 546 * swapped out for that process. 547 */ 548 TIMEVAL_TO_TIMESPEC(&time, &vap->va_ctime); 549 vap->va_atime = vap->va_mtime = vap->va_ctime; 550 551 switch (pfs->pfs_type) { 552 case PFSmem: 553 case PFSregs: 554 case PFSfpregs: 555 #if defined(__HAVE_PROCFS_MACHDEP) && defined(PROCFS_MACHDEP_PROTECT_CASES) 556 PROCFS_MACHDEP_PROTECT_CASES 557 #endif 558 /* 559 * If the process has exercised some setuid or setgid 560 * privilege, then rip away read/write permission so 561 * that only root can gain access. 562 */ 563 if (procp->p_flag & P_SUGID) 564 vap->va_mode &= ~(S_IRUSR|S_IWUSR); 565 /* FALLTHROUGH */ 566 case PFSctl: 567 case PFSstatus: 568 case PFSstat: 569 case PFSnote: 570 case PFSnotepg: 571 case PFSmap: 572 case PFSmaps: 573 case PFScmdline: 574 vap->va_nlink = 1; 575 vap->va_uid = procp->p_ucred->cr_uid; 576 vap->va_gid = procp->p_ucred->cr_gid; 577 break; 578 case PFSmeminfo: 579 case PFScpuinfo: 580 case PFSuptime: 581 vap->va_nlink = 1; 582 vap->va_uid = vap->va_gid = 0; 583 break; 584 585 default: 586 break; 587 } 588 589 /* 590 * now do the object specific fields 591 * 592 * The size could be set from struct reg, but it's hardly 593 * worth the trouble, and it puts some (potentially) machine 594 * dependent data into this machine-independent code. If it 595 * becomes important then this function should break out into 596 * a per-file stat function in the corresponding .c file. 597 */ 598 599 switch (pfs->pfs_type) { 600 case PFSroot: 601 /* 602 * Set nlink to 1 to tell fts(3) we don't actually know. 603 */ 604 vap->va_nlink = 1; 605 vap->va_uid = 0; 606 vap->va_gid = 0; 607 vap->va_bytes = vap->va_size = DEV_BSIZE; 608 break; 609 610 case PFScurproc: { 611 char buf[16]; /* should be enough */ 612 vap->va_nlink = 1; 613 vap->va_uid = 0; 614 vap->va_gid = 0; 615 vap->va_bytes = vap->va_size = 616 snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid); 617 break; 618 } 619 620 case PFSself: 621 vap->va_nlink = 1; 622 vap->va_uid = 0; 623 vap->va_gid = 0; 624 vap->va_bytes = vap->va_size = sizeof("curproc"); 625 break; 626 627 case PFSfd: 628 if (pfs->pfs_fd != -1) { 629 struct file *fp; 630 struct proc *pown; 631 632 if ((error = procfs_getfp(pfs, &pown, &fp)) != 0) 633 return error; 634 FILE_USE(fp); 635 vap->va_nlink = 1; 636 vap->va_uid = fp->f_cred->cr_uid; 637 vap->va_gid = fp->f_cred->cr_gid; 638 switch (fp->f_type) { 639 case DTYPE_VNODE: 640 vap->va_bytes = vap->va_size = 641 ((struct vnode *)fp->f_data)->v_size; 642 break; 643 default: 644 vap->va_bytes = vap->va_size = 0; 645 break; 646 } 647 FILE_UNUSE(fp, pown); 648 break; 649 } 650 /*FALLTHROUGH*/ 651 case PFSproc: 652 vap->va_nlink = 2; 653 vap->va_uid = procp->p_ucred->cr_uid; 654 vap->va_gid = procp->p_ucred->cr_gid; 655 vap->va_bytes = vap->va_size = DEV_BSIZE; 656 break; 657 658 case PFSfile: 659 error = EOPNOTSUPP; 660 break; 661 662 case PFSmem: 663 vap->va_bytes = vap->va_size = 664 ctob(procp->p_vmspace->vm_tsize + 665 procp->p_vmspace->vm_dsize + 666 procp->p_vmspace->vm_ssize); 667 break; 668 669 #if defined(PT_GETREGS) || defined(PT_SETREGS) 670 case PFSregs: 671 vap->va_bytes = vap->va_size = sizeof(struct reg); 672 break; 673 #endif 674 675 #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) 676 case PFSfpregs: 677 vap->va_bytes = vap->va_size = sizeof(struct fpreg); 678 break; 679 #endif 680 681 case PFSctl: 682 case PFSstatus: 683 case PFSstat: 684 case PFSnote: 685 case PFSnotepg: 686 case PFScmdline: 687 case PFSmeminfo: 688 case PFScpuinfo: 689 case PFSuptime: 690 vap->va_bytes = vap->va_size = 0; 691 break; 692 case PFSmap: 693 case PFSmaps: 694 /* 695 * Advise a larger blocksize for the map files, so that 696 * they may be read in one pass. 697 */ 698 vap->va_blocksize = 4 * PAGE_SIZE; 699 vap->va_bytes = vap->va_size = 0; 700 break; 701 702 #ifdef __HAVE_PROCFS_MACHDEP 703 PROCFS_MACHDEP_NODETYPE_CASES 704 error = procfs_machdep_getattr(ap->a_vp, vap, procp); 705 break; 706 #endif 707 708 default: 709 panic("procfs_getattr"); 710 } 711 712 return (error); 713 } 714 715 /*ARGSUSED*/ 716 int 717 procfs_setattr(v) 718 void *v; 719 { 720 /* 721 * just fake out attribute setting 722 * it's not good to generate an error 723 * return, otherwise things like creat() 724 * will fail when they try to set the 725 * file length to 0. worse, this means 726 * that echo $note > /proc/$pid/note will fail. 727 */ 728 729 return (0); 730 } 731 732 /* 733 * implement access checking. 734 * 735 * actually, the check for super-user is slightly 736 * broken since it will allow read access to write-only 737 * objects. this doesn't cause any particular trouble 738 * but does mean that the i/o entry points need to check 739 * that the operation really does make sense. 740 */ 741 int 742 procfs_access(v) 743 void *v; 744 { 745 struct vop_access_args /* { 746 struct vnode *a_vp; 747 int a_mode; 748 struct ucred *a_cred; 749 struct proc *a_p; 750 } */ *ap = v; 751 struct vattr va; 752 int error; 753 754 if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_p)) != 0) 755 return (error); 756 757 return (vaccess(va.va_type, va.va_mode, 758 va.va_uid, va.va_gid, ap->a_mode, ap->a_cred)); 759 } 760 761 /* 762 * lookup. this is incredibly complicated in the 763 * general case, however for most pseudo-filesystems 764 * very little needs to be done. 765 * 766 * Locking isn't hard here, just poorly documented. 767 * 768 * If we're looking up ".", just vref the parent & return it. 769 * 770 * If we're looking up "..", unlock the parent, and lock "..". If everything 771 * went ok, and we're on the last component and the caller requested the 772 * parent locked, try to re-lock the parent. We do this to prevent lock 773 * races. 774 * 775 * For anything else, get the needed node. Then unlock the parent if not 776 * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the 777 * parent in the .. case). 778 * 779 * We try to exit with the parent locked in error cases. 780 */ 781 int 782 procfs_lookup(v) 783 void *v; 784 { 785 struct vop_lookup_args /* { 786 struct vnode * a_dvp; 787 struct vnode ** a_vpp; 788 struct componentname * a_cnp; 789 } */ *ap = v; 790 struct componentname *cnp = ap->a_cnp; 791 struct vnode **vpp = ap->a_vpp; 792 struct vnode *dvp = ap->a_dvp; 793 const char *pname = cnp->cn_nameptr; 794 const struct proc_target *pt = NULL; 795 struct vnode *fvp; 796 pid_t pid; 797 struct pfsnode *pfs; 798 struct proc *p = NULL; 799 int i, error, wantpunlock, iscurproc = 0, isself = 0; 800 801 *vpp = NULL; 802 cnp->cn_flags &= ~PDIRUNLOCK; 803 804 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 805 return (EROFS); 806 807 if (cnp->cn_namelen == 1 && *pname == '.') { 808 *vpp = dvp; 809 VREF(dvp); 810 return (0); 811 } 812 813 wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN)); 814 pfs = VTOPFS(dvp); 815 switch (pfs->pfs_type) { 816 case PFSroot: 817 /* 818 * Shouldn't get here with .. in the root node. 819 */ 820 if (cnp->cn_flags & ISDOTDOT) 821 return (EIO); 822 823 iscurproc = CNEQ(cnp, "curproc", 7); 824 isself = CNEQ(cnp, "self", 4); 825 826 if (iscurproc || isself) { 827 error = procfs_allocvp(dvp->v_mount, vpp, 0, 828 iscurproc ? PFScurproc : PFSself, -1); 829 if ((error == 0) && (wantpunlock)) { 830 VOP_UNLOCK(dvp, 0); 831 cnp->cn_flags |= PDIRUNLOCK; 832 } 833 return (error); 834 } 835 836 for (i = 0; i < nproc_root_targets; i++) { 837 pt = &proc_root_targets[i]; 838 if (cnp->cn_namelen == pt->pt_namlen && 839 memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && 840 (pt->pt_valid == NULL || 841 (*pt->pt_valid)(p, dvp->v_mount))) 842 break; 843 } 844 845 if (i != nproc_root_targets) { 846 error = procfs_allocvp(dvp->v_mount, vpp, 0, 847 pt->pt_pfstype, -1); 848 if ((error == 0) && (wantpunlock)) { 849 VOP_UNLOCK(dvp, 0); 850 cnp->cn_flags |= PDIRUNLOCK; 851 } 852 return (error); 853 } 854 855 pid = (pid_t)atoi(pname, cnp->cn_namelen); 856 857 p = PFIND(pid); 858 if (p == NULL) 859 break; 860 861 error = procfs_allocvp(dvp->v_mount, vpp, pid, PFSproc, -1); 862 if ((error == 0) && (wantpunlock)) { 863 VOP_UNLOCK(dvp, 0); 864 cnp->cn_flags |= PDIRUNLOCK; 865 } 866 return (error); 867 868 case PFSproc: 869 /* 870 * do the .. dance. We unlock the directory, and then 871 * get the root dir. That will automatically return .. 872 * locked. Then if the caller wanted dvp locked, we 873 * re-lock. 874 */ 875 if (cnp->cn_flags & ISDOTDOT) { 876 VOP_UNLOCK(dvp, 0); 877 cnp->cn_flags |= PDIRUNLOCK; 878 error = procfs_root(dvp->v_mount, vpp); 879 if ((error == 0) && (wantpunlock == 0) && 880 ((error = vn_lock(dvp, LK_EXCLUSIVE)) == 0)) 881 cnp->cn_flags &= ~PDIRUNLOCK; 882 return (error); 883 } 884 885 p = PFIND(pfs->pfs_pid); 886 if (p == NULL) 887 break; 888 889 for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { 890 if (cnp->cn_namelen == pt->pt_namlen && 891 memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && 892 (pt->pt_valid == NULL || 893 (*pt->pt_valid)(p, dvp->v_mount))) 894 goto found; 895 } 896 break; 897 898 found: 899 if (pt->pt_pfstype == PFSfile) { 900 fvp = p->p_textvp; 901 /* We already checked that it exists. */ 902 VREF(fvp); 903 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY); 904 if (wantpunlock) { 905 VOP_UNLOCK(dvp, 0); 906 cnp->cn_flags |= PDIRUNLOCK; 907 } 908 *vpp = fvp; 909 return (0); 910 } 911 912 error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 913 pt->pt_pfstype, -1); 914 if ((error == 0) && (wantpunlock)) { 915 VOP_UNLOCK(dvp, 0); 916 cnp->cn_flags |= PDIRUNLOCK; 917 } 918 return (error); 919 920 case PFSfd: { 921 int fd; 922 struct file *fp; 923 /* 924 * do the .. dance. We unlock the directory, and then 925 * get the proc dir. That will automatically return .. 926 * locked. Then if the caller wanted dvp locked, we 927 * re-lock. 928 */ 929 if (cnp->cn_flags & ISDOTDOT) { 930 VOP_UNLOCK(dvp, 0); 931 cnp->cn_flags |= PDIRUNLOCK; 932 error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 933 PFSproc, -1); 934 if ((error == 0) && (wantpunlock == 0) && 935 ((error = vn_lock(dvp, LK_EXCLUSIVE)) == 0)) 936 cnp->cn_flags &= ~PDIRUNLOCK; 937 return (error); 938 } 939 fd = atoi(pname, cnp->cn_namelen); 940 p = PFIND(pfs->pfs_pid); 941 if (p == NULL || (fp = fd_getfile(p->p_fd, fd)) == NULL) 942 return ENOENT; 943 FILE_USE(fp); 944 945 switch (fp->f_type) { 946 case DTYPE_VNODE: 947 fvp = (struct vnode *)fp->f_data; 948 949 /* Don't show directories */ 950 if (fvp->v_type == VDIR) 951 goto symlink; 952 953 VREF(fvp); 954 FILE_UNUSE(fp, p); 955 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY | 956 (p == curproc ? LK_CANRECURSE : 0)); 957 *vpp = fvp; 958 error = 0; 959 break; 960 default: 961 symlink: 962 FILE_UNUSE(fp, p); 963 error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 964 PFSfd, fd); 965 break; 966 } 967 if ((error == 0) && (wantpunlock)) { 968 VOP_UNLOCK(dvp, 0); 969 cnp->cn_flags |= PDIRUNLOCK; 970 } 971 return error; 972 } 973 default: 974 return (ENOTDIR); 975 } 976 977 return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); 978 } 979 980 int 981 procfs_validfile(p, mp) 982 struct proc *p; 983 struct mount *mp; 984 { 985 return (p->p_textvp != NULL); 986 } 987 988 static int 989 procfs_validfile_linux(p, mp) 990 struct proc *p; 991 struct mount *mp; 992 { 993 int flags; 994 995 flags = VFSTOPROC(mp)->pmnt_flags; 996 return ((flags & PROCFSMNT_LINUXCOMPAT) && 997 (p == NULL || procfs_validfile(p, mp))); 998 } 999 1000 /* 1001 * readdir returns directory entries from pfsnode (vp). 1002 * 1003 * the strategy here with procfs is to generate a single 1004 * directory entry at a time (struct dirent) and then 1005 * copy that out to userland using uiomove. a more efficent 1006 * though more complex implementation, would try to minimize 1007 * the number of calls to uiomove(). for procfs, this is 1008 * hardly worth the added code complexity. 1009 * 1010 * this should just be done through read() 1011 */ 1012 int 1013 procfs_readdir(v) 1014 void *v; 1015 { 1016 struct vop_readdir_args /* { 1017 struct vnode *a_vp; 1018 struct uio *a_uio; 1019 struct ucred *a_cred; 1020 int *a_eofflag; 1021 off_t **a_cookies; 1022 int *a_ncookies; 1023 } */ *ap = v; 1024 struct uio *uio = ap->a_uio; 1025 struct dirent d; 1026 struct pfsnode *pfs; 1027 off_t i; 1028 int error; 1029 off_t *cookies = NULL; 1030 int ncookies, left, skip, j; 1031 struct vnode *vp; 1032 const struct proc_target *pt; 1033 1034 vp = ap->a_vp; 1035 pfs = VTOPFS(vp); 1036 1037 if (uio->uio_resid < UIO_MX) 1038 return (EINVAL); 1039 if (uio->uio_offset < 0) 1040 return (EINVAL); 1041 1042 error = 0; 1043 i = uio->uio_offset; 1044 memset(&d, 0, UIO_MX); 1045 d.d_reclen = UIO_MX; 1046 ncookies = uio->uio_resid / UIO_MX; 1047 1048 switch (pfs->pfs_type) { 1049 /* 1050 * this is for the process-specific sub-directories. 1051 * all that is needed to is copy out all the entries 1052 * from the procent[] table (top of this file). 1053 */ 1054 case PFSproc: { 1055 struct proc *p; 1056 1057 if (i >= nproc_targets) 1058 return 0; 1059 1060 p = PFIND(pfs->pfs_pid); 1061 if (p == NULL) 1062 break; 1063 1064 if (ap->a_ncookies) { 1065 ncookies = min(ncookies, (nproc_targets - i)); 1066 cookies = malloc(ncookies * sizeof (off_t), 1067 M_TEMP, M_WAITOK); 1068 *ap->a_cookies = cookies; 1069 } 1070 1071 for (pt = &proc_targets[i]; 1072 uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) { 1073 if (pt->pt_valid && 1074 (*pt->pt_valid)(p, vp->v_mount) == 0) 1075 continue; 1076 1077 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, 1078 pt->pt_pfstype, -1); 1079 d.d_namlen = pt->pt_namlen; 1080 memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1); 1081 d.d_type = pt->pt_type; 1082 1083 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1084 break; 1085 if (cookies) 1086 *cookies++ = i + 1; 1087 } 1088 1089 break; 1090 } 1091 case PFSfd: { 1092 struct proc *p; 1093 struct filedesc *fdp; 1094 struct file *fp; 1095 int lim, nc = 0; 1096 1097 p = PFIND(pfs->pfs_pid); 1098 if (p == NULL) 1099 return ESRCH; 1100 1101 fdp = p->p_fd; 1102 1103 lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); 1104 if (i >= lim) 1105 return 0; 1106 1107 if (ap->a_ncookies) { 1108 ncookies = min(ncookies, (fdp->fd_nfiles + 2 - i)); 1109 cookies = malloc(ncookies * sizeof (off_t), 1110 M_TEMP, M_WAITOK); 1111 *ap->a_cookies = cookies; 1112 } 1113 1114 for (; i < 2 && uio->uio_resid >= UIO_MX; i++) { 1115 pt = &proc_targets[i]; 1116 d.d_namlen = pt->pt_namlen; 1117 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, 1118 pt->pt_pfstype, -1); 1119 (void)memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1); 1120 d.d_type = pt->pt_type; 1121 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1122 break; 1123 if (cookies) 1124 *cookies++ = i + 1; 1125 nc++; 1126 } 1127 if (error) { 1128 ncookies = nc; 1129 break; 1130 } 1131 for (; uio->uio_resid >= UIO_MX && i < fdp->fd_nfiles; i++) { 1132 /* check the descriptor exists */ 1133 if ((fp = fd_getfile(fdp, i - 2)) == NULL) 1134 continue; 1135 simple_unlock(&fp->f_slock); 1136 1137 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, PFSfd, i - 2); 1138 d.d_namlen = snprintf(d.d_name, sizeof(d.d_name), 1139 "%lld", (long long)(i - 2)); 1140 d.d_type = VREG; 1141 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1142 break; 1143 if (cookies) 1144 *cookies++ = i + 1; 1145 nc++; 1146 } 1147 ncookies = nc; 1148 break; 1149 } 1150 1151 /* 1152 * this is for the root of the procfs filesystem 1153 * what is needed are special entries for "curproc" 1154 * and "self" followed by an entry for each process 1155 * on allproc 1156 #ifdef PROCFS_ZOMBIE 1157 * and deadproc and zombproc. 1158 #endif 1159 */ 1160 1161 case PFSroot: { 1162 int pcnt = i, nc = 0; 1163 const struct proclist_desc *pd; 1164 volatile struct proc *p; 1165 1166 if (pcnt > 3) 1167 pcnt = 3; 1168 if (ap->a_ncookies) { 1169 /* 1170 * XXX Potentially allocating too much space here, 1171 * but I'm lazy. This loop needs some work. 1172 */ 1173 cookies = malloc(ncookies * sizeof (off_t), 1174 M_TEMP, M_WAITOK); 1175 *ap->a_cookies = cookies; 1176 } 1177 /* 1178 * XXX: THIS LOOP ASSUMES THAT allproc IS THE FIRST 1179 * PROCLIST IN THE proclists! 1180 */ 1181 proclist_lock_read(); 1182 pd = proclists; 1183 #ifdef PROCFS_ZOMBIE 1184 again: 1185 #endif 1186 for (p = LIST_FIRST(pd->pd_list); 1187 p != NULL && uio->uio_resid >= UIO_MX; i++, pcnt++) { 1188 switch (i) { 1189 case 0: /* `.' */ 1190 case 1: /* `..' */ 1191 d.d_fileno = PROCFS_FILENO(0, PFSroot, -1); 1192 d.d_namlen = i + 1; 1193 memcpy(d.d_name, "..", d.d_namlen); 1194 d.d_name[i + 1] = '\0'; 1195 d.d_type = DT_DIR; 1196 break; 1197 1198 case 2: 1199 d.d_fileno = PROCFS_FILENO(0, PFScurproc, -1); 1200 d.d_namlen = sizeof("curproc") - 1; 1201 memcpy(d.d_name, "curproc", sizeof("curproc")); 1202 d.d_type = DT_LNK; 1203 break; 1204 1205 case 3: 1206 d.d_fileno = PROCFS_FILENO(0, PFSself, -1); 1207 d.d_namlen = sizeof("self") - 1; 1208 memcpy(d.d_name, "self", sizeof("self")); 1209 d.d_type = DT_LNK; 1210 break; 1211 1212 default: 1213 while (pcnt < i) { 1214 pcnt++; 1215 p = LIST_NEXT(p, p_list); 1216 if (!p) 1217 goto done; 1218 } 1219 d.d_fileno = PROCFS_FILENO(p->p_pid, PFSproc, -1); 1220 d.d_namlen = snprintf(d.d_name, 1221 sizeof(d.d_name), "%ld", (long)p->p_pid); 1222 d.d_type = DT_DIR; 1223 p = p->p_list.le_next; 1224 break; 1225 } 1226 1227 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1228 break; 1229 nc++; 1230 if (cookies) 1231 *cookies++ = i + 1; 1232 } 1233 done: 1234 1235 #ifdef PROCFS_ZOMBIE 1236 pd++; 1237 if (p == NULL && pd->pd_list != NULL) 1238 goto again; 1239 #endif 1240 proclist_unlock_read(); 1241 1242 skip = i - pcnt; 1243 if (skip >= nproc_root_targets) 1244 break; 1245 left = nproc_root_targets - skip; 1246 for (j = 0, pt = &proc_root_targets[0]; 1247 uio->uio_resid >= UIO_MX && j < left; 1248 pt++, j++, i++) { 1249 if (pt->pt_valid && 1250 (*pt->pt_valid)(NULL, vp->v_mount) == 0) 1251 continue; 1252 d.d_fileno = PROCFS_FILENO(0, pt->pt_pfstype, -1); 1253 d.d_namlen = pt->pt_namlen; 1254 memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1); 1255 d.d_type = pt->pt_type; 1256 1257 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1258 break; 1259 nc++; 1260 if (cookies) 1261 *cookies++ = i + 1; 1262 } 1263 1264 ncookies = nc; 1265 break; 1266 } 1267 1268 default: 1269 error = ENOTDIR; 1270 break; 1271 } 1272 1273 if (ap->a_ncookies) { 1274 if (error) { 1275 if (cookies) 1276 free(*ap->a_cookies, M_TEMP); 1277 *ap->a_ncookies = 0; 1278 *ap->a_cookies = NULL; 1279 } else 1280 *ap->a_ncookies = ncookies; 1281 } 1282 uio->uio_offset = i; 1283 return (error); 1284 } 1285 1286 /* 1287 * readlink reads the link of `curproc' 1288 */ 1289 int 1290 procfs_readlink(v) 1291 void *v; 1292 { 1293 struct vop_readlink_args *ap = v; 1294 char buf[16]; /* should be enough */ 1295 char *bp = buf; 1296 char *path = NULL; 1297 int len; 1298 int error = 0; 1299 struct pfsnode *pfs = VTOPFS(ap->a_vp); 1300 1301 if (pfs->pfs_fileno == PROCFS_FILENO(0, PFScurproc, -1)) 1302 len = snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid); 1303 else if (pfs->pfs_fileno == PROCFS_FILENO(0, PFSself, -1)) 1304 len = snprintf(buf, sizeof(buf), "%s", "curproc"); 1305 else { 1306 struct file *fp; 1307 struct proc *pown; 1308 struct vnode *vxp, *vp; 1309 1310 if ((error = procfs_getfp(pfs, &pown, &fp)) != 0) 1311 return error; 1312 FILE_USE(fp); 1313 switch (fp->f_type) { 1314 case DTYPE_VNODE: 1315 vxp = (struct vnode *)fp->f_data; 1316 if (vxp->v_type != VDIR) { 1317 FILE_UNUSE(fp, pown); 1318 return EINVAL; 1319 } 1320 if ((path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK)) 1321 == NULL) { 1322 FILE_UNUSE(fp, pown); 1323 return ENOMEM; 1324 } 1325 bp = path + MAXPATHLEN; 1326 *--bp = '\0'; 1327 vp = curproc->p_cwdi->cwdi_rdir; 1328 if (vp == NULL) 1329 vp = rootvnode; 1330 error = getcwd_common(vxp, vp, &bp, path, 1331 MAXPATHLEN / 2, 0, curproc); 1332 FILE_UNUSE(fp, pown); 1333 if (error) { 1334 free(path, M_TEMP); 1335 return error; 1336 } 1337 len = strlen(bp); 1338 break; 1339 1340 case DTYPE_MISC: 1341 len = snprintf(buf, sizeof(buf), "%s", "[misc]"); 1342 break; 1343 1344 case DTYPE_KQUEUE: 1345 len = snprintf(buf, sizeof(buf), "%s", "[kqueue]"); 1346 break; 1347 1348 default: 1349 return EINVAL; 1350 } 1351 } 1352 1353 error = uiomove(bp, len, ap->a_uio); 1354 if (path) 1355 free(path, M_TEMP); 1356 return error; 1357 } 1358 1359 /* 1360 * convert decimal ascii to int 1361 */ 1362 static int 1363 atoi(b, len) 1364 const char *b; 1365 size_t len; 1366 { 1367 int p = 0; 1368 1369 while (len--) { 1370 char c = *b++; 1371 if (c < '0' || c > '9') 1372 return -1; 1373 p = 10 * p + (c - '0'); 1374 } 1375 1376 return p; 1377 } 1378