blob: de49367c8c7c0a3bd1440bae949508cf294f20fd [file] [log] [blame]
// Copyright (c) 2011 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 "cros-disks/mount_options.h"
#include <sys/mount.h>
#include <algorithm>
#include <base/strings/string_util.h>
using std::pair;
using std::string;
using std::vector;
namespace cros_disks {
const char MountOptions::kOptionBind[] = "bind";
const char MountOptions::kOptionDirSync[] = "dirsync";
const char MountOptions::kOptionFlush[] = "flush";
const char MountOptions::kOptionNoDev[] = "nodev";
const char MountOptions::kOptionNoExec[] = "noexec";
const char MountOptions::kOptionNoSuid[] = "nosuid";
const char MountOptions::kOptionReadOnly[] = "ro";
const char MountOptions::kOptionReadWrite[] = "rw";
const char MountOptions::kOptionSynchronous[] = "sync";
const char MountOptions::kOptionUtf8[] = "utf8";
void MountOptions::Initialize(const vector<string>& options,
bool set_user_and_group_id,
const string& default_user_id,
const string& default_group_id) {
options_.clear();
options_.reserve(options.size());
bool option_read_only = false, option_read_write = false;
string option_user_id, option_group_id;
for (const auto& option : options) {
// Skip early if |option| contains a comma.
if (option.find(",") != string::npos) {
LOG(WARNING) << "Ignoring invalid mount option '" << option << "'.";
continue;
}
if (option == kOptionReadOnly) {
option_read_only = true;
} else if (option == kOptionReadWrite) {
option_read_write = true;
} else if (StartsWithASCII(option, "uid=", false)) {
option_user_id = option;
} else if (StartsWithASCII(option, "gid=", false)) {
option_group_id = option;
} else if (option == kOptionNoDev ||
option == kOptionNoExec ||
option == kOptionNoSuid) {
// We'll add these options unconditionally below.
continue;
} else if (option == kOptionBind ||
option == kOptionDirSync ||
option == kOptionFlush ||
option == kOptionSynchronous ||
option == kOptionUtf8 ||
StartsWithASCII(option, "shortname=", false)) {
// Only add options in the whitelist.
options_.push_back(option);
} else {
// Never add unknown/non-whitelisted options.
LOG(WARNING) << "Ignoring unsupported mount option '" << option << "'.";
}
}
if (option_read_only || !option_read_write) {
options_.push_back(kOptionReadOnly);
} else {
options_.push_back(kOptionReadWrite);
}
if (set_user_and_group_id) {
if (!option_user_id.empty()) {
options_.push_back(option_user_id);
} else if (!default_user_id.empty()) {
options_.push_back("uid=" + default_user_id);
}
if (!option_group_id.empty()) {
options_.push_back(option_group_id);
} else if (!default_group_id.empty()) {
options_.push_back("gid=" + default_group_id);
}
}
// Always set 'nodev', 'noexec', and 'nosuid'.
options_.push_back(kOptionNoDev);
options_.push_back(kOptionNoExec);
options_.push_back(kOptionNoSuid);
}
bool MountOptions::IsReadOnlyOptionSet() const {
for (vector<string>::const_reverse_iterator
option_iterator = options_.rbegin(); option_iterator != options_.rend();
++option_iterator) {
const string& option = *option_iterator;
if (option == kOptionReadOnly)
return true;
if (option == kOptionReadWrite)
return false;
}
return true;
}
void MountOptions::SetReadOnlyOption() {
std::replace(options_.begin(), options_.end(),
kOptionReadWrite, kOptionReadOnly);
}
pair<unsigned long, string> MountOptions::ToMountFlagsAndData() const {
unsigned long flags = MS_RDONLY;
vector<string> data;
data.reserve(options_.size());
for (const auto& option : options_) {
if (option == kOptionReadOnly) {
flags |= MS_RDONLY;
} else if (option == kOptionReadWrite) {
flags &= ~static_cast<unsigned long>(MS_RDONLY);
} else if (option == kOptionBind) {
flags |= MS_BIND;
} else if (option == kOptionDirSync) {
flags |= MS_DIRSYNC;
} else if (option == kOptionNoDev) {
flags |= MS_NODEV;
} else if (option == kOptionNoExec) {
flags |= MS_NOEXEC;
} else if (option == kOptionNoSuid) {
flags |= MS_NOSUID;
} else if (option == kOptionSynchronous) {
flags |= MS_SYNCHRONOUS;
} else {
data.push_back(option);
}
}
return std::make_pair(flags, JoinString(data, ','));
}
string MountOptions::ToString() const {
return options_.empty() ? kOptionReadOnly : JoinString(options_, ',');
}
} // namespace cros_disks