debugd: Add dmesg tool to debugd

Add a new tool to debugd that will return the output of dmesg given some
options. Will be used to be able to call dmesg from crosh.

BUG=chromium:1154528
TEST=dbus-send --system --print-reply --dest=org.chromium.debugd
/org/chromium/debugd org.chromium.debugd.CallDmesg string:''

Change-Id: I098fd14f93752e1ecf11cf7d54171b385fb8b27e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2599603
Tested-by: Nicole Anderson-Au <nvaa@google.com>
Commit-Queue: Nicole Anderson-Au <nvaa@google.com>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
diff --git a/debugd/BUILD.gn b/debugd/BUILD.gn
index f94d49f..96d19f5 100644
--- a/debugd/BUILD.gn
+++ b/debugd/BUILD.gn
@@ -84,6 +84,7 @@
     "src/debugd_dbus_adaptor.cc",
     "src/dev_features_tool.cc",
     "src/dev_mode_no_owner_restriction.cc",
+    "src/dmesg_tool.cc",
     "src/ec_typec_tool.cc",
     "src/ectool_util.cc",
     "src/example_tool.cc",
diff --git a/debugd/dbus_bindings/org.chromium.debugd.xml b/debugd/dbus_bindings/org.chromium.debugd.xml
index 34799e5..ed4f034 100644
--- a/debugd/dbus_bindings/org.chromium.debugd.xml
+++ b/debugd/dbus_bindings/org.chromium.debugd.xml
@@ -1205,5 +1205,31 @@
       </arg>
       <annotation name="org.chromium.DBus.Method.Kind" value="simple"/>
     </method>
+    <method name="CallDmesg">
+      <tp:docstring>
+        Runs the command 'dmesg' with the given inputs.
+      </tp:docstring>
+      <arg name="options" type="a{sv}" direction="in">
+        <tp:docstring>
+          Options to pass to the dmesg command:
+          show-delta (bool): Display the timestamp and the time delta
+            spent between messages.
+          human (bool): Enable human-readable output.
+          kernel (bool): Print kernel messages.
+          force-prefix (bool): Add facility, level or timestamp
+            information to each line of a multi-line message.
+          raw (bool): Print the raw message buffer.
+          ctime (bool): Print human-readable timestamps.
+          notime (bool): Do not print kernel's timestamps.
+          userspace (bool): Print userspace messages.
+          decode (bool): Decode facility and level (priority) numbers
+            to human-readable prefixes.
+        </tp:docstring>
+      </arg>
+      <arg name="output" type="s" direction="out">
+        Returns the output of the 'dmesg' command.
+      </arg>
+      <annotation name="org.chromium.DBus.Method.Kind" value="normal"/>
+    </method>
   </interface>
 </node>
diff --git a/debugd/src/debugd_dbus_adaptor.cc b/debugd/src/debugd_dbus_adaptor.cc
index 5ef4558..c80986a 100644
--- a/debugd/src/debugd_dbus_adaptor.cc
+++ b/debugd/src/debugd_dbus_adaptor.cc
@@ -46,6 +46,7 @@
   debug_mode_tool_ = std::make_unique<DebugModeTool>(bus);
   dev_features_tool_wrapper_ =
       std::make_unique<RestrictedToolWrapper<DevFeaturesTool>>(bus);
+  dmesg_tool_ = std::make_unique<DmesgTool>();
   ec_typec_tool_ = std::make_unique<EcTypeCTool>();
   example_tool_ = std::make_unique<ExampleTool>();
   icmp_tool_ = std::make_unique<ICMPTool>();
@@ -610,4 +611,10 @@
   return ec_typec_tool_->GetInventory();
 }
 
+bool DebugdDBusAdaptor::CallDmesg(brillo::ErrorPtr* error,
+                                  const brillo::VariantDictionary& options,
+                                  std::string* output) {
+  return dmesg_tool_->CallDmesg(options, error, output);
+}
+
 }  // namespace debugd
diff --git a/debugd/src/debugd_dbus_adaptor.h b/debugd/src/debugd_dbus_adaptor.h
index 93a9f29..2456da0 100644
--- a/debugd/src/debugd_dbus_adaptor.h
+++ b/debugd/src/debugd_dbus_adaptor.h
@@ -29,6 +29,7 @@
 #include "debugd/src/debug_logs_tool.h"
 #include "debugd/src/debug_mode_tool.h"
 #include "debugd/src/dev_features_tool.h"
+#include "debugd/src/dmesg_tool.h"
 #include "debugd/src/ec_typec_tool.h"
 #include "debugd/src/example_tool.h"
 #include "debugd/src/icmp_tool.h"
@@ -217,6 +218,9 @@
                                  const std::string& metric_name,
                                  std::string* output) override;
   std::string EcGetInventory() override;
