crosh: Make dmesg use debugd
Instead of calling dmesg from crosh directly, make a call to the debugd
dmesg tool. In the process, refactor the dmesg command to use crosh
rust.
BUG=chromium:1154528
TEST=Open crosh and run dmesg
Change-Id: I5bcf2aec2b511f9d41792c226e14b7a47f0300d2
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2599604
Tested-by: Nicole Anderson-Au <nvaa@google.com>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Nicole Anderson-Au <nvaa@google.com>
diff --git a/crosh/Cargo.toml b/crosh/Cargo.toml
index 0e4a8b1..45663f1 100644
--- a/crosh/Cargo.toml
+++ b/crosh/Cargo.toml
@@ -10,6 +10,7 @@
[dependencies]
dbus = "0.8"
+getopts = "0.2"
libc = "0.2.44"
remain = "*"
regex = "1.0.6"
diff --git a/crosh/crosh b/crosh/crosh
index 56da92c..794de14 100755
--- a/crosh/crosh
+++ b/crosh/crosh
@@ -1788,22 +1788,6 @@
EOF
)
-USAGE_dmesg='[-d|-H|-k|-L|-P|-p|-r|-T|-t|-u|-w|-x]'
-HELP_dmesg='
- Display kernel log buffer
-'
-cmd_dmesg() (
- # We allow only a few options.
- local opt
- for opt in "$@"; do
- if ! printf '%s' "${opt}" | grep -sqE '^-[dHkLPprTtuwx]+$'; then
- help "unknown option: $*"
- return 1
- fi
- done
- dmesg "$@"
-)
-
USAGE_free='[options]'
HELP_free='
Display free/used memory info
diff --git a/crosh/src/base/dmesg.rs b/crosh/src/base/dmesg.rs
new file mode 100644
index 0000000..c6dac01
--- /dev/null
+++ b/crosh/src/base/dmesg.rs
@@ -0,0 +1,108 @@
+// 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.
+
+// Provides the command "dmesg" for crosh through debugd.
+
+use std::collections::HashMap;
+use std::io::Write;
+use std::time::Duration;
+
+use dbus::arg::{self, Variant};
+use dbus::blocking::Connection;
+use getopts::{self, Options};
+use sys_util::error;
+use system_api::client::OrgChromiumDebugd;
+
+use crate::dispatcher::{self, Arguments, Command, Dispatcher};
+use crate::util::TIMEOUT_MILLIS;
+
+/* We keep a reduced set of options here for security */
+const FLAGS: [(&str, &str, &str); 10] = [
+ (
+ "d",
+ "show_delta",
+ "Display the timestamp and the time delta
+ spent between messages",
+ ),
+ ("H", "human", "Enable human-readable output."),
+ ("k", "kernel", "Print kernel messages."),
+ ("L", "color", "Colorize the output."),
+ (
+ "p",
+ "force-prefix",
+ "Add facility, level or timestamp
+ information to each line of a multi-line message.",
+ ),
+ ("r", "raw", "Print the raw message buffer."),
+ ("T", "ctime", "Print human-readable timestamps."),
+ ("t", "notime", "Do not print kernel's timestamps."),
+ ("u", "userspace", "Print userspace messages."),
+ (
+ "x",
+ "decode",
+ "Decode facility and level (priority) numbers
+ to human-readable prefixes.",
+ ),
+];
+
+pub fn register(dispatcher: &mut Dispatcher) {
+ dispatcher.register_command(
+ Command::new(
+ "dmesg".to_string(),
+ "".to_string(),
+ "Run the dmesg command via debugd.".to_string(),
+ )
+ .set_command_callback(Some(execute_dmesg))
+ .set_help_callback(dmesg_help),
+ );
+}
+
+fn dmesg_help(_cmd: &Command, w: &mut dyn Write, _level: usize) {
+ let mut help = "Usage: dmesg [options]\n".to_string();
+ for flag in FLAGS.iter() {
+ help.push_str(&format!("\t-{}, --{}\n\t\t{}\n", flag.0, flag.1, flag.2));
+ }
+ w.write_all(help.as_bytes()).unwrap();
+ w.flush().unwrap();
+}
+
+fn execute_dmesg(_cmd: &Command, args: &Arguments) -> Result<(), dispatcher::Error> {
+ let mut opts = Options::new();
+
+ for flag in FLAGS.iter() {
+ opts.optflag(flag.0, flag.1, flag.2);
+ }
+
+ let matches = opts
+ .parse(args.get_tokens())
+ .map_err(|_| dispatcher::Error::CommandReturnedError)?;
+
+ let mut dbus_options = HashMap::new();
+ for flag in FLAGS.iter() {
+ let name = flag.1;
+ if matches.opt_present(name) {
+ let val_true: Variant<Box<dyn arg::RefArg>> = Variant(Box::new(1));
+ dbus_options.insert(name, val_true);
+ }
+ }
+
+ let connection = Connection::new_system().map_err(|err| {
+ error!("ERROR: Failed to get D-Bus connection: {}", err);
+ dispatcher::Error::CommandReturnedError
+ })?;
+
+ let conn_path = connection.with_proxy(
+ "org.chromium.debugd",
+ "/org/chromium/debugd",
+ Duration::from_millis(TIMEOUT_MILLIS),
+ );
+
+ let output = conn_path.call_dmesg(dbus_options).map_err(|err| {
+ println!("ERROR: Got unexpected result: {}", err);
+ dispatcher::Error::CommandReturnedError
+ })?;
+ // Print the response.
+ print!("{}", output);
+ Ok(())
+}
diff --git a/crosh/src/base/mod.rs b/crosh/src/base/mod.rs
index cb5df1d..b3465a8 100644
--- a/crosh/src/base/mod.rs
+++ b/crosh/src/base/mod.rs
@@ -6,6 +6,7 @@
mod arc;
mod ccd_pass;
+mod dmesg;
mod set_time;
mod verify_ro;
mod vmc;
@@ -15,6 +16,7 @@
pub fn register(dispatcher: &mut Dispatcher) {
arc::register(dispatcher);
ccd_pass::register(dispatcher);
+ dmesg::register(dispatcher);
set_time::register(dispatcher);
verify_ro::register(dispatcher);
vmc::register(dispatcher);
diff --git a/crosh/src/legacy.rs b/crosh/src/legacy.rs
index c4a44b8..3513cdd 100644
--- a/crosh/src/legacy.rs
+++ b/crosh/src/legacy.rs
@@ -22,7 +22,6 @@
"cras",
"cryptohome_status",
"diag",
- "dmesg",
"dump_emk",
"enroll_status",
"evtest",
diff --git a/debugd/src/dmesg_tool.cc b/debugd/src/dmesg_tool.cc
index aa70520..413c84f 100644
--- a/debugd/src/dmesg_tool.cc
+++ b/debugd/src/dmesg_tool.cc
@@ -24,7 +24,7 @@
std::string* output) {
ProcessWithOutput process;
- process.SetCapabilities(CAP_TO_MASK(CAP_SYSLOG));
+ process.SetCapabilities(CAP_TO_MASK(CAP_SYS_ADMIN));
if (!process.Init()) {
*output = "<process init failed>";
return false;
@@ -32,15 +32,16 @@
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)) {
+ if (!AddBoolOption(&process, options, "show-delta", "-d", error) ||
+ !AddBoolOption(&process, options, "human", "--human", error) ||
+ !AddBoolOption(&process, options, "kernel", "-k", error) ||
+ !AddBoolOption(&process, options, "color", "--color=always", error) ||
+ !AddBoolOption(&process, options, "force-prefix", "-p", error) ||
+ !AddBoolOption(&process, options, "raw", "-r", error) ||
+ !AddBoolOption(&process, options, "ctime", "-T", error) ||
+ !AddBoolOption(&process, options, "notime", "-t", error) ||
+ !AddBoolOption(&process, options, "userspace", "-u", error) ||
+ !AddBoolOption(&process, options, "decode", "-x", error)) {
*output = "<invalid option>";
return false;
}
diff --git a/debugd/src/variant_utils.cc b/debugd/src/variant_utils.cc
index 269eebb..5ecc721 100644
--- a/debugd/src/variant_utils.cc
+++ b/debugd/src/variant_utils.cc
@@ -19,4 +19,17 @@
return result != ParseResult::PARSE_ERROR;
}
+bool AddBoolOption(SandboxedProcess* process,
+ const brillo::VariantDictionary& options,
+ const std::string& key,
+ const std::string& flag_name,
+ brillo::ErrorPtr* error) {
+ int value;
+ ParseResult result = GetOption(options, key, &value, error);
+ if (result == ParseResult::PARSED && value)
+ process->AddArg(flag_name);
+
+ return result != ParseResult::PARSE_ERROR;
+}
+
} // namespace debugd
diff --git a/debugd/src/variant_utils.h b/debugd/src/variant_utils.h
index fbe7e15..025b545 100644
--- a/debugd/src/variant_utils.h
+++ b/debugd/src/variant_utils.h
@@ -64,6 +64,15 @@
const std::string& flag_name,
brillo::ErrorPtr* error);
+// Looks up an option in the |options| dictionary. If it exists and
+// isn't a boolean, returns false. Otherwise, returns true, and if it
+// exists in the dictionary adds it to the command line for |process|.
+bool AddBoolOption(SandboxedProcess* process,
+ const brillo::VariantDictionary& options,
+ const std::string& key,
+ const std::string& flag_name,
+ brillo::ErrorPtr* error);
+
} // namespace debugd
#endif // DEBUGD_SRC_VARIANT_UTILS_H_