svn commit: r227839 - head/lib/libkvm

Mikolaj Golub trociny at FreeBSD.org
Tue Nov 22 21:12:29 UTC 2011


Author: trociny
Date: Tue Nov 22 21:12:28 2011
New Revision: 227839
URL: http://svn.freebsd.org/changeset/base/227839

Log:
  Now kvm_getenvv() and kvm_getargv() don't need procfs(5).
  
  MFC after:	2 weeks

Modified:
  head/lib/libkvm/kvm_getprocs.3
  head/lib/libkvm/kvm_proc.c

Modified: head/lib/libkvm/kvm_getprocs.3
==============================================================================
--- head/lib/libkvm/kvm_getprocs.3	Tue Nov 22 20:59:52 2011	(r227838)
+++ head/lib/libkvm/kvm_getprocs.3	Tue Nov 22 21:12:28 2011	(r227839)
@@ -32,7 +32,7 @@
 .\"     @(#)kvm_getprocs.3	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD$
 .\"
-.Dd September 27, 2003
+.Dd November 22, 2011
 .Dt KVM_GETPROCS 3
 .Os
 .Sh NAME
@@ -172,10 +172,3 @@ on failure.
 .Xr kvm_write 3
 .Sh BUGS
 These routines do not belong in the kvm interface.
-.Pp
-In order for
-.Xr kvm_getenvv 3
-to function correctly,
-.Xr procfs 5
-must be mounted on
-.Pa /proc .

Modified: head/lib/libkvm/kvm_proc.c
==============================================================================
--- head/lib/libkvm/kvm_proc.c	Tue Nov 22 20:59:52 2011	(r227838)
+++ head/lib/libkvm/kvm_proc.c	Tue Nov 22 21:12:28 2011	(r227839)
@@ -72,9 +72,6 @@ __FBSDID("$FreeBSD$");
 #include <nlist.h>
 #include <kvm.h>
 
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-
 #include <sys/sysctl.h>
 
 #include <limits.h>
@@ -623,276 +620,16 @@ _kvm_realloc(kvm_t *kd, void *p, size_t 
 	return (np);
 }
 
-#ifndef MAX
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#endif
-
 /*
- * Read in an argument vector from the user address space of process kp.
- * addr if the user-space base address of narg null-terminated contiguous
- * strings.  This is used to read in both the command arguments and
- * environment strings.  Read at most maxcnt characters of strings.
+ * Get the command args or environment.
  */
 static char **
