Skip to content

Commit

Permalink
Add sysctl utility functions to return strings
Browse files Browse the repository at this point in the history
This creates two sysctl utility functions to return C++ strings, and
modifies callers to use it.

Fixed: 1477725
Change-Id: I0bf200b12694c3604bc8c838ee20c11c218f1048
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4833071
Commit-Queue: Avi Drissman <avi@chromium.org>
Auto-Submit: Avi Drissman <avi@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1195389}
  • Loading branch information
Avi Drissman authored and Chromium LUCI CQ committed Sep 12, 2023
1 parent d1aaf8a commit 837d106
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 92 deletions.
10 changes: 10 additions & 0 deletions base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,13 @@ component("base") {
#"system/sys_info_openbsd.cc",
]

if (is_apple || current_os == "freebsd" || current_os == "openbsd") {
sources += [
"posix/sysctl.cc",
"posix/sysctl.h",
]
}

if (is_posix) {
sources += [
"debug/debugger_posix.cc",
Expand Down Expand Up @@ -3720,6 +3727,9 @@ test("base_unittests") {
sources += [ "debug/allocation_trace_unittest.cc" ]
}

if (is_apple || current_os == "freebsd" || current_os == "openbsd") {
sources += [ "posix/sysctl_unittest.cc" ]
}
if (is_apple) {
sources += [
"apple/backup_util_unittest.mm",
Expand Down
11 changes: 4 additions & 7 deletions base/base_paths_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "base/nix/xdg_util.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/posix/sysctl.h"
#include "base/process/process_metrics.h"
#include "build/build_config.h"

Expand All @@ -48,16 +49,12 @@ bool PathProviderPosix(int key, FilePath* result) {
return true;
#elif BUILDFLAG(IS_FREEBSD)
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
char bin_dir[PATH_MAX + 1];
size_t length = sizeof(bin_dir);
// Upon return, |length| is the number of bytes written to |bin_dir|
// including the string terminator.
int error = sysctl(name, 4, bin_dir, &length, NULL, 0);
if (error < 0 || length <= 1) {
absl::optional<std::string> bin_dir = StringSysctl(name, std::size(name));
if (!bin_dir.has_value() || bin_dir.value().length() <= 1) {
NOTREACHED() << "Unable to resolve path.";
return false;
}
*result = FilePath(FilePath::StringType(bin_dir, length - 1));
*result = FilePath(bin_dir.value());
return true;
#elif BUILDFLAG(IS_SOLARIS)
char bin_dir[PATH_MAX + 1];
Expand Down
8 changes: 2 additions & 6 deletions base/ios/device_util.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include "base/apple/scoped_cftyperef.h"
#include "base/check.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_util.h"
#include "base/posix/sysctl.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"

Expand Down Expand Up @@ -60,11 +60,7 @@
#if TARGET_OS_SIMULATOR
return getenv("SIMULATOR_MODEL_IDENTIFIER");
#elif TARGET_OS_IPHONE
std::string platform;
size_t size = 0;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
sysctlbyname("hw.machine", base::WriteInto(&platform, size), &size, NULL, 0);
return platform;
return base::StringSysctl({CTL_HW, HW_MACHINE}).value();
#endif
}

Expand Down
19 changes: 3 additions & 16 deletions base/mac/mac_util.mm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "base/logging.h"
#include "base/mac/scoped_aedesc.h"
#include "base/mac/scoped_ioobject.h"
#include "base/posix/sysctl.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
Expand Down Expand Up @@ -302,20 +303,6 @@ bool RemoveQuarantineAttribute(const FilePath& file_path) {

namespace {

std::string StringSysctlByName(const char* name) {
size_t buf_len;
int result = sysctlbyname(name, nullptr, &buf_len, nullptr, 0);
PCHECK(result == 0);
CHECK_GE(buf_len, 1u);

std::string value(buf_len - 1, '\0');
result = sysctlbyname(name, &value[0], &buf_len, nullptr, 0);
PCHECK(result == 0);
CHECK_EQ(value[buf_len - 1], '\0');

return value;
}

int ParseOSProductVersion(const std::string_view& version) {
int macos_version = 0;

Expand Down Expand Up @@ -373,8 +360,8 @@ int ParseOSProductVersionForTesting(const std::string_view& version) {
}

int MacOSVersion() {
static int macos_version =
ParseOSProductVersion(StringSysctlByName("kern.osproductversion"));
static int macos_version = ParseOSProductVersion(
StringSysctlByName("kern.osproductversion").value());

return macos_version;
}
Expand Down
60 changes: 60 additions & 0 deletions base/posix/sysctl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/posix/sysctl.h"

#include <sys/sysctl.h>

#include <initializer_list>
#include <string>

#include "base/check_op.h"
#include "base/functional/function_ref.h"
#include "base/numerics/safe_conversions.h"
#include "build/build_config.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

namespace {

absl::optional<std::string> StringSysctlImpl(
base::FunctionRef<int(char* /*out*/, size_t* /*out_len*/)> sysctl_func) {
size_t buf_len;
int result = sysctl_func(nullptr, &buf_len);
if (result < 0 || buf_len < 1) {
return absl::nullopt;
}

std::string value(buf_len - 1, '\0');
result = sysctl_func(&value[0], &buf_len);
if (result < 0) {
return absl::nullopt;
}
CHECK_LE(buf_len - 1, value.size());
CHECK_EQ(value[buf_len - 1], '\0');
value.resize(buf_len - 1);

return value;
}
} // namespace

namespace base {

absl::optional<std::string> StringSysctl(
const std::initializer_list<int>& mib) {
return StringSysctlImpl([mib](char* out, size_t* out_len) {
return sysctl(const_cast<int*>(std::data(mib)),
checked_cast<unsigned int>(std::size(mib)), out, out_len,
nullptr, 0);
});
}

#if !BUILDFLAG(IS_OPENBSD)
absl::optional<std::string> StringSysctlByName(const char* name) {
return StringSysctlImpl([name](char* out, size_t* out_len) {
return sysctlbyname(name, out, out_len, nullptr, 0);
});
}
#endif

} // namespace base
32 changes: 32 additions & 0 deletions base/posix/sysctl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_POSIX_SYSCTL_H_
#define BASE_POSIX_SYSCTL_H_

#include <initializer_list>
#include <string>

#include "base/base_export.h"
#include "build/build_config.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

// NB: While a BSD utility file, this lives in /base/posix/ for simplicity as
// there is no /base/bsd/.

namespace base {

// Returns the value returned by `sysctl` as a std::string, or nullopt on error.
BASE_EXPORT absl::optional<std::string> StringSysctl(
const std::initializer_list<int>& mib);

#if !BUILDFLAG(IS_OPENBSD)
// Returns the value returned by `sysctlbyname` as a std::string, or nullopt
// on error.
BASE_EXPORT absl::optional<std::string> StringSysctlByName(const char* name);
#endif

} // namespace base

#endif // BASE_POSIX_SYSCTL_H_
42 changes: 42 additions & 0 deletions base/posix/sysctl_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/posix/sysctl.h"

#include <sys/sysctl.h>

#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace base {

namespace {

using SysctlTest = testing::Test;

TEST(SysctlTest, MibSuccess) {
absl::optional<std::string> result1 = StringSysctl({CTL_HW, HW_MACHINE});
EXPECT_TRUE(result1);

#if !BUILDFLAG(IS_OPENBSD)
absl::optional<std::string> result2 = StringSysctlByName("hw.machine");
EXPECT_TRUE(result2);

EXPECT_EQ(result1, result2);
#endif
}

TEST(SysctlTest, MibFailure) {
absl::optional<std::string> result = StringSysctl({-1});
EXPECT_FALSE(result);

#if !BUILDFLAG(IS_OPENBSD)
result = StringSysctlByName("banananananananana");
EXPECT_FALSE(result);
#endif
}

} // namespace

} // namespace base
18 changes: 7 additions & 11 deletions base/process/process_handle_freebsd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#include <sys/user.h>
#include <unistd.h>

#include "base/files/file_path.h"
#include "base/posix/sysctl.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

namespace base {

ProcessId GetParentProcessId(ProcessHandle process) {
Expand All @@ -25,18 +29,10 @@ ProcessId GetParentProcessId(ProcessHandle process) {
}

FilePath GetProcessExecutablePath(ProcessHandle process) {
char pathname[PATH_MAX];
size_t length;
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, process };

length = sizeof(pathname);

if (sysctl(mib, std::size(mib), pathname, &length, NULL, 0) < 0 ||
length == 0) {
return FilePath();
}
absl::optional<std::string> pathname =
base::StringSysctl({CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, process});

return FilePath(std::string(pathname));
return FilePath(pathname.value_or(std::string{}));
}

} // namespace base
33 changes: 6 additions & 27 deletions base/system/sys_info_ios.mm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/posix/sysctl.h"
#include "base/process/process_metrics.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
Expand All @@ -23,23 +24,6 @@

namespace base {

namespace {

// Queries sysctlbyname() for the given key and returns the value from the
// system or the empty string on failure.
std::string GetSysctlValue(const char* key_name) {
char value[256];
size_t len = std::size(value);
if (sysctlbyname(key_name, &value, &len, nullptr, 0) == 0) {
DCHECK_GE(len, 1u);
DCHECK_EQ('\0', value[len - 1]);
return std::string(value, len - 1);
}
return std::string();
}

} // namespace

// static
std::string SysInfo::OperatingSystemName() {
static dispatch_once_t get_system_name_once;
Expand Down Expand Up @@ -96,14 +80,9 @@

// static
std::string SysInfo::GetIOSBuildNumber() {
int mib[2] = {CTL_KERN, KERN_OSVERSION};
unsigned int namelen = sizeof(mib) / sizeof(mib[0]);
size_t buffer_size = 0;
sysctl(mib, namelen, nullptr, &buffer_size, nullptr, 0);
char build_number[buffer_size];
int result = sysctl(mib, namelen, build_number, &buffer_size, nullptr, 0);
DCHECK(result == 0);
return build_number;
absl::optional<std::string> build_number =
StringSysctl({CTL_KERN, KERN_OSVERSION});
return build_number.value();
}

// static
Expand Down Expand Up @@ -133,7 +112,7 @@

// static
std::string SysInfo::CPUModelName() {
return GetSysctlValue("machdep.cpu.brand_string");
return StringSysctlByName("machdep.cpu.brand_string").value_or(std::string{});
}

// static
Expand All @@ -159,7 +138,7 @@
#else
// Note: This uses "hw.machine" instead of "hw.model" like the Mac code,
// because "hw.model" doesn't always return the right string on some devices.
return GetSysctlValue("hw.machine");
return StringSysctl({CTL_HW, HW_MACHINE}).value_or(std::string{});
#endif
}

Expand Down
Loading

0 comments on commit 837d106

Please sign in to comment.