summaryrefslogtreecommitdiffstats
path: root/sys/compat/linprocfs/linprocfs_vnops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linprocfs/linprocfs_vnops.c')
-rw-r--r--sys/compat/linprocfs/linprocfs_vnops.c556
1 files changed, 168 insertions, 388 deletions
diff --git a/sys/compat/linprocfs/linprocfs_vnops.c b/sys/compat/linprocfs/linprocfs_vnops.c
index 722544a..506a6f6 100644
--- a/sys/compat/linprocfs/linprocfs_vnops.c
+++ b/sys/compat/linprocfs/linprocfs_vnops.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2001 Jonathan Lemon <jlemon@freebsd.org>
* Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
* Copyright (c) 1999 Pierre Beyssac
* Copyright (c) 1993, 1995 Jan-Simon Pendry
@@ -80,33 +81,59 @@ static int linprocfs_readdir __P((struct vop_readdir_args *));
static int linprocfs_readlink __P((struct vop_readlink_args *));
static int linprocfs_reclaim __P((struct vop_reclaim_args *));
static int linprocfs_setattr __P((struct vop_setattr_args *));
+static pid_t atopid __P((const char *, u_int));
-/*
- * This is a list of the valid names in the
- * process-specific sub-directories. It is
- * used in linprocfs_lookup and linprocfs_readdir
- */
-static struct proc_target {
- u_char pt_type;
- u_char pt_namlen;
- char *pt_name;
- pfstype pt_pfstype;
- int (*pt_valid) __P((struct proc *p));
-} proc_targets[] = {
-#define N(s) sizeof(s)-1, s
- /* name type validp */
- { DT_DIR, N("."), Pproc, NULL },
- { DT_DIR, N(".."), Proot, NULL },
- { DT_REG, N("cmdline"), Pcmdline, NULL },
- { DT_LNK, N("exe"), Pexe, NULL },
- { DT_REG, N("mem"), Pmem, NULL },
- { DT_REG, N("stat"), Pprocstat, NULL },
- { DT_REG, N("status"), Pprocstatus, NULL },
-#undef N
+#define N(s) s, sizeof(s)-1
+#define A(s) linprocfs_ ## s
+#define D(s) (node_action_t *)(s)
+
+struct node_data net_dir[] = {
+ { N("."), VDIR, 0555, 0, D(net_dir) },
+ { N(".."), VDIR, 0555, 0, D(root_dir) },
+ { N("dev"), VREG, 0444, 0, A(donetdev) },
+ { N(""), VNON, 0000, 0, NULL },
};
-static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
-static pid_t atopid __P((const char *, u_int));
+struct node_data proc_dir[] = {
+ { N("."), VDIR, 0555, PDEP, D(proc_dir) },
+ { N(".."), VDIR, 0555, 0, D(root_dir) },
+ { N("cmdline"), VREG, 0444, PDEP, procfs_docmdline },
+ { N("exe"), VLNK, 0444, PDEP, A(doexelink) },
+ { N("mem"), VREG, 0600, PDEP, procfs_domem },
+ { N("stat"), VREG, 0444, PDEP, A(doprocstat) },
+ { N("status"), VREG, 0444, PDEP, A(doprocstatus) },
+ { N(""), VNON, 0000, 0, NULL },
+};
+
+struct node_data root_dir[] = {
+ { N("."), VDIR, 0555, 0, D(root_dir) },
+ { N(".."), VDIR, 0555, 0, NULL },
+ { N("cmdline"), VREG, 0444, 0, A(docmdline) },
+ { N("cpuinfo"), VREG, 0444, 0, A(docpuinfo) },
+ { N("devices"), VREG, 0444, 0, A(dodevices) },
+ { N("meminfo"), VREG, 0444, 0, A(domeminfo) },
+ { N("net"), VDIR, 0555, 0, D(net_dir) },
+ { N("self"), VLNK, 0444, 0, A(doselflink) },
+ { N("stat"), VREG, 0444, 0, A(dostat) },
+ { N("uptime"), VREG, 0444, 0, A(douptime) },
+ { N("version"), VREG, 0444, 0, A(doversion) },
+ { N(""), VNON, 0000, 0, NULL },
+};
+
+#undef N
+#undef A
+
+static int vn2ft[] = {
+ DT_UNKNOWN, /* VNON */
+ DT_REG, /* VREG */
+ DT_DIR, /* VDIR */
+ DT_BLK, /* VBLK */
+ DT_CHR, /* VCHR */
+ DT_LNK, /* VLNK */
+ DT_SOCK, /* VSOCK */
+ DT_FIFO, /* VFIFO */
+ DT_UNKNOWN, /* VBAD */
+};
/*
* set things up for doing i/o on
@@ -129,32 +156,28 @@ linprocfs_open(ap)
} */ *ap;
{
struct pfsnode *pfs = VTOPFS(ap->a_vp);
- struct proc *p1, *p2;
+ struct node_data *nd = pfs->pfs_nd;
+ struct proc *p1, *p2 = NULL;
- p2 = PFIND(pfs->pfs_pid);
- if (p2 == NULL)
- return (ENOENT);
- if (pfs->pfs_pid && p_can(ap->a_p, p2, P_CAN_SEE, NULL))
- return (ENOENT);
+ if (nd->nd_flags & PDEP) {
+ p2 = PFIND(pfs->pfs_pid);
+ if (p2 == NULL)
+ return (ENOENT);
+ if (pfs->pfs_pid && p_can(ap->a_p, p2, P_CAN_SEE, NULL))
+ return (ENOENT);
+ }
- switch (pfs->pfs_type) {
- case Pmem:
+ if (nd->nd_action == procfs_domem) {
if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)))
return (EBUSY);
p1 = ap->a_p;
- if (p_can(p1, p2, P_CAN_DEBUG, NULL) &&
- !procfs_kmemaccess(p1))
+ if (p_can(p1, p2, P_CAN_DEBUG, NULL) && !procfs_kmemaccess(p1))
return (EPERM);
if (ap->a_mode & FWRITE)
pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
-
- return (0);
-
- default:
- break;
}
return (0);
@@ -179,8 +202,7 @@ linprocfs_close(ap)
struct pfsnode *pfs = VTOPFS(ap->a_vp);
struct proc *p;
- switch (pfs->pfs_type) {
- case Pmem:
+ if (pfs->pfs_nd->nd_action == procfs_domem) {
if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
pfs->pfs_flags &= ~(FWRITE|O_EXCL);
/*
@@ -192,7 +214,7 @@ linprocfs_close(ap)
* told to stop on an event, but then the requesting process
* has gone away or forgotten about it.
*/
- if ((ap->a_vp->v_usecount < 2) && (p = pfind(pfs->pfs_pid))) {
+ if ((ap->a_vp->v_usecount < 2) && (p = PFIND(pfs->pfs_pid))) {
PROC_LOCK(p);
if (!(p->p_pfsflags & PF_LINGER)) {
p->p_stops = 0;
@@ -202,9 +224,6 @@ linprocfs_close(ap)
} else
PROC_UNLOCK(p);
}
- break;
- default:
- break;
}
return (0);
@@ -226,7 +245,7 @@ linprocfs_ioctl(ap)
unsigned char flags;
p = ap->a_p;
- procp = pfind(pfs->pfs_pid);
+ procp = PFIND(pfs->pfs_pid);
if (procp == NULL)
return ENOTTY;
@@ -398,9 +417,10 @@ linprocfs_print(ap)
} */ *ap;
{
struct pfsnode *pfs = VTOPFS(ap->a_vp);
+ struct node_data *nd = pfs->pfs_nd;
- printf("tag VT_PROCFS, type %d, pid %ld, mode %x, flags %lx\n",
- pfs->pfs_type, (long)pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
+ printf("tag VT_PROCFS, name %s, pid %ld, mode %x, flags %lx\n",
+ nd->nd_name, (long)pfs->pfs_pid, nd->nd_mode, pfs->pfs_flags);
return (0);
}
@@ -433,21 +453,15 @@ linprocfs_getattr(ap)
} */ *ap;
{
struct pfsnode *pfs = VTOPFS(ap->a_vp);
+ struct node_data *nd = pfs->pfs_nd;
struct vattr *vap = ap->a_vap;
struct proc *procp;
- int error;
/*
* First make sure that the process and its credentials
* still exist.
*/
- switch (pfs->pfs_type) {
- case Proot:
- case Pself:
- procp = NULL;
- break;
-
- default:
+ if (nd->nd_flags & PDEP) {
procp = PFIND(pfs->pfs_pid);
if (procp == NULL)
return (ENOENT);
@@ -459,21 +473,22 @@ linprocfs_getattr(ap)
PROC_UNLOCK(procp);
if (p_can(ap->a_p, procp, P_CAN_SEE, NULL))
return (ENOENT);
+ } else {
+ procp = NULL;
}
- error = 0;
-
/* start by zeroing out the attributes */
VATTR_NULL(vap);
/* next do all the common fields */
vap->va_type = ap->a_vp->v_type;
- vap->va_mode = pfs->pfs_mode;
+ vap->va_mode = nd->nd_mode;
vap->va_fileid = pfs->pfs_fileno;
vap->va_flags = 0;
vap->va_blocksize = PAGE_SIZE;
vap->va_bytes = vap->va_size = 0;
vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
+ vap->va_nlink = 1;
/*
* Make all times be current TOD.
@@ -487,23 +502,6 @@ linprocfs_getattr(ap)
vap->va_atime = vap->va_mtime = vap->va_ctime;
/*
- * If the process has exercised some setuid or setgid
- * privilege, then rip away read/write permission so
- * that only root can gain access.
- */
- switch (pfs->pfs_type) {
- case Pmem:
- /* Retain group kmem readablity. */
- PROC_LOCK(procp);
- if (procp->p_flag & P_SUGID)
- vap->va_mode &= ~(VREAD|VWRITE);
- PROC_UNLOCK(procp);
- break;
- default:
- break;
- }
-
- /*
* now do the object specific fields
*
* The size could be set from struct reg, but it's hardly
@@ -512,91 +510,28 @@ linprocfs_getattr(ap)
* becomes important then this function should break out into
* a per-file stat function in the corresponding .c file.
*/
-
- vap->va_nlink = 1;
if (procp) {
PROC_LOCK(procp);
vap->va_uid = procp->p_ucred->cr_uid;
vap->va_gid = procp->p_ucred->cr_gid;
PROC_UNLOCK(procp);
- }
-
- switch (pfs->pfs_type) {
- case Proot:
- /*
- * Set nlink to 1 to tell fts(3) we don't actually know.
- */
- vap->va_nlink = 1;
- vap->va_uid = 0;
- vap->va_gid = 0;
- vap->va_size = vap->va_bytes = DEV_BSIZE;
- break;
-
- case Pself: {
- char buf[16]; /* should be enough */
+ } else {
vap->va_uid = 0;
vap->va_gid = 0;
- vap->va_size = vap->va_bytes =
- snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
- break;
}
- case Pproc:
- vap->va_nlink = nproc_targets;
- vap->va_size = vap->va_bytes = DEV_BSIZE;
- break;
-
- case Pexe: {
- char *fullpath, *freepath;
- error = textvp_fullpath(procp, &fullpath, &freepath);
- if (error == 0) {
- vap->va_size = strlen(fullpath);
- free(freepath, M_TEMP);
- } else {
- vap->va_size = sizeof("unknown") - 1;
- error = 0;
- }
- vap->va_bytes = vap->va_size;
- break;
- }
-
- case Pmeminfo:
- case Pcpuinfo:
- case Pstat:
- case Puptime:
- case Pversion:
- vap->va_bytes = vap->va_size = 0;
- vap->va_uid = 0;
- vap->va_gid = 0;
- break;
-
- case Pmem:
- /*
- * If we denied owner access earlier, then we have to
- * change the owner to root - otherwise 'ps' and friends
- * will break even though they are setgid kmem. *SIGH*
- */
+ /*
+ * If the process has exercised some setuid or setgid
+ * privilege, then change the owner to root.
+ */
+ if (nd->nd_action == procfs_domem) {
PROC_LOCK(procp);
if (procp->p_flag & P_SUGID)
vap->va_uid = 0;
- else
- vap->va_uid = procp->p_ucred->cr_uid;
PROC_UNLOCK(procp);
- vap->va_gid = KMEM_GROUP;
- break;
-
- case Pcmdline:
- case Pprocstat:
- case Pprocstatus:
- vap->va_bytes = vap->va_size = 0;
- /* uid, gid are already set */
- break;
-
- default:
- panic("linprocfs_getattr");
}
- return (error);
+ return (0);
}
static int
@@ -649,16 +584,7 @@ linprocfs_access(ap)
struct vattr vattr;
int error;
- switch (pfs->pfs_type) {
- case Proot:
- case Pself:
- case Pmeminfo:
- case Pcpuinfo:
- case Pstat:
- case Puptime:
- case Pversion:
- break;
- default:
+ if (pfs->pfs_nd->nd_flags & PDEP) {
procp = PFIND(pfs->pfs_pid);
if (procp == NULL)
return (ENOENT);
@@ -697,16 +623,15 @@ linprocfs_lookup(ap)
struct vnode **vpp = ap->a_vpp;
struct vnode *dvp = ap->a_dvp;
char *pname = cnp->cn_nameptr;
- struct proc_target *pt;
+ struct node_data *nd;
pid_t pid;
struct pfsnode *pfs;
struct proc *p;
- int i;
+ int error;
*vpp = NULL;
- if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME ||
- cnp->cn_nameiop == CREATE)
+ if (cnp->cn_nameiop != LOOKUP)
return (EROFS);
if (cnp->cn_namelen == 1 && *pname == '.') {
@@ -717,62 +642,46 @@ linprocfs_lookup(ap)
}
pfs = VTOPFS(dvp);
- switch (pfs->pfs_type) {
- case Proot:
- if (cnp->cn_flags & ISDOTDOT)
+ nd = pfs->pfs_nd;
+ if (nd->nd_type != VDIR)
+ return (ENOTDIR);
+
+ if (cnp->cn_flags & ISDOTDOT) {
+ if (nd == root_dir)
return (EIO);
+ nd = (struct node_data *)nd[1].nd_action;
+ return (linprocfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, nd));
+ }
+
+ /* generic lookup */
+ for (nd = pfs->pfs_nd; nd->nd_type != VNON; nd++) {
+ if (cnp->cn_namelen != nd->nd_namlen ||
+ memcmp(pname, nd->nd_name, nd->nd_namlen))
+ continue;
+ if (nd->nd_type == VDIR)
+ nd = (struct node_data *)nd->nd_action;
+ return (linprocfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, nd));
+ }
- if (CNEQ(cnp, "self", 4))
- return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pself));
- if (CNEQ(cnp, "meminfo", 7))
- return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pmeminfo));
- if (CNEQ(cnp, "cpuinfo", 7))
- return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pcpuinfo));
- if (CNEQ(cnp, "stat", 4))
- return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pstat));
- if (CNEQ(cnp, "uptime", 6))
- return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Puptime));
- if (CNEQ(cnp, "version", 7))
- return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pversion));
+ error = ENOENT;
+ /* directory specific lookups */
+ if (pfs->pfs_nd == root_dir) {
pid = atopid(pname, cnp->cn_namelen);
if (pid == NO_PID)
- break;
+ goto done;
p = PFIND(pid);
if (p == NULL)
- break;
+ goto done;
if (p_can(curp, p, P_CAN_SEE, NULL))
- break;
-
- return (linprocfs_allocvp(dvp->v_mount, vpp, pid, Pproc));
-
- case Pproc:
- if (cnp->cn_flags & ISDOTDOT)
- return (linprocfs_root(dvp->v_mount, vpp));
-
- p = PFIND(pfs->pfs_pid);
- if (p == NULL)
- break;
-
- for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
- if (cnp->cn_namelen == pt->pt_namlen &&
- bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
- (pt->pt_valid == NULL || (*pt->pt_valid)(p)))
- goto found;
- }
- break;
+ goto done;
- found:
- return (linprocfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
- pt->pt_pfstype));
-
- default:
- return (ENOTDIR);
+ error = linprocfs_allocvp(dvp->v_mount, vpp, pid, proc_dir);
}
-
- return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
+done:
+ return (error);
}
/*
@@ -807,16 +716,21 @@ linprocfs_readdir(ap)
struct dirent d;
struct dirent *dp = &d;
struct pfsnode *pfs;
- int count, error, i, off;
+ struct node_data *nd;
+ struct proc *p;
+ int i, start, copied, error, off;
static u_int delen;
if (!delen) {
-
d.d_namlen = PROCFS_NAMELEN;
delen = GENERIC_DIRSIZ(&d);
}
pfs = VTOPFS(ap->a_vp);
+ nd = pfs->pfs_nd;
+
+ if (nd->nd_type != VDIR)
+ return (ENOTDIR);
off = (int)uio->uio_offset;
if (off != uio->uio_offset || off < 0 ||
@@ -824,164 +738,65 @@ linprocfs_readdir(ap)
return (EINVAL);
error = 0;
- count = 0;
- i = off / delen;
-
- 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;
- struct proc_target *pt;
+ copied = 0;
+ start = off / delen;
+ if (nd->nd_flags & PDEP) {
p = PFIND(pfs->pfs_pid);
if (p == NULL)
- break;
+ goto done;
if (p_can(curproc, p, P_CAN_SEE, NULL))
- break;
-
- for (pt = &proc_targets[i];
- uio->uio_resid >= delen && i < nproc_targets; pt++, i++) {
- if (pt->pt_valid && (*pt->pt_valid)(p) == 0)
- continue;
-
- dp->d_reclen = delen;
- dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype);
- dp->d_namlen = pt->pt_namlen;
- bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1);
- dp->d_type = pt->pt_type;
-
- if ((error = uiomove((caddr_t)dp, delen, uio)) != 0)
- break;
- }
+ goto done;
+ }
- break;
- }
+ /*
+ * copy out static entries
+ */
+ for (i = 0; i < start && nd->nd_type != VNON; nd++, i++);
+ for (; uio->uio_resid >= delen && nd->nd_type != VNON; nd++, copied++) {
+
+ dp->d_reclen = delen;
+ dp->d_fileno = PROCFS_FILENO(nd, pfs->pfs_pid);
+ dp->d_namlen = nd->nd_namlen;
+ memcpy(dp->d_name, nd->nd_name, nd->nd_namlen + 1);
+ dp->d_type = vn2ft[nd->nd_type];
+
+ error = uiomove((caddr_t)dp, delen, uio);
+ if (error)
+ goto done;
+ }
/*
* this is for the root of the procfs filesystem
- * what is needed is a special entry for "self"
- * 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 = 0;
- struct proc *p;
-
+ if (pfs->pfs_nd == root_dir) {
ALLPROC_LOCK(AP_SHARED);
p = LIST_FIRST(&allproc);
- for (; p && uio->uio_resid >= delen; i++, pcnt++) {
- bzero((char *) dp, delen);
- dp->d_reclen = delen;
-
- switch (i) {
- case 0: /* `.' */
- case 1: /* `..' */
- dp->d_fileno = PROCFS_FILENO(0, Proot);
- dp->d_namlen = i + 1;
- bcopy("..", dp->d_name, dp->d_namlen);
- dp->d_name[i + 1] = '\0';
- dp->d_type = DT_DIR;
- break;
-
- case 2:
- dp->d_fileno = PROCFS_FILENO(0, Pself);
- dp->d_namlen = 4;
- bcopy("self", dp->d_name, 5);
- dp->d_type = DT_LNK;
- break;
-
- case 3:
- dp->d_fileno = PROCFS_FILENO(0, Pmeminfo);
- dp->d_namlen = 7;
- bcopy("meminfo", dp->d_name, 8);
- dp->d_type = DT_REG;
- break;
-
- case 4:
- dp->d_fileno = PROCFS_FILENO(0, Pcpuinfo);
- dp->d_namlen = 7;
- bcopy("cpuinfo", dp->d_name, 8);
- dp->d_type = DT_REG;
- break;
-
- case 5:
- dp->d_fileno = PROCFS_FILENO(0, Pstat);
- dp->d_namlen = 4;
- bcopy("stat", dp->d_name, 5);
- dp->d_type = DT_REG;
- break;
-
- case 6:
- dp->d_fileno = PROCFS_FILENO(0, Puptime);
- dp->d_namlen = 6;
- bcopy("uptime", dp->d_name, 7);
- dp->d_type = DT_REG;
- break;
-
- case 7:
- dp->d_fileno = PROCFS_FILENO(0, Pversion);
- dp->d_namlen = 7;
- bcopy("version", dp->d_name, 8);
- dp->d_type = DT_REG;
- break;
-
- default:
- while (pcnt < i) {
- p = LIST_NEXT(p, p_list);
- if (p == NULL)
- goto done;
- if (p_can(curproc, p, P_CAN_SEE, NULL))
- continue;
- pcnt++;
- }
- while (p_can(curproc, p, P_CAN_SEE, NULL)) {
- p = LIST_NEXT(p, p_list);
- if (p == NULL)
- goto done;
- }
- dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
- dp->d_namlen = sprintf(dp->d_name, "%ld",
- (long)p->p_pid);
- dp->d_type = DT_DIR;
- p = LIST_NEXT(p, p_list);
- break;
- }
+ i = (nd - pfs->pfs_nd) / sizeof(*nd);
- if ((error = uiomove((caddr_t)dp, delen, uio)) != 0)
- break;
+ while (p && i < start) {
+ if (p_can(curproc, p, P_CAN_SEE, NULL) == 0)
+ i++;
+ p = LIST_NEXT(p, p_list);
}
- done:
+ for (; p && uio->uio_resid >= delen; p = LIST_NEXT(p, p_list)) {
+ if (p_can(curproc, p, P_CAN_SEE, NULL))
+ continue;
+ dp->d_reclen = delen;
+ dp->d_fileno = PROCFS_FILENO(proc_dir, p->p_pid);
+ dp->d_namlen = sprintf(dp->d_name, "%ld",
+ (long)p->p_pid);
+ dp->d_type = DT_DIR;
-#ifdef PROCFS_ZOMBIE
- if (p == NULL && doingzomb == 0) {
- doingzomb = 1;
- p = LIST_FIRST(&zombproc);
- goto again;
+ error = uiomove((caddr_t)dp, delen, uio);
+ if (error)
+ break;
+ copied++;
}
-#endif
-
ALLPROC_LOCK(AP_RELEASE);
- break;
-
- }
-
- default:
- error = ENOTDIR;
- break;
}
-
- uio->uio_offset = i * delen;
-
+done:
+ uio->uio_offset += copied * delen;
return (error);
}
@@ -992,49 +807,14 @@ static int
linprocfs_readlink(ap)
struct vop_readlink_args *ap;
{
- char buf[16]; /* should be enough */
- struct proc *procp;
- struct vnode *vp = ap->a_vp;
- struct pfsnode *pfs = VTOPFS(vp);
- char *fullpath, *freepath;
- int error, len;
-
- switch (pfs->pfs_type) {
- case Pself:
- if (pfs->pfs_fileno != PROCFS_FILENO(0, Pself))
- return (EINVAL);
-
- len = snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
+ struct pfsnode *pfs = VTOPFS(ap->a_vp);
+ struct node_data *nd = pfs->pfs_nd;
- return (uiomove(buf, len, ap->a_uio));
- /*
- * There _should_ be no way for an entire process to disappear
- * from under us...
- */
- case Pexe:
- procp = PFIND(pfs->pfs_pid);
- if (procp != NULL)
- PROC_LOCK(procp);
- if (procp == NULL || procp->p_cred == NULL ||
- procp->p_ucred == NULL) {
- if (procp != NULL)
- PROC_UNLOCK(procp);
- printf("linprocfs_readlink: pid %d disappeared\n",
- pfs->pfs_pid);
- return (uiomove("unknown", sizeof("unknown") - 1,
- ap->a_uio));
- }
- PROC_UNLOCK(procp);
- error = textvp_fullpath(procp, &fullpath, &freepath);
- if (error != 0)
- return (uiomove("unknown", sizeof("unknown") - 1,
- ap->a_uio));
- error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
- free(freepath, M_TEMP);
- return (error);
- default:
+ /* sanity check */
+ if (nd->nd_type != VLNK)
return (EINVAL);
- }
+
+ return (nd->nd_action(NULL, NULL, pfs, ap->a_uio));
}
/*
OpenPOWER on IntegriCloud