| // Copyright 2017 The Crashpad Authors. All rights reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "handler/mac/file_limit_annotation.h" | |
| #include <dirent.h> | |
| #include <errno.h> | |
| #include <string.h> | |
| #include <sys/resource.h> | |
| #include <sys/sysctl.h> | |
| #include <sys/types.h> | |
| #include <string> | |
| #include "base/format_macros.h" | |
| #include "base/stl_util.h" | |
| #include "base/strings/stringprintf.h" | |
| #include "client/crashpad_info.h" | |
| #include "client/simple_string_dictionary.h" | |
| #include "util/posix/scoped_dir.h" | |
| namespace crashpad { | |
| namespace { | |
| // rv is the return value from sysctl() or sysctlbyname(), and value and size | |
| // are the pointers passed as oldp and oldlenp. If sysctl() failed, the returned | |
| // string will be "E" followed by the error number. If there was a size | |
| // mismatch, the returned string will be "Z" followed by the size indicated by | |
| // sysctl(). Normally, a string representation of *value will be returned. | |
| std::string FormatFromSysctl(int rv, const int* value, const size_t* size) { | |
| if (rv != 0) { | |
| return base::StringPrintf("E%d", errno); | |
| } | |
| if (*size != sizeof(*value)) { | |
| return base::StringPrintf("Z%zu", *size); | |
| } | |
| return base::StringPrintf("%d", *value); | |
| } | |
| // Counts the number of open file descriptors in the process and returns it as a | |
| // string. This /dev/fd and the value returned will include the open file | |
| // descriptor for that directory. If opendir() fails, the returned string will | |
| // be "E" followed by the error number. If readdir() fails, it will be "R" | |
| // followed by the error number. | |
| std::string CountOpenFileDescriptors() { | |
| DIR* dir = opendir("/dev/fd"); | |
| if (!dir) { | |
| return base::StringPrintf("E%d", errno); | |
| } | |
| ScopedDIR dir_owner(dir); | |
| dirent* entry; | |
| int count = 0; | |
| while ((errno = 0, entry = readdir(dir)) != nullptr) { | |
| const char* entry_name = entry->d_name; | |
| if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) { | |
| continue; | |
| } | |
| ++count; | |
| } | |
| if (errno != 0) { | |
| return base::StringPrintf("R%d", errno); | |
| } | |
| return base::StringPrintf("%d", count); | |
| } | |
| // Returns a string for |limit|, or "inf" if |limit| is RLIM_INFINITY. | |
| std::string StringForRLim(rlim_t limit) { | |
| if (limit == RLIM_INFINITY) { | |
| return std::string("inf"); | |
| } | |
| return base::StringPrintf("%" PRIu64, limit); | |
| } | |
| } // namespace | |
| void RecordFileLimitAnnotation() { | |
| CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo(); | |
| SimpleStringDictionary* simple_annotations = | |
| crashpad_info->simple_annotations(); | |
| if (!simple_annotations) { | |
| simple_annotations = new SimpleStringDictionary(); | |
| crashpad_info->set_simple_annotations(simple_annotations); | |
| } | |
| int value; | |
| size_t size = sizeof(value); | |
| std::string num_files = FormatFromSysctl( | |
| sysctlbyname("kern.num_files", &value, &size, nullptr, 0), &value, &size); | |
| int mib[] = {CTL_KERN, KERN_MAXFILES}; | |
| size = sizeof(value); | |
| std::string max_files = FormatFromSysctl( | |
| sysctl(mib, base::size(mib), &value, &size, nullptr, 0), &value, &size); | |
| std::string open_files = CountOpenFileDescriptors(); | |
| rlimit limit; | |
| std::string nofile; | |
| if (getrlimit(RLIMIT_NOFILE, &limit) != 0) { | |
| nofile = base::StringPrintf("E%d,E%d", errno, errno); | |
| } else { | |
| nofile = | |
| StringForRLim(limit.rlim_cur) + "," + StringForRLim(limit.rlim_max); | |
| } | |
| std::string annotation = base::StringPrintf("%s,%s,%s,%s", | |
| num_files.c_str(), | |
| max_files.c_str(), | |
| open_files.c_str(), | |
| nofile.c_str()); | |
| simple_annotations->SetKeyValue("file-limits", annotation.c_str()); | |
| } | |
| } // namespace crashpad |