1// Copyright 2017 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 <dirent.h>
6#include <fcntl.h>
7#include <stdbool.h>
8#include <stddef.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12
13#include "pave-logging.h"
14#include "pave-lib.h"
15
16namespace {
17
18using paver::Arch;
19using paver::Command;
20using paver::Flags;
21
22void PrintUsage() {
23    ERROR("install-disk-image <command> [options...]\n");
24    ERROR("Commands:\n");
25    ERROR("  install-bootloader : Install a BOOTLOADER partition to the device\n");
26    ERROR("  install-efi        : Install an EFI partition to the device\n");
27    ERROR("  install-kernc      : Install a KERN-C CrOS partition to the device\n");
28    ERROR("  install-zircona    : Install a ZIRCON-A partition to the device\n");
29    ERROR("  install-zirconb    : Install a ZIRCON-B partition to the device\n");
30    ERROR("  install-zirconr    : Install a ZIRCON-R partition to the device\n");
31    ERROR("  install-fvm        : Install a sparse FVM to the device\n");
32    ERROR("  wipe               : Clean up the install disk\n");
33    ERROR("Options:\n");
34    ERROR("  --file <file>: Read from FILE instead of stdin\n");
35    ERROR("  --force: Install partition even if inappropriate for the device\n");
36}
37
38bool ParseFlags(int argc, char** argv, Flags* flags) {
39#define SHIFT_ARGS \
40    do {           \
41        argc--;    \
42        argv++;    \
43    } while (0)
44
45    // Parse command.
46    if (argc < 2) {
47        ERROR("install-disk-image needs a command\n");
48        return false;
49    }
50    SHIFT_ARGS;
51
52    if (!strcmp(argv[0], "install-bootloader")) {
53        flags->cmd = Command::kInstallBootloader;
54    } else if (!strcmp(argv[0], "install-efi")) {
55        flags->cmd = Command::kInstallEfi;
56    } else if (!strcmp(argv[0], "install-kernc")) {
57        flags->cmd = Command::kInstallKernc;
58    } else if (!strcmp(argv[0], "install-zircona")) {
59        flags->cmd = Command::kInstallZirconA;
60    } else if (!strcmp(argv[0], "install-zirconb")) {
61        flags->cmd = Command::kInstallZirconB;
62    } else if (!strcmp(argv[0], "install-zirconr")) {
63        flags->cmd = Command::kInstallZirconR;
64    } else if (!strcmp(argv[0], "install-fvm")) {
65        flags->cmd = Command::kInstallFvm;
66    } else if (!strcmp(argv[0], "wipe")) {
67        flags->cmd = Command::kWipe;
68    } else {
69        ERROR("Invalid command: %s\n", argv[0]);
70        return false;
71    }
72    SHIFT_ARGS;
73
74    // Parse options.
75    flags->force = false;
76#if defined(__x86_64__)
77    flags->arch = Arch::X64;
78#elif defined(__aarch64__)
79    flags->arch = Arch::ARM64;
80#endif
81    flags->payload_fd.reset(STDIN_FILENO);
82    while (argc > 0) {
83        if (!strcmp(argv[0], "--file")) {
84            SHIFT_ARGS;
85            if (argc < 1) {
86                ERROR("'--file' argument requires a file\n");
87                return false;
88            }
89            flags->payload_fd.reset(open(argv[0], O_RDONLY));
90            if (!flags->payload_fd) {
91                ERROR("Couldn't open supplied file\n");
92                return false;
93            }
94        } else if (!strcmp(argv[0], "--force")) {
95            flags->force = true;
96        } else {
97            return false;
98        }
99        SHIFT_ARGS;
100    }
101    return true;
102#undef SHIFT_ARGS
103}
104
105} // namespace
106
107int main(int argc, char** argv) {
108    Flags flags;
109    if (!(ParseFlags(argc, argv, &flags))) {
110        PrintUsage();
111        return -1;
112    }
113    return paver::RealMain(fbl::move(flags)) == ZX_OK ? 0 : -1;
114}
115