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 <fcntl.h>
6#include <limits.h>
7#include <unistd.h>
8
9#include <fbl/unique_fd.h>
10#include <fs-management/fvm.h>
11#include <lib/async-loop/cpp/loop.h>
12#include <lib/memfs/memfs.h>
13#include <unittest/unittest.h>
14#include <zircon/device/device.h>
15
16#include "filesystems.h"
17
18const char* filesystem_name_filter = "";
19
20static void print_test_help(FILE* f) {
21    fprintf(f,
22            "  -d <blkdev>\n"
23            "      Use block device <blkdev> instead of a ramdisk\n"
24            "\n"
25            "  -f <fs>\n"
26            "      Test only fileystem <fs>, where <fs> is one of:\n");
27    for (int j = 0; j < NUM_FILESYSTEMS; j++) {
28        fprintf(f, "%8s%s\n", "", FILESYSTEMS[j].name);
29    }
30}
31
32int main(int argc, char** argv) {
33    use_real_disk = false;
34
35    unittest_register_test_help_printer(print_test_help);
36
37    int i = 1;
38    while (i < argc) {
39        if (strcmp(argv[i], "-d") == 0 && (i + 1 < argc)) {
40            fbl::unique_fd fd(open(argv[i + 1], O_RDWR));
41            if (!fd) {
42                fprintf(stderr, "[fs] Could not open block device\n");
43                return -1;
44            } else if (ioctl_device_get_topo_path(fd.get(), test_disk_path, PATH_MAX) < 0) {
45                fprintf(stderr, "[fs] Could not acquire topological path of block device\n");
46                return -1;
47            } else if (ioctl_block_get_info(fd.get(), &test_disk_info) < 0) {
48                fprintf(stderr, "[fs] Could not read disk info\n");
49                return -1;
50            }
51            // If we previously tried running tests on this disk, it may
52            // have created an FVM and failed. (Try to) clean up from previous state
53            // before re-running.
54            fvm_destroy(test_disk_path);
55            use_real_disk = true;
56            i += 2;
57        } else if (!strcmp(argv[i], "-f") && (i + 1 < argc)) {
58            bool found = false;
59            for (int j = 0; j < NUM_FILESYSTEMS; j++) {
60                if (!strcmp(argv[i + 1], FILESYSTEMS[j].name)) {
61                    found = true;
62                    filesystem_name_filter = argv[i + 1];
63                    break;
64                }
65            }
66            if (!found) {
67                fprintf(stderr, "Error: Filesystem not found\n");
68                return -1;
69            }
70            i += 2;
71        } else {
72            // Ignore options we don't recognize. See ulib/unittest/README.md.
73            break;
74        }
75    }
76
77    // Initialize tmpfs.
78    async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
79    if (loop.StartThread() != ZX_OK) {
80        fprintf(stderr, "Error: Cannot initialize local tmpfs loop\n");
81        return -1;
82    }
83    if (memfs_install_at(loop.dispatcher(), kTmpfsPath) != ZX_OK) {
84        fprintf(stderr, "Error: Cannot install local tmpfs\n");
85        return -1;
86    }
87
88    return unittest_run_all_tests(argc, argv) ? 0 : -1;
89}
90