android_mt6572_jiabo/bootable/recovery/bu.cpp
2025-09-05 16:56:03 +08:00

386 lines
7.9 KiB
C++

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/vfs.h>
#include <cutils/properties.h>
#include <cutils/log.h>
#include <selinux/label.h>
#include "roots.h"
#include "bu.h"
#include "voldclient.h"
#define PATHNAME_RC "/tmp/burc"
#define PATHNAME_XCOMP_ENABLE "/sys/fs/xcomp/enable"
using namespace std;
using namespace android;
struct selabel_handle *sehandle;
int adb_ifd;
int adb_ofd;
TAR* tar;
gzFile gzf;
char* hash_name;
size_t hash_datalen;
SHA_CTX sha_ctx;
MD5_CTX md5_ctx;
void
ui_print(const char* format, ...) {
char buffer[256];
va_list ap;
va_start(ap, format);
vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
fputs(buffer, stdout);
}
void logmsg(const char *fmt, ...)
{
char msg[1024];
FILE* fp;
va_list ap;
va_start(ap, fmt);
vsnprintf(msg, sizeof(msg), fmt, ap);
va_end(ap);
fp = fopen("/tmp/bu.log", "a");
if (fp) {
fprintf(fp, "[%d] %s", getpid(), msg);
fclose(fp);
}
}
static int xcomp_enable_get(void)
{
int val = 0;
int fd;
char buf[12+1+1];
fd = open(PATHNAME_XCOMP_ENABLE, O_RDONLY);
if (fd < 0)
return 0;
memset(buf, 0, sizeof(buf));
if (read(fd, buf, sizeof(buf)) > 0) {
val = atoi(buf);
}
close(fd);
return val;
}
static void xcomp_enable_set(int val)
{
int fd;
char buf[12+1+1];
int len;
fd = open(PATHNAME_XCOMP_ENABLE, O_RDWR);
if (fd < 0)
return;
len = sprintf(buf, "%d\n", val);
write(fd, buf, len);
close(fd);
}
static partspec partlist[MAX_PART];
static partspec* curpart;
int part_add(const char* name)
{
Volume* vol = NULL;
char* path = NULL;
int i;
path = (char*)malloc(1+strlen(name)+1);
sprintf(path, "/%s", name);
vol = volume_for_path(path);
if (vol == NULL || vol->fs_type == NULL) {
logmsg("missing vol info for %s, ignoring\n", name);
goto err;
}
for (i = 0; i < MAX_PART; ++i) {
if (partlist[i].name == NULL) {
partlist[i].name = strdup(name);
partlist[i].path = path;
partlist[i].vol = vol;
logmsg("part_add: i=%d, name=%s, path=%s\n", i, name, path);
return 0;
}
if (strcmp(partlist[i].name, name) == 0) {
logmsg("duplicate partition %s, ignoring\n", name);
goto err;
}
}
err:
free(path);
return -1;
}
partspec* part_get(int i)
{
if (i >= 0 && i < MAX_PART) {
if (partlist[i].name != NULL) {
return &partlist[i];
}
}
return NULL;
}
partspec* part_find(const char* name)
{
for (int i = 0; i < MAX_PART; ++i) {
if (partlist[i].name && !strcmp(name, partlist[i].name)) {
return &partlist[i];
}
}
return NULL;
}
void part_set(partspec* part)
{
curpart = part;
curpart->off = 0;
}
int update_progress(uint64_t off)
{
static time_t last_time = 0;
static int last_pct = 0;
if (curpart) {
curpart->off += off;
time_t now = time(NULL);
int pct = min(100, (int)((uint64_t)100*curpart->off/curpart->used));
if (now != last_time && pct != last_pct) {
char msg[256];
sprintf(msg, "%s: %d%% complete", curpart->name, pct);
ui_print(msg);
last_time = now;
last_pct = pct;
}
}
return 0;
}
static int tar_cb_open(const char* path, int mode, ...)
{
errno = EINVAL;
return -1;
}
static int tar_cb_close(int fd)
{
return 0;
}
static ssize_t tar_cb_read(int fd, void* buf, size_t len)
{
ssize_t nread;
nread = ::read(fd, buf, len);
if (nread > 0 && hash_name) {
SHA1_Update(&sha_ctx, (u_char*)buf, nread);
MD5_Update(&md5_ctx, buf, nread);
hash_datalen += nread;
}
update_progress(nread);
return nread;
}
static ssize_t tar_cb_write(int fd, const void* buf, size_t len)
{
ssize_t written = 0;
if (hash_name) {
SHA1_Update(&sha_ctx, (u_char*)buf, len);
MD5_Update(&md5_ctx, buf, len);
hash_datalen += len;
}
while (len > 0) {
ssize_t n = ::write(fd, buf, len);
if (n < 0) {
logmsg("tar_cb_write: error: n=%d\n", n);
return n;
}
if (n == 0)
break;
buf = (const char *)buf + n;
len -= n;
written += n;
}
update_progress(written);
return written;
}
static tartype_t tar_io = {
tar_cb_open,
tar_cb_close,
tar_cb_read,
tar_cb_write
};
static ssize_t tar_gz_cb_read(int fd, void* buf, size_t len)
{
int nread;
nread = gzread(gzf, buf, len);
if (nread > 0 && hash_name) {
SHA1_Update(&sha_ctx, (u_char*)buf, nread);
MD5_Update(&md5_ctx, buf, nread);
hash_datalen += nread;
}
update_progress(nread);
return nread;
}
static ssize_t tar_gz_cb_write(int fd, const void* buf, size_t len)
{
ssize_t written = 0;
if (hash_name) {
SHA1_Update(&sha_ctx, (u_char*)buf, len);
MD5_Update(&md5_ctx, buf, len);
hash_datalen += len;
}
while (len > 0) {
ssize_t n = gzwrite(gzf, buf, len);
if (n < 0) {
logmsg("tar_gz_cb_write: error: n=%d\n", n);
return n;
}
if (n == 0)
break;
buf = (const char *)buf + n;
len -= n;
written += n;
}
update_progress(written);
return written;
}
static tartype_t tar_io_gz = {
tar_cb_open,
tar_cb_close,
tar_gz_cb_read,
tar_gz_cb_write
};
int create_tar(int fd, const char* compress, const char* mode)
{
int rc = -1;
SHA1_Init(&sha_ctx);
MD5_Init(&md5_ctx);
if (!compress || strcasecmp(compress, "none") == 0) {
rc = tar_fdopen(&tar, fd, "foobar", &tar_io,
0, /* oflags: unused */
0, /* mode: unused */
TAR_GNU | TAR_STORE_SELINUX /* options */);
}
else if (strcasecmp(compress, "gzip") == 0) {
gzf = gzdopen(fd, mode);
if (gzf != NULL) {
rc = tar_fdopen(&tar, 0, "foobar", &tar_io_gz,
0, /* oflags: unused */
0, /* mode: unused */
TAR_GNU | TAR_STORE_SELINUX /* options */);
}
}
return rc;
}
static void do_exit(int rc)
{
char rcstr[80];
int len;
len = sprintf(rcstr, "%d\n", rc);
unlink(PATHNAME_RC);
int fd = open(PATHNAME_RC, O_RDWR|O_CREAT, 0644);
write(fd, rcstr, len);
close(fd);
exit(rc);
}
int main(int argc, char **argv)
{
int n;
int rc = 1;
int xcomp_enable;
const char* logfile = "/tmp/recovery.log";
adb_ifd = dup(STDIN_FILENO);
adb_ofd = dup(STDOUT_FILENO);
freopen(logfile, "a", stdout); setbuf(stdout, NULL);
freopen(logfile, "a", stderr); setbuf(stderr, NULL);
logmsg("bu: invoked with %d args\n", argc);
if (argc < 2) {
logmsg("Not enough args (%d)\n", argc);
do_exit(1);
}
// progname args...
int optidx = 1;
const char* opname = argv[optidx++];
struct selinux_opt seopts[] = {
{ SELABEL_OPT_PATH, "/file_contexts" }
};
sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
xcomp_enable = xcomp_enable_get();
xcomp_enable_set(0);
load_volume_table();
vdc = new VoldClient();
vdc->start();
if (!strcmp(opname, "backup")) {
ui_print("Backup in progress...");
rc = do_backup(argc-optidx, &argv[optidx]);
}
else if (!strcmp(opname, "restore")) {
ui_print("Restore in progress...");
rc = do_restore(argc-optidx, &argv[optidx]);
}
else {
logmsg("Unknown operation %s\n", opname);
rc = 1;
}
xcomp_enable_set(xcomp_enable);
close(adb_ofd);
close(adb_ifd);
sleep(1);
logmsg("bu exiting\n");
do_exit(rc);
return rc;
}