blob: 8c2a220bc3602e60708c0a287612719bb38b066b [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 "login_manager/termina_manager_impl.h"
#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <sys/mount.h>
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/files/file_util.h>
#include <brillo/process.h>
#include "login_manager/system_utils.h"
using base::FilePath;
namespace login_manager {
namespace {
const char kVmLauncherPath[] = "/usr/bin/vm_launcher";
const char kVmToolAllVms[] = "all";
const char kVmToolContainerOpt[] = "--container";
const char kVmToolRwContainerOpt[] = "--rwcontainer";
const char kVmToolForceOpt[] = "--force";
const char kVmToolGetName[] = "getname";
const char kVmToolStart[] = "start";
const char kVmToolStop[] = "stop";
std::string VmNameFromPid(int pid) {
brillo::ProcessImpl vmtool;
vmtool.AddArg(std::string(kVmLauncherPath));
vmtool.AddArg(std::string(kVmToolGetName));
vmtool.AddArg(std::to_string(pid));
vmtool.RedirectUsingPipe(STDOUT_FILENO, false /* is_input */);
vmtool.Start();
int stdout_pipe = vmtool.GetPipe(STDOUT_FILENO);
char stdout_buff[256];
ssize_t ret = read(stdout_pipe, &stdout_buff, sizeof(stdout_buff) - 1);
if (ret < 0)
return std::string();
stdout_buff[ret] = '\0';
if (vmtool.Wait() < 0)
return std::string();
return stdout_buff;
}
void CleanUpVm(const std::string& name) {
brillo::ProcessImpl vmtool;
vmtool.AddArg(std::string(kVmLauncherPath));
vmtool.AddArg(std::string(kVmToolStop));
vmtool.AddArg(name);
vmtool.Run();
}
} // anonymous namespace
TerminaManagerImpl::TerminaManagerImpl(SystemUtils* system_utils)
: system_utils_(system_utils) {
DCHECK(system_utils_);
}
bool TerminaManagerImpl::IsManagedJob(pid_t pid) {
return !VmNameFromPid(pid).empty();
}
void TerminaManagerImpl::HandleExit(const siginfo_t& status) {
std::string vm_name = VmNameFromPid(status.si_pid);
if (vm_name.empty())
return;
CleanUpVm(vm_name);
}
void TerminaManagerImpl::RequestJobExit() {
CleanUpVm(kVmToolAllVms);
}
void TerminaManagerImpl::EnsureJobExit(base::TimeDelta timeout) {
brillo::ProcessImpl vmtool;
vmtool.AddArg(kVmLauncherPath);
vmtool.AddArg(kVmToolStop);
vmtool.AddArg(kVmToolForceOpt);
vmtool.AddArg(kVmToolAllVms);
vmtool.Run();
}
bool TerminaManagerImpl::StartVmContainer(const base::FilePath& image_path,
const std::string& name,
bool writable) {
LOG(INFO) << "Starting container " << image_path.value() << " in termina VM "
<< name;
brillo::ProcessImpl vmtool;
vmtool.AddArg(kVmLauncherPath);
vmtool.AddArg(kVmToolStart);
vmtool.AddArg(base::StringPrintf(
"%s=%s", writable ? kVmToolRwContainerOpt : kVmToolContainerOpt,
image_path.value().c_str()));
vmtool.AddArg(name);
return vmtool.Run() == 0;
}
bool TerminaManagerImpl::StopVmContainer(const std::string& name) {
LOG(INFO) << "Stopping termina VM " << name;
brillo::ProcessImpl vmtool;
vmtool.AddArg(kVmLauncherPath);
vmtool.AddArg(kVmToolStop);
vmtool.AddArg(name);
return vmtool.Run() == 0;
}
} // namespace login_manager