1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <fs-management/mount.h>
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <new>
10 #include <string.h>
11 #include <unistd.h>
12 
13 #include <fbl/unique_ptr.h>
14 #include <lib/fdio/limits.h>
15 #include <lib/fdio/util.h>
16 #include <lib/fdio/vfs.h>
17 #include <zircon/compiler.h>
18 #include <zircon/device/vfs.h>
19 #include <zircon/processargs.h>
20 #include <zircon/syscalls.h>
21 
22 namespace {
23 
FsckNativeFs(const char * device_path,const fsck_options_t * options,LaunchCallback cb,const char * cmd_path)24 zx_status_t FsckNativeFs(const char* device_path, const fsck_options_t* options,
25                          LaunchCallback cb, const char* cmd_path) {
26     zx_handle_t hnd[FDIO_MAX_HANDLES * 2];
27     uint32_t ids[FDIO_MAX_HANDLES * 2];
28     size_t n = 0;
29     int device_fd;
30     if ((device_fd = open(device_path, O_RDWR)) < 0) {
31         fprintf(stderr, "Failed to open device\n");
32         return ZX_ERR_BAD_STATE;
33     }
34     zx_status_t status;
35     if ((status = fdio_transfer_fd(device_fd, FS_FD_BLOCKDEVICE, hnd + n, ids + n)) <= 0) {
36         fprintf(stderr, "Failed to access device handle\n");
37         return status != 0 ? status : ZX_ERR_BAD_STATE;
38     }
39     n += status;
40 
41     fbl::unique_ptr<const char*[]> argv(new const char*[2 + NUM_FSCK_OPTIONS]);
42     int argc = 0;
43     argv[argc++] = cmd_path;
44     if (options->verbose) {
45         argv[argc++] = "-v";
46     }
47     // TODO(smklein): Add support for modify, force flags. Without them,
48     // we have "always_modify=true" and "force=true" effectively on by default.
49     argv[argc++] = "fsck";
50     status = static_cast<zx_status_t>(cb(argc, argv.get(), hnd, ids, n));
51     return status;
52 }
53 
FsckFat(const char * device_path,const fsck_options_t * options,LaunchCallback cb)54 zx_status_t FsckFat(const char* device_path, const fsck_options_t* options,
55                     LaunchCallback cb) {
56     fbl::unique_ptr<const char*[]> argv(new const char*[2 + NUM_FSCK_OPTIONS]);
57     int argc = 0;
58     argv[argc++] = "/boot/bin/fsck-msdosfs";
59     if (options->never_modify) {
60         argv[argc++] = "-n";
61     } else if (options->always_modify) {
62         argv[argc++] = "-y";
63     }
64     if (options->force) {
65         argv[argc++] = "-f";
66     }
67     argv[argc++] = device_path;
68     zx_status_t status = static_cast<zx_status_t>(cb(argc, argv.get(), NULL, NULL, 0));
69     return status;
70 }
71 
72 }  // namespace
73 
fsck(const char * device_path,disk_format_t df,const fsck_options_t * options,LaunchCallback cb)74 zx_status_t fsck(const char* device_path, disk_format_t df,
75                  const fsck_options_t* options, LaunchCallback cb) {
76     switch (df) {
77     case DISK_FORMAT_MINFS:
78         return FsckNativeFs(device_path, options, cb, "/boot/bin/minfs");
79     case DISK_FORMAT_FAT:
80         return FsckFat(device_path, options, cb);
81     case DISK_FORMAT_BLOBFS:
82         return FsckNativeFs(device_path, options, cb, "/boot/bin/blobfs");
83     default:
84         return ZX_ERR_NOT_SUPPORTED;
85     }
86 }
87