1e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "util.h"
2e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "debugfs.h"
3e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "cache.h"
4e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
5e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic int debugfs_premounted;
6e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic char debugfs_mountpoint[MAX_PATH+1];
7e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
8e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic const char *debugfs_known_mountpoints[] = {
9e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	"/sys/kernel/debug/",
10e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	"/debug/",
11e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	0,
12e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng};
13e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
14e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng/* use this to force a umount */
15e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengvoid debugfs_force_cleanup(void)
16e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
17e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	debugfs_find_mountpoint();
18e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	debugfs_premounted = 0;
19e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	debugfs_umount();
20e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
21e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
22e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng/* construct a full path to a debugfs element */
23e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint debugfs_make_path(const char *element, char *buffer, int size)
24e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
25e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int len;
26e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
27e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (strlen(debugfs_mountpoint) == 0) {
28e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		buffer[0] = '\0';
29e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -1;
30e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
31e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
32e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	len = strlen(debugfs_mountpoint) + strlen(element) + 1;
33e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (len >= size)
34e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return len+1;
35e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
36e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
37e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
38e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
39e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
40e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic int debugfs_found;
41e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
42e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng/* find the path to the mounted debugfs */
43e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengconst char *debugfs_find_mountpoint(void)
44e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
45e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	const char **ptr;
46e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char type[100];
47e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	FILE *fp;
48e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
49e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (debugfs_found)
50e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return (const char *) debugfs_mountpoint;
51e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
52e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	ptr = debugfs_known_mountpoints;
53e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	while (*ptr) {
54e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (debugfs_valid_mountpoint(*ptr) == 0) {
55e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			debugfs_found = 1;
56e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			strcpy(debugfs_mountpoint, *ptr);
57e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			return debugfs_mountpoint;
58e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
59e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		ptr++;
60e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
61e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
62e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* give up and parse /proc/mounts */
63e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	fp = fopen("/proc/mounts", "r");
64e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (fp == NULL)
65e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		die("Can't open /proc/mounts for read");
66e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
67e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	while (fscanf(fp, "%*s %"
68e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		      STR(MAX_PATH)
69e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		      "s %99s %*s %*d %*d\n",
70e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		      debugfs_mountpoint, type) == 2) {
71e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (strcmp(type, "debugfs") == 0)
72e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			break;
73e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
74e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	fclose(fp);
75e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
76e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (strcmp(type, "debugfs") != 0)
77e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return NULL;
78e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
79e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	debugfs_found = 1;
80e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
81e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return debugfs_mountpoint;
82e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
83e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
84e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng/* verify that a mountpoint is actually a debugfs instance */
85e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
86e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint debugfs_valid_mountpoint(const char *debugfs)
87e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
887d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng	/* ANDROID_CHANGE_BEGIN */
897d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#ifndef __APPLE__
90e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct statfs st_fs;
91e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
92e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (statfs(debugfs, &st_fs) < 0)
93e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -ENOENT;
94e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
95e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -ENOENT;
96e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
977d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#endif
987d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng	/* ANDROID_CHANGE_END */
99e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
100e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
101e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
102e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
103e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint debugfs_valid_entry(const char *path)
104e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
105e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct stat st;
106e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
107e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (stat(path, &st))
108e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -errno;
109e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
110e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
111e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
112e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
113e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng/* mount the debugfs somewhere if it's not mounted */
114e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
115e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengchar *debugfs_mount(const char *mountpoint)
116e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
1177d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng	/* ANDROID_CHANGE_BEGIN */
1187d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#ifndef __APPLE__
119e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* see if it's already mounted */
120e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (debugfs_find_mountpoint()) {
121e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		debugfs_premounted = 1;
122e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return debugfs_mountpoint;
123e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
124e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
125e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* if not mounted and no argument */
126e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (mountpoint == NULL) {
127e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/* see if environment variable set */
128e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
129e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/* if no environment variable, use default */
130e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (mountpoint == NULL)
131e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			mountpoint = "/sys/kernel/debug";
132e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
133e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
134e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
135e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return NULL;
136e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
137e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* save the mountpoint */
138e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
139e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	debugfs_found = 1;
140e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
141e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return debugfs_mountpoint;
1427d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#else
1437d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng	return "perfhost";
1447d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#endif
1457d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng	/* ANDROID_CHANGE_END */
146e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
147e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
148e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng/* umount the debugfs */
149e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
150e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint debugfs_umount(void)
151e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
152e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char umountcmd[128];
153e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int ret;
154e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
155e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* if it was already mounted, leave it */
156e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (debugfs_premounted)
157e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return 0;
158e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
159e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* make sure it's a valid mount point */
160e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	ret = debugfs_valid_mountpoint(debugfs_mountpoint);
161e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (ret)
162e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return ret;
163e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
164e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	snprintf(umountcmd, sizeof(umountcmd),
165e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 "/bin/umount %s", debugfs_mountpoint);
166e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return system(umountcmd);
167e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
168e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
169e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint debugfs_write(const char *entry, const char *value)
170e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
171e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char path[MAX_PATH+1];
172e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int ret, count;
173e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int fd;
174e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
175e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* construct the path */
176e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
177e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
178e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* verify that it exists */
179e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	ret = debugfs_valid_entry(path);
180e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (ret)
181e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return ret;
182e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
183e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* get how many chars we're going to write */
184e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	count = strlen(value);
185e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
186e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* open the debugfs entry */
187e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	fd = open(path, O_RDWR);
188e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (fd < 0)
189e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -errno;
190e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
191e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	while (count > 0) {
192e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/* write it */
193e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		ret = write(fd, value, count);
194e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (ret <= 0) {
195e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			if (ret == EAGAIN)
196e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				continue;
197e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			close(fd);
198e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			return -errno;
199e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
200e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		count -= ret;
201e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
202e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
203e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* close it */
204e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	close(fd);
205e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
206e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* return success */
207e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
208e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
209e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
210e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng/*
211e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng * read a debugfs entry
212e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng * returns the number of chars read or a negative errno
213e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng */
214e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint debugfs_read(const char *entry, char *buffer, size_t size)
215e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
216e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char path[MAX_PATH+1];
217e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int ret;
218e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int fd;
219e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
220e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* construct the path */
221e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
222e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
223e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* verify that it exists */
224e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	ret = debugfs_valid_entry(path);
225e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (ret)
226e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return ret;
227e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
228e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* open the debugfs entry */
229e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	fd = open(path, O_RDONLY);
230e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (fd < 0)
231e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -errno;
232e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
233e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	do {
234e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/* read it */
235e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		ret = read(fd, buffer, size);
236e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (ret == 0) {
237e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			close(fd);
238e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			return EOF;
239e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
240e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	} while (ret < 0 && errno == EAGAIN);
241e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
242e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* close it */
243e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	close(fd);
244e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
245e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* make *sure* there's a null character at the end */
246e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	buffer[ret] = '\0';
247e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
248e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/* return the number of chars read */
249e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return ret;
250e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
251