blob: 85c8f8457331489663b6a3d031cdbcdc889e1300 [file] [log] [blame]
// Copyright 2021 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 <sys/mount.h>
#include <unistd.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/time/time.h>
#include "minios/minios.h"
#include "minios/process_manager.h"
namespace {
bool ForceCreateSymbolicLink(const base::FilePath& target,
const base::FilePath& symlink) {
if (base::PathExists(symlink) && !base::DeleteFile(symlink))
return false;
return base::CreateSymbolicLink(target, symlink);
}
// Sanity checks the date (crosbug.com/13200).
bool InitClock() {
auto now = base::Time::Now();
base::Time::Exploded exploded;
now.UTCExplode(&exploded);
if (exploded.year >= 1970)
return true;
constexpr char kDayAfterUnixEpoch[] = "010200001970.00";
return ProcessManager().RunCommand({"/bin/date", kDayAfterUnixEpoch},
ProcessManager::IORedirection{
.input = minios::kDebugConsole,
.output = minios::kDebugConsole,
}) != 0;
}
// Sets up all the common system mount points.
bool InitMounts() {
if (mount("proc", "/proc", "proc", MS_NODEV | MS_NOEXEC | MS_NOSUID,
nullptr) != 0) {
PLOG(ERROR) << "Failed to mount proc";
return false;
}
if (mount("sysfs", "/sys", "sysfs", MS_NODEV | MS_NOEXEC | MS_NOSUID,
nullptr) != 0) {
PLOG(ERROR) << "Failed to mount sysfs";
return false;
}
if (mount("devtmpfs", "/dev", "devtmpfs", MS_NOSUID, "mode=0755") != 0) {
PLOG(ERROR) << "Failed to mount dev";
return false;
}
for (const auto& [target, symlink] :
std::vector<std::pair<std::string, std::string>>{
{"/proc/self/fd", "/dev/fd"},
{"/proc/self/fd/0", "/dev/stdin"},
{"/proc/self/fd/1", "/dev/stdout"},
{"/proc/self/fd/2", "/dev/stderr"}}) {
if (!ForceCreateSymbolicLink(base::FilePath(target),
base::FilePath(symlink))) {
PLOG(ERROR) << "Failed to create " << symlink << " symlink";
return false;
}
}
const base::FilePath kDevPts("/dev/pts");
if (!base::PathExists(kDevPts) && !base::CreateDirectory(kDevPts)) {
PLOG(ERROR) << "Failed to create /dev/pts directory";
return false;
}
if (mount("devpts", "/dev/pts", "devpts", MS_NOEXEC | MS_NOSUID, nullptr) !=
0) {
PLOG(ERROR) << "Failed to mount devpts";
return false;
}
if (mount("debugfs", "/sys/kernel/debug", "debugfs", 0, nullptr) != 0) {
PLOG(ERROR) << "Failed to mount debugfs";
return false;
}
return true;
}
} // namespace
// This init runs steps required for upstart to start successfully.
int main() {
if (!InitClock()) {
LOG(ERROR) << "Failed to init clock.";
return -1;
}
if (!InitMounts()) {
LOG(ERROR) << "Failed to init mounts.";
return -1;
}
// TODO(vyshu) : Remove init.sh and call upstart directly.
char* args[] = {const_cast<char*>("/init.sh"), NULL};
return execvp(args[0], args);
}