// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "file_utils.h" #include <ctype.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> namespace { bool IsNumeric(const char* str) { if (!str[0]) return false; for (const char* c = str; *c; c++) { if (!isdigit(*c)) return false; } return true; } } // namespace namespace file_utils { void ForEachPidInProcPath(const char* proc_path, std::function<void(int)> predicate) { DIR* root_dir = opendir(proc_path); ScopedDir autoclose(root_dir); struct dirent* child_dir; while ((child_dir = readdir(root_dir))) { if (child_dir->d_type != DT_DIR || !IsNumeric(child_dir->d_name)) continue; predicate(atoi(child_dir->d_name)); } } ssize_t ReadFile(const char* path, char* buf, size_t length) { buf[0] = '\0'; int fd = open(path, O_RDONLY); if (fd < 0 && errno == ENOENT) return -1; ScopedFD autoclose(fd); size_t tot_read = 0; do { ssize_t rsize = read(fd, buf + tot_read, length - tot_read); if (rsize == 0) break; if (rsize == -1 && errno == EINTR) continue; else if (rsize < 0) return -1; tot_read += static_cast<size_t>(rsize); } while (tot_read < length); buf[tot_read < length ? tot_read : length - 1] = '\0'; return tot_read; } bool ReadFileTrimmed(const char* path, char* buf, size_t length) { ssize_t rsize = ReadFile(path, buf, length); if (rsize < 0) return false; for (ssize_t i = 0; i < rsize; i++) { const char c = buf[i]; if (c == '\0' || c == '\r' || c == '\n') { buf[i] = '\0'; break; } buf[i] = isprint(c) ? c : '?'; } return true; } ssize_t ReadProcFile(int pid, const char* proc_file, char* buf, size_t length) { char proc_path[128]; snprintf(proc_path, sizeof(proc_path), "/proc/%d/%s", pid, proc_file); return ReadFile(proc_path, buf, length); } // Reads a single-line proc file, stripping out any \0, \r, \n and replacing // non-printable charcters with '?'. bool ReadProcFileTrimmed(int pid, const char* proc_file, char* buf, size_t length) { char proc_path[128]; snprintf(proc_path, sizeof(proc_path), "/proc/%d/%s", pid, proc_file); return ReadFileTrimmed(proc_path, buf, length); } LineReader::LineReader(char* buf, size_t size) : ptr_(buf), end_(buf + size) { } LineReader::~LineReader() { } const char* LineReader::NextLine() { if (ptr_ >= end_) return nullptr; const char* cur = ptr_; char* next = strchr(ptr_, '\n'); if (next) { *next = '\0'; ptr_ = next + 1; } else { ptr_ = end_; } return cur; } } // namespace file_utils