blob: e86d162e041e3b2eb914c69442042e296f36520a [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "partition_alloc/partition_alloc_base/mac/mac_util.h"
#include <stddef.h>
#include <string.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include "partition_alloc/partition_alloc_base/check.h"
#include "partition_alloc/partition_alloc_base/logging.h"
// This is a simplified version of base::mac. Because
// "base/strings/string_split.h" is unavailable, only provide access to the
// macOS major version number via direct string work on the Darwin version.
namespace partition_alloc::internal::base::mac {
namespace {
// Returns the running system's Darwin major version. Don't call this, it's an
// implementation detail and its result is meant to be cached by
// MacOSMajorVersion().
int DarwinMajorVersion() {
// base::OperatingSystemVersionNumbers() at one time called Gestalt(), which
// was observed to be able to spawn threads (see https://crbug.com/53200).
// Nowadays that function calls -[NSProcessInfo operatingSystemVersion], whose
// current implementation does things like hit the file system, which is
// possibly a blocking operation. Either way, it's overkill for what needs to
// be done here.
//
// uname, on the other hand, is implemented as a simple series of sysctl
// system calls to obtain the relevant data from the kernel. The data is
// compiled right into the kernel, so no threads or blocking or other
// funny business is necessary.
struct utsname uname_info;
if (uname(&uname_info) != 0) {
PA_DPLOG(ERROR) << "uname";
return 0;
}
if (strcmp(uname_info.sysname, "Darwin") != 0) {
PA_DLOG(ERROR) << "unexpected uname sysname " << uname_info.sysname;
return 0;
}
const char* dot = strchr(uname_info.release, '.');
if (!dot || uname_info.release == dot ||
// Darwin version should be 1 or 2 digits, it's unlikely to be more than
// 4 digits.
dot - uname_info.release > 4) {
PA_DLOG(ERROR) << "could not parse uname release " << uname_info.release;
return 0;
}
int darwin_major_version = 0;
constexpr int base = 10;
for (const char* p = uname_info.release; p < dot; ++p) {
if (!('0' <= *p && *p < '0' + base)) {
PA_DLOG(ERROR) << "could not parse uname release " << uname_info.release;
return 0;
}
// Since we checked the number of digits is 4 at most (see above), there is
// no chance to overflow.
darwin_major_version *= base;
darwin_major_version += *p - '0';
}
return darwin_major_version;
}
} // namespace
int MacOSMajorVersion() {
static int macos_major_version = [] {
int darwin_major_version = DarwinMajorVersion();
// Darwin major versions 6 through 19 corresponded to macOS versions 10.2
// through 10.15.
PA_BASE_CHECK(darwin_major_version >= 6);
if (darwin_major_version <= 19) {
return 10;
}
// Darwin major version 20 corresponds to macOS version 11.0. Assume a
// correspondence between Darwin's major version numbers and macOS major
// version numbers.
return darwin_major_version - 9;
}();
return macos_major_version;
}
} // namespace partition_alloc::internal::base::mac