blob: b32b28771d0f9c1539d35ee80021f6d56d6f9900 [file] [log] [blame]
// Copyright 2017 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.
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <linux/vm_sockets.h>
#include <memory>
#include <base/at_exit.h>
#include <base/bind_helpers.h>
#include <base/files/scoped_file.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/file_descriptor_watcher_posix.h>
#include <base/memory/ref_counted.h>
#include <base/run_loop.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <base/task/single_thread_task_executor.h>
#include <brillo/file_utils.h>
#include <brillo/flag_helper.h>
#include <brillo/syslog_logging.h>
#include <chromeos/dbus/service_constants.h>
#include <grpcpp/grpcpp.h>
#include <vm_protos/proto_bindings/vm_host.grpc.pb.h>
#include "vm_tools/syslog/forwarder.h"
#include "vm_tools/syslog/log_pipe.h"
namespace {
constexpr unsigned int kPort = 9999;
// Default syslogd path. When |FLAGS_log_destination| is |kDevLog| we forward
// all logs using a unix domain socket.
constexpr char kDevLog[] = "/dev/log";
} // namespace
int main(int argc, char** argv) {
base::AtExitManager at_exit;
base::SingleThreadTaskExecutor task_executor(base::MessagePumpType::IO);
base::FileDescriptorWatcher watcher(task_executor.task_runner());
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderrIfTty);
DEFINE_string(
log_destination, "",
"Path to unix domain datagram socket to which logs will be forwarded");
brillo::FlagHelper::Init(argc, argv, "VM log forwarding tool");
bool only_log_to_syslog = FLAGS_log_destination == kDevLog;
base::ScopedFD dest(socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (!dest.is_valid()) {
PLOG(ERROR) << "Failed to create unix domain datagram socket";
return EXIT_FAILURE;
}
struct sockaddr_un un = {
.sun_family = AF_UNIX,
};
DCHECK(sizeof(kDevLog) <= sizeof(un.sun_path));
// sun_path is zero-initialized above so we just need to copy the path.
memcpy(un.sun_path, kDevLog, sizeof(kDevLog));
if (connect(dest.get(), reinterpret_cast<struct sockaddr*>(&un),
sizeof(un)) != 0) {
PLOG(ERROR) << "Failed to connect to " << kDevLog;
return EXIT_FAILURE;
}
base::RunLoop run_loop;
vm_tools::syslog::LogPipeManager log_pipe_manager(run_loop.QuitClosure());
CHECK(log_pipe_manager.Init(std::move(dest), only_log_to_syslog));
grpc::ServerBuilder builder;
builder.AddListeningPort(
base::StringPrintf("vsock:%u:%u", VMADDR_CID_ANY, kPort),
grpc::InsecureServerCredentials());
builder.RegisterService(&log_pipe_manager);
std::unique_ptr<grpc::Server> server = builder.BuildAndStart();
CHECK(server);
LOG(INFO) << "VM log forwarder listening on port " << kPort;
run_loop.Run();
server->Shutdown();
return EXIT_SUCCESS;
}