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