1// Copyright 2017 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "file_utils.h" 6 7#include <ctype.h> 8#include <errno.h> 9#include <fcntl.h> 10#include <stdio.h> 11#include <string.h> 12#include <sys/stat.h> 13#include <sys/types.h> 14 15namespace { 16 17bool IsNumeric(const char* str) { 18 if (!str[0]) 19 return false; 20 for (const char* c = str; *c; c++) { 21 if (!isdigit(*c)) 22 return false; 23 } 24 return true; 25} 26 27} // namespace 28 29namespace file_utils { 30 31void ForEachPidInProcPath(const char* proc_path, 32 std::function<void(int)> predicate) { 33 DIR* root_dir = opendir(proc_path); 34 ScopedDir autoclose(root_dir); 35 struct dirent* child_dir; 36 while ((child_dir = readdir(root_dir))) { 37 if (child_dir->d_type != DT_DIR || !IsNumeric(child_dir->d_name)) 38 continue; 39 predicate(atoi(child_dir->d_name)); 40 } 41} 42 43ssize_t ReadFile(const char* path, char* buf, size_t length) { 44 buf[0] = '\0'; 45 int fd = open(path, O_RDONLY); 46 if (fd < 0 && errno == ENOENT) 47 return -1; 48 ScopedFD autoclose(fd); 49 size_t tot_read = 0; 50 do { 51 ssize_t rsize = read(fd, buf + tot_read, length - tot_read); 52 if (rsize == 0) 53 break; 54 if (rsize == -1 && errno == EINTR) 55 continue; 56 else if (rsize < 0) 57 return -1; 58 tot_read += static_cast<size_t>(rsize); 59 } while (tot_read < length); 60 buf[tot_read < length ? tot_read : length - 1] = '\0'; 61 return tot_read; 62} 63 64bool ReadFileTrimmed(const char* path, char* buf, size_t length) { 65 ssize_t rsize = ReadFile(path, buf, length); 66 if (rsize < 0) 67 return false; 68 for (ssize_t i = 0; i < rsize; i++) { 69 const char c = buf[i]; 70 if (c == '\0' || c == '\r' || c == '\n') { 71 buf[i] = '\0'; 72 break; 73 } 74 buf[i] = isprint(c) ? c : '?'; 75 } 76 return true; 77} 78 79ssize_t ReadProcFile(int pid, const char* proc_file, char* buf, size_t length) { 80 char proc_path[128]; 81 snprintf(proc_path, sizeof(proc_path), "/proc/%d/%s", pid, proc_file); 82 return ReadFile(proc_path, buf, length); 83} 84 85// Reads a single-line proc file, stripping out any \0, \r, \n and replacing 86// non-printable charcters with '?'. 87bool ReadProcFileTrimmed(int pid, 88 const char* proc_file, 89 char* buf, 90 size_t length) { 91 char proc_path[128]; 92 snprintf(proc_path, sizeof(proc_path), "/proc/%d/%s", pid, proc_file); 93 return ReadFileTrimmed(proc_path, buf, length); 94} 95 96LineReader::LineReader(char* buf, size_t size) 97 : ptr_(buf), end_(buf + size) { 98} 99 100LineReader::~LineReader() { 101} 102 103const char* LineReader::NextLine() { 104 if (ptr_ >= end_) 105 return nullptr; 106 const char* cur = ptr_; 107 char* next = strchr(ptr_, '\n'); 108 if (next) { 109 *next = '\0'; 110 ptr_ = next + 1; 111 } else { 112 ptr_ = end_; 113 } 114 return cur; 115} 116 117} // namespace file_utils 118