147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <sys/types.h>
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <dirent.h>
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <errno.h>
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <stdlib.h>
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <string.h>
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/linuxfdwalk.h"
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Parses a file descriptor number in base 10, requiring the strict format used
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// in /proc/*/fd. Returns the value, or -1 if not a valid string.
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic int parse_fd(const char *s) {
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!*s) {
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Empty string is invalid.
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int val = 0;
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  do {
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (*s < '0' || *s > '9') {
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Non-numeric characters anywhere are invalid.
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return -1;
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    int digit = *s++ - '0';
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    val = val * 10 + digit;
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } while (*s);
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return val;
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint fdwalk(void (*func)(void *, int), void *opaque) {
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  DIR *dir = opendir("/proc/self/fd");
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!dir) {
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int opendirfd = dirfd(dir);
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int parse_errors = 0;
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  struct dirent *ent;
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Have to clear errno to distinguish readdir() completion from failure.
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  while (errno = 0, (ent = readdir(dir)) != NULL) {
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (strcmp(ent->d_name, ".") == 0 ||
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        strcmp(ent->d_name, "..") == 0) {
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      continue;
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // We avoid atoi or strtol because those are part of libc and they involve
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // locale stuff, which is probably not safe from a post-fork context in a
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // multi-threaded app.
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    int fd = parse_fd(ent->d_name);
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (fd < 0) {
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      parse_errors = 1;
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      continue;
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (fd != opendirfd) {
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      (*func)(opaque, fd);
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int saved_errno = errno;
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (closedir(dir) < 0) {
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!saved_errno) {
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Return the closedir error.
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return -1;
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Else ignore it because we have a more relevant error to return.
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (saved_errno) {
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    errno = saved_errno;
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else if (parse_errors) {
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    errno = EBADF;
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return 0;
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
82