OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <sys/types.h> | 5 #include <sys/types.h> |
6 #include <sys/stat.h> | 6 #include <sys/stat.h> |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <unistd.h> | 9 #include <unistd.h> |
10 | 10 |
11 #include <set> | 11 #include <set> |
12 #include <string> | 12 #include <string> |
13 #include <vector> | 13 #include <vector> |
14 | 14 |
15 #include <base/command_line.h> | 15 #include <base/command_line.h> |
16 #include <base/logging.h> | 16 #include <base/logging.h> |
17 #include <gflags/gflags.h> | 17 #include <gflags/gflags.h> |
18 #include <glib.h> | 18 #include <glib.h> |
19 | 19 |
20 #include "update_engine/delta_diff_generator.h" | 20 #include "update_engine/delta_diff_generator.h" |
21 #include "update_engine/delta_performer.h" | 21 #include "update_engine/delta_performer.h" |
22 #include "update_engine/payload_signer.h" | |
22 #include "update_engine/prefs.h" | 23 #include "update_engine/prefs.h" |
23 #include "update_engine/subprocess.h" | 24 #include "update_engine/subprocess.h" |
24 #include "update_engine/terminator.h" | 25 #include "update_engine/terminator.h" |
25 #include "update_engine/update_metadata.pb.h" | 26 #include "update_engine/update_metadata.pb.h" |
26 #include "update_engine/utils.h" | 27 #include "update_engine/utils.h" |
27 | 28 |
28 DEFINE_string(old_dir, "", | 29 DEFINE_string(old_dir, "", |
29 "Directory where the old rootfs is loop mounted read-only"); | 30 "Directory where the old rootfs is loop mounted read-only."); |
adlr
2011/01/13 20:42:37
be consistent w/ adding a period to the end of hel
petkov
2011/01/13 20:47:35
Done.
| |
30 DEFINE_string(new_dir, "", | 31 DEFINE_string(new_dir, "", |
31 "Directory where the new rootfs is loop mounted read-only"); | 32 "Directory where the new rootfs is loop mounted read-only"); |
32 DEFINE_string(old_image, "", "Path to the old rootfs"); | 33 DEFINE_string(old_image, "", "Path to the old rootfs"); |
33 DEFINE_string(new_image, "", "Path to the new rootfs"); | 34 DEFINE_string(new_image, "", "Path to the new rootfs"); |
34 DEFINE_string(out_file, "", "Path to output file"); | |
35 DEFINE_string(old_kernel, "", "Path to the old kernel partition image"); | 35 DEFINE_string(old_kernel, "", "Path to the old kernel partition image"); |
36 DEFINE_string(new_kernel, "", "Path to the new kernel partition image"); | 36 DEFINE_string(new_kernel, "", "Path to the new kernel partition image"); |
37 DEFINE_string(in_file, "", | |
38 "Path to input delta payload file used to hash/sign payloads " | |
39 "and apply delta over old_image (for debugging)"); | |
40 DEFINE_string(out_file, "", "Path to output delta payload file"); | |
41 DEFINE_string(out_hash_file, "", "Path to output hash file"); | |
37 DEFINE_string(private_key, "", "Path to private key in .pem format"); | 42 DEFINE_string(private_key, "", "Path to private key in .pem format"); |
38 DEFINE_string(apply_delta, "", | |
39 "If set, apply delta over old_image. (For debugging.)"); | |
40 DEFINE_string(prefs_dir, "/tmp/update_engine_prefs", | 43 DEFINE_string(prefs_dir, "/tmp/update_engine_prefs", |
41 "Preferences directory, used with apply_delta."); | 44 "Preferences directory, used with apply_delta."); |
45 DEFINE_int32(signature_size, 0, "Raw signature size used for hash calculation"); | |
46 DEFINE_string(signature_file, "", "Raw signature file to sign payload with"); | |
42 | 47 |
43 // This file contains a simple program that takes an old path, a new path, | 48 // This file contains a simple program that takes an old path, a new path, |
44 // and an output file as arguments and the path to an output file and | 49 // and an output file as arguments and the path to an output file and |
45 // generates a delta that can be sent to Chrome OS clients. | 50 // generates a delta that can be sent to Chrome OS clients. |
46 | 51 |
47 using std::set; | 52 using std::set; |
48 using std::string; | 53 using std::string; |
49 using std::vector; | 54 using std::vector; |
50 | 55 |
51 namespace chromeos_update_engine { | 56 namespace chromeos_update_engine { |
52 | 57 |
53 namespace { | 58 namespace { |
54 | 59 |
55 bool IsDir(const char* path) { | 60 bool IsDir(const char* path) { |
56 struct stat stbuf; | 61 struct stat stbuf; |
57 TEST_AND_RETURN_FALSE_ERRNO(lstat(path, &stbuf) == 0); | 62 TEST_AND_RETURN_FALSE_ERRNO(lstat(path, &stbuf) == 0); |
58 return S_ISDIR(stbuf.st_mode); | 63 return S_ISDIR(stbuf.st_mode); |
59 } | 64 } |
60 | 65 |
66 void CalculatePayloadHashForSigning() { | |
67 LOG(INFO) << "Calculating payload hash for signing."; | |
68 LOG_IF(FATAL, FLAGS_in_file.empty()) | |
69 << "Must pass --in_file to calculate hash for signing."; | |
70 LOG_IF(FATAL, FLAGS_out_hash_file.empty()) | |
71 << "Must pass --out_hash_file to calculate hash for signing."; | |
72 LOG_IF(FATAL, FLAGS_signature_size <= 0) | |
73 << "Must pass --signature_size to calculate hash for signing."; | |
74 vector<char> hash; | |
75 CHECK(PayloadSigner::HashPayloadForSigning( | |
76 FLAGS_in_file, FLAGS_signature_size, &hash)); | |
77 CHECK(utils::WriteFile( | |
78 FLAGS_out_hash_file.c_str(), hash.data(), hash.size())); | |
79 LOG(INFO) << "Done calculating payload hash for signing."; | |
80 } | |
81 | |
82 void SignPayload() { | |
83 LOG(INFO) << "Signing payload."; | |
84 LOG_IF(FATAL, FLAGS_in_file.empty()) | |
85 << "Must pass --in_file to sign payload."; | |
86 LOG_IF(FATAL, FLAGS_out_file.empty()) | |
87 << "Must pass --out_file to sign payload."; | |
88 LOG_IF(FATAL, FLAGS_signature_file.empty()) | |
89 << "Must pass --signature_file to sign payload."; | |
90 vector<char> signature; | |
91 CHECK(utils::ReadFile(FLAGS_signature_file, &signature)); | |
92 CHECK(PayloadSigner::AddSignatureToPayload( | |
93 FLAGS_in_file, signature, FLAGS_out_file)); | |
94 LOG(INFO) << "Done signing payload."; | |
95 } | |
96 | |
97 void ApplyDelta() { | |
98 LOG(INFO) << "Applying delta."; | |
99 LOG_IF(FATAL, FLAGS_old_image.empty()) | |
100 << "Must pass --old_image to apply delta."; | |
101 Prefs prefs; | |
102 LOG(INFO) << "Setting up preferences under: " << FLAGS_prefs_dir; | |
103 LOG_IF(ERROR, !prefs.Init(FilePath(FLAGS_prefs_dir))) | |
104 << "Failed to initialize preferences."; | |
105 // Get original checksums | |
106 LOG(INFO) << "Calculating original checksums"; | |
107 PartitionInfo kern_info, root_info; | |
108 CHECK(DeltaDiffGenerator::InitializePartitionInfo(true, // is_kernel | |
109 FLAGS_old_kernel, | |
110 &kern_info)); | |
111 CHECK(DeltaDiffGenerator::InitializePartitionInfo(false, // is_kernel | |
112 FLAGS_old_image, | |
113 &root_info)); | |
114 vector<char> kern_hash(kern_info.hash().begin(), | |
115 kern_info.hash().end()); | |
116 vector<char> root_hash(root_info.hash().begin(), | |
117 root_info.hash().end()); | |
118 DeltaPerformer performer(&prefs); | |
119 performer.set_current_kernel_hash(kern_hash); | |
120 performer.set_current_rootfs_hash(root_hash); | |
121 CHECK_EQ(performer.Open(FLAGS_old_image.c_str(), 0, 0), 0); | |
122 CHECK(performer.OpenKernel(FLAGS_old_kernel.c_str())); | |
123 vector<char> buf(1024 * 1024); | |
124 int fd = open(FLAGS_in_file.c_str(), O_RDONLY, 0); | |
125 CHECK_GE(fd, 0); | |
126 ScopedFdCloser fd_closer(&fd); | |
127 for (off_t offset = 0;; offset += buf.size()) { | |
128 ssize_t bytes_read; | |
129 CHECK(utils::PReadAll(fd, &buf[0], buf.size(), offset, &bytes_read)); | |
130 if (bytes_read == 0) | |
131 break; | |
132 CHECK_EQ(performer.Write(&buf[0], bytes_read), bytes_read); | |
133 } | |
134 CHECK_EQ(performer.Close(), 0); | |
135 DeltaPerformer::ResetUpdateProgress(&prefs, false); | |
136 LOG(INFO) << "Done applying delta."; | |
137 } | |
138 | |
61 int Main(int argc, char** argv) { | 139 int Main(int argc, char** argv) { |
62 g_thread_init(NULL); | 140 g_thread_init(NULL); |
63 google::ParseCommandLineFlags(&argc, &argv, true); | 141 google::ParseCommandLineFlags(&argc, &argv, true); |
64 CommandLine::Init(argc, argv); | 142 CommandLine::Init(argc, argv); |
65 Terminator::Init(); | 143 Terminator::Init(); |
66 Subprocess::Init(); | 144 Subprocess::Init(); |
67 logging::InitLogging("delta_generator.log", | 145 logging::InitLogging("delta_generator.log", |
68 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, | 146 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, |
69 logging::DONT_LOCK_LOG_FILE, | 147 logging::DONT_LOCK_LOG_FILE, |
70 logging::APPEND_TO_OLD_LOG_FILE); | 148 logging::APPEND_TO_OLD_LOG_FILE); |
71 if (!FLAGS_apply_delta.empty()) { | 149 if (FLAGS_signature_size > 0 || !FLAGS_out_hash_file.empty()) { |
72 if (FLAGS_old_image.empty()) { | 150 CalculatePayloadHashForSigning(); |
73 LOG(FATAL) << "Must pass --old_image with --apply_delta."; | 151 return 0; |
74 } | 152 } |
75 Prefs prefs; | 153 if (!FLAGS_signature_file.empty()) { |
76 LOG(INFO) << "Setting up preferences under: " << FLAGS_prefs_dir; | 154 SignPayload(); |
77 LOG_IF(ERROR, !prefs.Init(FilePath(FLAGS_prefs_dir))) | 155 return 0; |
78 << "Failed to initialize preferences."; | 156 } |
79 // Get original checksums | 157 if (!FLAGS_in_file.empty()) { |
80 LOG(INFO) << "Calculating original checksums"; | 158 ApplyDelta(); |
81 PartitionInfo kern_info, root_info; | |
82 CHECK(DeltaDiffGenerator::InitializePartitionInfo(true, // is_kernel | |
83 FLAGS_old_kernel, | |
84 &kern_info)); | |
85 CHECK(DeltaDiffGenerator::InitializePartitionInfo(false, // is_kernel | |
86 FLAGS_old_image, | |
87 &root_info)); | |
88 vector<char> kern_hash(kern_info.hash().begin(), | |
89 kern_info.hash().end()); | |
90 vector<char> root_hash(root_info.hash().begin(), | |
91 root_info.hash().end()); | |
92 DeltaPerformer performer(&prefs); | |
93 performer.set_current_kernel_hash(kern_hash); | |
94 performer.set_current_rootfs_hash(root_hash); | |
95 CHECK_EQ(performer.Open(FLAGS_old_image.c_str(), 0, 0), 0); | |
96 CHECK(performer.OpenKernel(FLAGS_old_kernel.c_str())); | |
97 vector<char> buf(1024 * 1024); | |
98 int fd = open(FLAGS_apply_delta.c_str(), O_RDONLY, 0); | |
99 CHECK_GE(fd, 0); | |
100 ScopedFdCloser fd_closer(&fd); | |
101 for (off_t offset = 0;; offset += buf.size()) { | |
102 ssize_t bytes_read; | |
103 CHECK(utils::PReadAll(fd, &buf[0], buf.size(), offset, &bytes_read)); | |
104 if (bytes_read == 0) | |
105 break; | |
106 CHECK_EQ(performer.Write(&buf[0], bytes_read), bytes_read); | |
107 } | |
108 CHECK_EQ(performer.Close(), 0); | |
109 DeltaPerformer::ResetUpdateProgress(&prefs, false); | |
110 LOG(INFO) << "done applying delta."; | |
111 return 0; | 159 return 0; |
112 } | 160 } |
113 CHECK(!FLAGS_new_image.empty()); | 161 CHECK(!FLAGS_new_image.empty()); |
114 CHECK(!FLAGS_out_file.empty()); | 162 CHECK(!FLAGS_out_file.empty()); |
115 CHECK(!FLAGS_new_kernel.empty()); | 163 CHECK(!FLAGS_new_kernel.empty()); |
116 if (FLAGS_old_image.empty()) { | 164 if (FLAGS_old_image.empty()) { |
117 LOG(INFO) << "Generating full update"; | 165 LOG(INFO) << "Generating full update"; |
118 } else { | 166 } else { |
119 LOG(INFO) << "Generating delta update"; | 167 LOG(INFO) << "Generating delta update"; |
120 CHECK(!FLAGS_old_dir.empty()); | 168 CHECK(!FLAGS_old_dir.empty()); |
(...skipping 14 matching lines...) Expand all Loading... | |
135 return 0; | 183 return 0; |
136 } | 184 } |
137 | 185 |
138 } // namespace {} | 186 } // namespace {} |
139 | 187 |
140 } // namespace chromeos_update_engine | 188 } // namespace chromeos_update_engine |
141 | 189 |
142 int main(int argc, char** argv) { | 190 int main(int argc, char** argv) { |
143 return chromeos_update_engine::Main(argc, argv); | 191 return chromeos_update_engine::Main(argc, argv); |
144 } | 192 } |
OLD | NEW |