summaryrefslogtreecommitdiff
path: root/recovery/updater_extra/install_amlogic.cpp (plain)
blob: f408d708583ee2f42af58f06c23ee587630df614
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <ctype.h>
18#include <errno.h>
19#include <stdarg.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/mount.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/wait.h>
27#include <unistd.h>
28#include <fcntl.h>
29#include <time.h>
30#include <selinux/selinux.h>
31#include <ftw.h>
32#include <sys/capability.h>
33#include <sys/xattr.h>
34#include <linux/xattr.h>
35#include <inttypes.h>
36#include <ziparchive/zip_archive.h>
37
38#include <memory>
39#include <vector>
40
41#include "bootloader.h"
42#include "cutils/android_reboot.h"
43#include "cutils/properties.h"
44#include "edify/expr.h"
45#include "error_code.h"
46#include "updater/updater.h"
47#include "check/dtbcheck.h"
48#include "ubootenv/uboot_env.h"
49
50#include "roots.h"
51#include <bootloader_message/bootloader_message.h>
52#include <fs_mgr.h>
53
54
55#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0])
56#define EMMC_USER_PARTITION "bootloader"
57#define EMMC_BLK0BOOT0_PARTITION "mmcblk0boot0"
58#define EMMC_BLK0BOOT1_PARTITION "mmcblk0boot1"
59#define EMMC_BLK1BOOT0_PARTITION "mmcblk1boot0"
60#define EMMC_BLK1BOOT1_PARTITION "mmcblk1boot1"
61#define COMMAND_FILE "/cache/recovery/command"
62#define CACHE_ROOT "/cache"
63
64
65enum emmcPartition {
66 USER = 0,
67 BLK0BOOT0,
68 BLK0BOOT1,
69 BLK1BOOT0,
70 BLK1BOOT1,
71};
72
73static int sEmmcPartionIndex = -1;
74static const char *sEmmcPartionName[] = {
75 EMMC_USER_PARTITION,
76 EMMC_BLK0BOOT0_PARTITION,
77 EMMC_BLK0BOOT1_PARTITION,
78 EMMC_BLK1BOOT0_PARTITION,
79 EMMC_BLK1BOOT1_PARTITION,
80};
81
82int RecoverySecureCheck(const ZipArchiveHandle zipArchive);
83int RecoveryDtbCheck(const ZipArchiveHandle zipArchive);
84int GetEnvPartitionOffset(const ZipArchiveHandle za);
85/*
86 * return value: 0 if no error; 1 if path not existed, -1 if access failed
87 *
88 */
89static int read_sysfs_val(const char* path, char* rBuf, const unsigned bufSz, int * readCnt)
90{
91 int ret = 0;
92 int fd = -1;
93 int count = 0;
94
95 if (access(path, F_OK)) {
96 printf("path[%s] not existed\n", path);
97 return 1;
98 }
99 if (access(path, R_OK)) {
100 printf("path[%s] cannot read\n", path);
101 return -1;
102 }
103
104 fd = open(path, O_RDONLY);
105 if (fd < 0) {
106 printf("fail in open[%s] in O_RDONLY\n", path);
107 goto _exit;
108 }
109
110 count = read(fd, rBuf, bufSz);
111 if (count <= 0) {
112 printf("read %s failed (count:%d)\n",
113 path, count);
114 close(fd);
115 return -1;
116 }
117 *readCnt = count;
118
119 ret = 0;
120_exit:
121 if (fd >= 0) close(fd);
122 return ret;
123}
124
125static int getBootloaderOffset(int* bootloaderOffset)
126{
127 const char* PathBlOff = "/sys/class/aml_store/bl_off_bytes" ;
128 int iret = 0;
129 int blOff = 0;
130 char buf[16] = { 0 };
131 int readCnt = 0;
132
133 iret = read_sysfs_val(PathBlOff, buf, 16, &readCnt);
134 if (iret < 0) {
135 printf("fail when read path[%s]\n", PathBlOff);
136 return __LINE__;
137 }
138 buf[readCnt] = 0;
139 *bootloaderOffset = atoi(buf);
140 printf("bootloaderOffset is %s\n", buf);
141
142 return 0;
143}
144
145static int _mmcblOffBytes = 0;
146
147
148static int write_data(int fd, const char *data, ssize_t len)
149{
150 ssize_t size = len;
151 char *verify = NULL;
152
153 off_t pos = lseek(fd, 0, SEEK_CUR);
154 fprintf(stderr, "data len = %d, pos = %ld\n", len, pos);
155
156
157 if (write(fd, data, len) != len) {
158 fprintf(stderr, " write error at 0x%08lx (%s)\n",pos, strerror(errno));
159 return -1;
160 }
161
162 verify = (char *)malloc(size);
163 if (verify == NULL) {
164 fprintf(stderr, "block: failed to malloc size=%u (%s)\n", size, strerror(errno));
165 return -1;
166 }
167
168 if ((lseek(fd, pos, SEEK_SET) != pos) ||(read(fd, verify, size) != size)) {
169 fprintf(stderr, "block: re-read error at 0x%08lx (%s)\n",pos, strerror(errno));
170 if (verify) {
171 free(verify);
172 }
173 return -1;
174 }
175
176 if (memcmp(data, verify, size) != 0) {
177 fprintf(stderr, "block: verification error at 0x%08lx (%s)\n",pos, strerror(errno));
178 if (verify) {
179 free(verify);
180 }
181 return -1;
182 }
183
184 fprintf(stderr, "successfully wrote data at %ld\n", pos);
185 if (verify) {
186 free(verify);
187 }
188
189 return len;
190}
191
192
193//return value
194// -1 : failed
195// 0 : success
196static int backup_partition_data(const char *name,const char *dir, long offset) {
197 int ret = 0;
198 int fd = 0;
199 FILE *fp = NULL;
200 int sor_fd = -1;
201 int dst_fd = -1;
202 ssize_t wrote = 0;
203 ssize_t readed = 0;
204 char devpath[128] = {0};
205 char dstpath[128] = {0};
206 const int BUFFER_MAX = 32*1024*1024; //Max support 32*M
207 printf("backup partition name:%s, to dir:%s\n", name, dir);
208
209 if ((name == NULL) || (dir == NULL)) {
210 fprintf(stderr, "name(%s) or dir(%s) is NULL!\n", name, dir);
211 return -1;
212 }
213
214 if (!strcmp(name, "dtb")) {//dtb is char device
215 sprintf(devpath, "/dev/%s", name);
216 } else {
217 sprintf(devpath, "/dev/block/%s", name);
218 }
219
220 sprintf(dstpath, "%s%s.img", dir, name);
221
222 sor_fd = open(devpath, O_RDONLY);
223 if (sor_fd < 0) {
224 fprintf(stderr, "open %s failed (%s)\n",devpath, strerror(errno));
225 return -1;
226 }
227
228 dst_fd = open(dstpath, O_WRONLY | O_CREAT, 00777);
229 if (dst_fd < 0) {
230 fprintf(stderr, "open %s failed (%s)\n",dstpath, strerror(errno));
231 return -1;
232 }
233
234 char* buffer = (char *)malloc(BUFFER_MAX);
235 if (buffer == NULL) {
236 fprintf(stderr, "can't malloc %d buffer!\n", BUFFER_MAX);
237 goto err_out;
238 }
239
240 if (strcmp(name, "dtb")) {
241 lseek(sor_fd, offset, SEEK_SET);
242 }
243
244 readed = read(sor_fd, buffer, BUFFER_MAX);
245 if (readed <= 0) {
246 fprintf(stderr, "read failed read:%d!\n", readed);
247 goto err_out;
248 }
249
250 wrote = write(dst_fd, buffer, readed);
251 if (wrote != readed) {
252 fprintf(stderr, "write %s failed (%s)\n",dstpath, strerror(errno));
253 goto err_out;
254 }
255
256 close(dst_fd);
257 close(sor_fd);
258 free(buffer);
259 buffer == NULL;
260
261 //umount /cache and do fsync for data save
262 ret = umount("/cache");
263 if (ret != 0) {
264 fprintf(stderr, "umount cache failed (%s)\n",dstpath, strerror(errno));
265 }
266
267 fd = open("/dev/block/cache", O_RDWR);
268 if (fd < 0) {
269 fprintf(stderr, "open %s failed (%s)\n","/dev/block/cache", strerror(errno));
270 return -1;
271 }
272
273 fp = fdopen(fd, "r+");
274 if (fp == NULL) {
275 printf("fdopen failed!\n");
276 close(fd);
277 return -1;
278 }
279
280 fflush(fp);
281 fsync(fd);
282 fclose(fp);
283
284 ret = mount("/dev/block/cache", "/cache", "ext4",\
285 MS_NOATIME | MS_NODEV | MS_NODIRATIME,"discard");
286 if (ret < 0 ) {
287 fprintf(stderr, "mount cache failed (%s)\n","/dev/block/cache", strerror(errno));
288 }
289
290 return 0;
291
292
293err_out:
294 if (sor_fd > 0) {
295 close(sor_fd);
296 }
297
298 if (dst_fd > 0) {
299 close(dst_fd);
300 }
301
302 if (buffer) {
303 free(buffer);
304 buffer == NULL;
305 }
306
307 return -1;
308
309}
310
311
312static ssize_t write_chrdev_data(const char *dev, const char *data, const ssize_t size)
313{
314 int fd = -1;
315 ssize_t wrote = 0;
316 ssize_t readed = 0;
317 char *verify = NULL;
318
319 fd = open(dev, O_RDWR);
320 if (fd < 0) {
321 fprintf(stderr, "open %s failed (%s)\n", dev, strerror(errno));
322 return -1;
323 }
324
325 fprintf(stderr, "data len = %d\n", size);
326 if ((wrote = write(fd, data, size)) != size) {
327 fprintf(stderr, "wrote error, count %d (%s)\n",wrote, strerror(errno));
328 goto err;
329 }
330
331 fsync(fd);
332 close(fd);
333 sync();
334
335 fd = open(dev, O_RDWR);
336 if (fd < 0) {
337 fprintf(stderr, "open %s failed after wrote success (%s)\n", dev, strerror(errno));
338 return -1;
339 }
340
341 verify = (char *)malloc(256*1024);
342 if (verify == NULL) {
343 fprintf(stderr, "failed to malloc size=%d (%s)\n", size, strerror(errno));
344 goto err;
345 }
346
347 memset(verify, 0, 256*1024);
348
349 if ((readed = read(fd, verify, size)) != size) {
350 fprintf(stderr, "readed error, count %d (%s)\n", readed, strerror(errno));
351 if (verify != NULL) {
352 free(verify);
353 }
354 goto err;
355 }
356
357 if (memcmp(data, verify, size) != 0) {
358 fprintf(stderr, "verification error, wrote != readed\n");
359 if (verify != NULL) {
360 free(verify);
361 }
362 goto err;
363 }
364
365 fprintf(stderr, " successfully wrote data\n");
366 if (verify != NULL) {
367 free(verify);
368 }
369
370 if (fd > 0) {
371 close(fd);
372 }
373 return wrote;
374
375err:
376 if (fd > 0) {
377 close(fd);
378 }
379 return -1;
380}
381
382int block_write_data( const std::string& args, off_t offset) {
383 int fd = -1;
384 int result = 0;
385 bool success = false;
386 char * tmp_name = NULL;
387 char devname[64] = {0};
388
389 memset(devname, 0, sizeof(devname));
390 sprintf(devname, "/dev/%s", "bootloader"); //nand partition
391 fd = open(devname, O_RDWR);
392 if (fd < 0) {
393 memset(devname, 0, sizeof(devname));
394 // emmc user, boot0, boot1 partition
395 sprintf(devname, "/dev/block/%s", sEmmcPartionName[sEmmcPartionIndex]);
396 fd = open(devname, O_RDWR);
397 if (fd < 0) {
398 tmp_name = "mtdblock0";
399 memset(devname, 0, sizeof(devname));
400 sprintf(devname, "/dev/block/%s", tmp_name); //spi partition
401 fd = open(devname, O_RDWR);
402 if (fd < 0) {
403 printf("failed to open %s\n", devname);
404 goto done;
405 }
406 }
407
408 printf("start to write bootloader to %s...\n", devname);
409 lseek(fd, offset, SEEK_SET);//seek to skip mmc area since gxl
410 ssize_t wrote = write_data(fd, args.c_str(), args.size());
411 success = (wrote == args.size());
412
413
414 if (!success) {
415 fprintf(stderr, "write_data to %s partition failed: %s\n", devname, strerror(errno));
416 } else {
417 printf("write_data to %s partition successful\n", devname);
418 }
419 } else {
420 printf("start to write bootloader to %s...\n", devname);
421 success = true;
422 int size = args.size();
423 lseek(fd, offset, SEEK_SET);//need seek one sector to skip MBR area since gxl
424 fprintf(stderr, "size = %d offset = %d\n", size, offset);
425 if (write(fd, args.c_str(), size) != size) {
426 fprintf(stderr, " write error at offset :%d (%s)\n",offset, strerror(errno));
427 success = false;
428 }
429
430 if (!success) {
431 fprintf(stderr, "write_data to %s partition failed: %s\n", devname, strerror(errno));
432 } else {
433 printf("write_data to %s partition successful\n", devname);
434 }
435 }
436
437 result = success ? 0 : -1;
438 return result;
439
440done:
441 if (fd > 0) {
442 close(fd);
443 fd = -1;
444 }
445 return -1;
446}
447
448
449Value* WriteBootloaderImageFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
450 char* result = NULL;
451 int iRet = 0;
452
453 if (argv.size() != 1) {
454 return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name);
455 }
456
457 std::vector<std::unique_ptr<Value>> args;
458 if (!ReadValueArgs(state, argv, &args)) {
459 return nullptr;
460 }
461
462 if ((args[0]->type == VAL_STRING || (args[0]->data.size())) == 0) {
463 ErrorAbort(state, kArgsParsingFailure, "file argument to %s can't be empty", name);
464 return nullptr;
465 }
466
467 iRet = getBootloaderOffset(&_mmcblOffBytes);
468 if (iRet) {
469 printf("Fail in getBootloaderOffset, ret=%d\n", iRet);
470 return StringValue("bootloader err");
471 }
472
473 unsigned int i;
474 char emmcPartitionPath[128];
475 for (i = BLK0BOOT0; i < ARRAY_SIZE(sEmmcPartionName); i ++) {
476 memset(emmcPartitionPath, 0, sizeof(emmcPartitionPath));
477 sprintf(emmcPartitionPath, "/dev/block/%s", sEmmcPartionName[i]);
478 if (!access(emmcPartitionPath, F_OK)) {
479 sEmmcPartionIndex = i;
480 iRet = block_write_data(args[0]->data, _mmcblOffBytes);
481 if (iRet == 0) {
482 printf("Write Uboot Image to %s successful!\n\n", sEmmcPartionName[sEmmcPartionIndex]);
483 } else {
484 printf("Write Uboot Image to %s failed!\n\n", sEmmcPartionName[sEmmcPartionIndex]);
485 printf("iRet= %d, exit !!!\n", iRet);
486 return ErrorAbort(state, kFwriteFailure, "%s() update bootloader", name);
487 }
488 }
489 }
490
491 sEmmcPartionIndex = USER;
492 iRet = block_write_data(args[0]->data, _mmcblOffBytes);
493 if (iRet == 0) {
494 printf("Write Uboot Image successful!\n\n");
495 } else {
496 printf("Write Uboot Image failed!\n\n");
497 printf("iRet= %d, exit !!!\n", iRet);
498 return ErrorAbort(state, kFwriteFailure, "%s() update bootloader", name);
499 }
500
501 return StringValue("bootloader");
502}
503
504Value* WriteDtbImageFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
505 bool success = false;
506 const char *DTB_DEV= "/dev/dtb";
507 const int DTB_DATA_MAX = 256*1024;// write 256K dtb datas to dtb device maximum,kernel limit
508
509 if (argv.size() != 1) {
510 return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name);
511 }
512
513 std::vector<std::unique_ptr<Value>> args;
514
515 if (!ReadValueArgs(state, argv, &args)) {
516 return nullptr;
517 }
518
519 if (args[0]->type == VAL_INVALID) {
520 return StringValue("");
521 }
522
523 fprintf(stderr, "\nstart to write dtb.img to %s...\n", DTB_DEV);
524 if (args[0]->type == VAL_BLOB) {
525 fprintf(stderr, "contents type: VAL_BLOB\ncontents size: %d\n", args[0]->data.size());
526 if (!args[0]->data.c_str() || -1 == args[0]->data.size()) {
527 fprintf(stderr, "#ERR:BLOb Data extracted FAILED for dtb\n");
528 success = false;
529 } else {
530 if (args[0]->data.size() > DTB_DATA_MAX) {
531 fprintf(stderr, "data size(%d) out of range size(max:%d)\n", args[0]->data.size(), DTB_DATA_MAX);
532 return StringValue("");
533 }
534 ssize_t wrote = write_chrdev_data(DTB_DEV, args[0]->data.c_str(), args[0]->data.size());
535 success = (wrote == args[0]->data.size());
536 }
537 }
538
539 if (!success) {
540 return ErrorAbort(state, kFwriteFailure, "%s() update dtb failed", name);
541 } else {
542 return StringValue("dtb");
543 }
544}
545
546Value* SetBootloaderEnvFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
547 int ret = 0;
548 if (argv.size() != 2) {
549 return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %zu", name,argv.size());
550 }
551
552 std::vector<std::string> args;
553 if (!ReadArgs(state, argv, &args)) {
554 return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
555 }
556
557 const std::string& env_name = args[0];
558 const std::string& env_val = args[1];
559
560 if ((env_name.size() == 0) || (env_val.size() == 0)) {
561 return ErrorAbort(state, kArgsParsingFailure, "%s() Failed, one of the argument(s) is null ", name);
562 }
563
564 //rm backup dtb.img and recovery.img
565 if ((!strcmp(env_val.c_str(), "1")) || (!strcmp(env_val.c_str(), "2"))) {
566 struct stat st;
567 if (stat("/cache/recovery/dtb.img", &st) == 0) {
568 unlink("/cache/recovery/dtb.img");
569 }
570
571 if (stat("/cache/recovery/recovery.img", &st) == 0) {
572 unlink("/cache/recovery/recovery.img");
573 }
574 }
575
576 ret = set_bootloader_env(env_name.c_str(), env_val.c_str());
577 printf("setenv %s %s %s.(%d)\n", env_name.c_str(), env_val.c_str(), (ret < 0) ? "failed" : "successful", ret);
578 if (!ret) {
579 return StringValue("success");
580 } else {
581 return StringValue("");
582 }
583}
584
585
586Value* OtaZipCheck(const char* name, State* state,
587 const std::vector<std::unique_ptr<Expr>>&argv) {
588 int check = 0;
589 ZipArchiveHandle za = static_cast<UpdaterInfo*>(state->cookie)->package_zip;
590
591 printf("\n-- Secure Check...\n");
592
593 check = RecoverySecureCheck(za);
594 if (check <= 0) {
595 return ErrorAbort(state, "Secure check failed. %s\n\n", !check ? "(Not match)" : "");
596 } else if (check == 1) {
597 printf("Secure check complete.\n\n");
598 }
599
600#ifndef RECOVERY_DISABLE_DTB_CHECK
601 printf("\n-- Dtb Check...\n");
602
603 check = RecoveryDtbCheck(za);
604 if (check != 0) {
605 if (check > 1) {
606 printf("dtb check not match, but can upgrade by two step.\n\n");
607 return StringValue(strdup("1"));
608 }
609 return ErrorAbort(state, "Dtb check failed. %s\n\n", !check ? "(Not match)" : "");
610 } else {
611 printf("dtb check complete.\n\n");
612 }
613#endif
614 return StringValue(strdup("0"));
615}
616
617Value* BackupDataCache(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
618 int ret = 0;
619 if (argv.size() != 2) {
620 return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %zu", name, argv.size());
621 }
622
623 std::vector<std::string> args;
624 if (!ReadArgs(state, argv, &args)) {
625 return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
626 }
627
628 const std::string& partition = args[0];
629 const std::string& destination = args[1];
630
631 ret = backup_partition_data(partition.c_str(), destination.c_str(), 0);
632 if (ret != 0) {
633 printf("backup %s to %s , failed!\n", partition.c_str(), destination.c_str());
634 } else {
635 printf("backup %s to %s , success!\n", partition.c_str(), destination.c_str());
636 }
637
638 return StringValue("backup");
639}
640
641Value* RebootRecovery(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
642 struct bootloader_message boot {};
643 std::string err;
644
645 read_bootloader_message(&boot, &err);
646
647 if (strstr(boot.recovery, "--update_package=")) {
648 strlcat(boot.recovery, "--wipe_data\n", sizeof(boot.recovery));
649 }
650
651 printf("write_bootloader_message \n");
652 if (!write_bootloader_message(boot, &err)) {
653 printf("%s\n", err.c_str());
654 return ErrorAbort(state, "write_bootloader_message failed!\n");
655 }
656
657 property_set(ANDROID_RB_PROPERTY, "reboot,recovery");
658 sleep(5);
659
660 return ErrorAbort(state, "reboot to recovery failed!\n");
661}
662
663Value* SetUpdateStage(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
664 int ret = 0;
665 if (argv.size() != 1) {
666 return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 args, got %zu", name, argv.size());
667 }
668
669 std::vector<std::string> args;
670 if (!ReadArgs(state, argv, &args)) {
671 return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
672 }
673
674 const std::string& stage_step = args[0];
675
676 FILE *pf = fopen("/cache/recovery/stage", "w+");
677 if (pf == NULL) {
678 return ErrorAbort(state, "fopen stage failed!\n");
679 }
680
681 int len = fwrite(stage_step.c_str(), 1, strlen(stage_step.c_str()), pf);
682 printf("stage write len:%d, %s\n", len, stage_step.c_str());
683 fflush(pf);
684 fclose(pf);
685
686 return StringValue("done");
687}
688
689Value* GetUpdateStage(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
690 char buff[128] = {0};
691
692 FILE *pf = fopen("/cache/recovery/stage", "r");
693 if (pf == NULL) {
694 return StringValue("0");
695 }
696
697 int len = fread(buff, 1, 128, pf);
698 printf("stage fread len:%d, %s\n", len, buff);
699 fclose(pf);
700
701 return StringValue(buff);
702}
703
704Value* BackupEnvPartition(const char* name, State* state,
705 const std::vector<std::unique_ptr<Expr>>&argv) {
706 int offset = 0;
707 char tmpbuf[32] = {0};
708 ZipArchiveHandle za = static_cast<UpdaterInfo*>(state->cookie)->package_zip;
709
710 offset = GetEnvPartitionOffset(za);
711 if (offset <= 0) {
712 return ErrorAbort(state, "get env partition offset failed!\n");
713 }
714
715 offset = offset/(1024*1024);
716
717 sprintf(tmpbuf, "%s%d", "seek=", offset);
718 char *args2[7] = {"/sbin/busybox", "dd", "if=/dev/block/env", "of=/dev/block/mmcblk0", "bs=1M"};
719 args2[5] = &tmpbuf[0];
720 args2[6] = nullptr;
721 pid_t child = fork();
722 if (child == 0) {
723 execv("/sbin/busybox", args2);
724 printf("execv failed\n");
725 _exit(EXIT_FAILURE);
726 }
727
728 int status;
729 waitpid(child, &status, 0);
730 if (WIFEXITED(status)) {
731 if (WEXITSTATUS(status) != 0) {
732 ErrorAbort(state,"child exited with status:%d\n", WEXITSTATUS(status));
733 }
734 } else if (WIFSIGNALED(status)) {
735 ErrorAbort(state,"child terminated by signal :%d\n", WTERMSIG(status));
736 }
737
738 return StringValue(strdup("0"));
739}
740
741void Register_libinstall_amlogic() {
742 RegisterFunction("write_dtb_image", WriteDtbImageFn);
743 RegisterFunction("write_bootloader_image", WriteBootloaderImageFn);
744 RegisterFunction("reboot_recovery", RebootRecovery);
745 RegisterFunction("backup_data_cache", BackupDataCache);
746 RegisterFunction("set_bootloader_env", SetBootloaderEnvFn);
747 RegisterFunction("ota_zip_check", OtaZipCheck);
748 RegisterFunction("get_update_stage", GetUpdateStage);
749 RegisterFunction("set_update_stage", SetUpdateStage);
750 RegisterFunction("backup_env_partition", BackupEnvPartition);
751}
752