>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     r...@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:
_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to