kmod_module: extended information gathering.

provide means to get:
 * refcount
 * initstate
 * holders
 * sections

this can be used to individually query properties from modules,
similar to /proc/modules (kmod_loaded / kmod_loaded_module).
diff --git a/libkmod/libkmod-util.c b/libkmod/libkmod-util.c
index b6e3cfc..e506b52 100644
--- a/libkmod/libkmod-util.c
+++ b/libkmod/libkmod-util.c
@@ -143,3 +143,64 @@
 
 	return memcpy(r, p, n);
 }
+
+ssize_t read_str_safe(int fd, char *buf, size_t buflen) {
+	size_t todo = buflen;
+	size_t done;
+	do {
+		ssize_t r = read(fd, buf, todo);
+		if (r == 0)
+			break;
+		else if (r > 0)
+			todo -= r;
+		else {
+			if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				errno == EINTR)
+				continue;
+			else
+				return -errno;
+		}
+	} while (todo > 0);
+	done = buflen - todo;
+	if (done == 0)
+		buf[0] = '\0';
+	else {
+		if (done < buflen)
+			buf[done] = '\0';
+		else if (buf[done - 1] != '\0')
+			return -ENOSPC;
+	}
+	return done;
+}
+
+int read_str_long(int fd, long *value, int base) {
+	char buf[32], *end;
+	long v;
+	int err;
+	*value = 0;
+	err = read_str_safe(fd, buf, sizeof(buf));
+	if (err < 0)
+		return err;
+	errno = 0;
+	v = strtol(buf, &end, base);
+	if (end == buf || !isspace(*end))
+		return -EINVAL;
+	*value = v;
+	return 0;
+}
+
+int read_str_ulong(int fd, unsigned long *value, int base) {
+	char buf[32], *end;
+	long v;
+	int err;
+	*value = 0;
+	err = read_str_safe(fd, buf, sizeof(buf));
+	if (err < 0)
+		return err;
+	errno = 0;
+	v = strtoul(buf, &end, base);
+	if (end == buf || !isspace(*end))
+		return -EINVAL;
+	*value = v;
+	return 0;
+}