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 15 namespace { 16 17 bool 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 29 namespace file_utils { 30 31 void 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 43 ssize_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 64 bool 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 79 ssize_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 '?'. 87 bool 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 96 LineReader::LineReader(char* buf, size_t size) 97 : ptr_(buf), end_(buf + size) { 98 } 99 100 LineReader::~LineReader() { 101 } 102 103 const 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