+  bool CallDmesg(brillo::ErrorPtr* error,
+                 const brillo::VariantDictionary& options,
+                 std::string* output) override;
 
  private:
   brillo::dbus_utils::DBusObject dbus_object_;
@@ -230,6 +234,7 @@
   std::unique_ptr<CupsTool> cups_tool_;
   std::unique_ptr<DebugLogsTool> debug_logs_tool_;
   std::unique_ptr<DebugModeTool> debug_mode_tool_;
+  std::unique_ptr<DmesgTool> dmesg_tool_;
   std::unique_ptr<RestrictedToolWrapper<DevFeaturesTool>>
       dev_features_tool_wrapper_;
   std::unique_ptr<EcTypeCTool> ec_typec_tool_;
diff --git a/debugd/src/dmesg_tool.cc b/debugd/src/dmesg_tool.cc
new file mode 100644
index 0000000..aa70520
--- /dev/null
+++ b/debugd/src/dmesg_tool.cc
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This tool is used for getting dmesg information through debugd.
+
+#include "debugd/src/dmesg_tool.h"
+
+#include "debugd/src/error_utils.h"
+#include "debugd/src/process_with_output.h"
+#include "debugd/src/variant_utils.h"
+#include "linux/capability.h"
+
+namespace {
+
+constexpr char kDmesgPath[] = "/bin/dmesg";
+
+}  // namespace
+
+namespace debugd {
+
+bool DmesgTool::CallDmesg(const brillo::VariantDictionary& options,
+                          brillo::ErrorPtr* error,
+                          std::string* output) {
+  ProcessWithOutput process;
+
+  process.SetCapabilities(CAP_TO_MASK(CAP_SYSLOG));
+  if (!process.Init()) {
+    *output = "<process init failed>";
+    return false;
+  }
+
+  process.AddArg(kDmesgPath);
+
+  if (!AddIntOption(&process, options, "show-delta", "-d", error) ||
+      !AddIntOption(&process, options, "human", "-H", error) ||
+      !AddIntOption(&process, options, "kernel", "-k", error) ||
+      !AddIntOption(&process, options, "force-prefix", "-p", error) ||
+      !AddIntOption(&process, options, "raw", "-r", error) ||
+      !AddIntOption(&process, options, "ctime", "-T", error) ||
+      !AddIntOption(&process, options, "notime", "-t", error) ||
+      !AddIntOption(&process, options, "userspace", "-u", error) ||
+      !AddIntOption(&process, options, "decode", "-x", error)) {
+    *output = "<invalid option>";
+    return false;
+  }
+
+  if (process.Run() != 0) {
+    *output = "<process exited with nonzero status>";
+    return false;
+  }
+
+  process.GetOutput(output);
+  return true;
+}
+
+}  // namespace debugd
diff --git a/debugd/src/dmesg_tool.h b/debugd/src/dmesg_tool.h
new file mode 100644
index 0000000..5d9e042
--- /dev/null
+++ b/debugd/src/dmesg_tool.h
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This tool is used for getting dmesg information through debugd.
+
+#ifndef DEBUGD_SRC_DMESG_TOOL_H_
+#define DEBUGD_SRC_DMESG_TOOL_H_
+
+#include <string>
+
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+
+namespace debugd {
+
+class DmesgTool {
+ public:
+  DmesgTool() = default;
+  DmesgTool(const DmesgTool&) = delete;
+  DmesgTool& operator=(const DmesgTool&) = delete;
+
+  ~DmesgTool() = default;
+
+  bool CallDmesg(const brillo::VariantDictionary& options,
+                 brillo::ErrorPtr* error,
+                 std::string* output);
+};
+
+}  // namespace debugd
+
+#endif  // DEBUGD_SRC_DMESG_TOOL_H_
diff --git a/debugd/src/variant_utils.cc b/debugd/src/variant_utils.cc
index c245a71..269eebb 100644
--- a/debugd/src/variant_utils.cc
+++ b/debugd/src/variant_utils.cc
@@ -6,7 +6,7 @@
 
 namespace debugd {
 
-bool AddIntOption(ProcessWithId* process,
+bool AddIntOption(SandboxedProcess* process,
                   const brillo::VariantDictionary& options,
                   const std::string& key,
                   const std::string& flag_name,
diff --git a/debugd/src/variant_utils.h b/debugd/src/variant_utils.h
index b52fc76..fbe7e15 100644
--- a/debugd/src/variant_utils.h
+++ b/debugd/src/variant_utils.h
@@ -58,7 +58,7 @@
 // isn't an integer, returns false. Otherwise, returns true, and if it
 // exists in the dictionary adds it to the command line for |process|
 // as the value for key |flag_name|.
-bool AddIntOption(ProcessWithId* process,
+bool AddIntOption(SandboxedProcess* process,
                   const brillo::VariantDictionary& options,
                   const std::string& key,
                   const std::string& flag_name,