OLD | NEW |
(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/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 "base/logging.h" |
| 18 #include "chromecast/base/path_utils.h" |
| 19 |
| 20 namespace chromecast { |
| 21 |
| 22 namespace { |
| 23 |
| 24 const mode_t kDirMode = 0770; |
| 25 const mode_t kFileMode = 0660; |
| 26 |
| 27 } // namespace |
| 28 |
| 29 MinidumpManager::MinidumpManager() : nonblocking_(false), lockfile_fd_(-1) { |
| 30 dump_path_ = GetHomePathASCII("minidumps").value(); |
| 31 lockfile_path_ = dump_path_ + "/" + "lockfile"; |
| 32 } |
| 33 |
| 34 MinidumpManager::~MinidumpManager() { |
| 35 // Release the lock if held. |
| 36 ReleaseLockFile(); |
| 37 } |
| 38 |
| 39 int MinidumpManager::GetNumDumps(bool delete_all_dumps) { |
| 40 DIR* dirp; |
| 41 struct dirent* dptr; |
| 42 int num_dumps = 0; |
| 43 |
| 44 // folder does not exist |
| 45 dirp = opendir(dump_path_.c_str()); |
| 46 if (dirp == NULL) { |
| 47 LOG(ERROR) << "Unable to open directory " << dump_path_; |
| 48 return 0; |
| 49 } |
| 50 |
| 51 while ((dptr = readdir(dirp)) != NULL) { |
| 52 struct stat buf; |
| 53 const std::string file_fullname = dump_path_ + "/" + dptr->d_name; |
| 54 if (lstat(file_fullname.c_str(), &buf) == -1 || !S_ISREG(buf.st_mode)) { |
| 55 // if we cannot lstat this file, it is probably bad, so skip |
| 56 // if the file is not regular, skip |
| 57 continue; |
| 58 } |
| 59 // 'lockfile' is not counted |
| 60 if (lockfile_path_ != file_fullname) { |
| 61 ++num_dumps; |
| 62 if (delete_all_dumps) { |
| 63 LOG(INFO) << "Removing " << dptr->d_name |
| 64 << "which was not in the lockfile"; |
| 65 if (remove(file_fullname.c_str()) < 0) { |
| 66 LOG(INFO) << "remove failed. error " << strerror(errno); |
| 67 } |
| 68 } |
| 69 } |
| 70 } |
| 71 |
| 72 closedir(dirp); |
| 73 return num_dumps; |
| 74 } |
| 75 |
| 76 int MinidumpManager::DoWorkLocked() { |
| 77 int success = -1; |
| 78 if (AcquireLockFile() >= 0) { |
| 79 success = DoWork(); |
| 80 ReleaseLockFile(); |
| 81 } |
| 82 return success; |
| 83 } |
| 84 |
| 85 int MinidumpManager::AcquireLockFile() { |
| 86 // make the directory for the minidumps if it does not exist |
| 87 if (mkdir(dump_path_.c_str(), kDirMode) < 0 && errno != EEXIST) { |
| 88 LOG(ERROR) << "mkdir for " << dump_path_.c_str() |
| 89 << " failed. error = " << strerror(errno); |
| 90 return -1; |
| 91 } |
| 92 |
| 93 lockfile_fd_ = open(lockfile_path_.c_str(), O_RDWR | O_CREAT, kFileMode); |
| 94 |
| 95 // if opening or creating the lockfile failed, we don't want to proceed |
| 96 // with dump writing for fear of exhausting up system resources. |
| 97 if (lockfile_fd_ < 0) { |
| 98 LOG(ERROR) << "open lockfile failed " << lockfile_path_; |
| 99 return -1; |
| 100 } |
| 101 |
| 102 // acquire the lock on the file. Whether or not we are in non-blocking mode, |
| 103 // flock failure means that we did not acquire it and this method should fail. |
| 104 int operation_mode = nonblocking_ ? (LOCK_EX | LOCK_NB) : LOCK_EX; |
| 105 if (flock(lockfile_fd_, operation_mode) < 0) { |
| 106 ReleaseLockFile(); |
| 107 LOG(INFO) << "flock lockfile failed, error = " << strerror(errno); |
| 108 return -1; |
| 109 } |
| 110 |
| 111 return 0; |
| 112 } |
| 113 |
| 114 void MinidumpManager::ReleaseLockFile() { |
| 115 // flock is associated with the fd entry in the open fd table, so closing |
| 116 // all fd's will release the lock. To be safe, we explicitly unlock. |
| 117 if (lockfile_fd_ >= 0) { |
| 118 flock(lockfile_fd_, LOCK_UN); |
| 119 close(lockfile_fd_); |
| 120 // We may use this object again, so we should reset this. |
| 121 lockfile_fd_ = -1; |
| 122 } |
| 123 } |
| 124 |
| 125 } // namespace chromecast |
OLD | NEW |