Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: chromecast/crash/linux/minidump_manager.cc

Issue 1154383006: Adding crash utilities to chromecast/crash. (Closed) Base URL: https://eureka-internal.googlesource.com/chromium/src@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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 "chromecast/crash/linux/minidump_manager.h"
6
7 #include <dirent.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <grp.h>
11 #include <string.h>
12 #include <sys/file.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include <fstream>
18
19 #include "base/logging.h"
20 #include "chromecast/base/path_utils.h"
21 #include "chromecast/crash/linux/dump_info.h"
22
23 namespace chromecast {
24
25 namespace {
26
27 const mode_t kDirMode = 0770;
28 const mode_t kFileMode = 0660;
29 const char kLockfileName[] = "lockfile";
30 const char kMinidumpsDir[] = "minidumps";
31
32 } // namespace
33
34 MinidumpManager::MinidumpManager() : nonblocking_(false), lockfile_fd_(-1) {
35 dump_path_ = GetHomePathASCII(kMinidumpsDir);
36 lockfile_path_ = dump_path_.Append(kLockfileName).value();
37 }
38
39 MinidumpManager::~MinidumpManager() {
40 // Release the lock if held.
41 ReleaseLockFile();
42 }
43
44 // TODO(slan): Move some of this pruning logic to ReleaseLockFile?
45 int MinidumpManager::GetNumDumps(bool delete_all_dumps) {
46 DIR* dirp;
47 struct dirent* dptr;
48 int num_dumps = 0;
49
50 // folder does not exist
51 dirp = opendir(dump_path_.value().c_str());
52 if (dirp == NULL) {
53 LOG(ERROR) << "Unable to open directory " << dump_path_.value();
54 return 0;
55 }
56
57 while ((dptr = readdir(dirp)) != NULL) {
58 struct stat buf;
59 const std::string file_fullname = dump_path_.value() + "/" + dptr->d_name;
60 if (lstat(file_fullname.c_str(), &buf) == -1 || !S_ISREG(buf.st_mode)) {
61 // if we cannot lstat this file, it is probably bad, so skip
62 // if the file is not regular, skip
63 continue;
64 }
65 // 'lockfile' is not counted
66 if (lockfile_path_ != file_fullname) {
67 ++num_dumps;
68 if (delete_all_dumps) {
69 LOG(INFO) << "Removing " << dptr->d_name
70 << "which was not in the lockfile";
71 if (remove(file_fullname.c_str()) < 0) {
72 LOG(INFO) << "remove failed. error " << strerror(errno);
73 }
74 }
75 }
76 }
77
78 closedir(dirp);
79 return num_dumps;
80 }
81
82 int MinidumpManager::DoWorkLocked() {
83 int success = -1;
84 if (AcquireLockFile() >= 0) {
85 success = DoWork();
86 ReleaseLockFile();
87 }
88 return success;
89 }
90
91 const ScopedVector<DumpInfo>& MinidumpManager::GetDumpMetadata() {
92 DCHECK_GE(lockfile_fd_, 0);
93 if (!dump_metadata_)
94 ParseLockFile();
95 return *dump_metadata_;
96 }
97
98 int MinidumpManager::AcquireLockFile() {
99 DCHECK_LT(lockfile_fd_, 0);
100 // Make the directory for the minidumps if it does not exist.
101 if (mkdir(dump_path_.value().c_str(), kDirMode) < 0 && errno != EEXIST) {
102 LOG(ERROR) << "mkdir for " << dump_path_.value().c_str()
103 << " failed. error = " << strerror(errno);
104 return -1;
105 }
106
107 // Open the lockfile. Create it if it does not exist.
108 lockfile_fd_ = open(lockfile_path_.c_str(), O_RDWR | O_CREAT, kFileMode);
109
110 // If opening or creating the lockfile failed, we don't want to proceed
111 // with dump writing for fear of exhausting up system resources.
112 if (lockfile_fd_ < 0) {
113 LOG(ERROR) << "open lockfile failed " << lockfile_path_;
114 return -1;
115 }
116
117 // Acquire the lock on the file. Whether or not we are in non-blocking mode,
118 // flock failure means that we did not acquire it and this method should fail.
119 int operation_mode = nonblocking_ ? (LOCK_EX | LOCK_NB) : LOCK_EX;
120 if (flock(lockfile_fd_, operation_mode) < 0) {
121 ReleaseLockFile();
122 LOG(INFO) << "flock lockfile failed, error = " << strerror(errno);
123 return -1;
124 }
125
126 // The lockfile is open and locked. Parse it to provide subclasses with a
127 // record of all the current dumps.
128 if (ParseLockFile() < 0) {
129 LOG(ERROR) << "Lockfile did not parse correctly. ";
130 return -1;
131 }
132
133 // We successfully have acquired the lock.
134 return 0;
135 }
136
137 int MinidumpManager::ParseLockFile() {
138 DCHECK_GE(lockfile_fd_, 0);
139 DCHECK(!dump_metadata_);
140
141 scoped_ptr<ScopedVector<DumpInfo> > dumps(new ScopedVector<DumpInfo>());
142 std::string entry;
143
144 // Instead of using |lockfile_fd_|, use <fstream> for readability.
145 std::ifstream in(lockfile_path_);
146 if (!in.is_open()) {
147 NOTREACHED();
148 LOG(ERROR) << lockfile_path_ << " could not be opened.";
149 return -1;
150 }
151
152 // Grab each entry.
153 while (std::getline(in, entry)) {
154 scoped_ptr<DumpInfo> info(new DumpInfo(entry));
155 if (info->valid() && info->crashed_process_dump().size() > 0) {
156 dumps->push_back(info.Pass());
157 } else {
158 LOG(WARNING) << "Entry is not valid: " << entry;
159 return -1;
160 }
161 }
162
163 dump_metadata_ = dumps.Pass();
164 return 0;
165 }
166
167 int MinidumpManager::AddEntryToLockFile(const DumpInfo& dump_info) {
168 DCHECK_LE(0, lockfile_fd_);
169
170 // Make sure dump_info is valid.
171 if (!dump_info.valid()) {
172 LOG(ERROR) << "Entry to be added is invalid";
173 return -1;
174 }
175
176 // Open the file.
177 std::ofstream out(lockfile_path_, std::ios::app);
178 if (!out.is_open()) {
179 NOTREACHED() << "Lockfile would not open.";
180 return -1;
181 }
182
183 // Write the string and close the file.
184 out << dump_info.entry();
185 out.close();
186 return 0;
187 }
188
189 int MinidumpManager::RemoveEntryFromLockFile(int index) {
190 const auto& entries = GetDumpMetadata();
191 if (index < 0 || static_cast<size_t>(index) >= entries.size())
192 return -1;
193
194 // Remove the entry and write all remaining entries to file.
195 dump_metadata_->erase(dump_metadata_->begin() + index);
196 std::ofstream out(lockfile_path_);
197 for (auto info : *dump_metadata_) {
198 out << info->entry();
199 }
200 out.close();
201 return 0;
202 }
203
204 void MinidumpManager::ReleaseLockFile() {
205 // flock is associated with the fd entry in the open fd table, so closing
206 // all fd's will release the lock. To be safe, we explicitly unlock.
207 if (lockfile_fd_ >= 0) {
208 flock(lockfile_fd_, LOCK_UN);
209 close(lockfile_fd_);
210
211 // We may use this object again, so we should reset this.
212 lockfile_fd_ = -1;
213 }
214
215 dump_metadata_.reset();
216 }
217
218 } // namespace chromecast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698