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 <lib/bootfs/parser.h>
6 
7 #include <inttypes.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <lib/zx/vmar.h>
13 #include <lib/zx/vmo.h>
14 #include <zircon/boot/bootdata.h>
15 #include <zircon/process.h>
16 #include <zircon/syscalls.h>
17 #include <zircon/types.h>
18 
19 namespace bootfs {
20 
~Parser()21 Parser::~Parser() {
22     if (dir_) {
23         uintptr_t addr = reinterpret_cast<uintptr_t>(dir_) - sizeof(bootfs_header_t);
24         zx::vmar::root_self()->unmap(addr, MappingSize());
25     }
26 }
27 
Init(zx::unowned_vmo vmo)28 zx_status_t Parser::Init(zx::unowned_vmo vmo) {
29     if (dir_ != nullptr) {
30         return ZX_ERR_BAD_STATE;
31     }
32 
33     bootfs_header_t hdr;
34     zx_status_t r = vmo->read(&hdr, 0, sizeof(hdr));
35     if (r != ZX_OK) {
36         printf("Parser::Init: couldn't read boot_data - %d\n", r);
37         return r;
38     }
39     if (hdr.magic != BOOTFS_MAGIC) {
40         printf("Parser::Init: incorrect bootdata header: %x\n", hdr.magic);
41         return ZX_ERR_IO;
42     }
43     zx_vaddr_t addr = 0;
44     if ((r = zx::vmar::root_self()->map(0, *vmo, 0, sizeof(hdr) + hdr.dirsize,
45                                         ZX_VM_PERM_READ, &addr)) != ZX_OK) {
46         printf("Parser::Init: couldn't map directory: %d\n", r);
47         return r;
48     }
49     dirsize_ = hdr.dirsize;
50     dir_ = reinterpret_cast<char*>(addr) + sizeof(hdr);
51     return ZX_OK;
52 }
53 
Parse(Callback callback)54 zx_status_t Parser::Parse(Callback callback) {
55     if (dir_ == nullptr) {
56         return ZX_ERR_BAD_STATE;
57     }
58     size_t avail = dirsize_;
59     auto* p = static_cast<char*>(dir_);
60     zx_status_t r;
61     while (avail > sizeof(bootfs_entry_t)) {
62         auto e = reinterpret_cast<bootfs_entry_t*>(p);
63         size_t sz = BOOTFS_RECSIZE(e);
64         if ((e->name_len < 1) || (e->name_len > BOOTFS_MAX_NAME_LEN) ||
65             (e->name[e->name_len - 1] != 0) || (sz > avail)) {
66             printf("bootfs: bogus entry!\n");
67             return ZX_ERR_IO;
68         }
69         if ((r = callback(e)) != ZX_OK) {
70             return r;
71         }
72         p += sz;
73         avail -= sz;
74     }
75     return ZX_OK;
76 }
77 
78 } // namespace bootfs
79