blob: 2ef5f9b2edaaed3bdb53eb820020f006bc484fe6 [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 <fidl/fuchsia.fshost/cpp/wire.h>
#include <getopt.h>
#include <lib/service/llcpp/service.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <filesystem>
#include <fbl/unique_fd.h>
#include "src/storage/fshost/constants.h"
int usage(void) {
fprintf(stderr,
"usage: mount [ <option>* ] devicepath <mount-path>\n"
"options:\n"
" -r|--readonly : Open the filesystem as read-only\n"
" -v|--verbose : Verbose mode\n"
" --fshost-path : The path to the fshost admin service (if different from the default)\n"
" -h|--help : Display this message\n"
"\n"
"Filesystems can only be mounted in /mnt/...\n");
return EXIT_FAILURE;
}
int parse_args(int argc, char** argv, fidl::AnyArena& arena,
fuchsia_fshost::wire::MountOptions& options, char** devicepath,
std::string* mount_name, std::string& fshost_path) {
while (1) {
static struct option opts[] = {
{"readonly", no_argument, NULL, 'r'}, {"verbose", no_argument, NULL, 'v'},
{"compression", required_argument, NULL, 'c'}, {"help", no_argument, NULL, 'h'},
{"fshost-path", required_argument, NULL, 'p'}, {NULL, 0, NULL, 0},
};
int opt_index;
int c = getopt_long(argc, argv, "rmvc:h", opts, &opt_index);
if (c < 0) {
break;
}
switch (c) {
case 'r':
options.set_read_only(true);
break;
case 'v':
options.set_verbose(true);
break;
case 'c':
options.set_write_compression_algorithm(arena, arena, optarg);
break;
case 'p':
fshost_path = optarg;
break;
case 'h':
default:
return usage();
}
}
argc -= optind;
argv += optind;
if (argc < 2) {
return usage();
}
*devicepath = argv[0];
std::filesystem::path path(argv[1]);
if (path.parent_path() != "/mnt") {
std::error_code error;
auto directory = std::filesystem::canonical(path.parent_path(), error);
if (error) {
fprintf(stderr, "Bad mount path: %s\n\n", strerror(error.value()));
return usage();
}
if (directory != "/mnt") {
fprintf(stderr, "Only mounts in /mnt are supported.\n\n");
return usage();
}
}
*mount_name = path.filename();
return 0;
}
int main(int argc, char** argv) {
char* devicepath;
std::string mount_name;
std::string fshost_path(fshost::kHubAdminServicePath);
fidl::Arena arena;
fuchsia_fshost::wire::MountOptions options(arena);
if (int r = parse_args(argc, argv, arena, options, &devicepath, &mount_name, fshost_path)) {
return r;
}
if (options.has_verbose() && options.verbose()) {
printf("fs_mount: Mounting device [%s] on path [/mnt/%s]\n", devicepath, mount_name.c_str());
}
auto block_device_or = service::Connect<fuchsia_hardware_block::Block>(devicepath);
if (block_device_or.is_error()) {
fprintf(stderr, "Error opening block device: %s\n", block_device_or.status_string());
return EXIT_FAILURE;
}
auto fshost_or = service::Connect<fuchsia_fshost::Admin>(fshost_path.c_str());
if (fshost_or.is_error()) {
fprintf(stderr, "Error connecting to fshost (@ %s): %s\n", fshost_path.c_str(),
fshost_or.status_string());
return EXIT_FAILURE;
}
auto result =
fidl::WireCall(*fshost_or)
->Mount(std::move(*block_device_or), fidl::StringView::FromExternal(mount_name), options);
if (!result.ok()) {
fprintf(stderr, "Error mounting, fidl error: %s\n", result.FormatDescription().c_str());
return EXIT_FAILURE;
}
if (result->is_error()) {
fprintf(stderr, "Error mounting: %s\n", zx_status_get_string(result->error_value()));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}