1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "updater.hpp"
18 
19 #include "bt.hpp"
20 #include "raw.hpp"
21 #include "updatehelper.hpp"
22 
23 #include <experimental/filesystem>
24 #include <fstream>
25 #include <memory>
26 #include <set>
27 #include <stdexcept>
28 
29 extern "C" {
30 #include "ipmitoolintf.h"
31 } // extern "C"
32 
33 std::unique_ptr<UploadManager> UploadManager::BuildUploadMgr(
34     const std::string& image, const std::string& hash,
35     UpdateHelperInterface* helper, DataInterface* dintf)
36 {
37     std::ifstream imageStream, hashStream;
38 
39     imageStream.open(image);
40     hashStream.open(hash);
41     if (imageStream.bad() || hashStream.bad())
42     {
43         return nullptr;
44     }
45 
46     int32_t imageSize = std::experimental::filesystem::file_size(image);
47     int32_t hashSize = std::experimental::filesystem::file_size(hash);
48 
49     return std::make_unique<UploadManager>(std::move(imageStream),
50                                            std::move(hashStream), imageSize,
51                                            hashSize, helper, dintf);
52 }
53 
54 void UploadManager::UpdateBMC()
55 {
56     /* Let's build the raw command input.
57      *
58      * The sequence is:
59      * FLASH_START_TRANSFER,
60      * FLASH_DATA_BLOCK x times. (or FLASH_EXTERNAL_DATA_BLOCK)
61      * FLASH_DATA_FINISH
62      * FLASH_START_HASH
63      * FLASH_HASH_DATA x times. (or FLASH_EXTERNAL_HASH_BLOCK)
64      * FLASH_HASH_FINISH
65      * FLASH_DATA_VERIFY
66      * FLASH_VERIFY_CHECK x times.
67      */
68 
69     /* TODO: implement this. */
70 
71     /* UploadImage() */
72     /* UploadHash() */
73 
74     /*
75      * FLASH_DATA_VERIFY - The verify command will trigger verification of the
76      * image against the signature file sent down.
77      */
78     //  ret = helper_->SendEmptyCommand(FLASH_DATA_VERIFY, nullptr);
79     //  if (!ret.ok()) return ret;
80 
81     return;
82 }
83 
84 void UpdaterMain(const std::string& interface, const std::string& image,
85                  const std::string& signature)
86 {
87     static const std::set<std::string> supportedInterfaces = {"ipmibt"};
88 
89     /* Check if interface is supported. */
90     if (!supportedInterfaces.count(interface))
91     {
92         throw std::runtime_error("Unsupported interface");
93     }
94 
95     /* NOTE: Presently, the hash signature being separate is optional on the BMC
96      * but isn't here, for now.
97      */
98 
99     /* There are three key components to the process.  There's the data handler,
100      * which deals with sending the data, and it uses a convenience method to
101      * package the specific IPMI firmware update commands, and those commands
102      * are then routed through a convenience layer that will handle calling into
103      * the C-library.
104      */
105     IpmiRaw raw;
106     IpmiUpdateHelper ipmih(&raw);
107     std::unique_ptr<DataInterface> handler;
108 
109     if (interface == "ipmibt")
110     {
111         handler = std::make_unique<BtDataHandler>(&ipmih);
112     }
113 
114     if (handler == nullptr)
115     {
116         throw std::runtime_error("Unable to build interface handler.");
117     }
118 
119     auto updater =
120         UploadManager::BuildUploadMgr(image, signature, &ipmih, handler.get());
121 
122     if (updater == nullptr)
123     {
124         throw std::runtime_error("Unable to build update manager.");
125     }
126 
127     updater->UpdateBMC();
128 
129     return;
130 }
131