kern/148646: Implementation of the "environ" file for the linprocfs
Fernando
fernando.apesteguia at gmail.com
Thu Jul 15 16:50:05 UTC 2010
>Number: 148646
>Category: kern
>Synopsis: Implementation of the "environ" file for the linprocfs
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Thu Jul 15 16:50:04 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator: Fernando
>Release: 8.0-RELEASE-p2
>Organization:
Open Sistemas
>Environment:
FreeBSD beastie 8.0-RELEASE-p2 FreeBSD 8.0-RELEASE-p2 #4: Thu Mar 4 19:31:02 CET 2010 root at beastie:/usr/obj/usr/src/sys/APEKERNEL amd64
>Description:
The current version of linprocfs returns the string "doprocenviron".
The patch attached below tries to implement the "environ" file that can be found under /proc/<PID>/ in a Linux procfs. The patch tries to be consistent with lib/libkvm/kvm_proc.c
It was tested on a 8.0-RELEASE-p2 amd64 and on a 8.0-RELEASE i386 running on qemu.
>How-To-Repeat:
Just cat /compat/linux/proc/<PID>/environ
>Fix:
The attached patch could be an initial solution.
Patch attached with submission follows:
--- /sys/compat/linprocfs/linprocfs.c 2010-07-14 17:56:23.000000000 +0200
+++ linprocfs.c 2010-07-14 17:42:04.000000000 +0200
@@ -933,15 +933,130 @@
return (0);
}
+extern int proc_rwmem(struct proc *p, struct uio *uio);
+
+#define MAX_ARGV_STR 512 /* Max number of argv-like strings */
+#define UIO_CHUNK_SZ 256 /* Max chunk size (bytes) for uiomove */
+
+static int
+linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb,
+ void (*resolver)(const struct ps_strings *, u_long *, int *))
+{
+ int ret, i, n_elements;
+ char *buff;
+ char* env_vector[MAX_ARGV_STR];
+ char env_string[UIO_CHUNK_SZ];
+ u_long addr;
+ struct iovec iov;
+ struct uio tmp_uio;
+ struct ps_strings *pss;
+
+ buff = malloc(sizeof(struct ps_strings), M_TEMP, M_WAITOK);
+
+
+#define UIO_HELPER(uio, iov, base, len, iovcnt, \
+ offset, resid, segflg, rw, td) do { \
+ iov.iov_base = (caddr_t) base; \
+ iov.iov_len = len; \
+ uio.uio_iov = &iov; \
+ uio.uio_iovcnt = iovcnt; \
+ uio.uio_offset = (off_t) offset;\
+ uio.uio_resid = resid; \
+ uio.uio_segflg = segflg; \
+ uio.uio_rw = rw; \
+ uio.uio_td = td; \
+} while (0)
+
+ PROC_LOCK(p);
+
+ UIO_HELPER(tmp_uio, iov, buff, sizeof(struct ps_strings),
+ 1, (off_t)(p->p_sysent->sv_psstrings),
+ sizeof(struct ps_strings), UIO_SYSSPACE, UIO_READ, td);
+ ret = proc_rwmem(p, &tmp_uio);
+ if (ret != 0)
+ return ret;
+
+ pss = (struct ps_strings *)(buff);
+
+ resolver(pss, &addr, &n_elements);
+
+ /* Consistent with lib/libkvm/kvm_proc.c */
+ if (n_elements > MAX_ARGV_STR ||
+ (u_long)addr < VM_MIN_ADDRESS ||
+ (u_long)addr >= VM_MAXUSER_ADDRESS) {
+ PROC_UNLOCK(p);
+ /* What error code should we return? */
+ return 0;
+ }
+
+ UIO_HELPER(tmp_uio, iov, env_vector, MAX_ARGV_STR, 1,
+ (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
+ ret = proc_rwmem(p, &tmp_uio);
+ if (ret != 0)
+ return ret;
+
+ /* Now we can iterate through the list of strings */
+ int found_end = 0;
+ char *pbegin;
+ for (i = 0; i < n_elements; i++) {
+ found_end = 0;
+ pbegin = env_vector[i];
+ while(!found_end) {
+ UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
+ 1, (vm_offset_t) pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
+ ret = proc_rwmem(p, &tmp_uio);
+ if (ret != 0)
+ return ret;
+
+ if (!strvalid(env_string, UIO_CHUNK_SZ)) {
+ /*
+ * We didn't find the end of the string
+ * Add the string to the buffer and move
+ * the pointer
+ */
+ sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
+ pbegin = &(*pbegin) + UIO_CHUNK_SZ;
+ } else {
+ found_end = 1;
+ }
+ }
+ sbuf_printf(sb, "%s", env_string);
+ }
+
+ PROC_UNLOCK(p);
+#undef UIO_HELPER
+
+
+ free(buff, M_TEMP);
+
+ return (0);
+}
+
+static void
+ps_string_env(const struct ps_strings *ps, u_long *addr, int *n)
+{
+
+ *addr = (u_long) ps->ps_envstr;
+ *n = ps->ps_nenvstr;
+}
+
/*
* Filler function for proc/pid/environ
*/
static int
linprocfs_doprocenviron(PFS_FILL_ARGS)
{
+ int ret;
- sbuf_printf(sb, "doprocenviron\n%c", '\0');
- return (0);
+ PROC_LOCK(p);
+ if ((ret = p_cansee(td, p)) != 0) {
+ PROC_UNLOCK(p);
+ return ret;
+ }
+
+
+ PROC_UNLOCK(p);
+ return (linprocfs_doargv(td, p, sb, ps_string_env));
}
/*
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list