-kvm_argv(kvm_t *kd, const struct kinfo_proc *kp, u_long addr, int narg,
-    int maxcnt)
-{
-	char *np, *cp, *ep, *ap;
-	u_long oaddr = -1;
-	int len, cc;
-	char **argv;
-
-	/*
-	 * Check that there aren't an unreasonable number of arguments,
-	 * and that the address is in user space.  Special test for
-	 * VM_MIN_ADDRESS as it evaluates to zero, but is not a simple zero
-	 * constant for some archs.  We cannot use the pre-processor here and
-	 * for some archs the compiler would trigger a signedness warning.
-	 */
-	if (narg > 512 || addr + 1 < VM_MIN_ADDRESS + 1 || addr >= VM_MAXUSER_ADDRESS)
-		return (0);
-
-	/*
-	 * kd->argv : work space for fetching the strings from the target 
-	 *            process's space, and is converted for returning to caller
-	 */
-	if (kd->argv == 0) {
-		/*
-		 * Try to avoid reallocs.
-		 */
-		kd->argc = MAX(narg + 1, 32);
-		kd->argv = (char **)_kvm_malloc(kd, kd->argc *
-						sizeof(*kd->argv));
-		if (kd->argv == 0)
-			return (0);
-	} else if (narg + 1 > kd->argc) {
-		kd->argc = MAX(2 * kd->argc, narg + 1);
-		kd->argv = (char **)_kvm_realloc(kd, kd->argv, kd->argc *
-						sizeof(*kd->argv));
-		if (kd->argv == 0)
-			return (0);
-	}
-	/*
-	 * kd->argspc : returned to user, this is where the kd->argv
-	 *              arrays are left pointing to the collected strings.
-	 */
-	if (kd->argspc == 0) {
-		kd->argspc = (char *)_kvm_malloc(kd, PAGE_SIZE);
-		if (kd->argspc == 0)
-			return (0);
-		kd->arglen = PAGE_SIZE;
-	}
-	/*
-	 * kd->argbuf : used to pull in pages from the target process.
-	 *              the strings are copied out of here.
-	 */
-	if (kd->argbuf == 0) {
-		kd->argbuf = (char *)_kvm_malloc(kd, PAGE_SIZE);
-		if (kd->argbuf == 0)
-			return (0);
-	}
-
-	/* Pull in the target process'es argv vector */
-	cc = sizeof(char *) * narg;
-	if (kvm_uread(kd, kp, addr, (char *)kd->argv, cc) != cc)
-		return (0);
-	/*
-	 * ap : saved start address of string we're working on in kd->argspc
-	 * np : pointer to next place to write in kd->argspc
-	 * len: length of data in kd->argspc
-	 * argv: pointer to the argv vector that we are hunting around the
-	 *       target process space for, and converting to addresses in
-	 *       our address space (kd->argspc).
-	 */
-	ap = np = kd->argspc;
-	argv = kd->argv;
-	len = 0;
-	/*
-	 * Loop over pages, filling in the argument vector.
-	 * Note that the argv strings could be pointing *anywhere* in
-	 * the user address space and are no longer contiguous.
-	 * Note that *argv is modified when we are going to fetch a string
-	 * that crosses a page boundary.  We copy the next part of the string
-	 * into to "np" and eventually convert the pointer.
-	 */
-	while (argv < kd->argv + narg && *argv != 0) {
-
-		/* get the address that the current argv string is on */
-		addr = (u_long)*argv & ~(PAGE_SIZE - 1);
-
-		/* is it the same page as the last one? */
-		if (addr != oaddr) {
-			if (kvm_uread(kd, kp, addr, kd->argbuf, PAGE_SIZE) !=
-			    PAGE_SIZE)
-				return (0);
-			oaddr = addr;
-		}
-
-		/* offset within the page... kd->argbuf */
-		addr = (u_long)*argv & (PAGE_SIZE - 1);
-
-		/* cp = start of string, cc = count of chars in this chunk */
-		cp = kd->argbuf + addr;
-		cc = PAGE_SIZE - addr;
-
-		/* dont get more than asked for by user process */
-		if (maxcnt > 0 && cc > maxcnt - len)
-			cc = maxcnt - len;
-
-		/* pointer to end of string if we found it in this page */
-		ep = memchr(cp, '\0', cc);
-		if (ep != 0)
-			cc = ep - cp + 1;
-		/*
-		 * at this point, cc is the count of the chars that we are
-		 * going to retrieve this time. we may or may not have found
-		 * the end of it.  (ep points to the null if the end is known)
-		 */
-
-		/* will we exceed the malloc/realloced buffer? */
-		if (len + cc > kd->arglen) {
-			int off;
-			char **pp;
-			char *op = kd->argspc;
-
-			kd->arglen *= 2;
-			kd->argspc = (char *)_kvm_realloc(kd, kd->argspc,
-							  kd->arglen);
-			if (kd->argspc == 0)
-				return (0);
-			/*
-			 * Adjust argv pointers in case realloc moved
-			 * the string space.
-			 */
-			off = kd->argspc - op;
-			for (pp = kd->argv; pp < argv; pp++)
-				*pp += off;
-			ap += off;
-			np += off;
-		}
-		/* np = where to put the next part of the string in kd->argspc*/
-		/* np is kinda redundant.. could use "kd->argspc + len" */
-		memcpy(np, cp, cc);
-		np += cc;	/* inc counters */
-		len += cc;
-
-		/*
-		 * if end of string found, set the *argv pointer to the
-		 * saved beginning of string, and advance. argv points to
-		 * somewhere in kd->argv..  This is initially relative
-		 * to the target process, but when we close it off, we set
-		 * it to point in our address space.
-		 */
-		if (ep != 0) {
-			*argv++ = ap;
-			ap = np;
-		} else {
-			/* update the address relative to the target process */
-			*argv += cc;
-		}
-
-		if (maxcnt > 0 && len >= maxcnt) {
-			/*
-			 * We're stopping prematurely.  Terminate the
-			 * current string.
-			 */
-			if (ep == 0) {
-				*np = '\0';
-				*argv++ = ap;
-			}
-			break;
-		}
-	}
-	/* Make sure argv is terminated. */
-	*argv = 0;
-	return (kd->argv);
-}
-
-static void
-ps_str_a(struct ps_strings *p, u_long *addr, int *n)
-{
-	*addr = (u_long)p->ps_argvstr;
-	*n = p->ps_nargvstr;
-}
-
-static void
-ps_str_e (struct ps_strings *p, u_long *addr, int *n)
-{
-	*addr = (u_long)p->ps_envstr;
-	*n = p->ps_nenvstr;
-}
-
-/*
- * Determine if the proc indicated by p is still active.
- * This test is not 100% foolproof in theory, but chances of
- * being wrong are very low.
- */
-static int
-proc_verify(const struct kinfo_proc *curkp)
-{
-	struct kinfo_proc newkp;
-	int mib[4];
-	size_t len;
-
-	mib[0] = CTL_KERN;
-	mib[1] = KERN_PROC;
-	mib[2] = KERN_PROC_PID;
-	mib[3] = curkp->ki_pid;
-	len = sizeof(newkp);
-	if (sysctl(mib, 4, &newkp, &len, NULL, 0) == -1)
-		return (0);
-	return (curkp->ki_pid == newkp.ki_pid &&
-	    (newkp.ki_stat != SZOMB || curkp->ki_stat == SZOMB));
-}
-
-static char **
-kvm_doargv(kvm_t *kd, const struct kinfo_proc *kp, int nchr,
-    void (*info)(struct ps_strings *, u_long *, int *))
-{
-	char **ap;
-	u_long addr;
-	int cnt;
-	static struct ps_strings arginfo;
-	static u_long ps_strings;
-	size_t len;
-
-	if (ps_strings == 0) {
-		len = sizeof(ps_strings);
-		if (sysctlbyname("kern.ps_strings", &ps_strings, &len, NULL,
-		    0) == -1)
-			ps_strings = PS_STRINGS;
-	}
-
-	/*
-	 * Pointers are stored at the top of the user stack.
-	 */
-	if (kp->ki_stat == SZOMB ||
-	    kvm_uread(kd, kp, ps_strings, (char *)&arginfo,
-		      sizeof(arginfo)) != sizeof(arginfo))
-		return (0);
-
-	(*info)(&arginfo, &addr, &cnt);
-	if (cnt == 0)
-		return (0);
-	ap = kvm_argv(kd, kp, addr, cnt, nchr);
-	/*
-	 * For live kernels, make sure this process didn't go away.
-	 */
-	if (ap != 0 && ISALIVE(kd) && !proc_verify(kp))
-		ap = 0;
-	return (ap);
-}
-
-/*
- * Get the command args.  This code is now machine independent.
- */
-char **
-kvm_getargv(kvm_t *kd, const struct kinfo_proc *kp, int nchr)
+kvm_argv(kvm_t *kd, const struct kinfo_proc *kp, int env, int nchr)
 {
 	int oid[4];
 	int i;
 	size_t bufsz;
-	static unsigned long buflen;
+	static int buflen;
 	static char *buf, *p;
 	static char **bufp;
 	static int argc;
@@ -903,24 +640,28 @@ kvm_getargv(kvm_t *kd, const struct kinf
 		return (0);
 	}
 
-	if (!buflen) {
-		bufsz = sizeof(buflen);
-		i = sysctlbyname("kern.ps_arg_cache_limit", 
-		    &buflen, &bufsz, NULL, 0);
-		if (i == -1) {
-			buflen = 0;
-		} else {
-			buf = malloc(buflen);
-			if (buf == NULL)
-				buflen = 0;
-			argc = 32;
-			bufp = malloc(sizeof(char *) * argc);
+	if (nchr == 0 || nchr > ARG_MAX)
+		nchr = ARG_MAX;
+	if (buflen == 0) {
+		buf = malloc(nchr);
+		if (buf == NULL) {
+			_kvm_err(kd, kd->program, "cannot allocate memory");
+			return (0);
+		}
+		buflen = nchr;
+		argc = 32;
+		bufp = malloc(sizeof(char *) * argc);
+	} else if (nchr > buflen) {
+		p = realloc(buf, nchr);
+		if (p != NULL) {
+			buf = p;
+			buflen = nchr;
 		}
 	}
 	if (buf != NULL) {
 		oid[0] = CTL_KERN;
 		oid[1] = KERN_PROC;
-		oid[2] = KERN_PROC_ARGS;
+		oid[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS;
 		oid[3] = kp->ki_pid;
 		bufsz = buflen;
 		i = sysctl(oid, 4, buf, &bufsz, 0, 0);
@@ -940,65 +681,17 @@ kvm_getargv(kvm_t *kd, const struct kinf
 			return (bufp);
 		}
 	}
-	if (kp->ki_flag & P_SYSTEM)
-		return (NULL);
-	return (kvm_doargv(kd, kp, nchr, ps_str_a));
+	return (NULL);
 }
 
 char **
-kvm_getenvv(kvm_t *kd, const struct kinfo_proc *kp, int nchr)
+kvm_getargv(kvm_t *kd, const struct kinfo_proc *kp, int nchr)
 {
-	return (kvm_doargv(kd, kp, nchr, ps_str_e));
+	return (kvm_argv(kd, kp, 0, nchr));
 }
 
-/*
- * Read from user space.  The user context is given by p.
- */
-ssize_t
-kvm_uread(kvm_t *kd, const struct kinfo_proc *kp, u_long uva, char *buf,
-	size_t len)
+char **
+kvm_getenvv(kvm_t *kd, const struct kinfo_proc *kp, int nchr)
 {
-	char *cp;
-	char procfile[MAXPATHLEN];
-	ssize_t amount;
-	int fd;
-
-	if (!ISALIVE(kd)) {
-		_kvm_err(kd, kd->program,
-		    "cannot read user space from dead kernel");
-		return (0);
-	}
-
-	sprintf(procfile, "/proc/%d/mem", kp->ki_pid);
-	fd = open(procfile, O_RDONLY, 0);
-	if (fd < 0) {
-		_kvm_err(kd, kd->program, "cannot open %s", procfile);
-		return (0);
-	}
-
-	cp = buf;
-	while (len > 0) {
-		errno = 0;
-		if (lseek(fd, (off_t)uva, 0) == -1 && errno != 0) {
-			_kvm_err(kd, kd->program, "invalid address (%lx) in %s",
-			    uva, procfile);
-			break;
-		}
-		amount = read(fd, cp, len);
-		if (amount < 0) {
-			_kvm_syserr(kd, kd->program, "error reading %s",
-			    procfile);
-			break;
-		}
-		if (amount == 0) {
-			_kvm_err(kd, kd->program, "EOF reading %s", procfile);
-			break;
-		}
-		cp += amount;
-		uva += amount;
-		len -= amount;
-	}
-
-	close(fd);
-	return ((ssize_t)(cp - buf));
+	return (kvm_argv(kd, kp, 1, nchr));
 }


More information about the svn-src-head mailing list