blob: 7ff890b26c6b357c79ccab2e09ffff6354582f02 [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 <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <zircon/process.h>
#include <zircon/processargs.h>
#include <fbl/ref_ptr.h>
#include "blobstore-private.h"
#include <fs/vfs.h>
#ifdef __Fuchsia__
#include <async/loop.h>
#include <fs/async-dispatcher.h>
#endif
namespace {
#ifdef __Fuchsia__
int do_blobstore_mount(int fd, int argc, char** argv) {
fbl::RefPtr<blobstore::VnodeBlob> vn;
if (blobstore::blobstore_mount(&vn, fd) < 0) {
return -1;
}
zx_handle_t h = zx_get_startup_handle(PA_HND(PA_USER0, 0));
if (h == ZX_HANDLE_INVALID) {
FS_TRACE_ERROR("blobstore: Could not access startup handle to mount point\n");
return h;
}
async::Loop loop;
fs::AsyncDispatcher dispatcher(loop.async());
fs::Vfs vfs(&dispatcher);
zx_status_t status;
if ((status = vfs.ServeDirectory(fbl::move(vn), zx::channel(h))) != ZX_OK) {
return status;
}
loop.Run();
return 0;
}
int do_blobstore_check(int fd, int argc, char** argv) {
fbl::RefPtr<blobstore::Blobstore> vn;
if (blobstore::blobstore_create(&vn, fd) < 0) {
return -1;
}
return blobstore::blobstore_check(vn);
}
#else
int do_blobstore_add_blob(int fd, int argc, char** argv) {
if (argc < 1) {
fprintf(stderr, "Adding a blob requires an additional file argument\n");
return -1;
}
int data_fd = open(argv[0], O_RDONLY, 0644);
if (data_fd < 0) {
fprintf(stderr, "error: cannot open '%s'\n", argv[0]);
return -1;
}
// TODO(smklein): Implement
fprintf(stderr, "Unimplemented: Adding blob %s\n", argv[0]);
close(data_fd);
return -1;
}
#endif
int do_blobstore_mkfs(int fd, int argc, char** argv) {
uint64_t block_count;
if (blobstore::blobstore_get_blockcount(fd, &block_count)) {
fprintf(stderr, "blobstore: cannot find end of underlying device\n");
return -1;
}
return blobstore::blobstore_mkfs(fd, block_count);
}
struct {
const char* name;
int (*func)(int fd, int argc, char** argv);
const char* help;
} CMDS[] = {
{"create", do_blobstore_mkfs, "initialize filesystem"},
{"mkfs", do_blobstore_mkfs, "initialize filesystem"},
#ifdef __Fuchsia__
{"mount", do_blobstore_mount, "mount filesystem"},
{"check", do_blobstore_check, "check filesystem integrity"},
{"fsck", do_blobstore_check, "check filesystem integrity"},
#else
{"add", do_blobstore_add_blob, "add a blob to a blobstore image"},
#endif
};
int usage() {
fprintf(stderr,
#ifdef __Fuchsia__
"usage: blobstore <command> [ <arg>* ]\n"
"\n"
"On Fuchsia, blobstore takes the block device argument by handle.\n"
"This can make 'blobstore' commands hard to invoke from command line.\n"
"Try using the [mkfs,fsck,mount,umount] commands instead\n"
#else
"usage: blobstore <file-or-device>[@<size>] <command> [ <arg>* ]\n"
#endif
"\n");
for (unsigned n = 0; n < (sizeof(CMDS) / sizeof(CMDS[0])); n++) {
fprintf(stderr, "%9s %-10s %s\n", n ? "" : "commands:",
CMDS[n].name, CMDS[n].help);
}
fprintf(stderr, "\n");
return -1;
}
} // namespace
int main(int argc, char** argv) {
int fd;
#ifdef __Fuchsia__
if (argc < 2) {
return usage();
}
char* cmd = argv[1];
// Block device passed by handle
fd = FS_FD_BLOCKDEVICE;
argv += 2;
argc -= 2;
#else
if (argc < 3) {
return usage();
}
char* device = argv[1];
char* cmd = argv[2];
char* sizestr = nullptr;
if ((sizestr = strchr(device, '@')) != nullptr) {
// Create a file with an explicitly requested size
*sizestr++ = 0;
char* end;
size_t size = strtoull(sizestr, &end, 10);
if (end == sizestr) {
fprintf(stderr, "blobstore: bad size: %s\n", sizestr);
return usage();
}
switch (end[0]) {
case 'M':
case 'm':
size *= (1024 * 1024);
end++;
break;
case 'G':
case 'g':
size *= (1024 * 1024 * 1024);
end++;
break;
}
if (end[0]) {
fprintf(stderr, "blobstore: bad size: %s\n", sizestr);
return usage();
}
if ((fd = open(device, O_RDWR | O_CREAT, 0644)) < 0) {
fprintf(stderr, "error: cannot open '%s'\n", device);
return -1;
} else if (ftruncate(fd, size)) {
fprintf(stderr, "error: cannot truncate device '%s'\n", device);
return -1;
}
} else if ((fd = open(device, O_RDWR, 0644)) < 0) {
// Open a file without an explicit size
fprintf(stderr, "error: cannot open '%s'\n", device);
return -1;
}
argv += 3;
argc -= 3;
#endif
for (unsigned i = 0; i < sizeof(CMDS) / sizeof(CMDS[0]); i++) {
if (!strcmp(cmd, CMDS[i].name)) {
return CMDS[i].func(fd, argc, argv);
}
}
close(fd);
return usage();
}