blob: 3c68b32fab8291292d0564e443a84c17656a0f8d [file] [log] [blame]
// Copyright 2017 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 <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <async/cpp/loop.h>
#include <fbl/unique_free_ptr.h>
#include <fbl/unique_ptr.h>
#include <fs/trace.h>
#include <minfs/fsck.h>
#include <minfs/minfs.h>
#include <trace-provider/provider.h>
#include <zircon/compiler.h>
#include <zircon/process.h>
#include <zircon/processargs.h>
namespace {
int do_minfs_check(fbl::unique_ptr<minfs::Bcache> bc, int argc, char** argv) {
return minfs_check(fbl::move(bc));
}
int do_minfs_mount(fbl::unique_ptr<minfs::Bcache> bc, bool readonly) {
zx_handle_t h = zx_get_startup_handle(PA_HND(PA_USER0, 0));
if (h == ZX_HANDLE_INVALID) {
FS_TRACE_ERROR("minfs: Could not access startup handle to mount point\n");
return ZX_ERR_BAD_STATE;
}
async::Loop loop;
fs::Vfs vfs(loop.async());
trace::TraceProvider trace_provider(loop.async());
vfs.SetReadonly(readonly);
if (MountAndServe(&vfs, fbl::move(bc), zx::channel(h)) != ZX_OK) {
return -1;
}
loop.Run();
return 0;
}
int do_minfs_mkfs(fbl::unique_ptr<minfs::Bcache> bc, int argc, char** argv) {
return Mkfs(fbl::move(bc));
}
struct {
const char* name;
int (*func)(fbl::unique_ptr<minfs::Bcache> bc, int argc, char** argv);
uint32_t flags;
const char* help;
} CMDS[] = {
{"create", do_minfs_mkfs, O_RDWR | O_CREAT, "initialize filesystem"},
{"mkfs", do_minfs_mkfs, O_RDWR | O_CREAT, "initialize filesystem"},
{"check", do_minfs_check, O_RDONLY, "check filesystem integrity"},
{"fsck", do_minfs_check, O_RDONLY, "check filesystem integrity"},
};
int usage() {
fprintf(stderr,
"usage: minfs [ <option>* ] <file-or-device>[@<size>] <command> [ <arg>* ]\n"
"\n"
"options: -v some debug messages\n"
" -vv all debug messages\n"
" --readonly Mount filesystem read-only\n"
"\n"
"On Fuchsia, MinFS takes the block device argument by handle.\n"
"This can make 'minfs' commands hard to invoke from command line.\n"
"Try using the [mkfs,fsck,mount,umount] commands instead\n"
"\n");
for (unsigned n = 0; n < fbl::count_of(CMDS); n++) {
fprintf(stderr, "%9s %-10s %s\n", n ? "" : "commands:",
CMDS[n].name, CMDS[n].help);
}
fprintf(stderr, "%9s %-10s %s\n", "", "mount", "mount filesystem");
fprintf(stderr, "\n");
return -1;
}
off_t get_size(int fd) {
block_info_t info;
if (ioctl_block_get_info(fd, &info) != sizeof(info)) {
fprintf(stderr, "error: minfs could not find size of device\n");
return 0;
}
return info.block_size * info.block_count;
}
} // namespace
int main(int argc, char** argv) {
off_t size = 0;
bool readonly = false;
__UNUSED off_t offset = 0;
off_t length = 0;
// handle options
while (argc > 1) {
if (!strcmp(argv[1], "--readonly")) {
readonly = true;
} else {
break;
}
argc--;
argv++;
}
// Block device passed by handle
if (argc < 2) {
return usage();
}
char* cmd = argv[1];
fbl::unique_fd fd;
fd.reset(FS_FD_BLOCKDEVICE);
if (!readonly) {
block_info_t block_info;
zx_status_t status = static_cast<zx_status_t>(ioctl_block_get_info(fd.get(), &block_info));
if (status < ZX_OK) {
fprintf(stderr, "minfs: Unable to query block device, fd: %d status: 0x%x\n", fd.get(),
status);
return -1;
}
readonly = block_info.flags & BLOCK_FLAG_READONLY;
}
if (size == 0) {
size = get_size(fd.get());
if (size == 0) {
fprintf(stderr, "minfs: failed to access block device\n");
return usage();
}
}
if (length > size) {
fprintf(stderr, "Invalid length\n");
return usage();
} else if (length > 0) {
size = length;
}
size /= minfs::kMinfsBlockSize;
fbl::unique_ptr<minfs::Bcache> bc;
if (minfs::Bcache::Create(&bc, fbl::move(fd), (uint32_t)size) < 0) {
fprintf(stderr, "error: cannot create block cache\n");
return -1;
}
if (!strcmp(cmd, "mount")) {
return do_minfs_mount(fbl::move(bc), readonly);
}
for (unsigned i = 0; i < fbl::count_of(CMDS); i++) {
if (!strcmp(cmd, CMDS[i].name)) {
return CMDS[i].func(fbl::move(bc), argc - 3, argv + 3);
}
}
return -1;
}