1 /* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <sys/types.h> 12 #include <dirent.h> 13 #include <errno.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include "webrtc/base/linuxfdwalk.h" 18 19 // Parses a file descriptor number in base 10, requiring the strict format used 20 // in /proc/*/fd. Returns the value, or -1 if not a valid string. 21 static int parse_fd(const char *s) { 22 if (!*s) { 23 // Empty string is invalid. 24 return -1; 25 } 26 int val = 0; 27 do { 28 if (*s < '0' || *s > '9') { 29 // Non-numeric characters anywhere are invalid. 30 return -1; 31 } 32 int digit = *s++ - '0'; 33 val = val * 10 + digit; 34 } while (*s); 35 return val; 36 } 37 38 int fdwalk(void (*func)(void *, int), void *opaque) { 39 DIR *dir = opendir("/proc/self/fd"); 40 if (!dir) { 41 return -1; 42 } 43 int opendirfd = dirfd(dir); 44 int parse_errors = 0; 45 struct dirent *ent; 46 // Have to clear errno to distinguish readdir() completion from failure. 47 while (errno = 0, (ent = readdir(dir)) != NULL) { 48 if (strcmp(ent->d_name, ".") == 0 || 49 strcmp(ent->d_name, "..") == 0) { 50 continue; 51 } 52 // We avoid atoi or strtol because those are part of libc and they involve 53 // locale stuff, which is probably not safe from a post-fork context in a 54 // multi-threaded app. 55 int fd = parse_fd(ent->d_name); 56 if (fd < 0) { 57 parse_errors = 1; 58 continue; 59 } 60 if (fd != opendirfd) { 61 (*func)(opaque, fd); 62 } 63 } 64 int saved_errno = errno; 65 if (closedir(dir) < 0) { 66 if (!saved_errno) { 67 // Return the closedir error. 68 return -1; 69 } 70 // Else ignore it because we have a more relevant error to return. 71 } 72 if (saved_errno) { 73 errno = saved_errno; 74 return -1; 75 } else if (parse_errors) { 76 errno = EBADF; 77 return -1; 78 } else { 79 return 0; 80 } 81 } 82