• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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