int procfs_validfile_linux(struct proc *p, struct mount *mp) { int flags; flags = VFSTOPROC(mp)->pmnt_flags; return ((flags & PROCFSMNT_LINUXCOMPAT) && (p == NULL || procfs_validfile(p, mp))); }
/* ARGSUSED */ int procfs_mount( struct mount *mp, const char *path, void *data, size_t *data_len) { struct lwp *l = curlwp; struct procfsmount *pmnt; struct procfs_args *args = data; int error; if (args == NULL) return EINVAL; if (UIO_MX & (UIO_MX-1)) { log(LOG_ERR, "procfs: invalid directory entry size"); return (EINVAL); } if (mp->mnt_flag & MNT_GETARGS) { if (*data_len < sizeof *args) return EINVAL; pmnt = VFSTOPROC(mp); if (pmnt == NULL) return EIO; args->version = PROCFS_ARGSVERSION; args->flags = pmnt->pmnt_flags; *data_len = sizeof *args; return 0; } if (mp->mnt_flag & MNT_UPDATE) return (EOPNOTSUPP); if (*data_len >= sizeof *args && args->version != PROCFS_ARGSVERSION) return EINVAL; pmnt = kmem_zalloc(sizeof(struct procfsmount), KM_SLEEP); mp->mnt_stat.f_namemax = PROCFS_MAXNAMLEN; mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = pmnt; vfs_getnewfsid(mp); error = set_statvfs_info(path, UIO_USERSPACE, "procfs", UIO_SYSSPACE, mp->mnt_op->vfs_name, mp, l); pmnt->pmnt_exechook = exechook_establish(procfs_revoke_vnodes, mp); if (*data_len >= sizeof *args) pmnt->pmnt_flags = args->flags; else pmnt->pmnt_flags = 0; mp->mnt_iflag |= IMNT_MPSAFE; return error; }
/* * unmount system call */ int procfs_unmount(struct mount *mp, int mntflags) { int error; int flags = 0; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; if ((error = vflush(mp, 0, flags)) != 0) return (error); exechook_disestablish(VFSTOPROC(mp)->pmnt_exechook); kmem_free(mp->mnt_data, sizeof(struct procfsmount)); mp->mnt_data = NULL; return 0; }
/* * unmount system call */ int procfs_unmount(struct mount *mp, int mntflags, struct proc *p) { int error; extern int doforce; int flags = 0; if (mntflags & MNT_FORCE) { /* procfs can never be rootfs so don't check for it */ if (!doforce) return (EINVAL); flags |= FORCECLOSE; } if ((error = vflush(mp, 0, flags)) != 0) return (error); free(VFSTOPROC(mp), M_MISCFSMNT); mp->mnt_data = 0; return (0); }
/* * readdir returns directory entries from pfsnode (vp). * * the strategy here with procfs is to generate a single * directory entry at a time (struct dirent) and then * copy that out to userland using uiomove. a more efficent * though more complex implementation, would try to minimize * the number of calls to uiomove(). for procfs, this is * hardly worth the added code complexity. * * this should just be done through read() */ int procfs_readdir(void *v) { struct vop_readdir_args *ap = v; struct uio *uio = ap->a_uio; struct dirent d; struct pfsnode *pfs; struct vnode *vp; int i; int error; vp = ap->a_vp; pfs = VTOPFS(vp); if (uio->uio_resid < UIO_MX) return (EINVAL); error = 0; i = uio->uio_offset; if (i < 0) return (EINVAL); bzero(&d, UIO_MX); d.d_reclen = UIO_MX; switch (pfs->pfs_type) { /* * this is for the process-specific sub-directories. * all that is needed to is copy out all the entries * from the procent[] table (top of this file). */ case Pproc: { struct proc *p; const struct proc_target *pt; p = pfind(pfs->pfs_pid); if (p == NULL) break; for (pt = &proc_targets[i]; uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) { if (pt->pt_valid && (*pt->pt_valid)(p, vp->v_mount) == 0) continue; d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype); d.d_namlen = pt->pt_namlen; bcopy(pt->pt_name, d.d_name, pt->pt_namlen + 1); d.d_type = pt->pt_type; if ((error = uiomove(&d, UIO_MX, uio)) != 0) break; } break; } /* * this is for the root of the procfs filesystem * what is needed is a special entry for "curproc" * followed by an entry for each process on allproc #ifdef PROCFS_ZOMBIE * and zombproc. #endif */ case Proot: { #ifdef PROCFS_ZOMBIE int doingzomb = 0; #endif int pcnt = i; volatile struct proc *p = LIST_FIRST(&allproc); if (pcnt > 3) pcnt = 3; #ifdef PROCFS_ZOMBIE again: #endif for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) { switch (i) { case 0: /* `.' */ case 1: /* `..' */ d.d_fileno = PROCFS_FILENO(0, Proot); d.d_namlen = i + 1; bcopy("..", d.d_name, d.d_namlen); d.d_name[i + 1] = '\0'; d.d_type = DT_DIR; break; case 2: d.d_fileno = PROCFS_FILENO(0, Pcurproc); d.d_namlen = 7; bcopy("curproc", d.d_name, 8); d.d_type = DT_LNK; break; case 3: d.d_fileno = PROCFS_FILENO(0, Pself); d.d_namlen = 4; bcopy("self", d.d_name, 5); d.d_type = DT_LNK; break; case 4: if (VFSTOPROC(vp->v_mount)->pmnt_flags & PROCFSMNT_LINUXCOMPAT) { d.d_fileno = PROCFS_FILENO(0, Pcpuinfo); d.d_namlen = 7; bcopy("cpuinfo", d.d_name, 8); d.d_type = DT_REG; break; } /* fall through */ case 5: if (VFSTOPROC(vp->v_mount)->pmnt_flags & PROCFSMNT_LINUXCOMPAT) { d.d_fileno = PROCFS_FILENO(0, Pmeminfo); d.d_namlen = 7; bcopy("meminfo", d.d_name, 8); d.d_type = DT_REG; break; } /* fall through */ default: while (pcnt < i) { pcnt++; p = LIST_NEXT(p, p_list); if (!p) goto done; } d.d_fileno = PROCFS_FILENO(p->p_pid, Pproc); d.d_namlen = snprintf(d.d_name, sizeof(d.d_name), "%ld", (long)p->p_pid); d.d_type = DT_REG; p = LIST_NEXT(p, p_list); break; } if ((error = uiomove(&d, UIO_MX, uio)) != 0) break; } done: #ifdef PROCFS_ZOMBIE if (p == 0 && doingzomb == 0) { doingzomb = 1; p = LIST_FIRST(&zombproc); goto again; } #endif break; } default: error = ENOTDIR; break; } uio->uio_offset = i; return (error); }