1*5a923131SAndroid Build Coastguard Worker //
2*5a923131SAndroid Build Coastguard Worker // Copyright (C) 2012 The Android Open Source Project
3*5a923131SAndroid Build Coastguard Worker //
4*5a923131SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*5a923131SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*5a923131SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*5a923131SAndroid Build Coastguard Worker //
8*5a923131SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
9*5a923131SAndroid Build Coastguard Worker //
10*5a923131SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*5a923131SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*5a923131SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5a923131SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*5a923131SAndroid Build Coastguard Worker // limitations under the License.
15*5a923131SAndroid Build Coastguard Worker //
16*5a923131SAndroid Build Coastguard Worker
17*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/utils.h"
18*5a923131SAndroid Build Coastguard Worker
19*5a923131SAndroid Build Coastguard Worker #include <stdint.h>
20*5a923131SAndroid Build Coastguard Worker
21*5a923131SAndroid Build Coastguard Worker #include <dirent.h>
22*5a923131SAndroid Build Coastguard Worker #include <elf.h>
23*5a923131SAndroid Build Coastguard Worker #include <endian.h>
24*5a923131SAndroid Build Coastguard Worker #include <errno.h>
25*5a923131SAndroid Build Coastguard Worker #include <fcntl.h>
26*5a923131SAndroid Build Coastguard Worker #include <stdio.h>
27*5a923131SAndroid Build Coastguard Worker #include <stdlib.h>
28*5a923131SAndroid Build Coastguard Worker #include <string.h>
29*5a923131SAndroid Build Coastguard Worker #include <sys/mount.h>
30*5a923131SAndroid Build Coastguard Worker #include <sys/resource.h>
31*5a923131SAndroid Build Coastguard Worker #include <sys/sendfile.h>
32*5a923131SAndroid Build Coastguard Worker #include <sys/stat.h>
33*5a923131SAndroid Build Coastguard Worker #include <sys/types.h>
34*5a923131SAndroid Build Coastguard Worker #include <time.h>
35*5a923131SAndroid Build Coastguard Worker #include <unistd.h>
36*5a923131SAndroid Build Coastguard Worker
37*5a923131SAndroid Build Coastguard Worker #include <algorithm>
38*5a923131SAndroid Build Coastguard Worker #include <filesystem>
39*5a923131SAndroid Build Coastguard Worker #include <utility>
40*5a923131SAndroid Build Coastguard Worker #include <vector>
41*5a923131SAndroid Build Coastguard Worker
42*5a923131SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
43*5a923131SAndroid Build Coastguard Worker #include <android-base/strings.h>
44*5a923131SAndroid Build Coastguard Worker #include <base/callback.h>
45*5a923131SAndroid Build Coastguard Worker #include <base/files/file_path.h>
46*5a923131SAndroid Build Coastguard Worker #include <base/files/file_util.h>
47*5a923131SAndroid Build Coastguard Worker #include <base/files/scoped_file.h>
48*5a923131SAndroid Build Coastguard Worker #include <base/format_macros.h>
49*5a923131SAndroid Build Coastguard Worker #include <base/location.h>
50*5a923131SAndroid Build Coastguard Worker #include <base/logging.h>
51*5a923131SAndroid Build Coastguard Worker #include <base/posix/eintr_wrapper.h>
52*5a923131SAndroid Build Coastguard Worker #include <base/rand_util.h>
53*5a923131SAndroid Build Coastguard Worker #include <base/strings/string_number_conversions.h>
54*5a923131SAndroid Build Coastguard Worker #include <base/strings/string_split.h>
55*5a923131SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
56*5a923131SAndroid Build Coastguard Worker #include <brillo/data_encoding.h>
57*5a923131SAndroid Build Coastguard Worker
58*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/constants.h"
59*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/subprocess.h"
60*5a923131SAndroid Build Coastguard Worker #ifdef __ANDROID__
61*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/platform_constants.h"
62*5a923131SAndroid Build Coastguard Worker #endif
63*5a923131SAndroid Build Coastguard Worker #include "update_engine/payload_consumer/file_descriptor.h"
64*5a923131SAndroid Build Coastguard Worker
65*5a923131SAndroid Build Coastguard Worker using base::Time;
66*5a923131SAndroid Build Coastguard Worker using base::TimeDelta;
67*5a923131SAndroid Build Coastguard Worker using std::min;
68*5a923131SAndroid Build Coastguard Worker using std::numeric_limits;
69*5a923131SAndroid Build Coastguard Worker using std::string;
70*5a923131SAndroid Build Coastguard Worker using std::vector;
71*5a923131SAndroid Build Coastguard Worker
72*5a923131SAndroid Build Coastguard Worker namespace chromeos_update_engine {
73*5a923131SAndroid Build Coastguard Worker
74*5a923131SAndroid Build Coastguard Worker namespace {
75*5a923131SAndroid Build Coastguard Worker
76*5a923131SAndroid Build Coastguard Worker // The following constants control how UnmountFilesystem should retry if
77*5a923131SAndroid Build Coastguard Worker // umount() fails with an errno EBUSY, i.e. retry 5 times over the course of
78*5a923131SAndroid Build Coastguard Worker // one second.
79*5a923131SAndroid Build Coastguard Worker const int kUnmountMaxNumOfRetries = 5;
80*5a923131SAndroid Build Coastguard Worker const int kUnmountRetryIntervalInMicroseconds = 200 * 1000; // 200 ms
81*5a923131SAndroid Build Coastguard Worker
82*5a923131SAndroid Build Coastguard Worker // Number of bytes to read from a file to attempt to detect its contents. Used
83*5a923131SAndroid Build Coastguard Worker // in GetFileFormat.
84*5a923131SAndroid Build Coastguard Worker const int kGetFileFormatMaxHeaderSize = 32;
85*5a923131SAndroid Build Coastguard Worker
86*5a923131SAndroid Build Coastguard Worker // The path to the kernel's boot_id.
87*5a923131SAndroid Build Coastguard Worker const char kBootIdPath[] = "/proc/sys/kernel/random/boot_id";
88*5a923131SAndroid Build Coastguard Worker
89*5a923131SAndroid Build Coastguard Worker } // namespace
90*5a923131SAndroid Build Coastguard Worker // If |path| is absolute, or explicit relative to the current working directory,
91*5a923131SAndroid Build Coastguard Worker // leaves it as is. Otherwise, uses the system's temp directory, as defined by
92*5a923131SAndroid Build Coastguard Worker // base::GetTempDir() and prepends it to |path|. On success stores the full
93*5a923131SAndroid Build Coastguard Worker // temporary path in |template_path| and returns true.
GetTempName(const string & path,base::FilePath * template_path)94*5a923131SAndroid Build Coastguard Worker bool GetTempName(const string& path, base::FilePath* template_path) {
95*5a923131SAndroid Build Coastguard Worker if (path[0] == '/' ||
96*5a923131SAndroid Build Coastguard Worker base::StartsWith(path, "./", base::CompareCase::SENSITIVE) ||
97*5a923131SAndroid Build Coastguard Worker base::StartsWith(path, "../", base::CompareCase::SENSITIVE)) {
98*5a923131SAndroid Build Coastguard Worker *template_path = base::FilePath(path);
99*5a923131SAndroid Build Coastguard Worker return true;
100*5a923131SAndroid Build Coastguard Worker }
101*5a923131SAndroid Build Coastguard Worker
102*5a923131SAndroid Build Coastguard Worker base::FilePath temp_dir;
103*5a923131SAndroid Build Coastguard Worker #ifdef __ANDROID__
104*5a923131SAndroid Build Coastguard Worker temp_dir = base::FilePath(constants::kNonVolatileDirectory).Append("tmp");
105*5a923131SAndroid Build Coastguard Worker #else
106*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE(base::GetTempDir(&temp_dir));
107*5a923131SAndroid Build Coastguard Worker #endif // __ANDROID__
108*5a923131SAndroid Build Coastguard Worker if (!base::PathExists(temp_dir))
109*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE(base::CreateDirectory(temp_dir));
110*5a923131SAndroid Build Coastguard Worker *template_path = temp_dir.Append(path);
111*5a923131SAndroid Build Coastguard Worker return true;
112*5a923131SAndroid Build Coastguard Worker }
113*5a923131SAndroid Build Coastguard Worker
114*5a923131SAndroid Build Coastguard Worker namespace utils {
115*5a923131SAndroid Build Coastguard Worker
WriteFile(const char * path,const void * data,size_t data_len)116*5a923131SAndroid Build Coastguard Worker bool WriteFile(const char* path, const void* data, size_t data_len) {
117*5a923131SAndroid Build Coastguard Worker int fd = HANDLE_EINTR(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600));
118*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
119*5a923131SAndroid Build Coastguard Worker ScopedFdCloser fd_closer(&fd);
120*5a923131SAndroid Build Coastguard Worker return WriteAll(fd, data, data_len);
121*5a923131SAndroid Build Coastguard Worker }
122*5a923131SAndroid Build Coastguard Worker
ReadAll(int fd,void * buf,size_t count,size_t * out_bytes_read,bool * eof)123*5a923131SAndroid Build Coastguard Worker bool ReadAll(
124*5a923131SAndroid Build Coastguard Worker int fd, void* buf, size_t count, size_t* out_bytes_read, bool* eof) {
125*5a923131SAndroid Build Coastguard Worker char* c_buf = static_cast<char*>(buf);
126*5a923131SAndroid Build Coastguard Worker size_t bytes_read = 0;
127*5a923131SAndroid Build Coastguard Worker *eof = false;
128*5a923131SAndroid Build Coastguard Worker while (bytes_read < count) {
129*5a923131SAndroid Build Coastguard Worker ssize_t rc = HANDLE_EINTR(read(fd, c_buf + bytes_read, count - bytes_read));
130*5a923131SAndroid Build Coastguard Worker if (rc < 0) {
131*5a923131SAndroid Build Coastguard Worker // EAGAIN and EWOULDBLOCK are normal return values when there's no more
132*5a923131SAndroid Build Coastguard Worker // input and we are in non-blocking mode.
133*5a923131SAndroid Build Coastguard Worker if (errno != EWOULDBLOCK && errno != EAGAIN) {
134*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Error reading fd " << fd;
135*5a923131SAndroid Build Coastguard Worker *out_bytes_read = bytes_read;
136*5a923131SAndroid Build Coastguard Worker return false;
137*5a923131SAndroid Build Coastguard Worker }
138*5a923131SAndroid Build Coastguard Worker break;
139*5a923131SAndroid Build Coastguard Worker } else if (rc == 0) {
140*5a923131SAndroid Build Coastguard Worker // A value of 0 means that we reached EOF and there is nothing else to
141*5a923131SAndroid Build Coastguard Worker // read from this fd.
142*5a923131SAndroid Build Coastguard Worker *eof = true;
143*5a923131SAndroid Build Coastguard Worker break;
144*5a923131SAndroid Build Coastguard Worker } else {
145*5a923131SAndroid Build Coastguard Worker bytes_read += rc;
146*5a923131SAndroid Build Coastguard Worker }
147*5a923131SAndroid Build Coastguard Worker }
148*5a923131SAndroid Build Coastguard Worker *out_bytes_read = bytes_read;
149*5a923131SAndroid Build Coastguard Worker return true;
150*5a923131SAndroid Build Coastguard Worker }
151*5a923131SAndroid Build Coastguard Worker
WriteAll(int fd,const void * buf,size_t count)152*5a923131SAndroid Build Coastguard Worker bool WriteAll(int fd, const void* buf, size_t count) {
153*5a923131SAndroid Build Coastguard Worker const char* c_buf = static_cast<const char*>(buf);
154*5a923131SAndroid Build Coastguard Worker ssize_t bytes_written = 0;
155*5a923131SAndroid Build Coastguard Worker while (bytes_written < static_cast<ssize_t>(count)) {
156*5a923131SAndroid Build Coastguard Worker ssize_t rc = write(fd, c_buf + bytes_written, count - bytes_written);
157*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
158*5a923131SAndroid Build Coastguard Worker bytes_written += rc;
159*5a923131SAndroid Build Coastguard Worker }
160*5a923131SAndroid Build Coastguard Worker return true;
161*5a923131SAndroid Build Coastguard Worker }
162*5a923131SAndroid Build Coastguard Worker
PWriteAll(int fd,const void * buf,size_t count,off_t offset)163*5a923131SAndroid Build Coastguard Worker bool PWriteAll(int fd, const void* buf, size_t count, off_t offset) {
164*5a923131SAndroid Build Coastguard Worker const char* c_buf = static_cast<const char*>(buf);
165*5a923131SAndroid Build Coastguard Worker size_t bytes_written = 0;
166*5a923131SAndroid Build Coastguard Worker int num_attempts = 0;
167*5a923131SAndroid Build Coastguard Worker while (bytes_written < count) {
168*5a923131SAndroid Build Coastguard Worker num_attempts++;
169*5a923131SAndroid Build Coastguard Worker ssize_t rc = pwrite(fd,
170*5a923131SAndroid Build Coastguard Worker c_buf + bytes_written,
171*5a923131SAndroid Build Coastguard Worker count - bytes_written,
172*5a923131SAndroid Build Coastguard Worker offset + bytes_written);
173*5a923131SAndroid Build Coastguard Worker // TODO(garnold) for debugging failure in chromium-os:31077; to be removed.
174*5a923131SAndroid Build Coastguard Worker if (rc < 0) {
175*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "pwrite error; num_attempts=" << num_attempts
176*5a923131SAndroid Build Coastguard Worker << " bytes_written=" << bytes_written << " count=" << count
177*5a923131SAndroid Build Coastguard Worker << " offset=" << offset;
178*5a923131SAndroid Build Coastguard Worker }
179*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
180*5a923131SAndroid Build Coastguard Worker bytes_written += rc;
181*5a923131SAndroid Build Coastguard Worker }
182*5a923131SAndroid Build Coastguard Worker return true;
183*5a923131SAndroid Build Coastguard Worker }
184*5a923131SAndroid Build Coastguard Worker
WriteAll(FileDescriptor * fd,const void * buf,size_t count)185*5a923131SAndroid Build Coastguard Worker bool WriteAll(FileDescriptor* fd, const void* buf, size_t count) {
186*5a923131SAndroid Build Coastguard Worker const char* c_buf = static_cast<const char*>(buf);
187*5a923131SAndroid Build Coastguard Worker ssize_t bytes_written = 0;
188*5a923131SAndroid Build Coastguard Worker while (bytes_written < static_cast<ssize_t>(count)) {
189*5a923131SAndroid Build Coastguard Worker ssize_t rc = fd->Write(c_buf + bytes_written, count - bytes_written);
190*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
191*5a923131SAndroid Build Coastguard Worker bytes_written += rc;
192*5a923131SAndroid Build Coastguard Worker }
193*5a923131SAndroid Build Coastguard Worker return true;
194*5a923131SAndroid Build Coastguard Worker }
195*5a923131SAndroid Build Coastguard Worker
WriteAll(const FileDescriptorPtr & fd,const void * buf,size_t count,off_t offset)196*5a923131SAndroid Build Coastguard Worker bool WriteAll(const FileDescriptorPtr& fd,
197*5a923131SAndroid Build Coastguard Worker const void* buf,
198*5a923131SAndroid Build Coastguard Worker size_t count,
199*5a923131SAndroid Build Coastguard Worker off_t offset) {
200*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(fd->Seek(offset, SEEK_SET) !=
201*5a923131SAndroid Build Coastguard Worker static_cast<off_t>(-1));
202*5a923131SAndroid Build Coastguard Worker return WriteAll(fd, buf, count);
203*5a923131SAndroid Build Coastguard Worker }
204*5a923131SAndroid Build Coastguard Worker
PReadAll(int fd,void * buf,size_t count,off_t offset,ssize_t * out_bytes_read)205*5a923131SAndroid Build Coastguard Worker bool PReadAll(
206*5a923131SAndroid Build Coastguard Worker int fd, void* buf, size_t count, off_t offset, ssize_t* out_bytes_read) {
207*5a923131SAndroid Build Coastguard Worker char* c_buf = static_cast<char*>(buf);
208*5a923131SAndroid Build Coastguard Worker ssize_t bytes_read = 0;
209*5a923131SAndroid Build Coastguard Worker while (bytes_read < static_cast<ssize_t>(count)) {
210*5a923131SAndroid Build Coastguard Worker ssize_t rc =
211*5a923131SAndroid Build Coastguard Worker pread(fd, c_buf + bytes_read, count - bytes_read, offset + bytes_read);
212*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
213*5a923131SAndroid Build Coastguard Worker if (rc == 0) {
214*5a923131SAndroid Build Coastguard Worker break;
215*5a923131SAndroid Build Coastguard Worker }
216*5a923131SAndroid Build Coastguard Worker bytes_read += rc;
217*5a923131SAndroid Build Coastguard Worker }
218*5a923131SAndroid Build Coastguard Worker *out_bytes_read = bytes_read;
219*5a923131SAndroid Build Coastguard Worker return true;
220*5a923131SAndroid Build Coastguard Worker }
221*5a923131SAndroid Build Coastguard Worker
ReadAll(FileDescriptor * fd,void * buf,size_t count,off_t offset,ssize_t * out_bytes_read)222*5a923131SAndroid Build Coastguard Worker bool ReadAll(FileDescriptor* fd,
223*5a923131SAndroid Build Coastguard Worker void* buf,
224*5a923131SAndroid Build Coastguard Worker size_t count,
225*5a923131SAndroid Build Coastguard Worker off_t offset,
226*5a923131SAndroid Build Coastguard Worker ssize_t* out_bytes_read) {
227*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(fd->Seek(offset, SEEK_SET) !=
228*5a923131SAndroid Build Coastguard Worker static_cast<off_t>(-1));
229*5a923131SAndroid Build Coastguard Worker char* c_buf = static_cast<char*>(buf);
230*5a923131SAndroid Build Coastguard Worker ssize_t bytes_read = 0;
231*5a923131SAndroid Build Coastguard Worker while (bytes_read < static_cast<ssize_t>(count)) {
232*5a923131SAndroid Build Coastguard Worker ssize_t rc = fd->Read(c_buf + bytes_read, count - bytes_read);
233*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
234*5a923131SAndroid Build Coastguard Worker if (rc == 0) {
235*5a923131SAndroid Build Coastguard Worker break;
236*5a923131SAndroid Build Coastguard Worker }
237*5a923131SAndroid Build Coastguard Worker bytes_read += rc;
238*5a923131SAndroid Build Coastguard Worker }
239*5a923131SAndroid Build Coastguard Worker *out_bytes_read = bytes_read;
240*5a923131SAndroid Build Coastguard Worker return true;
241*5a923131SAndroid Build Coastguard Worker }
242*5a923131SAndroid Build Coastguard Worker
PReadAll(FileDescriptor * fd,void * buf,size_t count,off_t offset,ssize_t * out_bytes_read)243*5a923131SAndroid Build Coastguard Worker bool PReadAll(FileDescriptor* fd,
244*5a923131SAndroid Build Coastguard Worker void* buf,
245*5a923131SAndroid Build Coastguard Worker size_t count,
246*5a923131SAndroid Build Coastguard Worker off_t offset,
247*5a923131SAndroid Build Coastguard Worker ssize_t* out_bytes_read) {
248*5a923131SAndroid Build Coastguard Worker auto old_off = fd->Seek(0, SEEK_CUR);
249*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(old_off >= 0);
250*5a923131SAndroid Build Coastguard Worker
251*5a923131SAndroid Build Coastguard Worker auto success = ReadAll(fd, buf, count, offset, out_bytes_read);
252*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(fd->Seek(old_off, SEEK_SET) == old_off);
253*5a923131SAndroid Build Coastguard Worker return success;
254*5a923131SAndroid Build Coastguard Worker }
255*5a923131SAndroid Build Coastguard Worker
PWriteAll(const FileDescriptorPtr & fd,const void * buf,size_t count,off_t offset)256*5a923131SAndroid Build Coastguard Worker bool PWriteAll(const FileDescriptorPtr& fd,
257*5a923131SAndroid Build Coastguard Worker const void* buf,
258*5a923131SAndroid Build Coastguard Worker size_t count,
259*5a923131SAndroid Build Coastguard Worker off_t offset) {
260*5a923131SAndroid Build Coastguard Worker auto old_off = fd->Seek(0, SEEK_CUR);
261*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(old_off >= 0);
262*5a923131SAndroid Build Coastguard Worker
263*5a923131SAndroid Build Coastguard Worker auto success = WriteAll(fd, buf, count, offset);
264*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(fd->Seek(old_off, SEEK_SET) == old_off);
265*5a923131SAndroid Build Coastguard Worker return success;
266*5a923131SAndroid Build Coastguard Worker }
267*5a923131SAndroid Build Coastguard Worker
268*5a923131SAndroid Build Coastguard Worker // Append |nbytes| of content from |buf| to the vector pointed to by either
269*5a923131SAndroid Build Coastguard Worker // |vec_p| or |str_p|.
AppendBytes(const uint8_t * buf,size_t nbytes,brillo::Blob * vec_p)270*5a923131SAndroid Build Coastguard Worker static void AppendBytes(const uint8_t* buf,
271*5a923131SAndroid Build Coastguard Worker size_t nbytes,
272*5a923131SAndroid Build Coastguard Worker brillo::Blob* vec_p) {
273*5a923131SAndroid Build Coastguard Worker CHECK(buf);
274*5a923131SAndroid Build Coastguard Worker CHECK(vec_p);
275*5a923131SAndroid Build Coastguard Worker vec_p->insert(vec_p->end(), buf, buf + nbytes);
276*5a923131SAndroid Build Coastguard Worker }
AppendBytes(const uint8_t * buf,size_t nbytes,string * str_p)277*5a923131SAndroid Build Coastguard Worker static void AppendBytes(const uint8_t* buf, size_t nbytes, string* str_p) {
278*5a923131SAndroid Build Coastguard Worker CHECK(buf);
279*5a923131SAndroid Build Coastguard Worker CHECK(str_p);
280*5a923131SAndroid Build Coastguard Worker str_p->append(buf, buf + nbytes);
281*5a923131SAndroid Build Coastguard Worker }
282*5a923131SAndroid Build Coastguard Worker
283*5a923131SAndroid Build Coastguard Worker // Reads from an open file |fp|, appending the read content to the container
284*5a923131SAndroid Build Coastguard Worker // pointer to by |out_p|. Returns true upon successful reading all of the
285*5a923131SAndroid Build Coastguard Worker // file's content, false otherwise. If |size| is not -1, reads up to |size|
286*5a923131SAndroid Build Coastguard Worker // bytes.
287*5a923131SAndroid Build Coastguard Worker template <class T>
Read(FILE * fp,off_t size,T * out_p)288*5a923131SAndroid Build Coastguard Worker static bool Read(FILE* fp, off_t size, T* out_p) {
289*5a923131SAndroid Build Coastguard Worker CHECK(fp);
290*5a923131SAndroid Build Coastguard Worker CHECK(size == -1 || size >= 0);
291*5a923131SAndroid Build Coastguard Worker uint8_t buf[1024];
292*5a923131SAndroid Build Coastguard Worker while (size == -1 || size > 0) {
293*5a923131SAndroid Build Coastguard Worker off_t bytes_to_read = sizeof(buf);
294*5a923131SAndroid Build Coastguard Worker if (size > 0 && bytes_to_read > size) {
295*5a923131SAndroid Build Coastguard Worker bytes_to_read = size;
296*5a923131SAndroid Build Coastguard Worker }
297*5a923131SAndroid Build Coastguard Worker size_t nbytes = fread(buf, 1, bytes_to_read, fp);
298*5a923131SAndroid Build Coastguard Worker if (!nbytes) {
299*5a923131SAndroid Build Coastguard Worker break;
300*5a923131SAndroid Build Coastguard Worker }
301*5a923131SAndroid Build Coastguard Worker AppendBytes(buf, nbytes, out_p);
302*5a923131SAndroid Build Coastguard Worker if (size != -1) {
303*5a923131SAndroid Build Coastguard Worker CHECK(size >= static_cast<off_t>(nbytes));
304*5a923131SAndroid Build Coastguard Worker size -= nbytes;
305*5a923131SAndroid Build Coastguard Worker }
306*5a923131SAndroid Build Coastguard Worker }
307*5a923131SAndroid Build Coastguard Worker if (ferror(fp)) {
308*5a923131SAndroid Build Coastguard Worker return false;
309*5a923131SAndroid Build Coastguard Worker }
310*5a923131SAndroid Build Coastguard Worker return size == 0 || feof(fp);
311*5a923131SAndroid Build Coastguard Worker }
312*5a923131SAndroid Build Coastguard Worker
313*5a923131SAndroid Build Coastguard Worker // Opens a file |path| for reading and appends its the contents to a container
314*5a923131SAndroid Build Coastguard Worker // |out_p|. Starts reading the file from |offset|. If |offset| is beyond the end
315*5a923131SAndroid Build Coastguard Worker // of the file, returns success. If |size| is not -1, reads up to |size| bytes.
316*5a923131SAndroid Build Coastguard Worker template <class T>
ReadFileChunkAndAppend(const string & path,off_t offset,off_t size,T * out_p)317*5a923131SAndroid Build Coastguard Worker static bool ReadFileChunkAndAppend(const string& path,
318*5a923131SAndroid Build Coastguard Worker off_t offset,
319*5a923131SAndroid Build Coastguard Worker off_t size,
320*5a923131SAndroid Build Coastguard Worker T* out_p) {
321*5a923131SAndroid Build Coastguard Worker CHECK_GE(offset, 0);
322*5a923131SAndroid Build Coastguard Worker CHECK(size == -1 || size >= 0);
323*5a923131SAndroid Build Coastguard Worker base::ScopedFILE fp(fopen(path.c_str(), "r"));
324*5a923131SAndroid Build Coastguard Worker if (!fp.get())
325*5a923131SAndroid Build Coastguard Worker return false;
326*5a923131SAndroid Build Coastguard Worker if (offset) {
327*5a923131SAndroid Build Coastguard Worker // Return success without appending any data if a chunk beyond the end of
328*5a923131SAndroid Build Coastguard Worker // the file is requested.
329*5a923131SAndroid Build Coastguard Worker if (offset >= FileSize(path)) {
330*5a923131SAndroid Build Coastguard Worker return true;
331*5a923131SAndroid Build Coastguard Worker }
332*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(fseek(fp.get(), offset, SEEK_SET) == 0);
333*5a923131SAndroid Build Coastguard Worker }
334*5a923131SAndroid Build Coastguard Worker return Read(fp.get(), size, out_p);
335*5a923131SAndroid Build Coastguard Worker }
336*5a923131SAndroid Build Coastguard Worker
337*5a923131SAndroid Build Coastguard Worker // TODO(deymo): This is only used in unittest, but requires the private
338*5a923131SAndroid Build Coastguard Worker // Read<string>() defined here. Expose Read<string>() or move to base/ version.
ReadPipe(const string & cmd,string * out_p)339*5a923131SAndroid Build Coastguard Worker bool ReadPipe(const string& cmd, string* out_p) {
340*5a923131SAndroid Build Coastguard Worker FILE* fp = popen(cmd.c_str(), "r");
341*5a923131SAndroid Build Coastguard Worker if (!fp)
342*5a923131SAndroid Build Coastguard Worker return false;
343*5a923131SAndroid Build Coastguard Worker bool success = Read(fp, -1, out_p);
344*5a923131SAndroid Build Coastguard Worker return (success && pclose(fp) >= 0);
345*5a923131SAndroid Build Coastguard Worker }
346*5a923131SAndroid Build Coastguard Worker
ReadFile(const string & path,brillo::Blob * out_p)347*5a923131SAndroid Build Coastguard Worker bool ReadFile(const string& path, brillo::Blob* out_p) {
348*5a923131SAndroid Build Coastguard Worker return ReadFileChunkAndAppend(path, 0, -1, out_p);
349*5a923131SAndroid Build Coastguard Worker }
350*5a923131SAndroid Build Coastguard Worker
ReadFile(const string & path,string * out_p)351*5a923131SAndroid Build Coastguard Worker bool ReadFile(const string& path, string* out_p) {
352*5a923131SAndroid Build Coastguard Worker return ReadFileChunkAndAppend(path, 0, -1, out_p);
353*5a923131SAndroid Build Coastguard Worker }
354*5a923131SAndroid Build Coastguard Worker
ReadFileChunk(const string & path,off_t offset,off_t size,brillo::Blob * out_p)355*5a923131SAndroid Build Coastguard Worker bool ReadFileChunk(const string& path,
356*5a923131SAndroid Build Coastguard Worker off_t offset,
357*5a923131SAndroid Build Coastguard Worker off_t size,
358*5a923131SAndroid Build Coastguard Worker brillo::Blob* out_p) {
359*5a923131SAndroid Build Coastguard Worker return ReadFileChunkAndAppend(path, offset, size, out_p);
360*5a923131SAndroid Build Coastguard Worker }
361*5a923131SAndroid Build Coastguard Worker
BlockDevSize(int fd)362*5a923131SAndroid Build Coastguard Worker off_t BlockDevSize(int fd) {
363*5a923131SAndroid Build Coastguard Worker uint64_t dev_size{};
364*5a923131SAndroid Build Coastguard Worker int rc = ioctl(fd, BLKGETSIZE64, &dev_size);
365*5a923131SAndroid Build Coastguard Worker if (rc == -1) {
366*5a923131SAndroid Build Coastguard Worker dev_size = -1;
367*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Error running ioctl(BLKGETSIZE64) on " << fd;
368*5a923131SAndroid Build Coastguard Worker }
369*5a923131SAndroid Build Coastguard Worker return dev_size;
370*5a923131SAndroid Build Coastguard Worker }
371*5a923131SAndroid Build Coastguard Worker
FileSize(int fd)372*5a923131SAndroid Build Coastguard Worker off_t FileSize(int fd) {
373*5a923131SAndroid Build Coastguard Worker struct stat stbuf {};
374*5a923131SAndroid Build Coastguard Worker int rc = fstat(fd, &stbuf);
375*5a923131SAndroid Build Coastguard Worker CHECK_EQ(rc, 0);
376*5a923131SAndroid Build Coastguard Worker if (rc < 0) {
377*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Error stat-ing " << fd;
378*5a923131SAndroid Build Coastguard Worker return rc;
379*5a923131SAndroid Build Coastguard Worker }
380*5a923131SAndroid Build Coastguard Worker if (S_ISREG(stbuf.st_mode))
381*5a923131SAndroid Build Coastguard Worker return stbuf.st_size;
382*5a923131SAndroid Build Coastguard Worker if (S_ISBLK(stbuf.st_mode))
383*5a923131SAndroid Build Coastguard Worker return BlockDevSize(fd);
384*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "Couldn't determine the type of " << fd;
385*5a923131SAndroid Build Coastguard Worker return -1;
386*5a923131SAndroid Build Coastguard Worker }
387*5a923131SAndroid Build Coastguard Worker
FileSize(const string & path)388*5a923131SAndroid Build Coastguard Worker off_t FileSize(const string& path) {
389*5a923131SAndroid Build Coastguard Worker int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
390*5a923131SAndroid Build Coastguard Worker if (fd == -1) {
391*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Error opening " << path;
392*5a923131SAndroid Build Coastguard Worker return fd;
393*5a923131SAndroid Build Coastguard Worker }
394*5a923131SAndroid Build Coastguard Worker off_t size = FileSize(fd);
395*5a923131SAndroid Build Coastguard Worker if (size == -1)
396*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Error getting file size of " << path;
397*5a923131SAndroid Build Coastguard Worker close(fd);
398*5a923131SAndroid Build Coastguard Worker return size;
399*5a923131SAndroid Build Coastguard Worker }
400*5a923131SAndroid Build Coastguard Worker
SendFile(int out_fd,int in_fd,size_t count)401*5a923131SAndroid Build Coastguard Worker bool SendFile(int out_fd, int in_fd, size_t count) {
402*5a923131SAndroid Build Coastguard Worker off64_t offset = lseek(in_fd, 0, SEEK_CUR);
403*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(offset >= 0);
404*5a923131SAndroid Build Coastguard Worker constexpr size_t BUFFER_SIZE = 4096;
405*5a923131SAndroid Build Coastguard Worker while (count > 0) {
406*5a923131SAndroid Build Coastguard Worker const auto bytes_written =
407*5a923131SAndroid Build Coastguard Worker sendfile(out_fd, in_fd, &offset, std::min(count, BUFFER_SIZE));
408*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(bytes_written > 0);
409*5a923131SAndroid Build Coastguard Worker count -= bytes_written;
410*5a923131SAndroid Build Coastguard Worker }
411*5a923131SAndroid Build Coastguard Worker return true;
412*5a923131SAndroid Build Coastguard Worker }
413*5a923131SAndroid Build Coastguard Worker
DeleteDirectory(const char * dirname)414*5a923131SAndroid Build Coastguard Worker bool DeleteDirectory(const char* dirname) {
415*5a923131SAndroid Build Coastguard Worker if (!std::filesystem::exists(dirname)) {
416*5a923131SAndroid Build Coastguard Worker return true;
417*5a923131SAndroid Build Coastguard Worker }
418*5a923131SAndroid Build Coastguard Worker const std::string tmpdir = std::string(dirname) + "_deleted";
419*5a923131SAndroid Build Coastguard Worker std::filesystem::remove_all(tmpdir);
420*5a923131SAndroid Build Coastguard Worker if (rename(dirname, tmpdir.c_str()) != 0) {
421*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to rename " << dirname << " to " << tmpdir;
422*5a923131SAndroid Build Coastguard Worker return false;
423*5a923131SAndroid Build Coastguard Worker }
424*5a923131SAndroid Build Coastguard Worker std::filesystem::remove_all(tmpdir);
425*5a923131SAndroid Build Coastguard Worker return true;
426*5a923131SAndroid Build Coastguard Worker }
427*5a923131SAndroid Build Coastguard Worker
FsyncDirectoryContents(const char * dirname)428*5a923131SAndroid Build Coastguard Worker bool FsyncDirectoryContents(const char* dirname) {
429*5a923131SAndroid Build Coastguard Worker std::filesystem::path dir_path(dirname);
430*5a923131SAndroid Build Coastguard Worker
431*5a923131SAndroid Build Coastguard Worker std::error_code ec;
432*5a923131SAndroid Build Coastguard Worker if (!std::filesystem::exists(dir_path, ec) ||
433*5a923131SAndroid Build Coastguard Worker !std::filesystem::is_directory(dir_path, ec)) {
434*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "Error: Invalid directory path: " << dirname << std::endl;
435*5a923131SAndroid Build Coastguard Worker return false;
436*5a923131SAndroid Build Coastguard Worker }
437*5a923131SAndroid Build Coastguard Worker
438*5a923131SAndroid Build Coastguard Worker for (const auto& entry : std::filesystem::directory_iterator(dirname, ec)) {
439*5a923131SAndroid Build Coastguard Worker if (entry.is_regular_file()) {
440*5a923131SAndroid Build Coastguard Worker int fd = open(entry.path().c_str(), O_RDONLY | O_CLOEXEC);
441*5a923131SAndroid Build Coastguard Worker if (fd == -1) {
442*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "open failed: " << entry.path();
443*5a923131SAndroid Build Coastguard Worker return false;
444*5a923131SAndroid Build Coastguard Worker }
445*5a923131SAndroid Build Coastguard Worker
446*5a923131SAndroid Build Coastguard Worker if (fsync(fd) == -1) {
447*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "fsync failed";
448*5a923131SAndroid Build Coastguard Worker return false;
449*5a923131SAndroid Build Coastguard Worker }
450*5a923131SAndroid Build Coastguard Worker
451*5a923131SAndroid Build Coastguard Worker close(fd);
452*5a923131SAndroid Build Coastguard Worker }
453*5a923131SAndroid Build Coastguard Worker }
454*5a923131SAndroid Build Coastguard Worker
455*5a923131SAndroid Build Coastguard Worker return true;
456*5a923131SAndroid Build Coastguard Worker }
457*5a923131SAndroid Build Coastguard Worker
FsyncDirectory(const char * dirname)458*5a923131SAndroid Build Coastguard Worker bool FsyncDirectory(const char* dirname) {
459*5a923131SAndroid Build Coastguard Worker if (!FsyncDirectoryContents(dirname)) {
460*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "failed to fsync directory contents";
461*5a923131SAndroid Build Coastguard Worker return false;
462*5a923131SAndroid Build Coastguard Worker }
463*5a923131SAndroid Build Coastguard Worker android::base::unique_fd fd(
464*5a923131SAndroid Build Coastguard Worker TEMP_FAILURE_RETRY(open(dirname, O_RDONLY | O_CLOEXEC)));
465*5a923131SAndroid Build Coastguard Worker if (fd == -1) {
466*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to open " << dirname;
467*5a923131SAndroid Build Coastguard Worker return false;
468*5a923131SAndroid Build Coastguard Worker }
469*5a923131SAndroid Build Coastguard Worker if (fsync(fd) == -1) {
470*5a923131SAndroid Build Coastguard Worker if (errno == EROFS || errno == EINVAL) {
471*5a923131SAndroid Build Coastguard Worker PLOG(WARNING) << "Skip fsync " << dirname
472*5a923131SAndroid Build Coastguard Worker << " on a file system does not support synchronization";
473*5a923131SAndroid Build Coastguard Worker } else {
474*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to fsync " << dirname;
475*5a923131SAndroid Build Coastguard Worker return false;
476*5a923131SAndroid Build Coastguard Worker }
477*5a923131SAndroid Build Coastguard Worker }
478*5a923131SAndroid Build Coastguard Worker return true;
479*5a923131SAndroid Build Coastguard Worker }
480*5a923131SAndroid Build Coastguard Worker
WriteStringToFileAtomic(const std::string & path,std::string_view content)481*5a923131SAndroid Build Coastguard Worker bool WriteStringToFileAtomic(const std::string& path,
482*5a923131SAndroid Build Coastguard Worker std::string_view content) {
483*5a923131SAndroid Build Coastguard Worker const std::string tmp_path = path + ".tmp";
484*5a923131SAndroid Build Coastguard Worker {
485*5a923131SAndroid Build Coastguard Worker const int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
486*5a923131SAndroid Build Coastguard Worker android::base::unique_fd fd(
487*5a923131SAndroid Build Coastguard Worker TEMP_FAILURE_RETRY(open(tmp_path.c_str(), flags, 0644)));
488*5a923131SAndroid Build Coastguard Worker if (fd == -1) {
489*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to open " << path;
490*5a923131SAndroid Build Coastguard Worker return false;
491*5a923131SAndroid Build Coastguard Worker }
492*5a923131SAndroid Build Coastguard Worker if (!WriteAll(fd.get(), content.data(), content.size())) {
493*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write to fd " << fd;
494*5a923131SAndroid Build Coastguard Worker return false;
495*5a923131SAndroid Build Coastguard Worker }
496*5a923131SAndroid Build Coastguard Worker // rename() without fsync() is not safe. Data could still be living on page
497*5a923131SAndroid Build Coastguard Worker // cache. To ensure atomiticity, call fsync()
498*5a923131SAndroid Build Coastguard Worker if (fsync(fd) != 0) {
499*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to fsync " << tmp_path;
500*5a923131SAndroid Build Coastguard Worker }
501*5a923131SAndroid Build Coastguard Worker }
502*5a923131SAndroid Build Coastguard Worker if (rename(tmp_path.c_str(), path.c_str()) == -1) {
503*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "rename failed from " << tmp_path << " to " << path;
504*5a923131SAndroid Build Coastguard Worker return false;
505*5a923131SAndroid Build Coastguard Worker }
506*5a923131SAndroid Build Coastguard Worker return FsyncDirectory(std::filesystem::path(path).parent_path().c_str());
507*5a923131SAndroid Build Coastguard Worker }
508*5a923131SAndroid Build Coastguard Worker
HexDumpArray(const uint8_t * const arr,const size_t length)509*5a923131SAndroid Build Coastguard Worker void HexDumpArray(const uint8_t* const arr, const size_t length) {
510*5a923131SAndroid Build Coastguard Worker LOG(INFO) << "Logging array of length: " << length;
511*5a923131SAndroid Build Coastguard Worker const unsigned int bytes_per_line = 16;
512*5a923131SAndroid Build Coastguard Worker for (uint32_t i = 0; i < length; i += bytes_per_line) {
513*5a923131SAndroid Build Coastguard Worker const unsigned int bytes_remaining = length - i;
514*5a923131SAndroid Build Coastguard Worker const unsigned int bytes_per_this_line =
515*5a923131SAndroid Build Coastguard Worker min(bytes_per_line, bytes_remaining);
516*5a923131SAndroid Build Coastguard Worker char header[100];
517*5a923131SAndroid Build Coastguard Worker int r = snprintf(header, sizeof(header), "0x%08x : ", i);
518*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN(r == 13);
519*5a923131SAndroid Build Coastguard Worker string line = header;
520*5a923131SAndroid Build Coastguard Worker for (unsigned int j = 0; j < bytes_per_this_line; j++) {
521*5a923131SAndroid Build Coastguard Worker char buf[20];
522*5a923131SAndroid Build Coastguard Worker uint8_t c = arr[i + j];
523*5a923131SAndroid Build Coastguard Worker r = snprintf(buf, sizeof(buf), "%02x ", static_cast<unsigned int>(c));
524*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN(r == 3);
525*5a923131SAndroid Build Coastguard Worker line += buf;
526*5a923131SAndroid Build Coastguard Worker }
527*5a923131SAndroid Build Coastguard Worker LOG(INFO) << line;
528*5a923131SAndroid Build Coastguard Worker }
529*5a923131SAndroid Build Coastguard Worker }
530*5a923131SAndroid Build Coastguard Worker
SplitPartitionName(const string & partition_name,string * out_disk_name,int * out_partition_num)531*5a923131SAndroid Build Coastguard Worker bool SplitPartitionName(const string& partition_name,
532*5a923131SAndroid Build Coastguard Worker string* out_disk_name,
533*5a923131SAndroid Build Coastguard Worker int* out_partition_num) {
534*5a923131SAndroid Build Coastguard Worker if (!base::StartsWith(
535*5a923131SAndroid Build Coastguard Worker partition_name, "/dev/", base::CompareCase::SENSITIVE)) {
536*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "Invalid partition device name: " << partition_name;
537*5a923131SAndroid Build Coastguard Worker return false;
538*5a923131SAndroid Build Coastguard Worker }
539*5a923131SAndroid Build Coastguard Worker
540*5a923131SAndroid Build Coastguard Worker size_t last_nondigit_pos = partition_name.find_last_not_of("0123456789");
541*5a923131SAndroid Build Coastguard Worker if (last_nondigit_pos == string::npos ||
542*5a923131SAndroid Build Coastguard Worker (last_nondigit_pos + 1) == partition_name.size()) {
543*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "Unable to parse partition device name: " << partition_name;
544*5a923131SAndroid Build Coastguard Worker return false;
545*5a923131SAndroid Build Coastguard Worker }
546*5a923131SAndroid Build Coastguard Worker
547*5a923131SAndroid Build Coastguard Worker if (out_disk_name) {
548*5a923131SAndroid Build Coastguard Worker // Special case for MMC devices which have the following naming scheme:
549*5a923131SAndroid Build Coastguard Worker // mmcblk0p2
550*5a923131SAndroid Build Coastguard Worker size_t disk_name_len = last_nondigit_pos;
551*5a923131SAndroid Build Coastguard Worker if (partition_name[last_nondigit_pos] != 'p' || last_nondigit_pos == 0 ||
552*5a923131SAndroid Build Coastguard Worker !isdigit(partition_name[last_nondigit_pos - 1])) {
553*5a923131SAndroid Build Coastguard Worker disk_name_len++;
554*5a923131SAndroid Build Coastguard Worker }
555*5a923131SAndroid Build Coastguard Worker *out_disk_name = partition_name.substr(0, disk_name_len);
556*5a923131SAndroid Build Coastguard Worker }
557*5a923131SAndroid Build Coastguard Worker
558*5a923131SAndroid Build Coastguard Worker if (out_partition_num) {
559*5a923131SAndroid Build Coastguard Worker string partition_str = partition_name.substr(last_nondigit_pos + 1);
560*5a923131SAndroid Build Coastguard Worker *out_partition_num = atoi(partition_str.c_str());
561*5a923131SAndroid Build Coastguard Worker }
562*5a923131SAndroid Build Coastguard Worker return true;
563*5a923131SAndroid Build Coastguard Worker }
564*5a923131SAndroid Build Coastguard Worker
MakePartitionName(const string & disk_name,int partition_num)565*5a923131SAndroid Build Coastguard Worker string MakePartitionName(const string& disk_name, int partition_num) {
566*5a923131SAndroid Build Coastguard Worker if (partition_num < 1) {
567*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "Invalid partition number: " << partition_num;
568*5a923131SAndroid Build Coastguard Worker return string();
569*5a923131SAndroid Build Coastguard Worker }
570*5a923131SAndroid Build Coastguard Worker
571*5a923131SAndroid Build Coastguard Worker if (!base::StartsWith(disk_name, "/dev/", base::CompareCase::SENSITIVE)) {
572*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "Invalid disk name: " << disk_name;
573*5a923131SAndroid Build Coastguard Worker return string();
574*5a923131SAndroid Build Coastguard Worker }
575*5a923131SAndroid Build Coastguard Worker
576*5a923131SAndroid Build Coastguard Worker string partition_name = disk_name;
577*5a923131SAndroid Build Coastguard Worker if (isdigit(partition_name.back())) {
578*5a923131SAndroid Build Coastguard Worker // Special case for devices with names ending with a digit.
579*5a923131SAndroid Build Coastguard Worker // Add "p" to separate the disk name from partition number,
580*5a923131SAndroid Build Coastguard Worker // e.g. "/dev/loop0p2"
581*5a923131SAndroid Build Coastguard Worker partition_name += 'p';
582*5a923131SAndroid Build Coastguard Worker }
583*5a923131SAndroid Build Coastguard Worker
584*5a923131SAndroid Build Coastguard Worker partition_name += std::to_string(partition_num);
585*5a923131SAndroid Build Coastguard Worker
586*5a923131SAndroid Build Coastguard Worker return partition_name;
587*5a923131SAndroid Build Coastguard Worker }
588*5a923131SAndroid Build Coastguard Worker
FileExists(const char * path)589*5a923131SAndroid Build Coastguard Worker bool FileExists(const char* path) {
590*5a923131SAndroid Build Coastguard Worker struct stat stbuf {};
591*5a923131SAndroid Build Coastguard Worker return 0 == lstat(path, &stbuf);
592*5a923131SAndroid Build Coastguard Worker }
593*5a923131SAndroid Build Coastguard Worker
IsSymlink(const char * path)594*5a923131SAndroid Build Coastguard Worker bool IsSymlink(const char* path) {
595*5a923131SAndroid Build Coastguard Worker struct stat stbuf {};
596*5a923131SAndroid Build Coastguard Worker return lstat(path, &stbuf) == 0 && S_ISLNK(stbuf.st_mode) != 0;
597*5a923131SAndroid Build Coastguard Worker }
598*5a923131SAndroid Build Coastguard Worker
IsRegFile(const char * path)599*5a923131SAndroid Build Coastguard Worker bool IsRegFile(const char* path) {
600*5a923131SAndroid Build Coastguard Worker struct stat stbuf {};
601*5a923131SAndroid Build Coastguard Worker return lstat(path, &stbuf) == 0 && S_ISREG(stbuf.st_mode) != 0;
602*5a923131SAndroid Build Coastguard Worker }
603*5a923131SAndroid Build Coastguard Worker
MakeTempFile(const string & base_filename_template,string * filename,int * fd)604*5a923131SAndroid Build Coastguard Worker bool MakeTempFile(const string& base_filename_template,
605*5a923131SAndroid Build Coastguard Worker string* filename,
606*5a923131SAndroid Build Coastguard Worker int* fd) {
607*5a923131SAndroid Build Coastguard Worker base::FilePath filename_template;
608*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE(
609*5a923131SAndroid Build Coastguard Worker GetTempName(base_filename_template, &filename_template));
610*5a923131SAndroid Build Coastguard Worker DCHECK(filename || fd);
611*5a923131SAndroid Build Coastguard Worker vector<char> buf(filename_template.value().size() + 1);
612*5a923131SAndroid Build Coastguard Worker memcpy(buf.data(),
613*5a923131SAndroid Build Coastguard Worker filename_template.value().data(),
614*5a923131SAndroid Build Coastguard Worker filename_template.value().size());
615*5a923131SAndroid Build Coastguard Worker buf[filename_template.value().size()] = '\0';
616*5a923131SAndroid Build Coastguard Worker
617*5a923131SAndroid Build Coastguard Worker int mkstemp_fd = mkstemp(buf.data());
618*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(mkstemp_fd >= 0);
619*5a923131SAndroid Build Coastguard Worker if (filename) {
620*5a923131SAndroid Build Coastguard Worker *filename = buf.data();
621*5a923131SAndroid Build Coastguard Worker }
622*5a923131SAndroid Build Coastguard Worker if (fd) {
623*5a923131SAndroid Build Coastguard Worker *fd = mkstemp_fd;
624*5a923131SAndroid Build Coastguard Worker } else {
625*5a923131SAndroid Build Coastguard Worker close(mkstemp_fd);
626*5a923131SAndroid Build Coastguard Worker }
627*5a923131SAndroid Build Coastguard Worker return true;
628*5a923131SAndroid Build Coastguard Worker }
629*5a923131SAndroid Build Coastguard Worker
SetBlockDeviceReadOnly(const string & device,bool read_only)630*5a923131SAndroid Build Coastguard Worker bool SetBlockDeviceReadOnly(const string& device, bool read_only) {
631*5a923131SAndroid Build Coastguard Worker int fd = HANDLE_EINTR(open(device.c_str(), O_RDONLY | O_CLOEXEC));
632*5a923131SAndroid Build Coastguard Worker if (fd < 0) {
633*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Opening block device " << device;
634*5a923131SAndroid Build Coastguard Worker return false;
635*5a923131SAndroid Build Coastguard Worker }
636*5a923131SAndroid Build Coastguard Worker ScopedFdCloser fd_closer(&fd);
637*5a923131SAndroid Build Coastguard Worker // We take no action if not needed.
638*5a923131SAndroid Build Coastguard Worker int read_only_flag{};
639*5a923131SAndroid Build Coastguard Worker int expected_flag = read_only ? 1 : 0;
640*5a923131SAndroid Build Coastguard Worker int rc = ioctl(fd, BLKROGET, &read_only_flag);
641*5a923131SAndroid Build Coastguard Worker // In case of failure reading the setting we will try to set it anyway.
642*5a923131SAndroid Build Coastguard Worker if (rc == 0 && read_only_flag == expected_flag)
643*5a923131SAndroid Build Coastguard Worker return true;
644*5a923131SAndroid Build Coastguard Worker
645*5a923131SAndroid Build Coastguard Worker rc = ioctl(fd, BLKROSET, &expected_flag);
646*5a923131SAndroid Build Coastguard Worker if (rc != 0) {
647*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Marking block device " << device
648*5a923131SAndroid Build Coastguard Worker << " as read_only=" << expected_flag;
649*5a923131SAndroid Build Coastguard Worker return false;
650*5a923131SAndroid Build Coastguard Worker }
651*5a923131SAndroid Build Coastguard Worker
652*5a923131SAndroid Build Coastguard Worker /*
653*5a923131SAndroid Build Coastguard Worker * Read back the value to check if it is configured successfully.
654*5a923131SAndroid Build Coastguard Worker * If fail, use the second method, set the file
655*5a923131SAndroid Build Coastguard Worker * /sys/block/<partition_name>/force_ro
656*5a923131SAndroid Build Coastguard Worker * to config the read only property.
657*5a923131SAndroid Build Coastguard Worker */
658*5a923131SAndroid Build Coastguard Worker rc = ioctl(fd, BLKROGET, &read_only_flag);
659*5a923131SAndroid Build Coastguard Worker if (rc != 0) {
660*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to read back block device read-only value:"
661*5a923131SAndroid Build Coastguard Worker << device;
662*5a923131SAndroid Build Coastguard Worker return false;
663*5a923131SAndroid Build Coastguard Worker }
664*5a923131SAndroid Build Coastguard Worker if (read_only_flag == expected_flag) {
665*5a923131SAndroid Build Coastguard Worker return true;
666*5a923131SAndroid Build Coastguard Worker }
667*5a923131SAndroid Build Coastguard Worker
668*5a923131SAndroid Build Coastguard Worker std::array<char, PATH_MAX> device_name;
669*5a923131SAndroid Build Coastguard Worker char* pdevice = realpath(device.c_str(), device_name.data());
670*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(pdevice);
671*5a923131SAndroid Build Coastguard Worker
672*5a923131SAndroid Build Coastguard Worker std::string real_path(pdevice);
673*5a923131SAndroid Build Coastguard Worker std::size_t offset = real_path.find_last_of('/');
674*5a923131SAndroid Build Coastguard Worker if (offset == std::string::npos) {
675*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "Could not find partition name from " << real_path;
676*5a923131SAndroid Build Coastguard Worker return false;
677*5a923131SAndroid Build Coastguard Worker }
678*5a923131SAndroid Build Coastguard Worker const std::string partition_name = real_path.substr(offset + 1);
679*5a923131SAndroid Build Coastguard Worker
680*5a923131SAndroid Build Coastguard Worker std::string force_ro_file = "/sys/block/" + partition_name + "/force_ro";
681*5a923131SAndroid Build Coastguard Worker android::base::unique_fd fd_force_ro{
682*5a923131SAndroid Build Coastguard Worker HANDLE_EINTR(open(force_ro_file.c_str(), O_WRONLY | O_CLOEXEC))};
683*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(fd_force_ro >= 0);
684*5a923131SAndroid Build Coastguard Worker
685*5a923131SAndroid Build Coastguard Worker rc = write(fd_force_ro, expected_flag ? "1" : "0", 1);
686*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(rc > 0);
687*5a923131SAndroid Build Coastguard Worker
688*5a923131SAndroid Build Coastguard Worker // Read back again
689*5a923131SAndroid Build Coastguard Worker rc = ioctl(fd, BLKROGET, &read_only_flag);
690*5a923131SAndroid Build Coastguard Worker if (rc != 0) {
691*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to read back block device read-only value:"
692*5a923131SAndroid Build Coastguard Worker << device;
693*5a923131SAndroid Build Coastguard Worker return false;
694*5a923131SAndroid Build Coastguard Worker }
695*5a923131SAndroid Build Coastguard Worker if (read_only_flag != expected_flag) {
696*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "After modifying force_ro, marking block device " << device
697*5a923131SAndroid Build Coastguard Worker << " as read_only=" << expected_flag;
698*5a923131SAndroid Build Coastguard Worker return false;
699*5a923131SAndroid Build Coastguard Worker }
700*5a923131SAndroid Build Coastguard Worker return true;
701*5a923131SAndroid Build Coastguard Worker }
702*5a923131SAndroid Build Coastguard Worker
MountFilesystem(const string & device,const string & mountpoint,unsigned long mountflags,const string & type,const string & fs_mount_options)703*5a923131SAndroid Build Coastguard Worker bool MountFilesystem(const string& device,
704*5a923131SAndroid Build Coastguard Worker const string& mountpoint,
705*5a923131SAndroid Build Coastguard Worker unsigned long mountflags, // NOLINT(runtime/int)
706*5a923131SAndroid Build Coastguard Worker const string& type,
707*5a923131SAndroid Build Coastguard Worker const string& fs_mount_options) {
708*5a923131SAndroid Build Coastguard Worker vector<const char*> fstypes;
709*5a923131SAndroid Build Coastguard Worker if (type.empty()) {
710*5a923131SAndroid Build Coastguard Worker fstypes = {"ext2", "ext3", "ext4", "squashfs", "erofs"};
711*5a923131SAndroid Build Coastguard Worker } else {
712*5a923131SAndroid Build Coastguard Worker fstypes = {type.c_str()};
713*5a923131SAndroid Build Coastguard Worker }
714*5a923131SAndroid Build Coastguard Worker for (const char* fstype : fstypes) {
715*5a923131SAndroid Build Coastguard Worker int rc = mount(device.c_str(),
716*5a923131SAndroid Build Coastguard Worker mountpoint.c_str(),
717*5a923131SAndroid Build Coastguard Worker fstype,
718*5a923131SAndroid Build Coastguard Worker mountflags,
719*5a923131SAndroid Build Coastguard Worker fs_mount_options.c_str());
720*5a923131SAndroid Build Coastguard Worker if (rc == 0)
721*5a923131SAndroid Build Coastguard Worker return true;
722*5a923131SAndroid Build Coastguard Worker
723*5a923131SAndroid Build Coastguard Worker PLOG(WARNING) << "Unable to mount destination device " << device << " on "
724*5a923131SAndroid Build Coastguard Worker << mountpoint << " as " << fstype;
725*5a923131SAndroid Build Coastguard Worker }
726*5a923131SAndroid Build Coastguard Worker if (!type.empty()) {
727*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "Unable to mount " << device << " with any supported type";
728*5a923131SAndroid Build Coastguard Worker }
729*5a923131SAndroid Build Coastguard Worker return false;
730*5a923131SAndroid Build Coastguard Worker }
731*5a923131SAndroid Build Coastguard Worker
UnmountFilesystem(const string & mountpoint)732*5a923131SAndroid Build Coastguard Worker bool UnmountFilesystem(const string& mountpoint) {
733*5a923131SAndroid Build Coastguard Worker int num_retries = 1;
734*5a923131SAndroid Build Coastguard Worker for (;; ++num_retries) {
735*5a923131SAndroid Build Coastguard Worker if (umount(mountpoint.c_str()) == 0)
736*5a923131SAndroid Build Coastguard Worker return true;
737*5a923131SAndroid Build Coastguard Worker if (errno != EBUSY || num_retries >= kUnmountMaxNumOfRetries)
738*5a923131SAndroid Build Coastguard Worker break;
739*5a923131SAndroid Build Coastguard Worker usleep(kUnmountRetryIntervalInMicroseconds);
740*5a923131SAndroid Build Coastguard Worker }
741*5a923131SAndroid Build Coastguard Worker if (errno == EINVAL) {
742*5a923131SAndroid Build Coastguard Worker LOG(INFO) << "Not a mountpoint: " << mountpoint;
743*5a923131SAndroid Build Coastguard Worker return false;
744*5a923131SAndroid Build Coastguard Worker }
745*5a923131SAndroid Build Coastguard Worker PLOG(WARNING) << "Error unmounting " << mountpoint << " after " << num_retries
746*5a923131SAndroid Build Coastguard Worker << " attempts. Lazy unmounting instead, error was";
747*5a923131SAndroid Build Coastguard Worker if (umount2(mountpoint.c_str(), MNT_DETACH) != 0) {
748*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Lazy unmount failed";
749*5a923131SAndroid Build Coastguard Worker return false;
750*5a923131SAndroid Build Coastguard Worker }
751*5a923131SAndroid Build Coastguard Worker return true;
752*5a923131SAndroid Build Coastguard Worker }
753*5a923131SAndroid Build Coastguard Worker
IsMountpoint(const std::string & mountpoint)754*5a923131SAndroid Build Coastguard Worker bool IsMountpoint(const std::string& mountpoint) {
755*5a923131SAndroid Build Coastguard Worker struct stat stdir {
756*5a923131SAndroid Build Coastguard Worker }, stparent{};
757*5a923131SAndroid Build Coastguard Worker
758*5a923131SAndroid Build Coastguard Worker // Check whether the passed mountpoint is a directory and the /.. is in the
759*5a923131SAndroid Build Coastguard Worker // same device or not. If mountpoint/.. is in a different device it means that
760*5a923131SAndroid Build Coastguard Worker // there is a filesystem mounted there. If it is not, but they both point to
761*5a923131SAndroid Build Coastguard Worker // the same inode it basically is the special case of /.. pointing to /. This
762*5a923131SAndroid Build Coastguard Worker // test doesn't play well with bind mount but that's out of the scope of what
763*5a923131SAndroid Build Coastguard Worker // we want to detect here.
764*5a923131SAndroid Build Coastguard Worker if (lstat(mountpoint.c_str(), &stdir) != 0) {
765*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Error stat'ing " << mountpoint;
766*5a923131SAndroid Build Coastguard Worker return false;
767*5a923131SAndroid Build Coastguard Worker }
768*5a923131SAndroid Build Coastguard Worker if (!S_ISDIR(stdir.st_mode))
769*5a923131SAndroid Build Coastguard Worker return false;
770*5a923131SAndroid Build Coastguard Worker
771*5a923131SAndroid Build Coastguard Worker base::FilePath parent(mountpoint);
772*5a923131SAndroid Build Coastguard Worker parent = parent.Append("..");
773*5a923131SAndroid Build Coastguard Worker if (lstat(parent.value().c_str(), &stparent) != 0) {
774*5a923131SAndroid Build Coastguard Worker PLOG(ERROR) << "Error stat'ing " << parent.value();
775*5a923131SAndroid Build Coastguard Worker return false;
776*5a923131SAndroid Build Coastguard Worker }
777*5a923131SAndroid Build Coastguard Worker return S_ISDIR(stparent.st_mode) &&
778*5a923131SAndroid Build Coastguard Worker (stparent.st_dev != stdir.st_dev || stparent.st_ino == stdir.st_ino);
779*5a923131SAndroid Build Coastguard Worker }
780*5a923131SAndroid Build Coastguard Worker
781*5a923131SAndroid Build Coastguard Worker // Tries to parse the header of an ELF file to obtain a human-readable
782*5a923131SAndroid Build Coastguard Worker // description of it on the |output| string.
GetFileFormatELF(const uint8_t * buffer,size_t size,string * output)783*5a923131SAndroid Build Coastguard Worker static bool GetFileFormatELF(const uint8_t* buffer,
784*5a923131SAndroid Build Coastguard Worker size_t size,
785*5a923131SAndroid Build Coastguard Worker string* output) {
786*5a923131SAndroid Build Coastguard Worker // 0x00: EI_MAG - ELF magic header, 4 bytes.
787*5a923131SAndroid Build Coastguard Worker if (size < SELFMAG || memcmp(buffer, ELFMAG, SELFMAG) != 0)
788*5a923131SAndroid Build Coastguard Worker return false;
789*5a923131SAndroid Build Coastguard Worker *output = "ELF";
790*5a923131SAndroid Build Coastguard Worker
791*5a923131SAndroid Build Coastguard Worker // 0x04: EI_CLASS, 1 byte.
792*5a923131SAndroid Build Coastguard Worker if (size < EI_CLASS + 1)
793*5a923131SAndroid Build Coastguard Worker return true;
794*5a923131SAndroid Build Coastguard Worker switch (buffer[EI_CLASS]) {
795*5a923131SAndroid Build Coastguard Worker case ELFCLASS32:
796*5a923131SAndroid Build Coastguard Worker *output += " 32-bit";
797*5a923131SAndroid Build Coastguard Worker break;
798*5a923131SAndroid Build Coastguard Worker case ELFCLASS64:
799*5a923131SAndroid Build Coastguard Worker *output += " 64-bit";
800*5a923131SAndroid Build Coastguard Worker break;
801*5a923131SAndroid Build Coastguard Worker default:
802*5a923131SAndroid Build Coastguard Worker *output += " ?-bit";
803*5a923131SAndroid Build Coastguard Worker }
804*5a923131SAndroid Build Coastguard Worker
805*5a923131SAndroid Build Coastguard Worker // 0x05: EI_DATA, endianness, 1 byte.
806*5a923131SAndroid Build Coastguard Worker if (size < EI_DATA + 1)
807*5a923131SAndroid Build Coastguard Worker return true;
808*5a923131SAndroid Build Coastguard Worker uint8_t ei_data = buffer[EI_DATA];
809*5a923131SAndroid Build Coastguard Worker switch (ei_data) {
810*5a923131SAndroid Build Coastguard Worker case ELFDATA2LSB:
811*5a923131SAndroid Build Coastguard Worker *output += " little-endian";
812*5a923131SAndroid Build Coastguard Worker break;
813*5a923131SAndroid Build Coastguard Worker case ELFDATA2MSB:
814*5a923131SAndroid Build Coastguard Worker *output += " big-endian";
815*5a923131SAndroid Build Coastguard Worker break;
816*5a923131SAndroid Build Coastguard Worker default:
817*5a923131SAndroid Build Coastguard Worker *output += " ?-endian";
818*5a923131SAndroid Build Coastguard Worker // Don't parse anything after the 0x10 offset if endianness is unknown.
819*5a923131SAndroid Build Coastguard Worker return true;
820*5a923131SAndroid Build Coastguard Worker }
821*5a923131SAndroid Build Coastguard Worker
822*5a923131SAndroid Build Coastguard Worker const Elf32_Ehdr* hdr = reinterpret_cast<const Elf32_Ehdr*>(buffer);
823*5a923131SAndroid Build Coastguard Worker // 0x12: e_machine, 2 byte endianness based on ei_data. The position (0x12)
824*5a923131SAndroid Build Coastguard Worker // and size is the same for both 32 and 64 bits.
825*5a923131SAndroid Build Coastguard Worker if (size < offsetof(Elf32_Ehdr, e_machine) + sizeof(hdr->e_machine))
826*5a923131SAndroid Build Coastguard Worker return true;
827*5a923131SAndroid Build Coastguard Worker uint16_t e_machine{};
828*5a923131SAndroid Build Coastguard Worker // Fix endianness regardless of the host endianness.
829*5a923131SAndroid Build Coastguard Worker if (ei_data == ELFDATA2LSB)
830*5a923131SAndroid Build Coastguard Worker e_machine = le16toh(hdr->e_machine);
831*5a923131SAndroid Build Coastguard Worker else
832*5a923131SAndroid Build Coastguard Worker e_machine = be16toh(hdr->e_machine);
833*5a923131SAndroid Build Coastguard Worker
834*5a923131SAndroid Build Coastguard Worker switch (e_machine) {
835*5a923131SAndroid Build Coastguard Worker case EM_386:
836*5a923131SAndroid Build Coastguard Worker *output += " x86";
837*5a923131SAndroid Build Coastguard Worker break;
838*5a923131SAndroid Build Coastguard Worker case EM_MIPS:
839*5a923131SAndroid Build Coastguard Worker *output += " mips";
840*5a923131SAndroid Build Coastguard Worker break;
841*5a923131SAndroid Build Coastguard Worker case EM_ARM:
842*5a923131SAndroid Build Coastguard Worker *output += " arm";
843*5a923131SAndroid Build Coastguard Worker break;
844*5a923131SAndroid Build Coastguard Worker case EM_X86_64:
845*5a923131SAndroid Build Coastguard Worker *output += " x86-64";
846*5a923131SAndroid Build Coastguard Worker break;
847*5a923131SAndroid Build Coastguard Worker default:
848*5a923131SAndroid Build Coastguard Worker *output += " unknown-arch";
849*5a923131SAndroid Build Coastguard Worker }
850*5a923131SAndroid Build Coastguard Worker return true;
851*5a923131SAndroid Build Coastguard Worker }
852*5a923131SAndroid Build Coastguard Worker
GetFileFormat(const string & path)853*5a923131SAndroid Build Coastguard Worker string GetFileFormat(const string& path) {
854*5a923131SAndroid Build Coastguard Worker brillo::Blob buffer;
855*5a923131SAndroid Build Coastguard Worker if (!ReadFileChunkAndAppend(path, 0, kGetFileFormatMaxHeaderSize, &buffer))
856*5a923131SAndroid Build Coastguard Worker return "File not found.";
857*5a923131SAndroid Build Coastguard Worker
858*5a923131SAndroid Build Coastguard Worker string result;
859*5a923131SAndroid Build Coastguard Worker if (GetFileFormatELF(buffer.data(), buffer.size(), &result))
860*5a923131SAndroid Build Coastguard Worker return result;
861*5a923131SAndroid Build Coastguard Worker
862*5a923131SAndroid Build Coastguard Worker return "data";
863*5a923131SAndroid Build Coastguard Worker }
864*5a923131SAndroid Build Coastguard Worker
FuzzInt(int value,unsigned int range)865*5a923131SAndroid Build Coastguard Worker int FuzzInt(int value, unsigned int range) {
866*5a923131SAndroid Build Coastguard Worker int min = value - range / 2;
867*5a923131SAndroid Build Coastguard Worker int max = value + range - range / 2;
868*5a923131SAndroid Build Coastguard Worker return base::RandInt(min, max);
869*5a923131SAndroid Build Coastguard Worker }
870*5a923131SAndroid Build Coastguard Worker
FormatSecs(unsigned secs)871*5a923131SAndroid Build Coastguard Worker string FormatSecs(unsigned secs) {
872*5a923131SAndroid Build Coastguard Worker return FormatTimeDelta(TimeDelta::FromSeconds(secs));
873*5a923131SAndroid Build Coastguard Worker }
874*5a923131SAndroid Build Coastguard Worker
FormatTimeDelta(TimeDelta delta)875*5a923131SAndroid Build Coastguard Worker string FormatTimeDelta(TimeDelta delta) {
876*5a923131SAndroid Build Coastguard Worker string str;
877*5a923131SAndroid Build Coastguard Worker
878*5a923131SAndroid Build Coastguard Worker // Handle negative durations by prefixing with a minus.
879*5a923131SAndroid Build Coastguard Worker if (delta.ToInternalValue() < 0) {
880*5a923131SAndroid Build Coastguard Worker delta *= -1;
881*5a923131SAndroid Build Coastguard Worker str = "-";
882*5a923131SAndroid Build Coastguard Worker }
883*5a923131SAndroid Build Coastguard Worker
884*5a923131SAndroid Build Coastguard Worker // Canonicalize into days, hours, minutes, seconds and microseconds.
885*5a923131SAndroid Build Coastguard Worker unsigned days = delta.InDays();
886*5a923131SAndroid Build Coastguard Worker delta -= TimeDelta::FromDays(days);
887*5a923131SAndroid Build Coastguard Worker unsigned hours = delta.InHours();
888*5a923131SAndroid Build Coastguard Worker delta -= TimeDelta::FromHours(hours);
889*5a923131SAndroid Build Coastguard Worker unsigned mins = delta.InMinutes();
890*5a923131SAndroid Build Coastguard Worker delta -= TimeDelta::FromMinutes(mins);
891*5a923131SAndroid Build Coastguard Worker unsigned secs = delta.InSeconds();
892*5a923131SAndroid Build Coastguard Worker delta -= TimeDelta::FromSeconds(secs);
893*5a923131SAndroid Build Coastguard Worker unsigned usecs = delta.InMicroseconds();
894*5a923131SAndroid Build Coastguard Worker
895*5a923131SAndroid Build Coastguard Worker if (days)
896*5a923131SAndroid Build Coastguard Worker android::base::StringAppendF(&str, "%ud", days);
897*5a923131SAndroid Build Coastguard Worker if (days || hours)
898*5a923131SAndroid Build Coastguard Worker android::base::StringAppendF(&str, "%uh", hours);
899*5a923131SAndroid Build Coastguard Worker if (days || hours || mins)
900*5a923131SAndroid Build Coastguard Worker android::base::StringAppendF(&str, "%um", mins);
901*5a923131SAndroid Build Coastguard Worker android::base::StringAppendF(&str, "%u", secs);
902*5a923131SAndroid Build Coastguard Worker if (usecs) {
903*5a923131SAndroid Build Coastguard Worker int width = 6;
904*5a923131SAndroid Build Coastguard Worker while ((usecs / 10) * 10 == usecs) {
905*5a923131SAndroid Build Coastguard Worker usecs /= 10;
906*5a923131SAndroid Build Coastguard Worker width--;
907*5a923131SAndroid Build Coastguard Worker }
908*5a923131SAndroid Build Coastguard Worker android::base::StringAppendF(&str, ".%0*u", width, usecs);
909*5a923131SAndroid Build Coastguard Worker }
910*5a923131SAndroid Build Coastguard Worker android::base::StringAppendF(&str, "s");
911*5a923131SAndroid Build Coastguard Worker return str;
912*5a923131SAndroid Build Coastguard Worker }
913*5a923131SAndroid Build Coastguard Worker
ToString(const Time utc_time)914*5a923131SAndroid Build Coastguard Worker string ToString(const Time utc_time) {
915*5a923131SAndroid Build Coastguard Worker Time::Exploded exp_time{};
916*5a923131SAndroid Build Coastguard Worker utc_time.UTCExplode(&exp_time);
917*5a923131SAndroid Build Coastguard Worker return android::base::StringPrintf("%d/%d/%d %d:%02d:%02d GMT",
918*5a923131SAndroid Build Coastguard Worker exp_time.month,
919*5a923131SAndroid Build Coastguard Worker exp_time.day_of_month,
920*5a923131SAndroid Build Coastguard Worker exp_time.year,
921*5a923131SAndroid Build Coastguard Worker exp_time.hour,
922*5a923131SAndroid Build Coastguard Worker exp_time.minute,
923*5a923131SAndroid Build Coastguard Worker exp_time.second);
924*5a923131SAndroid Build Coastguard Worker }
925*5a923131SAndroid Build Coastguard Worker
ToString(bool b)926*5a923131SAndroid Build Coastguard Worker string ToString(bool b) {
927*5a923131SAndroid Build Coastguard Worker return (b ? "true" : "false");
928*5a923131SAndroid Build Coastguard Worker }
929*5a923131SAndroid Build Coastguard Worker
ToString(DownloadSource source)930*5a923131SAndroid Build Coastguard Worker string ToString(DownloadSource source) {
931*5a923131SAndroid Build Coastguard Worker switch (source) {
932*5a923131SAndroid Build Coastguard Worker case kDownloadSourceHttpsServer:
933*5a923131SAndroid Build Coastguard Worker return "HttpsServer";
934*5a923131SAndroid Build Coastguard Worker case kDownloadSourceHttpServer:
935*5a923131SAndroid Build Coastguard Worker return "HttpServer";
936*5a923131SAndroid Build Coastguard Worker case kDownloadSourceHttpPeer:
937*5a923131SAndroid Build Coastguard Worker return "HttpPeer";
938*5a923131SAndroid Build Coastguard Worker case kNumDownloadSources:
939*5a923131SAndroid Build Coastguard Worker return "Unknown";
940*5a923131SAndroid Build Coastguard Worker // Don't add a default case to let the compiler warn about newly added
941*5a923131SAndroid Build Coastguard Worker // download sources which should be added here.
942*5a923131SAndroid Build Coastguard Worker }
943*5a923131SAndroid Build Coastguard Worker
944*5a923131SAndroid Build Coastguard Worker return "Unknown";
945*5a923131SAndroid Build Coastguard Worker }
946*5a923131SAndroid Build Coastguard Worker
ToString(PayloadType payload_type)947*5a923131SAndroid Build Coastguard Worker string ToString(PayloadType payload_type) {
948*5a923131SAndroid Build Coastguard Worker switch (payload_type) {
949*5a923131SAndroid Build Coastguard Worker case kPayloadTypeDelta:
950*5a923131SAndroid Build Coastguard Worker return "Delta";
951*5a923131SAndroid Build Coastguard Worker case kPayloadTypeFull:
952*5a923131SAndroid Build Coastguard Worker return "Full";
953*5a923131SAndroid Build Coastguard Worker case kPayloadTypeForcedFull:
954*5a923131SAndroid Build Coastguard Worker return "ForcedFull";
955*5a923131SAndroid Build Coastguard Worker case kNumPayloadTypes:
956*5a923131SAndroid Build Coastguard Worker return "Unknown";
957*5a923131SAndroid Build Coastguard Worker // Don't add a default case to let the compiler warn about newly added
958*5a923131SAndroid Build Coastguard Worker // payload types which should be added here.
959*5a923131SAndroid Build Coastguard Worker }
960*5a923131SAndroid Build Coastguard Worker
961*5a923131SAndroid Build Coastguard Worker return "Unknown";
962*5a923131SAndroid Build Coastguard Worker }
963*5a923131SAndroid Build Coastguard Worker
GetBaseErrorCode(ErrorCode code)964*5a923131SAndroid Build Coastguard Worker ErrorCode GetBaseErrorCode(ErrorCode code) {
965*5a923131SAndroid Build Coastguard Worker // Ignore the higher order bits in the code by applying the mask as
966*5a923131SAndroid Build Coastguard Worker // we want the enumerations to be in the small contiguous range
967*5a923131SAndroid Build Coastguard Worker // with values less than ErrorCode::kUmaReportedMax.
968*5a923131SAndroid Build Coastguard Worker ErrorCode base_code = static_cast<ErrorCode>(
969*5a923131SAndroid Build Coastguard Worker static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
970*5a923131SAndroid Build Coastguard Worker
971*5a923131SAndroid Build Coastguard Worker // Make additional adjustments required for UMA and error classification.
972*5a923131SAndroid Build Coastguard Worker // TODO(jaysri): Move this logic to UeErrorCode.cc when we fix
973*5a923131SAndroid Build Coastguard Worker // chromium-os:34369.
974*5a923131SAndroid Build Coastguard Worker if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
975*5a923131SAndroid Build Coastguard Worker // Since we want to keep the enums to a small value, aggregate all HTTP
976*5a923131SAndroid Build Coastguard Worker // errors into this one bucket for UMA and error classification purposes.
977*5a923131SAndroid Build Coastguard Worker LOG(INFO) << "Converting error code " << base_code
978*5a923131SAndroid Build Coastguard Worker << " to ErrorCode::kOmahaErrorInHTTPResponse";
979*5a923131SAndroid Build Coastguard Worker base_code = ErrorCode::kOmahaErrorInHTTPResponse;
980*5a923131SAndroid Build Coastguard Worker }
981*5a923131SAndroid Build Coastguard Worker
982*5a923131SAndroid Build Coastguard Worker return base_code;
983*5a923131SAndroid Build Coastguard Worker }
984*5a923131SAndroid Build Coastguard Worker
StringVectorToString(const vector<string> & vec_str)985*5a923131SAndroid Build Coastguard Worker string StringVectorToString(const vector<string>& vec_str) {
986*5a923131SAndroid Build Coastguard Worker string str = "[";
987*5a923131SAndroid Build Coastguard Worker for (vector<string>::const_iterator i = vec_str.begin(); i != vec_str.end();
988*5a923131SAndroid Build Coastguard Worker ++i) {
989*5a923131SAndroid Build Coastguard Worker if (i != vec_str.begin())
990*5a923131SAndroid Build Coastguard Worker str += ", ";
991*5a923131SAndroid Build Coastguard Worker str += '"';
992*5a923131SAndroid Build Coastguard Worker str += *i;
993*5a923131SAndroid Build Coastguard Worker str += '"';
994*5a923131SAndroid Build Coastguard Worker }
995*5a923131SAndroid Build Coastguard Worker str += "]";
996*5a923131SAndroid Build Coastguard Worker return str;
997*5a923131SAndroid Build Coastguard Worker }
998*5a923131SAndroid Build Coastguard Worker
999*5a923131SAndroid Build Coastguard Worker // The P2P file id should be the same for devices running new version and old
1000*5a923131SAndroid Build Coastguard Worker // version so that they can share it with each other. The hash in the response
1001*5a923131SAndroid Build Coastguard Worker // was base64 encoded, but now that we switched to use "hash_sha256" field which
1002*5a923131SAndroid Build Coastguard Worker // is hex encoded, we have to convert them back to base64 for P2P. However, the
1003*5a923131SAndroid Build Coastguard Worker // base64 encoded hash was base64 encoded here again historically for some
1004*5a923131SAndroid Build Coastguard Worker // reason, so we keep the same behavior here.
CalculateP2PFileId(const brillo::Blob & payload_hash,size_t payload_size)1005*5a923131SAndroid Build Coastguard Worker string CalculateP2PFileId(const brillo::Blob& payload_hash,
1006*5a923131SAndroid Build Coastguard Worker size_t payload_size) {
1007*5a923131SAndroid Build Coastguard Worker string encoded_hash = brillo::data_encoding::Base64Encode(
1008*5a923131SAndroid Build Coastguard Worker brillo::data_encoding::Base64Encode(payload_hash));
1009*5a923131SAndroid Build Coastguard Worker return android::base::StringPrintf("cros_update_size_%" PRIuS "_hash_%s",
1010*5a923131SAndroid Build Coastguard Worker payload_size,
1011*5a923131SAndroid Build Coastguard Worker encoded_hash.c_str());
1012*5a923131SAndroid Build Coastguard Worker }
1013*5a923131SAndroid Build Coastguard Worker
ConvertToOmahaInstallDate(Time time,int * out_num_days)1014*5a923131SAndroid Build Coastguard Worker bool ConvertToOmahaInstallDate(Time time, int* out_num_days) {
1015*5a923131SAndroid Build Coastguard Worker time_t unix_time = time.ToTimeT();
1016*5a923131SAndroid Build Coastguard Worker // Output of: date +"%s" --date="Jan 1, 2007 0:00 PST".
1017*5a923131SAndroid Build Coastguard Worker const time_t kOmahaEpoch = 1167638400;
1018*5a923131SAndroid Build Coastguard Worker const int64_t kNumSecondsPerWeek = 7 * 24 * 3600;
1019*5a923131SAndroid Build Coastguard Worker const int64_t kNumDaysPerWeek = 7;
1020*5a923131SAndroid Build Coastguard Worker
1021*5a923131SAndroid Build Coastguard Worker time_t omaha_time = unix_time - kOmahaEpoch;
1022*5a923131SAndroid Build Coastguard Worker
1023*5a923131SAndroid Build Coastguard Worker if (omaha_time < 0)
1024*5a923131SAndroid Build Coastguard Worker return false;
1025*5a923131SAndroid Build Coastguard Worker
1026*5a923131SAndroid Build Coastguard Worker // Note, as per the comment in utils.h we are deliberately not
1027*5a923131SAndroid Build Coastguard Worker // handling DST correctly.
1028*5a923131SAndroid Build Coastguard Worker
1029*5a923131SAndroid Build Coastguard Worker int64_t num_weeks_since_omaha_epoch = omaha_time / kNumSecondsPerWeek;
1030*5a923131SAndroid Build Coastguard Worker *out_num_days = num_weeks_since_omaha_epoch * kNumDaysPerWeek;
1031*5a923131SAndroid Build Coastguard Worker
1032*5a923131SAndroid Build Coastguard Worker return true;
1033*5a923131SAndroid Build Coastguard Worker }
1034*5a923131SAndroid Build Coastguard Worker
GetMinorVersion(const brillo::KeyValueStore & store,uint32_t * minor_version)1035*5a923131SAndroid Build Coastguard Worker bool GetMinorVersion(const brillo::KeyValueStore& store,
1036*5a923131SAndroid Build Coastguard Worker uint32_t* minor_version) {
1037*5a923131SAndroid Build Coastguard Worker string result;
1038*5a923131SAndroid Build Coastguard Worker if (store.GetString("PAYLOAD_MINOR_VERSION", &result)) {
1039*5a923131SAndroid Build Coastguard Worker if (!base::StringToUint(result, minor_version)) {
1040*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "StringToUint failed when parsing delta minor version.";
1041*5a923131SAndroid Build Coastguard Worker return false;
1042*5a923131SAndroid Build Coastguard Worker }
1043*5a923131SAndroid Build Coastguard Worker return true;
1044*5a923131SAndroid Build Coastguard Worker }
1045*5a923131SAndroid Build Coastguard Worker return false;
1046*5a923131SAndroid Build Coastguard Worker }
1047*5a923131SAndroid Build Coastguard Worker
ReadExtents(const std::string & path,const google::protobuf::RepeatedPtrField<Extent> & extents,brillo::Blob * out_data,size_t block_size)1048*5a923131SAndroid Build Coastguard Worker bool ReadExtents(const std::string& path,
1049*5a923131SAndroid Build Coastguard Worker const google::protobuf::RepeatedPtrField<Extent>& extents,
1050*5a923131SAndroid Build Coastguard Worker brillo::Blob* out_data,
1051*5a923131SAndroid Build Coastguard Worker size_t block_size) {
1052*5a923131SAndroid Build Coastguard Worker return ReadExtents(path,
1053*5a923131SAndroid Build Coastguard Worker {extents.begin(), extents.end()},
1054*5a923131SAndroid Build Coastguard Worker out_data,
1055*5a923131SAndroid Build Coastguard Worker utils::BlocksInExtents(extents) * block_size,
1056*5a923131SAndroid Build Coastguard Worker block_size);
1057*5a923131SAndroid Build Coastguard Worker }
1058*5a923131SAndroid Build Coastguard Worker
WriteExtents(const std::string & path,const google::protobuf::RepeatedPtrField<Extent> & extents,const brillo::Blob & data,size_t block_size)1059*5a923131SAndroid Build Coastguard Worker bool WriteExtents(const std::string& path,
1060*5a923131SAndroid Build Coastguard Worker const google::protobuf::RepeatedPtrField<Extent>& extents,
1061*5a923131SAndroid Build Coastguard Worker const brillo::Blob& data,
1062*5a923131SAndroid Build Coastguard Worker size_t block_size) {
1063*5a923131SAndroid Build Coastguard Worker EintrSafeFileDescriptor fd;
1064*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE(fd.Open(path.c_str(), O_RDWR));
1065*5a923131SAndroid Build Coastguard Worker size_t bytes_written = 0;
1066*5a923131SAndroid Build Coastguard Worker for (const auto& ext : extents) {
1067*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(
1068*5a923131SAndroid Build Coastguard Worker fd.Seek(ext.start_block() * block_size, SEEK_SET));
1069*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE_ERRNO(
1070*5a923131SAndroid Build Coastguard Worker fd.Write(data.data() + bytes_written, ext.num_blocks() * block_size));
1071*5a923131SAndroid Build Coastguard Worker bytes_written += ext.num_blocks() * block_size;
1072*5a923131SAndroid Build Coastguard Worker }
1073*5a923131SAndroid Build Coastguard Worker return true;
1074*5a923131SAndroid Build Coastguard Worker }
ReadExtents(const std::string & path,const vector<Extent> & extents,brillo::Blob * out_data,ssize_t out_data_size,size_t block_size)1075*5a923131SAndroid Build Coastguard Worker bool ReadExtents(const std::string& path,
1076*5a923131SAndroid Build Coastguard Worker const vector<Extent>& extents,
1077*5a923131SAndroid Build Coastguard Worker brillo::Blob* out_data,
1078*5a923131SAndroid Build Coastguard Worker ssize_t out_data_size,
1079*5a923131SAndroid Build Coastguard Worker size_t block_size) {
1080*5a923131SAndroid Build Coastguard Worker FileDescriptorPtr fd = std::make_shared<EintrSafeFileDescriptor>();
1081*5a923131SAndroid Build Coastguard Worker fd->Open(path.c_str(), O_RDONLY);
1082*5a923131SAndroid Build Coastguard Worker return ReadExtents(fd, extents, out_data, out_data_size, block_size);
1083*5a923131SAndroid Build Coastguard Worker }
1084*5a923131SAndroid Build Coastguard Worker
ReadExtents(FileDescriptorPtr fd,const google::protobuf::RepeatedPtrField<Extent> & extents,brillo::Blob * out_data,size_t block_size)1085*5a923131SAndroid Build Coastguard Worker bool ReadExtents(FileDescriptorPtr fd,
1086*5a923131SAndroid Build Coastguard Worker const google::protobuf::RepeatedPtrField<Extent>& extents,
1087*5a923131SAndroid Build Coastguard Worker brillo::Blob* out_data,
1088*5a923131SAndroid Build Coastguard Worker size_t block_size) {
1089*5a923131SAndroid Build Coastguard Worker return ReadExtents(fd,
1090*5a923131SAndroid Build Coastguard Worker {extents.begin(), extents.end()},
1091*5a923131SAndroid Build Coastguard Worker out_data,
1092*5a923131SAndroid Build Coastguard Worker utils::BlocksInExtents(extents) * block_size,
1093*5a923131SAndroid Build Coastguard Worker block_size);
1094*5a923131SAndroid Build Coastguard Worker }
1095*5a923131SAndroid Build Coastguard Worker
ReadExtents(FileDescriptorPtr fd,const vector<Extent> & extents,brillo::Blob * out_data,ssize_t out_data_size,size_t block_size)1096*5a923131SAndroid Build Coastguard Worker bool ReadExtents(FileDescriptorPtr fd,
1097*5a923131SAndroid Build Coastguard Worker const vector<Extent>& extents,
1098*5a923131SAndroid Build Coastguard Worker brillo::Blob* out_data,
1099*5a923131SAndroid Build Coastguard Worker ssize_t out_data_size,
1100*5a923131SAndroid Build Coastguard Worker size_t block_size) {
1101*5a923131SAndroid Build Coastguard Worker brillo::Blob data(out_data_size);
1102*5a923131SAndroid Build Coastguard Worker ssize_t bytes_read = 0;
1103*5a923131SAndroid Build Coastguard Worker
1104*5a923131SAndroid Build Coastguard Worker for (const Extent& extent : extents) {
1105*5a923131SAndroid Build Coastguard Worker ssize_t bytes_read_this_iteration = 0;
1106*5a923131SAndroid Build Coastguard Worker ssize_t bytes = extent.num_blocks() * block_size;
1107*5a923131SAndroid Build Coastguard Worker TEST_LE(bytes_read + bytes, out_data_size);
1108*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE(utils::PReadAll(fd,
1109*5a923131SAndroid Build Coastguard Worker &data[bytes_read],
1110*5a923131SAndroid Build Coastguard Worker bytes,
1111*5a923131SAndroid Build Coastguard Worker extent.start_block() * block_size,
1112*5a923131SAndroid Build Coastguard Worker &bytes_read_this_iteration));
1113*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE(bytes_read_this_iteration == bytes);
1114*5a923131SAndroid Build Coastguard Worker bytes_read += bytes_read_this_iteration;
1115*5a923131SAndroid Build Coastguard Worker }
1116*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE(out_data_size == bytes_read);
1117*5a923131SAndroid Build Coastguard Worker *out_data = data;
1118*5a923131SAndroid Build Coastguard Worker return true;
1119*5a923131SAndroid Build Coastguard Worker }
1120*5a923131SAndroid Build Coastguard Worker
GetVpdValue(string key,string * result)1121*5a923131SAndroid Build Coastguard Worker bool GetVpdValue(string key, string* result) {
1122*5a923131SAndroid Build Coastguard Worker int exit_code = 0;
1123*5a923131SAndroid Build Coastguard Worker string value, error;
1124*5a923131SAndroid Build Coastguard Worker vector<string> cmd = {"vpd_get_value", key};
1125*5a923131SAndroid Build Coastguard Worker if (!chromeos_update_engine::Subprocess::SynchronousExec(
1126*5a923131SAndroid Build Coastguard Worker cmd, &exit_code, &value, &error) ||
1127*5a923131SAndroid Build Coastguard Worker exit_code) {
1128*5a923131SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to get vpd key for " << value
1129*5a923131SAndroid Build Coastguard Worker << " with exit code: " << exit_code << " and error: " << error;
1130*5a923131SAndroid Build Coastguard Worker return false;
1131*5a923131SAndroid Build Coastguard Worker } else if (!error.empty()) {
1132*5a923131SAndroid Build Coastguard Worker LOG(INFO) << "vpd_get_value succeeded but with following errors: " << error;
1133*5a923131SAndroid Build Coastguard Worker }
1134*5a923131SAndroid Build Coastguard Worker
1135*5a923131SAndroid Build Coastguard Worker base::TrimWhitespaceASCII(value, base::TRIM_ALL, &value);
1136*5a923131SAndroid Build Coastguard Worker *result = value;
1137*5a923131SAndroid Build Coastguard Worker return true;
1138*5a923131SAndroid Build Coastguard Worker }
1139*5a923131SAndroid Build Coastguard Worker
GetBootId(string * boot_id)1140*5a923131SAndroid Build Coastguard Worker bool GetBootId(string* boot_id) {
1141*5a923131SAndroid Build Coastguard Worker TEST_AND_RETURN_FALSE(
1142*5a923131SAndroid Build Coastguard Worker base::ReadFileToString(base::FilePath(kBootIdPath), boot_id));
1143*5a923131SAndroid Build Coastguard Worker base::TrimWhitespaceASCII(*boot_id, base::TRIM_TRAILING, boot_id);
1144*5a923131SAndroid Build Coastguard Worker return true;
1145*5a923131SAndroid Build Coastguard Worker }
1146*5a923131SAndroid Build Coastguard Worker
VersionPrefix(const std::string & version)1147*5a923131SAndroid Build Coastguard Worker int VersionPrefix(const std::string& version) {
1148*5a923131SAndroid Build Coastguard Worker if (version.empty()) {
1149*5a923131SAndroid Build Coastguard Worker return 0;
1150*5a923131SAndroid Build Coastguard Worker }
1151*5a923131SAndroid Build Coastguard Worker vector<string> tokens = base::SplitString(
1152*5a923131SAndroid Build Coastguard Worker version, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
1153*5a923131SAndroid Build Coastguard Worker int value{};
1154*5a923131SAndroid Build Coastguard Worker if (tokens.empty() || !base::StringToInt(tokens[0], &value))
1155*5a923131SAndroid Build Coastguard Worker return -1; // Target version is invalid.
1156*5a923131SAndroid Build Coastguard Worker return value;
1157*5a923131SAndroid Build Coastguard Worker }
1158*5a923131SAndroid Build Coastguard Worker
ParseRollbackKeyVersion(const string & raw_version,uint16_t * high_version,uint16_t * low_version)1159*5a923131SAndroid Build Coastguard Worker void ParseRollbackKeyVersion(const string& raw_version,
1160*5a923131SAndroid Build Coastguard Worker uint16_t* high_version,
1161*5a923131SAndroid Build Coastguard Worker uint16_t* low_version) {
1162*5a923131SAndroid Build Coastguard Worker DCHECK(high_version);
1163*5a923131SAndroid Build Coastguard Worker DCHECK(low_version);
1164*5a923131SAndroid Build Coastguard Worker *high_version = numeric_limits<uint16_t>::max();
1165*5a923131SAndroid Build Coastguard Worker *low_version = numeric_limits<uint16_t>::max();
1166*5a923131SAndroid Build Coastguard Worker
1167*5a923131SAndroid Build Coastguard Worker vector<string> parts = base::SplitString(
1168*5a923131SAndroid Build Coastguard Worker raw_version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1169*5a923131SAndroid Build Coastguard Worker if (parts.size() != 2) {
1170*5a923131SAndroid Build Coastguard Worker // The version string must have exactly one period.
1171*5a923131SAndroid Build Coastguard Worker return;
1172*5a923131SAndroid Build Coastguard Worker }
1173*5a923131SAndroid Build Coastguard Worker
1174*5a923131SAndroid Build Coastguard Worker int high{};
1175*5a923131SAndroid Build Coastguard Worker int low{};
1176*5a923131SAndroid Build Coastguard Worker if (!(base::StringToInt(parts[0], &high) &&
1177*5a923131SAndroid Build Coastguard Worker base::StringToInt(parts[1], &low))) {
1178*5a923131SAndroid Build Coastguard Worker // Both parts of the version could not be parsed correctly.
1179*5a923131SAndroid Build Coastguard Worker return;
1180*5a923131SAndroid Build Coastguard Worker }
1181*5a923131SAndroid Build Coastguard Worker
1182*5a923131SAndroid Build Coastguard Worker if (high >= 0 && high < numeric_limits<uint16_t>::max() && low >= 0 &&
1183*5a923131SAndroid Build Coastguard Worker low < numeric_limits<uint16_t>::max()) {
1184*5a923131SAndroid Build Coastguard Worker *high_version = static_cast<uint16_t>(high);
1185*5a923131SAndroid Build Coastguard Worker *low_version = static_cast<uint16_t>(low);
1186*5a923131SAndroid Build Coastguard Worker }
1187*5a923131SAndroid Build Coastguard Worker }
1188*5a923131SAndroid Build Coastguard Worker
GetFilePath(int fd)1189*5a923131SAndroid Build Coastguard Worker string GetFilePath(int fd) {
1190*5a923131SAndroid Build Coastguard Worker base::FilePath proc("/proc/self/fd/" + std::to_string(fd));
1191*5a923131SAndroid Build Coastguard Worker base::FilePath file_name;
1192*5a923131SAndroid Build Coastguard Worker
1193*5a923131SAndroid Build Coastguard Worker if (!base::ReadSymbolicLink(proc, &file_name)) {
1194*5a923131SAndroid Build Coastguard Worker return "not found";
1195*5a923131SAndroid Build Coastguard Worker }
1196*5a923131SAndroid Build Coastguard Worker return file_name.value();
1197*5a923131SAndroid Build Coastguard Worker }
1198*5a923131SAndroid Build Coastguard Worker
GetTimeAsString(time_t utime)1199*5a923131SAndroid Build Coastguard Worker string GetTimeAsString(time_t utime) {
1200*5a923131SAndroid Build Coastguard Worker struct tm tm {};
1201*5a923131SAndroid Build Coastguard Worker CHECK_EQ(localtime_r(&utime, &tm), &tm);
1202*5a923131SAndroid Build Coastguard Worker char str[16];
1203*5a923131SAndroid Build Coastguard Worker CHECK_EQ(strftime(str, sizeof(str), "%Y%m%d-%H%M%S", &tm), 15u);
1204*5a923131SAndroid Build Coastguard Worker return str;
1205*5a923131SAndroid Build Coastguard Worker }
1206*5a923131SAndroid Build Coastguard Worker
GetExclusionName(const string & str_to_convert)1207*5a923131SAndroid Build Coastguard Worker string GetExclusionName(const string& str_to_convert) {
1208*5a923131SAndroid Build Coastguard Worker return std::format("{}", base::StringPieceHash()(str_to_convert));
1209*5a923131SAndroid Build Coastguard Worker }
1210*5a923131SAndroid Build Coastguard Worker
ParseTimestamp(std::string_view str,int64_t * out)1211*5a923131SAndroid Build Coastguard Worker static bool ParseTimestamp(std::string_view str, int64_t* out) {
1212*5a923131SAndroid Build Coastguard Worker if (!base::StringToInt64(base::StringPiece(str.data(), str.size()), out)) {
1213*5a923131SAndroid Build Coastguard Worker LOG(WARNING) << "Invalid timestamp: " << str;
1214*5a923131SAndroid Build Coastguard Worker return false;
1215*5a923131SAndroid Build Coastguard Worker }
1216*5a923131SAndroid Build Coastguard Worker return true;
1217*5a923131SAndroid Build Coastguard Worker }
1218*5a923131SAndroid Build Coastguard Worker
IsTimestampNewer(const std::string_view old_version,const std::string_view new_version)1219*5a923131SAndroid Build Coastguard Worker ErrorCode IsTimestampNewer(const std::string_view old_version,
1220*5a923131SAndroid Build Coastguard Worker const std::string_view new_version) {
1221*5a923131SAndroid Build Coastguard Worker if (old_version.empty() || new_version.empty()) {
1222*5a923131SAndroid Build Coastguard Worker LOG(WARNING)
1223*5a923131SAndroid Build Coastguard Worker << "One of old/new timestamp is empty, permit update anyway. Old: "
1224*5a923131SAndroid Build Coastguard Worker << old_version << " New: " << new_version;
1225*5a923131SAndroid Build Coastguard Worker return ErrorCode::kSuccess;
1226*5a923131SAndroid Build Coastguard Worker }
1227*5a923131SAndroid Build Coastguard Worker int64_t old_ver = 0;
1228*5a923131SAndroid Build Coastguard Worker if (!ParseTimestamp(old_version, &old_ver)) {
1229*5a923131SAndroid Build Coastguard Worker return ErrorCode::kError;
1230*5a923131SAndroid Build Coastguard Worker }
1231*5a923131SAndroid Build Coastguard Worker int64_t new_ver = 0;
1232*5a923131SAndroid Build Coastguard Worker if (!ParseTimestamp(new_version, &new_ver)) {
1233*5a923131SAndroid Build Coastguard Worker return ErrorCode::kDownloadManifestParseError;
1234*5a923131SAndroid Build Coastguard Worker }
1235*5a923131SAndroid Build Coastguard Worker if (old_ver > new_ver) {
1236*5a923131SAndroid Build Coastguard Worker return ErrorCode::kPayloadTimestampError;
1237*5a923131SAndroid Build Coastguard Worker }
1238*5a923131SAndroid Build Coastguard Worker return ErrorCode::kSuccess;
1239*5a923131SAndroid Build Coastguard Worker }
1240*5a923131SAndroid Build Coastguard Worker
GetReadonlyZeroBlock(size_t size)1241*5a923131SAndroid Build Coastguard Worker std::unique_ptr<android::base::MappedFile> GetReadonlyZeroBlock(size_t size) {
1242*5a923131SAndroid Build Coastguard Worker android::base::unique_fd fd{HANDLE_EINTR(open("/dev/zero", O_RDONLY))};
1243*5a923131SAndroid Build Coastguard Worker return android::base::MappedFile::FromFd(fd, 0, size, PROT_READ);
1244*5a923131SAndroid Build Coastguard Worker }
1245*5a923131SAndroid Build Coastguard Worker
GetReadonlyZeroString(size_t size)1246*5a923131SAndroid Build Coastguard Worker std::string_view GetReadonlyZeroString(size_t size) {
1247*5a923131SAndroid Build Coastguard Worker // Reserve 512MB of Virtual Address Space. No actual memory will be used.
1248*5a923131SAndroid Build Coastguard Worker static auto zero_block = GetReadonlyZeroBlock(1024 * 1024 * 512);
1249*5a923131SAndroid Build Coastguard Worker if (size > zero_block->size()) {
1250*5a923131SAndroid Build Coastguard Worker auto larger_block = GetReadonlyZeroBlock(size);
1251*5a923131SAndroid Build Coastguard Worker zero_block = std::move(larger_block);
1252*5a923131SAndroid Build Coastguard Worker }
1253*5a923131SAndroid Build Coastguard Worker return {zero_block->data(), size};
1254*5a923131SAndroid Build Coastguard Worker }
1255*5a923131SAndroid Build Coastguard Worker
1256*5a923131SAndroid Build Coastguard Worker } // namespace utils
1257*5a923131SAndroid Build Coastguard Worker
HexEncode(const brillo::Blob & blob)1258*5a923131SAndroid Build Coastguard Worker std::string HexEncode(const brillo::Blob& blob) noexcept {
1259*5a923131SAndroid Build Coastguard Worker return base::HexEncode(blob.data(), blob.size());
1260*5a923131SAndroid Build Coastguard Worker }
1261*5a923131SAndroid Build Coastguard Worker
HexEncode(const std::string_view blob)1262*5a923131SAndroid Build Coastguard Worker std::string HexEncode(const std::string_view blob) noexcept {
1263*5a923131SAndroid Build Coastguard Worker return base::HexEncode(blob.data(), blob.size());
1264*5a923131SAndroid Build Coastguard Worker }
1265*5a923131SAndroid Build Coastguard Worker
ToStringView(const std::vector<unsigned char> & blob)1266*5a923131SAndroid Build Coastguard Worker [[nodiscard]] std::string_view ToStringView(
1267*5a923131SAndroid Build Coastguard Worker const std::vector<unsigned char>& blob) noexcept {
1268*5a923131SAndroid Build Coastguard Worker return std::string_view{reinterpret_cast<const char*>(blob.data()),
1269*5a923131SAndroid Build Coastguard Worker blob.size()};
1270*5a923131SAndroid Build Coastguard Worker }
1271*5a923131SAndroid Build Coastguard Worker
ToStringView(const void * data,size_t size)1272*5a923131SAndroid Build Coastguard Worker [[nodiscard]] std::string_view ToStringView(const void* data,
1273*5a923131SAndroid Build Coastguard Worker size_t size) noexcept {
1274*5a923131SAndroid Build Coastguard Worker return std::string_view(reinterpret_cast<const char*>(data), size);
1275*5a923131SAndroid Build Coastguard Worker }
1276*5a923131SAndroid Build Coastguard Worker
1277*5a923131SAndroid Build Coastguard Worker } // namespace chromeos_update_engine
1278