mirror of
https://github.com/topjohnwu/Magisk
synced 2024-11-10 15:59:04 +01:00
Refactor magiskboot
This commit is contained in:
parent
e8dd1b292f
commit
a3c49de6a5
6
build.py
6
build.py
@ -266,7 +266,7 @@ def zip_main(args):
|
|||||||
with open(source, 'r') as script:
|
with open(source, 'r') as script:
|
||||||
# Add version info util_functions.sh
|
# Add version info util_functions.sh
|
||||||
util_func = script.read().replace(
|
util_func = script.read().replace(
|
||||||
'MAGISK_VERSION_STUB', 'MAGISK_VER="{}"\nMAGISK_VER_CODE={}'.format(args.versionString, args.versionCode))
|
'#MAGISK_VERSION_STUB', 'MAGISK_VER="{}"\nMAGISK_VER_CODE={}'.format(args.versionString, args.versionCode))
|
||||||
target = os.path.join('common', 'util_functions.sh')
|
target = os.path.join('common', 'util_functions.sh')
|
||||||
print('zip: ' + source + ' -> ' + target)
|
print('zip: ' + source + ' -> ' + target)
|
||||||
zipf.writestr(target, util_func)
|
zipf.writestr(target, util_func)
|
||||||
@ -316,11 +316,9 @@ def zip_uninstaller(args):
|
|||||||
source = os.path.join('scripts', 'util_functions.sh')
|
source = os.path.join('scripts', 'util_functions.sh')
|
||||||
with open(source, 'r') as script:
|
with open(source, 'r') as script:
|
||||||
# Remove the stub
|
# Remove the stub
|
||||||
util_func = script.read().replace(
|
|
||||||
'MAGISK_VERSION_STUB', '')
|
|
||||||
target = os.path.join('util_functions.sh')
|
target = os.path.join('util_functions.sh')
|
||||||
print('zip: ' + source + ' -> ' + target)
|
print('zip: ' + source + ' -> ' + target)
|
||||||
zipf.writestr(target, util_func)
|
zipf.writestr(target, script.read())
|
||||||
|
|
||||||
# Prebuilts
|
# Prebuilts
|
||||||
for chromeos in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
|
for chromeos in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
|
||||||
|
@ -182,22 +182,24 @@ static void patch_ramdisk(int root) {
|
|||||||
close(fd);
|
close(fd);
|
||||||
free(addr);
|
free(addr);
|
||||||
|
|
||||||
char *key, *value;
|
/* Disabled for now */
|
||||||
full_read("/.backup/.magisk", &addr, &size);
|
|
||||||
for (char *tok = strtok(addr, "\n"); tok; tok = strtok(NULL, "\n")) {
|
|
||||||
key = tok;
|
|
||||||
value = strchr(tok, '=') + 1;
|
|
||||||
value[-1] = '\0';
|
|
||||||
if (strcmp(key, "KEEPVERITY") == 0)
|
|
||||||
keepverity = strcmp(value, "true") == 0;
|
|
||||||
else if (strcmp(key, "KEEPFORCEENCRYPT") == 0)
|
|
||||||
keepencrypt = strcmp(value, "true") == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
excl_list = (char *[]) { "system_root", "system", "vendor", NULL };
|
// char *key, *value;
|
||||||
in_order_walk(root, fstab_patch_cb);
|
// full_read("/.backup/.magisk", &addr, &size);
|
||||||
if (!keepverity)
|
// for (char *tok = strtok(addr, "\n"); tok; tok = strtok(NULL, "\n")) {
|
||||||
unlink("/verity_key");
|
// key = tok;
|
||||||
|
// value = strchr(tok, '=') + 1;
|
||||||
|
// value[-1] = '\0';
|
||||||
|
// if (strcmp(key, "KEEPVERITY") == 0)
|
||||||
|
// keepverity = strcmp(value, "true") == 0;
|
||||||
|
// else if (strcmp(key, "KEEPFORCEENCRYPT") == 0)
|
||||||
|
// keepencrypt = strcmp(value, "true") == 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// excl_list = (char *[]) { "system_root", "system", "vendor", NULL };
|
||||||
|
// in_order_walk(root, fstab_patch_cb);
|
||||||
|
// if (!keepverity)
|
||||||
|
// unlink("/verity_key");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int strend(const char *s1, const char *s2) {
|
static int strend(const char *s1, const char *s2) {
|
||||||
@ -472,17 +474,11 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
close(system_root);
|
close(system_root);
|
||||||
} else {
|
} else {
|
||||||
char *ramdisk_xz = NULL;
|
if (access("/ramdisk.cpio.xz", R_OK) == 0) {
|
||||||
if (access("/ramdisk-recovery.xz", R_OK) == 0)
|
// High compression mode
|
||||||
ramdisk_xz = "/ramdisk-recovery.xz";
|
|
||||||
else if (access("/ramdisk.cpio.xz", R_OK) == 0)
|
|
||||||
ramdisk_xz = "/ramdisk.cpio.xz";
|
|
||||||
|
|
||||||
if (ramdisk_xz) {
|
|
||||||
// High compress mode
|
|
||||||
void *addr;
|
void *addr;
|
||||||
size_t size;
|
size_t size;
|
||||||
mmap_ro(ramdisk_xz, &addr, &size);
|
mmap_ro("/ramdisk.cpio.xz", &addr, &size);
|
||||||
int fd = creat("/ramdisk.cpio", 0);
|
int fd = creat("/ramdisk.cpio", 0);
|
||||||
unxz(addr, size, fd);
|
unxz(addr, size, fd);
|
||||||
munmap(addr, size);
|
munmap(addr, size);
|
||||||
|
@ -42,6 +42,8 @@ typedef struct cpio_newc_header {
|
|||||||
} cpio_newc_header;
|
} cpio_newc_header;
|
||||||
|
|
||||||
// Basic cpio functions
|
// Basic cpio functions
|
||||||
|
void cpio_free(cpio_entry *e);
|
||||||
|
int cpio_find(struct vector *v, const char *entry);
|
||||||
int cpio_cmp(const void *a, const void *b);
|
int cpio_cmp(const void *a, const void *b);
|
||||||
void parse_cpio(struct vector *v, const char *filename);
|
void parse_cpio(struct vector *v, const char *filename);
|
||||||
void dump_cpio(struct vector *v, const char *filename);
|
void dump_cpio(struct vector *v, const char *filename);
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
struct vector {
|
struct vector {
|
||||||
size_t size;
|
unsigned size;
|
||||||
size_t cap;
|
unsigned cap;
|
||||||
void **data;
|
void **data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,11 +26,11 @@ struct vector *vec_dup(struct vector *v);
|
|||||||
/* Usage: vec_for_each(vector *v, void *e) */
|
/* Usage: vec_for_each(vector *v, void *e) */
|
||||||
#define vec_for_each(v, e) \
|
#define vec_for_each(v, e) \
|
||||||
e = v ? (v)->data[0] : NULL; \
|
e = v ? (v)->data[0] : NULL; \
|
||||||
for (size_t _ = 0; v && _ < (v)->size; ++_, e = (v)->data[_])
|
for (int _ = 0; v && _ < (v)->size; ++_, e = (v)->data[_])
|
||||||
|
|
||||||
#define vec_for_each_r(v, e) \
|
#define vec_for_each_r(v, e) \
|
||||||
e = v ? (v)->data[(v)->size - 1] : NULL; \
|
e = v ? (v)->data[(v)->size - 1] : NULL; \
|
||||||
for (size_t _ = (v)->size; v && _ > 0; --_, e = (v)->data[_ - 1])
|
for (int _ = ((int) (v)->size) - 1; v && _ >= 0; --_, e = (v)->data[_])
|
||||||
|
|
||||||
#define vec_cur(v) vec_entry(v)[_]
|
#define vec_cur(v) vec_entry(v)[_]
|
||||||
|
|
||||||
|
@ -55,7 +55,6 @@ static void print_hdr(const boot_img_hdr *hdr) {
|
|||||||
}
|
}
|
||||||
fprintf(stderr, "NAME [%s]\n", hdr->name);
|
fprintf(stderr, "NAME [%s]\n", hdr->name);
|
||||||
fprintf(stderr, "CMDLINE [%s]\n", hdr->cmdline);
|
fprintf(stderr, "CMDLINE [%s]\n", hdr->cmdline);
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_img(const char *image, boot_img *boot) {
|
int parse_img(const char *image, boot_img *boot) {
|
||||||
@ -63,7 +62,7 @@ int parse_img(const char *image, boot_img *boot) {
|
|||||||
int is_blk = mmap_ro(image, &boot->map_addr, &boot->map_size);
|
int is_blk = mmap_ro(image, &boot->map_addr, &boot->map_size);
|
||||||
|
|
||||||
// Parse image
|
// Parse image
|
||||||
fprintf(stderr, "Parsing boot image: [%s]\n\n", image);
|
fprintf(stderr, "Parsing boot image: [%s]\n", image);
|
||||||
for (size_t pos = 0; pos < boot->map_size; pos += 256) {
|
for (size_t pos = 0; pos < boot->map_size; pos += 256) {
|
||||||
switch (check_type(boot->map_addr + pos)) {
|
switch (check_type(boot->map_addr + pos)) {
|
||||||
case CHROMEOS:
|
case CHROMEOS:
|
||||||
@ -143,7 +142,6 @@ int parse_img(const char *image, boot_img *boot) {
|
|||||||
fprintf(stderr, "KERNEL_FMT [%s]\n", fmt);
|
fprintf(stderr, "KERNEL_FMT [%s]\n", fmt);
|
||||||
get_type_name(boot->ramdisk_type, fmt);
|
get_type_name(boot->ramdisk_type, fmt);
|
||||||
fprintf(stderr, "RAMDISK_FMT [%s]\n", fmt);
|
fprintf(stderr, "RAMDISK_FMT [%s]\n", fmt);
|
||||||
fprintf(stderr, "\n");
|
|
||||||
|
|
||||||
return boot->flags & CHROMEOS_FLAG ? CHROMEOS_RET :
|
return boot->flags & CHROMEOS_FLAG ? CHROMEOS_RET :
|
||||||
((is_blk && boot->tail_size < 500 * 1024) ? INSUF_BLOCK_RET : 0);
|
((is_blk && boot->tail_size < 500 * 1024) ? INSUF_BLOCK_RET : 0);
|
||||||
@ -206,7 +204,7 @@ void repack(const char* orig_image, const char* out_image) {
|
|||||||
// Parse original image
|
// Parse original image
|
||||||
parse_img(orig_image, &boot);
|
parse_img(orig_image, &boot);
|
||||||
|
|
||||||
fprintf(stderr, "Repack to boot image: [%s]\n\n", out_image);
|
fprintf(stderr, "Repack to boot image: [%s]\n", out_image);
|
||||||
|
|
||||||
// Create new image
|
// Create new image
|
||||||
int fd = creat(out_image, 0644);
|
int fd = creat(out_image, 0644);
|
||||||
|
@ -437,7 +437,7 @@ void decomp_file(char *from, const char *to) {
|
|||||||
fd = STDOUT_FILENO;
|
fd = STDOUT_FILENO;
|
||||||
} else {
|
} else {
|
||||||
fd = creat(to, 0644);
|
fd = creat(to, 0644);
|
||||||
fprintf(stderr, "Decompressing to [%s]\n\n", to);
|
fprintf(stderr, "Decompressing to [%s]\n", to);
|
||||||
}
|
}
|
||||||
|
|
||||||
decomp(type, fd, file, size);
|
decomp(type, fd, file, size);
|
||||||
@ -498,7 +498,7 @@ void comp_file(const char *method, const char *from, const char *to) {
|
|||||||
fd = STDOUT_FILENO;
|
fd = STDOUT_FILENO;
|
||||||
} else {
|
} else {
|
||||||
fd = creat(dest, 0644);
|
fd = creat(dest, 0644);
|
||||||
fprintf(stderr, "Compressing to [%s]\n\n", dest);
|
fprintf(stderr, "Compressing to [%s]\n", dest);
|
||||||
}
|
}
|
||||||
comp(type, fd, file, size);
|
comp(type, fd, file, size);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -26,7 +26,7 @@ void hexpatch(const char *image, const char *from, const char *to) {
|
|||||||
hex2byte(to, patch);
|
hex2byte(to, patch);
|
||||||
for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) {
|
for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) {
|
||||||
if (memcmp(file + i, pattern, patternsize) == 0) {
|
if (memcmp(file + i, pattern, patternsize) == 0) {
|
||||||
fprintf(stderr, "Pattern %s found!\nPatching to %s\n", from, to);
|
fprintf(stderr, "Patch @ %08X [%s]->[%s]\n", (unsigned) i, from, to);
|
||||||
memset(file + i, 0, patternsize);
|
memset(file + i, 0, patternsize);
|
||||||
memcpy(file + i, patch, patchsize);
|
memcpy(file + i, patch, patchsize);
|
||||||
i += patternsize - 1;
|
i += patternsize - 1;
|
||||||
|
@ -18,7 +18,7 @@ void unpack(const char *image);
|
|||||||
void repack(const char* orig_image, const char* out_image);
|
void repack(const char* orig_image, const char* out_image);
|
||||||
void hexpatch(const char *image, const char *from, const char *to);
|
void hexpatch(const char *image, const char *from, const char *to);
|
||||||
int parse_img(const char *image, boot_img *boot);
|
int parse_img(const char *image, boot_img *boot);
|
||||||
int cpio_commands(const char *cmd, int argc, char *argv[]);
|
int cpio_commands(int argc, char *argv[]);
|
||||||
void comp_file(const char *method, const char *from, const char *to);
|
void comp_file(const char *method, const char *from, const char *to);
|
||||||
void decomp_file(char *from, const char *to);
|
void decomp_file(char *from, const char *to);
|
||||||
int dtb_commands(const char *cmd, int argc, char *argv[]);
|
int dtb_commands(const char *cmd, int argc, char *argv[]);
|
||||||
|
@ -36,34 +36,39 @@ static void usage(char *arg0) {
|
|||||||
" --hexpatch <file> <hexpattern1> <hexpattern2>\n"
|
" --hexpatch <file> <hexpattern1> <hexpattern2>\n"
|
||||||
" Search <hexpattern1> in <file>, and replace with <hexpattern2>\n"
|
" Search <hexpattern1> in <file>, and replace with <hexpattern2>\n"
|
||||||
"\n"
|
"\n"
|
||||||
" --cpio-<cmd> <incpio> [flags...] [args...]\n"
|
" --cpio <incpio> [commands...]\n"
|
||||||
" Do cpio related cmds to <incpio> (modifications are done directly)\n"
|
" Do cpio commands to <incpio> (modifications are done directly)\n"
|
||||||
|
" Each command is a single argument, use quotes if necessary\n"
|
||||||
" Supported commands:\n"
|
" Supported commands:\n"
|
||||||
" -rm [-r] <entry>\n"
|
" rm [-r] ENTRY\n"
|
||||||
" Remove entry from <incpio>, flag [-r] to remove recursively\n"
|
" Remove ENTRY, specify [-r] to remove recursively\n"
|
||||||
" -mkdir <mode> <entry>\n"
|
" mkdir MODE ENTRY\n"
|
||||||
" Create directory as an <entry>\n"
|
" Create directory ENTRY in permissions MODE\n"
|
||||||
" -ln <target> <entry>\n"
|
" ln TARGET ENTRY\n"
|
||||||
" Create symlink <entry> to point to <target>\n"
|
" Create a symlink to TARGET with the name ENTRY\n"
|
||||||
" -mv <from-entry> <to-entry>\n"
|
" mv SOURCE DEST\n"
|
||||||
" Move <from-entry> to <to-entry>\n"
|
" Move SOURCE to DEST\n"
|
||||||
" -add <mode> <entry> <infile>\n"
|
" add MODE ENTRY INFILE\n"
|
||||||
" Add <infile> as an <entry>; replaces <entry> if already exists\n"
|
" Add INFILE as ENTRY in permissions MODE; replaces ENTRY if exists\n"
|
||||||
" -extract [<entry> <outfile>]\n"
|
" extract [ENTRY OUT]\n"
|
||||||
" Extract <entry> to <outfile>, or extract all to current directory\n"
|
" Extract ENTRY to OUT, or extract all entries to current directory\n"
|
||||||
" -test\n"
|
" test\n"
|
||||||
|
" Test the current cpio's patch status\n"
|
||||||
" Return value: 0/stock 1/Magisk 2/other (phh, SuperSU, Xposed)\n"
|
" Return value: 0/stock 1/Magisk 2/other (phh, SuperSU, Xposed)\n"
|
||||||
" -patch <KEEPVERITY> <KEEPFORCEENCRYPT>\n"
|
" patch KEEPVERITY KEEPFORCEENCRYPT\n"
|
||||||
" Ramdisk patches. KEEP**** are boolean values\n"
|
" Ramdisk patches. KEEP**** are boolean values\n"
|
||||||
" This command is no longer used in Magisk installations\n"
|
" backup ORIG [SHA1]\n"
|
||||||
" -backup <origcpio> <HIGHCOMP> <KEEPVERITY> <KEEPFORCEENCRYPT> [SHA1]\n"
|
" Create ramdisk backups from ORIG\n"
|
||||||
" Create ramdisk backups into <incpio> from <origcpio>\n"
|
" SHA1 of stock boot image is optional\n"
|
||||||
|
" restore\n"
|
||||||
|
" Restore ramdisk from ramdisk backup stored within incpio\n"
|
||||||
|
" magisk ORIG HIGHCOMP KEEPVERITY KEEPFORCEENCRYPT [SHA1]\n"
|
||||||
|
" Do Magisk patches and backups all in one step\n"
|
||||||
|
" Create ramdisk backups from ORIG\n"
|
||||||
" HIGHCOMP, KEEP**** are boolean values\n"
|
" HIGHCOMP, KEEP**** are boolean values\n"
|
||||||
" SHA1 of stock boot image is optional\n"
|
" SHA1 of stock boot image is optional\n"
|
||||||
" -restore\n"
|
" sha1\n"
|
||||||
" Restore ramdisk from ramdisk backup within <incpio>\n"
|
" Print stock boot SHA1 if previously stored\n"
|
||||||
" -stocksha1\n"
|
|
||||||
" Get stock boot SHA1 recorded within <incpio>\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
" --dtb-<cmd> <dtb>\n"
|
" --dtb-<cmd> <dtb>\n"
|
||||||
" Do dtb related cmds to <dtb> (modifications are done directly)\n"
|
" Do dtb related cmds to <dtb> (modifications are done directly)\n"
|
||||||
@ -104,11 +109,11 @@ static void usage(char *arg0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
fprintf(stderr, "MagiskBoot v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - Boot Image Modification Tool\n\n");
|
fprintf(stderr, "MagiskBoot v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - Boot Image Modification Tool\n");
|
||||||
|
|
||||||
umask(0);
|
umask(0);
|
||||||
if (argc > 1 && strcmp(argv[1], "--cleanup") == 0) {
|
if (argc > 1 && strcmp(argv[1], "--cleanup") == 0) {
|
||||||
fprintf(stderr, "Cleaning up...\n\n");
|
fprintf(stderr, "Cleaning up...\n");
|
||||||
char name[PATH_MAX];
|
char name[PATH_MAX];
|
||||||
unlink(KERNEL_FILE);
|
unlink(KERNEL_FILE);
|
||||||
unlink(RAMDISK_FILE);
|
unlink(RAMDISK_FILE);
|
||||||
@ -146,11 +151,8 @@ int main(int argc, char *argv[]) {
|
|||||||
comp_file(method, argv[2], argc > 3 ? argv[3] : NULL);
|
comp_file(method, argv[2], argc > 3 ? argv[3] : NULL);
|
||||||
} else if (argc > 4 && strcmp(argv[1], "--hexpatch") == 0) {
|
} else if (argc > 4 && strcmp(argv[1], "--hexpatch") == 0) {
|
||||||
hexpatch(argv[2], argv[3], argv[4]);
|
hexpatch(argv[2], argv[3], argv[4]);
|
||||||
} else if (argc > 2 && strncmp(argv[1], "--cpio", 6) == 0) {
|
} else if (argc > 2 && strcmp(argv[1], "--cpio") == 0) {
|
||||||
char *cmd = argv[1] + 6;
|
if (cpio_commands(argc - 2, argv + 2)) usage(argv[0]);
|
||||||
if (*cmd == '\0') usage(argv[0]);
|
|
||||||
else ++cmd;
|
|
||||||
if (cpio_commands(cmd, argc - 2, argv + 2)) usage(argv[0]);
|
|
||||||
} else if (argc > 2 && strncmp(argv[1], "--dtb", 5) == 0) {
|
} else if (argc > 2 && strncmp(argv[1], "--dtb", 5) == 0) {
|
||||||
char *cmd = argv[1] + 5;
|
char *cmd = argv[1] + 5;
|
||||||
if (*cmd == '\0') usage(argv[0]);
|
if (*cmd == '\0') usage(argv[0]);
|
||||||
|
@ -9,19 +9,21 @@
|
|||||||
#include "cpio.h"
|
#include "cpio.h"
|
||||||
|
|
||||||
static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
|
static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
|
||||||
cpio_entry *f;
|
cpio_entry *e;
|
||||||
vec_for_each(v, f) {
|
vec_for_each(v, e) {
|
||||||
|
if (!e) continue;
|
||||||
if (!keepverity) {
|
if (!keepverity) {
|
||||||
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
|
if (strncmp(e->filename, ".backup", 7) && strstr(e->filename, "fstab") && S_ISREG(e->mode)) {
|
||||||
patch_verity(&f->data, &f->filesize, 1);
|
patch_verity(&e->data, &e->filesize, 1);
|
||||||
} else if (strcmp(f->filename, "verity_key") == 0) {
|
} else if (strcmp(e->filename, "verity_key") == 0) {
|
||||||
fprintf(stderr, "Remove [verity_key]\n");
|
fprintf(stderr, "Remove [verity_key]\n");
|
||||||
f->remove = 1;
|
cpio_free(e);
|
||||||
|
vec_cur(v) = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!keepforceencrypt) {
|
if (!keepforceencrypt) {
|
||||||
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
|
if (strstr(e->filename, "fstab") != NULL && S_ISREG(e->mode)) {
|
||||||
patch_encryption(&f->data, &f->filesize);
|
patch_encryption(&e->data, &e->filesize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,33 +34,28 @@ static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
|
|||||||
#define OTHER_PATCH 0x2
|
#define OTHER_PATCH 0x2
|
||||||
|
|
||||||
static int cpio_test(struct vector *v) {
|
static int cpio_test(struct vector *v) {
|
||||||
int ret = STOCK_BOOT;
|
|
||||||
cpio_entry *f;
|
|
||||||
const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL };
|
const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL };
|
||||||
const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL };
|
const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL };
|
||||||
vec_for_each(v, f) {
|
|
||||||
for (int i = 0; OTHER_LIST[i]; ++i) {
|
for (int i = 0; OTHER_LIST[i]; ++i)
|
||||||
if (strcmp(f->filename, OTHER_LIST[i]) == 0) {
|
if (cpio_find(v, OTHER_LIST[i]) > 0)
|
||||||
// Already find other files, abort
|
|
||||||
return OTHER_PATCH;
|
return OTHER_PATCH;
|
||||||
}
|
|
||||||
}
|
for (int i = 0; MAGISK_LIST[i]; ++i)
|
||||||
for (int i = 0; MAGISK_LIST[i]; ++i) {
|
if (cpio_find(v, MAGISK_LIST[i]) > 0)
|
||||||
if (strcmp(f->filename, MAGISK_LIST[i]) == 0)
|
return MAGISK_PATCH;
|
||||||
ret = MAGISK_PATCH;
|
|
||||||
}
|
return STOCK_BOOT;
|
||||||
}
|
|
||||||
cpio_vec_destroy(v);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *cpio_stocksha1(struct vector *v) {
|
static char *cpio_sha1(struct vector *v) {
|
||||||
cpio_entry *f;
|
cpio_entry *e;
|
||||||
char sha1[41];
|
char sha1[41];
|
||||||
vec_for_each(v, f) {
|
vec_for_each(v, e) {
|
||||||
if (strcmp(f->filename, "init.magisk.rc") == 0
|
if (!e) continue;
|
||||||
|| strcmp(f->filename, "overlay/init.magisk.rc") == 0) {
|
if (strcmp(e->filename, "init.magisk.rc") == 0
|
||||||
for (void *pos = f->data; pos < f->data + f->filesize; pos = strchr(pos + 1, '\n') + 1) {
|
|| strcmp(e->filename, "overlay/init.magisk.rc") == 0) {
|
||||||
|
for (void *pos = e->data; pos < e->data + e->filesize; pos = strchr(pos + 1, '\n') + 1) {
|
||||||
if (memcmp(pos, "# STOCKSHA1=", 12) == 0) {
|
if (memcmp(pos, "# STOCKSHA1=", 12) == 0) {
|
||||||
pos += 12;
|
pos += 12;
|
||||||
memcpy(sha1, pos, 40);
|
memcpy(sha1, pos, 40);
|
||||||
@ -66,61 +63,47 @@ static char *cpio_stocksha1(struct vector *v) {
|
|||||||
return strdup(sha1);
|
return strdup(sha1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (strcmp(f->filename, ".backup/.sha1") == 0) {
|
} else if (strcmp(e->filename, ".backup/.sha1") == 0) {
|
||||||
return f->data;
|
return e->data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct vector *cpio_backup(struct vector *v, const char *orig, const char *keepverity,
|
static void cpio_backup(struct vector *v, struct vector *bak, const char *orig, const char *sha1) {
|
||||||
const char *keepforceencrypt, const char *sha1) {
|
struct vector o_body, *o = &o_body;
|
||||||
struct vector o_body, *o = &o_body, *ret;
|
|
||||||
cpio_entry *m, *n, *rem, *cksm;
|
cpio_entry *m, *n, *rem, *cksm;
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
int res, backup;
|
int res, backup;
|
||||||
|
|
||||||
ret = xcalloc(sizeof(*ret), 1);
|
|
||||||
|
|
||||||
vec_init(o);
|
|
||||||
vec_init(ret);
|
|
||||||
|
|
||||||
m = xcalloc(sizeof(*m), 1);
|
m = xcalloc(sizeof(*m), 1);
|
||||||
m->filename = strdup(".backup");
|
m->filename = strdup(".backup");
|
||||||
m->mode = S_IFDIR;
|
m->mode = S_IFDIR;
|
||||||
vec_push_back(ret, m);
|
vec_push_back(bak, m);
|
||||||
|
|
||||||
m = xcalloc(sizeof(*m), 1);
|
|
||||||
m->filename = strdup(".backup/.magisk");
|
|
||||||
m->mode = S_IFREG;
|
|
||||||
m->data = xmalloc(50);
|
|
||||||
snprintf(m->data, 50, "KEEPVERITY=%s\nKEEPFORCEENCRYPT=%s\n", keepverity, keepforceencrypt);
|
|
||||||
m->filesize = strlen(m->data) + 1;
|
|
||||||
vec_push_back(ret, m);
|
|
||||||
|
|
||||||
rem = xcalloc(sizeof(*rem), 1);
|
rem = xcalloc(sizeof(*rem), 1);
|
||||||
rem->filename = strdup(".backup/.rmlist");
|
rem->filename = strdup(".backup/.rmlist");
|
||||||
rem->mode = S_IFREG;
|
rem->mode = S_IFREG;
|
||||||
vec_push_back(ret, rem);
|
|
||||||
|
|
||||||
if (sha1) {
|
if (sha1) {
|
||||||
fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1);
|
fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1);
|
||||||
cksm = xcalloc(sizeof(*cksm), 1);
|
cksm = xcalloc(sizeof(*cksm), 1);
|
||||||
vec_push_back(ret, cksm);
|
vec_push_back(bak, cksm);
|
||||||
cksm->filename = strdup(".backup/.sha1");
|
cksm->filename = strdup(".backup/.sha1");
|
||||||
cksm->mode = S_IFREG;
|
cksm->mode = S_IFREG;
|
||||||
cksm->data = strdup(sha1);
|
cksm->data = strdup(sha1);
|
||||||
cksm->filesize = strlen(sha1) + 1;
|
cksm->filesize = strlen(sha1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec_init(o);
|
||||||
parse_cpio(o, orig);
|
parse_cpio(o, orig);
|
||||||
// Remove possible backups in original ramdisk
|
// Remove possible backups in original ramdisk
|
||||||
cpio_rm(o, 1, ".backup");
|
cpio_rm(o, 1, ".backup");
|
||||||
cpio_rm(v, 1, ".backup");
|
cpio_rm(v, 1, ".backup");
|
||||||
|
|
||||||
// Sort both vectors before comparing
|
// Sort both vectors before comparing
|
||||||
vec_sort(v, cpio_cmp);
|
|
||||||
vec_sort(o, cpio_cmp);
|
vec_sort(o, cpio_cmp);
|
||||||
|
vec_sort(v, cpio_cmp);
|
||||||
|
|
||||||
// Start comparing
|
// Start comparing
|
||||||
size_t i = 0, j = 0;
|
size_t i = 0, j = 0;
|
||||||
@ -153,7 +136,6 @@ static struct vector *cpio_backup(struct vector *v, const char *orig, const char
|
|||||||
} else {
|
} else {
|
||||||
// Someting new in ramdisk, record in rem
|
// Someting new in ramdisk, record in rem
|
||||||
++j;
|
++j;
|
||||||
if (n->remove) continue;
|
|
||||||
rem->data = xrealloc(rem->data, rem->filesize + strlen(n->filename) + 1);
|
rem->data = xrealloc(rem->data, rem->filesize + strlen(n->filename) + 1);
|
||||||
memcpy(rem->data + rem->filesize, n->filename, strlen(n->filename) + 1);
|
memcpy(rem->data + rem->filesize, n->filename, strlen(n->filename) + 1);
|
||||||
rem->filesize += strlen(n->filename) + 1;
|
rem->filesize += strlen(n->filename) + 1;
|
||||||
@ -161,51 +143,49 @@ static struct vector *cpio_backup(struct vector *v, const char *orig, const char
|
|||||||
}
|
}
|
||||||
if (backup) {
|
if (backup) {
|
||||||
sprintf(buf, ".backup/%s", m->filename);
|
sprintf(buf, ".backup/%s", m->filename);
|
||||||
|
fprintf(stderr, "[%s] -> [%s]\n", m->filename, buf);
|
||||||
free(m->filename);
|
free(m->filename);
|
||||||
m->filename = strdup(buf);
|
m->filename = strdup(buf);
|
||||||
fprintf(stderr, "[%s] -> [%s]\n", buf, m->filename);
|
vec_push_back(bak, m);
|
||||||
vec_push_back(ret, m);
|
|
||||||
// NULL the original entry, so it won't be freed
|
// NULL the original entry, so it won't be freed
|
||||||
vec_entry(o)[i - 1] = NULL;
|
vec_entry(o)[i - 1] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rem->filesize == 0)
|
if (rem->filesize)
|
||||||
rem->remove = 1;
|
vec_push_back(bak, rem);
|
||||||
|
else
|
||||||
|
cpio_free(rem);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
cpio_vec_destroy(o);
|
cpio_vec_destroy(o);
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpio_restore(struct vector *v) {
|
static void cpio_restore(struct vector *v) {
|
||||||
cpio_entry *f, *n;
|
cpio_entry *e;
|
||||||
vec_for_each(v, f) {
|
vec_for_each(v, e) {
|
||||||
if (strncmp(f->filename, ".backup", 7) == 0) {
|
if (!e) continue;
|
||||||
f->remove = 1;
|
if (strncmp(e->filename, ".backup", 7) == 0) {
|
||||||
if (f->filename[7] == '\0') continue;
|
if (e->filename[7] == '\0') continue;
|
||||||
if (f->filename[8] == '.') {
|
if (e->filename[8] == '.') {
|
||||||
if (strcmp(f->filename, ".backup/.rmlist") == 0) {
|
if (strcmp(e->filename, ".backup/.rmlist") == 0) {
|
||||||
for (int pos = 0; pos < f->filesize; pos += strlen(f->data + pos) + 1)
|
for (int pos = 0; pos < e->filesize; pos += strlen(e->data + pos) + 1)
|
||||||
cpio_rm(v, 0, f->data + pos);
|
cpio_rm(v, 0, e->data + pos);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
n = xcalloc(sizeof(*n), 1);
|
fprintf(stderr, "Restore [%s] -> [%s]\n", e->filename, e->filename + 8);
|
||||||
memcpy(n, f, sizeof(*f));
|
vec_cur(v) = NULL;
|
||||||
n->filename = strdup(f->filename + 8);
|
char *new_name = strdup(e->filename + 8);
|
||||||
n->data = f->data;
|
free(e->filename);
|
||||||
f->data = NULL;
|
e->filename = new_name;
|
||||||
n->remove = 0;
|
cpio_vec_insert(v, e);
|
||||||
fprintf(stderr, "Restore [%s] -> [%s]\n", f->filename, n->filename);
|
|
||||||
cpio_vec_insert(v, n);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strncmp(f->filename, "overlay", 7) == 0)
|
|
||||||
f->remove = 1;
|
|
||||||
}
|
}
|
||||||
// Some known stuff we can remove
|
// Some known stuff we can remove
|
||||||
|
cpio_rm(v, 1, ".backup");
|
||||||
|
cpio_rm(v, 1, "overlay");
|
||||||
cpio_rm(v, 0, "sbin/magic_mask.sh");
|
cpio_rm(v, 0, "sbin/magic_mask.sh");
|
||||||
cpio_rm(v, 0, "init.magisk.rc");
|
cpio_rm(v, 0, "init.magisk.rc");
|
||||||
cpio_rm(v, 0, "magisk");
|
cpio_rm(v, 0, "magisk");
|
||||||
@ -235,25 +215,16 @@ static void restore_high_compress(struct vector *v, const char *incpio) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void enable_high_compress(struct vector *v, struct vector *b, const char *incpio) {
|
static void enable_high_compress(struct vector *v, struct vector *b, const char *incpio) {
|
||||||
cpio_entry *e, *magiskinit, *init;
|
cpio_entry *init, *magiskinit;
|
||||||
|
|
||||||
// Swap magiskinit with original init
|
// Swap magiskinit with original init
|
||||||
vec_for_each(b, e) {
|
int i = cpio_find(b, ".backup/init"), j = cpio_find(v, "init");
|
||||||
if (strcmp(e->filename, ".backup/init") == 0) {
|
init = vec_entry(b)[i];
|
||||||
free(e->filename);
|
magiskinit = vec_entry(v)[j];
|
||||||
e->filename = strdup("init");
|
free(init->filename);
|
||||||
init = e;
|
init->filename = strdup("init");
|
||||||
vec_for_each(v, e) {
|
vec_entry(v)[j] = init;
|
||||||
if (strcmp(e->filename, "init") == 0) {
|
vec_entry(b)[i] = NULL;
|
||||||
magiskinit = e;
|
|
||||||
vec_cur(v) = init;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vec_cur(b) = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dump_cpio(v, incpio);
|
dump_cpio(v, incpio);
|
||||||
cpio_vec_destroy(v);
|
cpio_vec_destroy(v);
|
||||||
@ -269,64 +240,93 @@ static void enable_high_compress(struct vector *v, struct vector *b, const char
|
|||||||
cpio_add(v, 0, "ramdisk.cpio.xz", incpio);
|
cpio_add(v, 0, "ramdisk.cpio.xz", incpio);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpio_commands(const char *command, int argc, char *argv[]) {
|
int cpio_commands(int argc, char *argv[]) {
|
||||||
char *incpio = argv[0];
|
char *incpio = argv[0];
|
||||||
++argv;
|
++argv;
|
||||||
--argc;
|
--argc;
|
||||||
|
|
||||||
struct vector v;
|
struct vector v;
|
||||||
vec_init(&v);
|
vec_init(&v);
|
||||||
parse_cpio(&v, incpio);
|
parse_cpio(&v, incpio);
|
||||||
|
|
||||||
if (strcmp(command, "test") == 0) {
|
int cmdc;
|
||||||
|
char *cmdv[6];
|
||||||
|
|
||||||
|
while (argc) {
|
||||||
|
cmdc = 0;
|
||||||
|
for (char *tok = strtok(argv[0], " "); tok; tok = strtok(NULL, " "))
|
||||||
|
cmdv[cmdc++] = tok;
|
||||||
|
|
||||||
|
if (strcmp(cmdv[0], "test") == 0) {
|
||||||
exit(cpio_test(&v));
|
exit(cpio_test(&v));
|
||||||
} else if (strcmp(command, "restore") == 0) {
|
} else if (strcmp(cmdv[0], "restore") == 0) {
|
||||||
restore_high_compress(&v, incpio);
|
restore_high_compress(&v, incpio);
|
||||||
cpio_restore(&v);
|
cpio_restore(&v);
|
||||||
} else if (strcmp(command, "stocksha1") == 0) {
|
} else if (strcmp(cmdv[0], "sha1") == 0) {
|
||||||
printf("%s\n", cpio_stocksha1(&v));
|
char *sha1 = cpio_sha1(&v);
|
||||||
|
if (sha1)
|
||||||
|
printf("%s\n", sha1);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (argc >= 4 && strcmp(command, "backup") == 0) {
|
} else if (cmdc >= 2 && strcmp(cmdv[0], "backup") == 0) {
|
||||||
struct vector *back;
|
struct vector back;
|
||||||
|
vec_init(&back);
|
||||||
|
cpio_backup(&v, &back, cmdv[1], cmdc > 2 ? cmdv[2] : NULL);
|
||||||
cpio_entry *e;
|
cpio_entry *e;
|
||||||
back = cpio_backup(&v, argv[0], argv[2], argv[3], argc > 4 ? argv[4] : NULL);
|
vec_for_each(&back, e)
|
||||||
|
if (e) vec_push_back(&v, e);
|
||||||
|
vec_destroy(&back);
|
||||||
|
} else if (cmdc >= 5 && strcmp(cmdv[0], "magisk") == 0) {
|
||||||
|
cpio_patch(&v, strcmp(cmdv[3], "true") == 0, strcmp(cmdv[4], "true") == 0);
|
||||||
|
|
||||||
|
struct vector back;
|
||||||
|
vec_init(&back);
|
||||||
|
cpio_backup(&v, &back, cmdv[1], cmdc > 5 ? cmdv[5] : NULL);
|
||||||
|
|
||||||
|
cpio_entry *e;
|
||||||
|
e = xcalloc(sizeof(*e), 1);
|
||||||
|
e->filename = strdup(".backup/.magisk");
|
||||||
|
e->mode = S_IFREG;
|
||||||
|
e->data = xmalloc(50);
|
||||||
|
snprintf(e->data, 50, "KEEPVERITY=%s\nKEEPFORCEENCRYPT=%s\n", cmdv[3], cmdv[4]);
|
||||||
|
e->filesize = strlen(e->data) + 1;
|
||||||
|
vec_push_back(&back, e);
|
||||||
|
|
||||||
// Enable high compression mode
|
// Enable high compression mode
|
||||||
if (strcmp(argv[1], "true") == 0)
|
if (strcmp(cmdv[2], "true") == 0)
|
||||||
enable_high_compress(&v, back, incpio);
|
enable_high_compress(&v, &back, incpio);
|
||||||
|
|
||||||
vec_for_each(back, e)
|
vec_for_each(&back, e)
|
||||||
if (e) vec_push_back(&v, e);
|
if (e) vec_push_back(&v, e);
|
||||||
|
vec_destroy(&back);
|
||||||
} else if (argc > 0 && strcmp(command, "rm") == 0) {
|
} else if (cmdc >= 2 && strcmp(cmdv[0], "rm") == 0) {
|
||||||
int recursive = 0;
|
int recur = cmdc > 2 && strcmp(cmdv[1], "-r") == 0;
|
||||||
if (argc == 2 && strcmp(argv[0], "-r") == 0) {
|
cpio_rm(&v, recur, cmdv[1 + recur]);
|
||||||
recursive = 1;
|
} else if (cmdc == 3 && strcmp(cmdv[0], "mv") == 0) {
|
||||||
++argv;
|
cpio_mv(&v, cmdv[1], cmdv[2]);
|
||||||
}
|
} else if (cmdc == 3 && strcmp(cmdv[0], "patch") == 0) {
|
||||||
cpio_rm(&v, recursive, argv[0]);
|
cpio_patch(&v, strcmp(cmdv[1], "true") == 0, strcmp(cmdv[2], "true") == 0);
|
||||||
} else if (argc == 2 && strcmp(command, "mv") == 0) {
|
} else if (strcmp(cmdv[0], "extract") == 0) {
|
||||||
if (cpio_mv(&v, argv[0], argv[1]))
|
if (cmdc == 3) {
|
||||||
return 1;
|
return cpio_extract(&v, cmdv[1], cmdv[2]);
|
||||||
} else if (argc == 2 && strcmp(command, "patch") == 0) {
|
|
||||||
cpio_patch(&v, strcmp(argv[0], "true") == 0, strcmp(argv[1], "true") == 0);
|
|
||||||
} else if (strcmp(command, "extract") == 0) {
|
|
||||||
if (argc == 2) {
|
|
||||||
return cpio_extract(&v, argv[0], argv[1]);
|
|
||||||
} else {
|
} else {
|
||||||
cpio_extract_all(&v);
|
cpio_extract_all(&v);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (argc == 2 && strcmp(command, "mkdir") == 0) {
|
} else if (cmdc == 3 && strcmp(cmdv[0], "mkdir") == 0) {
|
||||||
cpio_mkdir(&v, strtoul(argv[0], NULL, 8), argv[1]);
|
cpio_mkdir(&v, strtoul(cmdv[1], NULL, 8), cmdv[2]);
|
||||||
} else if (argc == 2 && strcmp(command, "ln") == 0) {
|
} else if (cmdc == 3 && strcmp(cmdv[0], "ln") == 0) {
|
||||||
cpio_ln(&v, argv[0], argv[1]);
|
cpio_ln(&v, cmdv[1], cmdv[2]);
|
||||||
} else if (argc == 3 && strcmp(command, "add") == 0) {
|
} else if (cmdc == 4 && strcmp(cmdv[0], "add") == 0) {
|
||||||
cpio_add(&v, strtoul(argv[0], NULL, 8), argv[1], argv[2]);
|
cpio_add(&v, strtoul(cmdv[1], NULL, 8), cmdv[2], cmdv[3]);
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--argc;
|
||||||
|
++argv;
|
||||||
|
}
|
||||||
|
|
||||||
dump_cpio(&v, incpio);
|
dump_cpio(&v, incpio);
|
||||||
cpio_vec_destroy(&v);
|
cpio_vec_destroy(&v);
|
||||||
exit(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ public:
|
|||||||
vector prop_list;
|
vector prop_list;
|
||||||
|
|
||||||
static int prop_cmp(const void *p1, const void *p2) {
|
static int prop_cmp(const void *p1, const void *p2) {
|
||||||
return strcmp((*((property **) p1))->name, (*((property **) p2))->name);
|
return strcmp(((property *) p1)->name, ((property *) p2)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_all_props_cb(const char *name, const char *value) {
|
static void print_all_props_cb(const char *name, const char *value) {
|
||||||
|
@ -22,34 +22,42 @@ static uint32_t x8u(char *hex) {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpio_free(cpio_entry *f) {
|
void cpio_free(cpio_entry *e) {
|
||||||
if (f) {
|
if (e) {
|
||||||
free(f->filename);
|
free(e->filename);
|
||||||
free(f->data);
|
free(e->data);
|
||||||
free(f);
|
free(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cpio_find(struct vector *v, const char *entry) {
|
||||||
|
cpio_entry *e;
|
||||||
|
vec_for_each(v, e) {
|
||||||
|
if (!e) continue;
|
||||||
|
if (strcmp(e->filename, entry) == 0)
|
||||||
|
return _;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int cpio_cmp(const void *a, const void *b) {
|
int cpio_cmp(const void *a, const void *b) {
|
||||||
return strcmp((*(cpio_entry **) a)->filename, (*(cpio_entry **) b)->filename);
|
return strcmp(((cpio_entry *) a)->filename, ((cpio_entry *) b)->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpio_vec_insert(struct vector *v, cpio_entry *n) {
|
void cpio_vec_insert(struct vector *v, cpio_entry *n) {
|
||||||
cpio_entry *f;
|
int i = cpio_find(v, n->filename);
|
||||||
vec_for_each(v, f) {
|
if (i > 0) {
|
||||||
if (strcmp(f->filename, n->filename) == 0) {
|
|
||||||
// Replace, then all is done
|
// Replace, then all is done
|
||||||
cpio_free(f);
|
cpio_free(vec_entry(v)[i]);
|
||||||
vec_cur(v) = n;
|
vec_entry(v)[i] = n;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
vec_push_back(v, n);
|
vec_push_back(v, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse cpio file to a vector of cpio_entry
|
// Parse cpio file to a vector of cpio_entry
|
||||||
void parse_cpio(struct vector *v, const char *filename) {
|
void parse_cpio(struct vector *v, const char *filename) {
|
||||||
fprintf(stderr, "Loading cpio: [%s]\n\n", filename);
|
fprintf(stderr, "Loading cpio: [%s]\n", filename);
|
||||||
int fd = open(filename, O_RDONLY);
|
int fd = open(filename, O_RDONLY);
|
||||||
if (fd < 0) return;
|
if (fd < 0) return;
|
||||||
cpio_newc_header header;
|
cpio_newc_header header;
|
||||||
@ -91,35 +99,34 @@ void parse_cpio(struct vector *v, const char *filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dump_cpio(struct vector *v, const char *filename) {
|
void dump_cpio(struct vector *v, const char *filename) {
|
||||||
fprintf(stderr, "\nDump cpio: [%s]\n\n", filename);
|
fprintf(stderr, "Dump cpio: [%s]\n", filename);
|
||||||
int fd = creat(filename, 0644);
|
|
||||||
unsigned inode = 300000;
|
unsigned inode = 300000;
|
||||||
char header[111];
|
char header[111];
|
||||||
// Sort by name
|
// Sort by name
|
||||||
vec_sort(v, cpio_cmp);
|
vec_sort(v, cpio_cmp);
|
||||||
cpio_entry *f;
|
cpio_entry *e;
|
||||||
vec_for_each(v, f) {
|
int fd = creat(filename, 0644);
|
||||||
if (f->remove) continue;
|
vec_for_each(v, e) {
|
||||||
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
|
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
|
||||||
inode++, // f->ino
|
inode++, // e->ino
|
||||||
f->mode,
|
e->mode,
|
||||||
f->uid,
|
e->uid,
|
||||||
f->gid,
|
e->gid,
|
||||||
1, // f->nlink
|
1, // e->nlink
|
||||||
0, // f->mtime
|
0, // e->mtime
|
||||||
f->filesize,
|
e->filesize,
|
||||||
0, // f->devmajor
|
0, // e->devmajor
|
||||||
0, // f->devminor
|
0, // e->devminor
|
||||||
0, // f->rdevmajor
|
0, // e->rdevmajor
|
||||||
0, // f->rdevminor
|
0, // e->rdevminor
|
||||||
(uint32_t) strlen(f->filename) + 1,
|
(uint32_t) strlen(e->filename) + 1,
|
||||||
0 // f->check
|
0 // e->check
|
||||||
);
|
);
|
||||||
xwrite(fd, header, 110);
|
xwrite(fd, header, 110);
|
||||||
xwrite(fd, f->filename, strlen(f->filename) + 1);
|
xwrite(fd, e->filename, strlen(e->filename) + 1);
|
||||||
file_align(fd, 4, 1);
|
file_align(fd, 4, 1);
|
||||||
if (f->filesize) {
|
if (e->filesize) {
|
||||||
xwrite(fd, f->data, f->filesize);
|
xwrite(fd, e->data, e->filesize);
|
||||||
file_align(fd, 4, 1);
|
file_align(fd, 4, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,23 +140,22 @@ void dump_cpio(struct vector *v, const char *filename) {
|
|||||||
|
|
||||||
void cpio_vec_destroy(struct vector *v) {
|
void cpio_vec_destroy(struct vector *v) {
|
||||||
// Free each cpio_entry
|
// Free each cpio_entry
|
||||||
cpio_entry *f;
|
cpio_entry *e;
|
||||||
vec_for_each(v, f) {
|
vec_for_each(v, e)
|
||||||
cpio_free(f);
|
cpio_free(e);
|
||||||
}
|
|
||||||
vec_destroy(v);
|
vec_destroy(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpio_rm(struct vector *v, int recursive, const char *entry) {
|
void cpio_rm(struct vector *v, int recursive, const char *entry) {
|
||||||
cpio_entry *f;
|
cpio_entry *e;
|
||||||
vec_for_each(v, f) {
|
size_t len = strlen(entry);
|
||||||
if (strncmp(f->filename, entry, strlen(entry)) == 0) {
|
vec_for_each(v, e) {
|
||||||
char next = f->filename[strlen(entry)];
|
if (!e) continue;
|
||||||
if ((recursive && next == '/') || next == '\0') {
|
if (strncmp(e->filename, entry, len) == 0) {
|
||||||
if (!f->remove) {
|
if ((recursive && e->filename[len] == '/') || e->filename[len] == '\0') {
|
||||||
fprintf(stderr, "Remove [%s]\n", f->filename);
|
fprintf(stderr, "Remove [%s]\n", e->filename);
|
||||||
f->remove = 1;
|
cpio_free(e);
|
||||||
}
|
vec_cur(v) = NULL;
|
||||||
if (!recursive) return;
|
if (!recursive) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,97 +163,94 @@ void cpio_rm(struct vector *v, int recursive, const char *entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cpio_mkdir(struct vector *v, mode_t mode, const char *entry) {
|
void cpio_mkdir(struct vector *v, mode_t mode, const char *entry) {
|
||||||
cpio_entry *f = xcalloc(sizeof(*f), 1);
|
cpio_entry *e = xcalloc(sizeof(*e), 1);
|
||||||
f->mode = S_IFDIR | mode;
|
e->mode = S_IFDIR | mode;
|
||||||
f->filename = strdup(entry);
|
e->filename = strdup(entry);
|
||||||
cpio_vec_insert(v, f);
|
cpio_vec_insert(v, e);
|
||||||
fprintf(stderr, "Create directory [%s] (%04o)\n",entry, mode);
|
fprintf(stderr, "Create directory [%s] (%04o)\n",entry, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpio_ln(struct vector *v, const char *target, const char *entry) {
|
void cpio_ln(struct vector *v, const char *target, const char *entry) {
|
||||||
cpio_entry *f = xcalloc(sizeof(*f), 1);
|
cpio_entry *e = xcalloc(sizeof(*e), 1);
|
||||||
f->mode = S_IFLNK;
|
e->mode = S_IFLNK;
|
||||||
f->filename = strdup(entry);
|
e->filename = strdup(entry);
|
||||||
f->filesize = strlen(target);
|
e->filesize = strlen(target);
|
||||||
f->data = strdup(target);
|
e->data = strdup(target);
|
||||||
cpio_vec_insert(v, f);
|
cpio_vec_insert(v, e);
|
||||||
fprintf(stderr, "Create symlink [%s] -> [%s]\n", entry, target);
|
fprintf(stderr, "Create symlink [%s] -> [%s]\n", entry, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpio_add(struct vector *v, mode_t mode, const char *entry, const char *filename) {
|
void cpio_add(struct vector *v, mode_t mode, const char *entry, const char *filename) {
|
||||||
int fd = xopen(filename, O_RDONLY);
|
int fd = xopen(filename, O_RDONLY);
|
||||||
cpio_entry *f = xcalloc(sizeof(*f), 1);
|
cpio_entry *e = xcalloc(sizeof(*e), 1);
|
||||||
f->mode = S_IFREG | mode;
|
e->mode = S_IFREG | mode;
|
||||||
f->filename = strdup(entry);
|
e->filename = strdup(entry);
|
||||||
f->filesize = lseek(fd, 0, SEEK_END);
|
e->filesize = lseek(fd, 0, SEEK_END);
|
||||||
lseek(fd, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
f->data = xmalloc(f->filesize);
|
e->data = xmalloc(e->filesize);
|
||||||
xxread(fd, f->data, f->filesize);
|
xxread(fd, e->data, e->filesize);
|
||||||
close(fd);
|
close(fd);
|
||||||
cpio_vec_insert(v, f);
|
cpio_vec_insert(v, e);
|
||||||
fprintf(stderr, "Add entry [%s] (%04o)\n", entry, mode);
|
fprintf(stderr, "Add entry [%s] (%04o)\n", entry, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpio_mv(struct vector *v, const char *from, const char *to) {
|
int cpio_mv(struct vector *v, const char *from, const char *to) {
|
||||||
struct cpio_entry *f, *t;
|
struct cpio_entry *e;
|
||||||
vec_for_each(v, f) {
|
int f = cpio_find(v, from), t = cpio_find(v, to);
|
||||||
if (strcmp(f->filename, from) == 0) {
|
if (f > 0) {
|
||||||
fprintf(stderr, "Move [%s] -> [%s]\n", from, to);
|
if (t > 0) {
|
||||||
vec_for_each(v, t) {
|
cpio_free(vec_entry(v)[t]);
|
||||||
if (strcmp(t->filename, to) == 0) {
|
vec_entry(v)[t] = NULL;
|
||||||
t->remove = 1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
e = vec_entry(v)[f];
|
||||||
free(f->filename);
|
free(e->filename);
|
||||||
f->filename = strdup(to);
|
e->filename = strdup(to);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fprintf(stderr, "Cannot find entry %s\n", from);
|
fprintf(stderr, "Cannot find entry %s\n", from);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpio_extract(struct vector *v, const char *entry, const char *filename) {
|
int cpio_extract(struct vector *v, const char *entry, const char *filename) {
|
||||||
cpio_entry *f;
|
int i = cpio_find(v, entry);
|
||||||
vec_for_each(v, f) {
|
if (i > 0) {
|
||||||
if (strcmp(f->filename, entry) == 0) {
|
cpio_entry *e = vec_entry(v)[i];
|
||||||
fprintf(stderr, "Extracting [%s] to [%s]\n\n", entry, filename);
|
fprintf(stderr, "Extracting [%s] to [%s]\n", entry, filename);
|
||||||
if (S_ISREG(f->mode)) {
|
if (S_ISREG(e->mode)) {
|
||||||
int fd = creat(filename, f->mode & 0777);
|
int fd = creat(filename, e->mode & 0777);
|
||||||
xwrite(fd, f->data, f->filesize);
|
xwrite(fd, e->data, e->filesize);
|
||||||
fchown(fd, f->uid, f->gid);
|
fchown(fd, e->uid, e->gid);
|
||||||
close(fd);
|
close(fd);
|
||||||
} else if (S_ISLNK(f->mode)) {
|
} else if (S_ISLNK(e->mode)) {
|
||||||
char *target = xcalloc(f->filesize + 1, 1);
|
char *target = xcalloc(e->filesize + 1, 1);
|
||||||
memcpy(target, f->data, f->filesize);
|
memcpy(target, e->data, e->filesize);
|
||||||
unlink(filename);
|
unlink(filename);
|
||||||
symlink(target, filename);
|
symlink(target, filename);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fprintf(stderr, "Cannot find the file entry [%s]\n", entry);
|
fprintf(stderr, "Cannot find the file entry [%s]\n", entry);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpio_extract_all(struct vector *v) {
|
void cpio_extract_all(struct vector *v) {
|
||||||
cpio_entry *f;
|
cpio_entry *e;
|
||||||
vec_for_each(v, f) {
|
vec_for_each(v, e) {
|
||||||
fprintf(stderr, "Extracting [%s]\n", f->filename);
|
if (!e) continue;
|
||||||
unlink(f->filename);
|
fprintf(stderr, "Extracting [%s]\n", e->filename);
|
||||||
rmdir(f->filename);
|
unlink(e->filename);
|
||||||
if (S_ISDIR(f->mode)) {
|
rmdir(e->filename);
|
||||||
mkdir(f->filename, f->mode & 0777);
|
if (S_ISDIR(e->mode)) {
|
||||||
} else if (S_ISREG(f->mode)) {
|
mkdir(e->filename, e->mode & 0777);
|
||||||
int fd = creat(f->filename, f->mode & 0777);
|
} else if (S_ISREG(e->mode)) {
|
||||||
xwrite(fd, f->data, f->filesize);
|
int fd = creat(e->filename, e->mode & 0777);
|
||||||
fchown(fd, f->uid, f->gid);
|
xwrite(fd, e->data, e->filesize);
|
||||||
|
fchown(fd, e->uid, e->gid);
|
||||||
close(fd);
|
close(fd);
|
||||||
} else if (S_ISLNK(f->mode)) {
|
} else if (S_ISLNK(e->mode)) {
|
||||||
char *target = xcalloc(f->filesize + 1, 1);
|
char *target = xcalloc(e->filesize + 1, 1);
|
||||||
memcpy(target, f->data, f->filesize);
|
memcpy(target, e->data, e->filesize);
|
||||||
symlink(target, f->filename);
|
symlink(target, e->filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,25 @@ void *vec_pop_back(struct vector *v) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int (*cmp)(const void *, const void *);
|
||||||
|
|
||||||
|
static int vec_comp(const void *a, const void *b) {
|
||||||
|
void *aa = *((void **)a), *bb = *((void **)b);
|
||||||
|
if (aa == NULL && bb == NULL) return 0;
|
||||||
|
else if (aa == NULL) return 1;
|
||||||
|
else if (bb == NULL) return -1;
|
||||||
|
else return cmp ? cmp(aa, bb) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
void vec_sort(struct vector *v, int (*compar)(const void *, const void *)) {
|
void vec_sort(struct vector *v, int (*compar)(const void *, const void *)) {
|
||||||
if (v == NULL) return;
|
if (v == NULL) return;
|
||||||
qsort(vec_entry(v), vec_size(v), sizeof(void*), compar);
|
cmp = compar;
|
||||||
|
qsort(vec_entry(v), vec_size(v), sizeof(void*), vec_comp);
|
||||||
|
void *e;
|
||||||
|
vec_for_each_r(v, e) {
|
||||||
|
if (e) break;
|
||||||
|
--vec_size(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Will cleanup only the vector itself
|
/* Will cleanup only the vector itself
|
||||||
|
@ -89,6 +89,7 @@ case $? in
|
|||||||
2 )
|
2 )
|
||||||
ui_print "! Insufficient boot partition size detected"
|
ui_print "! Insufficient boot partition size detected"
|
||||||
HIGHCOMP=true
|
HIGHCOMP=true
|
||||||
|
ui_print "- Enable high compression mode"
|
||||||
;;
|
;;
|
||||||
3 )
|
3 )
|
||||||
ui_print "- ChromeOS boot image detected"
|
ui_print "- ChromeOS boot image detected"
|
||||||
@ -103,20 +104,13 @@ case $? in
|
|||||||
abort "! Stock kernel cannot be patched, please use a custom kernel"
|
abort "! Stock kernel cannot be patched, please use a custom kernel"
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ -f /sdcard/ramdisk-recovery.img ]; then
|
|
||||||
HIGHCOMP=true
|
|
||||||
ui_print "- Detected ramdisk-recovery.img"
|
|
||||||
fi
|
|
||||||
|
|
||||||
$HIGHCOMP && ui_print "- Enable high compression mode"
|
|
||||||
|
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
# Ramdisk restores
|
# Ramdisk restores
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
|
|
||||||
# Test patch status and do restore, after this section, ramdisk.cpio.orig is guaranteed to exist
|
# Test patch status and do restore, after this section, ramdisk.cpio.orig is guaranteed to exist
|
||||||
ui_print "- Checking ramdisk status"
|
ui_print "- Checking ramdisk status"
|
||||||
./magiskboot --cpio-test ramdisk.cpio
|
./magiskboot --cpio ramdisk.cpio test
|
||||||
case $? in
|
case $? in
|
||||||
0 ) # Stock boot
|
0 ) # Stock boot
|
||||||
ui_print "- Stock boot image detected!"
|
ui_print "- Stock boot image detected!"
|
||||||
@ -129,8 +123,8 @@ case $? in
|
|||||||
1 ) # Magisk patched
|
1 ) # Magisk patched
|
||||||
ui_print "- Magisk patched image detected!"
|
ui_print "- Magisk patched image detected!"
|
||||||
# Find SHA1 of stock boot image
|
# Find SHA1 of stock boot image
|
||||||
[ -z $SHA1 ] && SHA1=`./magiskboot --cpio-stocksha1 ramdisk.cpio 2>/dev/null`
|
[ -z $SHA1 ] && SHA1=`./magiskboot --cpio ramdisk.cpio sha1 2>/dev/null`
|
||||||
./magiskboot --cpio-restore ramdisk.cpio
|
./magiskboot --cpio ramdisk.cpio restore
|
||||||
cp -af ramdisk.cpio ramdisk.cpio.orig
|
cp -af ramdisk.cpio ramdisk.cpio.orig
|
||||||
;;
|
;;
|
||||||
2 ) # Other patched
|
2 ) # Other patched
|
||||||
@ -145,18 +139,12 @@ esac
|
|||||||
|
|
||||||
ui_print "- Patching ramdisk"
|
ui_print "- Patching ramdisk"
|
||||||
|
|
||||||
./magiskboot --cpio-add ramdisk.cpio 750 init magiskinit
|
./magiskboot --cpio ramdisk.cpio \
|
||||||
./magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig $HIGHCOMP $KEEPVERITY $KEEPFORCEENCRYPT $SHA1
|
'add 750 init magiskinit' \
|
||||||
|
"magisk ramdisk.cpio.orig $HIGHCOMP $KEEPVERITY $KEEPFORCEENCRYPT $SHA1"
|
||||||
|
|
||||||
rm -f ramdisk.cpio.orig
|
rm -f ramdisk.cpio.orig
|
||||||
|
|
||||||
if [ -f /sdcard/ramdisk-recovery.img ]; then
|
|
||||||
ui_print "- Adding ramdisk-recovery.img"
|
|
||||||
./magiskboot --decompress - < /sdcard/ramdisk-recovery.img | ./magiskboot --compress=xz - ramdisk-recovery.xz
|
|
||||||
./magiskboot --cpio-add ramdisk.cpio 0 ramdisk-recovery.xz ramdisk-recovery.xz
|
|
||||||
rm ramdisk-recovery.xz
|
|
||||||
fi
|
|
||||||
|
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
# Binary patches
|
# Binary patches
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
|
@ -71,7 +71,7 @@ esac
|
|||||||
|
|
||||||
# Detect boot image state
|
# Detect boot image state
|
||||||
ui_print "- Checking ramdisk status"
|
ui_print "- Checking ramdisk status"
|
||||||
./magiskboot --cpio-test ramdisk.cpio
|
./magiskboot --cpio ramdisk.cpio test
|
||||||
case $? in
|
case $? in
|
||||||
0 ) # Stock boot
|
0 ) # Stock boot
|
||||||
ui_print "- Stock boot image detected!"
|
ui_print "- Stock boot image detected!"
|
||||||
@ -80,13 +80,13 @@ case $? in
|
|||||||
1 ) # Magisk patched
|
1 ) # Magisk patched
|
||||||
ui_print "- Magisk patched image detected!"
|
ui_print "- Magisk patched image detected!"
|
||||||
# Find SHA1 of stock boot image
|
# Find SHA1 of stock boot image
|
||||||
[ -z $SHA1 ] && SHA1=`./magiskboot --cpio-stocksha1 ramdisk.cpio 2>/dev/null`
|
[ -z $SHA1 ] && SHA1=`./magiskboot --cpio ramdisk.cpio sha1 2>/dev/null`
|
||||||
OK=false
|
OK=false
|
||||||
[ ! -z $SHA1 ] && restore_imgs $SHA1 && OK=true
|
[ ! -z $SHA1 ] && restore_imgs $SHA1 && OK=true
|
||||||
if ! $OK; then
|
if ! $OK; then
|
||||||
ui_print "! Boot image backup unavailable"
|
ui_print "! Boot image backup unavailable"
|
||||||
ui_print "- Restoring ramdisk with internal backup"
|
ui_print "- Restoring ramdisk with internal backup"
|
||||||
./magiskboot --cpio-restore ramdisk.cpio
|
./magiskboot --cpio ramdisk.cpio restore
|
||||||
./magiskboot --repack $BOOTIMAGE
|
./magiskboot --repack $BOOTIMAGE
|
||||||
# Sign chromeos boot
|
# Sign chromeos boot
|
||||||
$CHROMEOS && sign_chromeos
|
$CHROMEOS && sign_chromeos
|
||||||
@ -104,6 +104,7 @@ cd /
|
|||||||
ui_print "- Removing Magisk files"
|
ui_print "- Removing Magisk files"
|
||||||
rm -rf /cache/*magisk* /cache/unblock /data/*magisk* /data/cache/*magisk* /data/property/*magisk* \
|
rm -rf /cache/*magisk* /cache/unblock /data/*magisk* /data/cache/*magisk* /data/property/*magisk* \
|
||||||
/data/Magisk.apk /data/busybox /data/custom_ramdisk_patch.sh /data/app/com.topjohnwu.magisk* \
|
/data/Magisk.apk /data/busybox /data/custom_ramdisk_patch.sh /data/app/com.topjohnwu.magisk* \
|
||||||
/data/user*/*/magisk.db /data/user*/*/com.topjohnwu.magisk /data/adb/*magisk* 2>/dev/null
|
/data/user*/*/magisk.db /data/user*/*/com.topjohnwu.magisk /data/user*/*/.tmp.magisk.config \
|
||||||
|
/data/adb/*magisk* 2>/dev/null
|
||||||
|
|
||||||
$BOOTMODE && reboot
|
$BOOTMODE && reboot
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
#
|
#
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
|
|
||||||
MAGISK_VERSION_STUB
|
#MAGISK_VERSION_STUB
|
||||||
SCRIPT_VERSION=$MAGISK_VER_CODE
|
SCRIPT_VERSION=$MAGISK_VER_CODE
|
||||||
|
|
||||||
# Default location, will override if needed
|
# Default location, will override if needed
|
||||||
MAGISKBIN=/data/adb/magisk
|
[ -d /data/adb/magisk ] && MAGISKBIN=/data/adb/magisk || MAGISKBIN=/data/magisk
|
||||||
|
|
||||||
BOOTSIGNER="/system/bin/dalvikvm -Xnodex2oat -Xnoimage-dex2oat -cp \$APK com.topjohnwu.magisk.utils.BootSigner"
|
BOOTSIGNER="/system/bin/dalvikvm -Xnodex2oat -Xnoimage-dex2oat -cp \$APK com.topjohnwu.magisk.utils.BootSigner"
|
||||||
BOOTSIGNED=false
|
BOOTSIGNED=false
|
||||||
|
Loading…
Reference in New Issue
Block a user