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
IsNumeric(const char * str)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
ForEachPidInProcPath(const char * proc_path,std::function<void (int)> predicate)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
ReadFile(const char * path,char * buf,size_t length)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
ReadFileTrimmed(const char * path,char * buf,size_t length)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
ReadProcFile(int pid,const char * proc_file,char * buf,size_t length)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 '?'.
ReadProcFileTrimmed(int pid,const char * proc_file,char * buf,size_t length)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
LineReader(char * buf,size_t size)96 LineReader::LineReader(char* buf, size_t size)
97 : ptr_(buf), end_(buf + size) {
98 }
99
~LineReader()100 LineReader::~LineReader() {
101 }
102
NextLine()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