diff --git a/native/jni/core/bootstages.c b/native/jni/core/bootstages.c index 7a74c4cf9..bd0ad3838 100644 --- a/native/jni/core/bootstages.c +++ b/native/jni/core/bootstages.c @@ -441,17 +441,10 @@ static int prepare_img() { vec_push_back(&module_list, strdup(entry->d_name)); } } - closedir(dir); - // Trim image - umount_image(MOUNTPOINT, magiskloop); - free(magiskloop); - trim_img(MAINIMG); - - // Remount them back :) - magiskloop = mount_image(MAINIMG, MOUNTPOINT); - free(magiskloop); + if (trim_img(MAINIMG, MOUNTPOINT, magiskloop)) + return 1; return 0; } diff --git a/native/jni/core/magisk.c b/native/jni/core/magisk.c index cc0470967..926f3b32f 100644 --- a/native/jni/core/magisk.c +++ b/native/jni/core/magisk.c @@ -12,7 +12,8 @@ char *argv0; -int (*applet_main[]) (int, char *[]) = { su_client_main, resetprop_main, magiskhide_main, NULL }; +int (*applet_main[]) (int, char *[]) = + { su_client_main, resetprop_main, magiskhide_main, imgtool_main, NULL }; int create_links(const char *bin, const char *path) { char self[PATH_MAX], linkpath[PATH_MAX]; @@ -42,11 +43,6 @@ static void usage() { " -V print running daemon version code\n" " --list list all available applets\n" " --install [SOURCE] DIR symlink all applets to DIR. SOURCE is optional\n" - " --createimg IMG SIZE create ext4 image. SIZE is interpreted in MB\n" - " --imgsize IMG report ext4 image used/total size\n" - " --resizeimg IMG SIZE resize ext4 image. SIZE is interpreted in MB\n" - " --mountimg IMG PATH mount IMG to PATH and prints the loop device\n" - " --umountimg PATH LOOP unmount PATH and delete LOOP device\n" " --daemon manually start magisk daemon\n" " --[init trigger] start service for init trigger\n" " --unlock-blocks set BLKROSET flag to OFF for all block devices\n" @@ -90,48 +86,6 @@ int magisk_main(int argc, char *argv[]) { for (int i = 0; applet[i]; ++i) printf("%s\n", applet[i]); return 0; - } else if (strcmp(argv[1], "--createimg") == 0) { - if (argc < 4) usage(); - int size; - sscanf(argv[3], "%d", &size); - return create_img(argv[2], size); - } else if (strcmp(argv[1], "--imgsize") == 0) { - if (argc < 3) usage(); - int used, total; - if (get_img_size(argv[2], &used, &total)) { - fprintf(stderr, "Cannot check %s size\n", argv[2]); - return 1; - } - printf("%d %d\n", used, total); - return 0; - } else if (strcmp(argv[1], "--resizeimg") == 0) { - if (argc < 4) usage(); - int used, total, size; - sscanf(argv[3], "%d", &size); - if (get_img_size(argv[2], &used, &total)) { - fprintf(stderr, "Cannot check %s size\n", argv[2]); - return 1; - } - if (size <= used) { - fprintf(stderr, "Cannot resize smaller than %dM\n", used); - return 1; - } - return resize_img(argv[2], size); - } else if (strcmp(argv[1], "--mountimg") == 0) { - if (argc < 4) usage(); - char *loop = mount_image(argv[2], argv[3]); - if (loop == NULL) { - fprintf(stderr, "Cannot mount image!\n"); - return 1; - } else { - printf("%s\n", loop); - free(loop); - return 0; - } - } else if (strcmp(argv[1], "--umountimg") == 0) { - if (argc < 4) usage(); - umount_image(argv[2], argv[3]); - return 0; } else if (strcmp(argv[1], "--unlock-blocks") == 0) { unlock_blocks(); return 0; diff --git a/native/jni/include/magisk.h b/native/jni/include/magisk.h index 7607858e5..15356746f 100644 --- a/native/jni/include/magisk.h +++ b/native/jni/include/magisk.h @@ -54,7 +54,7 @@ extern char *argv0; /* For changing process name */ -#define applet ((char *[]) { "su", "resetprop", "magiskhide", NULL }) +#define applet ((char *[]) { "su", "resetprop", "magiskhide", "imgtool", NULL }) #define init_applet ((char *[]) { "magiskpolicy", "supolicy", NULL }) extern int (*applet_main[]) (int, char *[]), (*init_applet_main[]) (int, char *[]); @@ -66,5 +66,6 @@ int magiskhide_main(int argc, char *argv[]); int magiskpolicy_main(int argc, char *argv[]); int su_client_main(int argc, char *argv[]); int resetprop_main(int argc, char *argv[]); +int imgtool_main(int argc, char *argv[]); #endif diff --git a/native/jni/include/utils.h b/native/jni/include/utils.h index 8a2c86285..c43242b15 100644 --- a/native/jni/include/utils.h +++ b/native/jni/include/utils.h @@ -134,16 +134,15 @@ void write_zero(int fd, size_t size); // img.c #define round_size(a) ((((a) / 32) + 2) * 32) -#define SOURCE_TMP "/dev/source" -#define TARGET_TMP "/dev/target" +#define SOURCE_TMP "/dev/.img_src" +#define TARGET_TMP "/dev/.img_tgt" int create_img(const char *img, int size); -int get_img_size(const char *img, int *used, int *total); -int resize_img(const char *img, int size); +int resize_img(const char *img, int size, int enforce); char *mount_image(const char *img, const char *target); -void umount_image(const char *target, const char *device); +int umount_image(const char *target, const char *device); int merge_img(const char *source, const char *target); -void trim_img(const char *img); +int trim_img(const char *img, const char *mount, char *loop); // pattern.c diff --git a/native/jni/utils/img.c b/native/jni/utils/img.c index 418dd91d7..0c69bed51 100644 --- a/native/jni/utils/img.c +++ b/native/jni/utils/img.c @@ -8,11 +8,18 @@ #include #include #include +#include #include #include "magisk.h" #include "utils.h" +struct fs_info { + unsigned size; + unsigned free; + unsigned used; +}; + static int e2fsck(const char *img) { // Check and repair ext4 image char buffer[128]; @@ -51,59 +58,86 @@ static char *loopsetup(const char *img) { return strdup(device); } +static void check_filesystem(struct fs_info *info, const char *img, const char *mount) { + struct stat st; + struct statvfs vfs; + stat(img, &st); + statvfs(mount, &vfs); + info->size = st.st_size / 1048576; + info->free = vfs.f_bfree * vfs.f_frsize / 1048576; + info->used = (vfs.f_blocks - vfs.f_bfree) * vfs.f_frsize / 1048576; +} + +static void usage() { + fprintf(stderr, + "ImgTool v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - EXT4 Image Tools\n" + "\n" + "Usage: imgtool [args...]\n" + "\n" + "Actions:\n" + " create IMG SIZE create ext4 image. SIZE is interpreted in MB\n" + " resize IMG SIZE resize ext4 image. SIZE is interpreted in MB\n" + " mount IMG PATH mount IMG to PATH and prints the loop device\n" + " umount PATH LOOP unmount PATH and delete LOOP device\n" + ); + exit(1); +} + +int imgtool_main(int argc, char *argv[]) { + if (argc < 2) + usage(); + if (strcmp(argv[1], "create") == 0) { + if (argc < 4) + usage(); + return create_img(argv[2], atoi(argv[3])); + } else if (strcmp(argv[1], "resize") == 0) { + if (argc < 4) + usage(); + return resize_img(argv[2], atoi(argv[3]), 1); + } else if (strcmp(argv[1], "mount") == 0) { + if (argc < 4) + usage(); + char *loop = mount_image(argv[2], argv[3]); + if (loop == NULL) { + fprintf(stderr, "Cannot mount image!\n"); + return 1; + } else { + printf("%s\n", loop); + free(loop); + return 0; + } + } else if (strcmp(argv[1], "umount") == 0) { + if (argc < 4) + usage(); + umount_image(argv[2], argv[3]); + return 0; + } + usage(); + return 1; +} + int create_img(const char *img, int size) { if (size == 128) /* WTF...? */ size = 132; unlink(img); LOGI("Create %s with size %dM\n", img, size); - int ret; - char size_str[16]; snprintf(size_str, sizeof(size_str), "%dM", size); - ret = exec_command_sync("/system/bin/make_ext4fs", "-b", "4096", "-l", size_str, img, NULL); - if (ret < 0) { + if (access("/system/bin/make_ext4fs", X_OK) == 0) + return exec_command_sync("/system/bin/make_ext4fs", "-b", "4096", "-l", size_str, img, NULL); + else if (access("/system/bin/mke2fs", X_OK) == 0) // On Android P there is no make_ext4fs, use mke2fs - ret = exec_command_sync("/system/bin/mke2fs", "-b", "4096", "-t", "ext4", img, size_str, NULL); - } - return ret; + return exec_command_sync("/system/bin/mke2fs", "-b", "4096", "-t", "ext4", img, size_str, NULL); + else + return 1; } -int get_img_size(const char *img, int *used, int *total) { - if (access(img, R_OK) == -1) - return 1; - char buffer[PATH_MAX]; - int pid, fd = -1, status = 1; - pid = exec_command(1, &fd, NULL, "/system/bin/e2fsck", "-n", img, NULL); - if (pid < 0) - return 1; - while (fdgets(buffer, sizeof(buffer), fd)) { - if (strstr(buffer, img)) { - char *tok = strtok(buffer, ","); - while(tok != NULL) { - if (strstr(tok, "blocks")) { - status = 0; - break; - } - tok = strtok(NULL, ","); - } - if (status) continue; - sscanf(tok, "%d/%d", used, total); - *used = (*used + 255) / 256; - *total = (*total + 128) / 256; - break; - } - } - close(fd); - waitpid(pid, NULL, 0); - return 0; -} - -int resize_img(const char *img, int size) { +int resize_img(const char *img, int size, int enforce) { LOGI("Resize %s to %dM\n", img, size); if (e2fsck(img)) return 1; char buffer[128]; - int pid, fd = -1, used, total; + int pid, fd = -1; snprintf(buffer, sizeof(buffer), "%dM", size); pid = exec_command(1, &fd, NULL, "/system/bin/resize2fs", img, buffer, NULL); if (pid < 0) @@ -113,29 +147,32 @@ int resize_img(const char *img, int size) { close(fd); waitpid(pid, NULL, 0); - // Double check our image size - get_img_size(img, &used, &total); - if (total != size) { - // Sammy crap occurs or resize2fs failed, lets create a new image! - char *dir = dirname(img); - snprintf(buffer, sizeof(buffer), "%s/tmp.img", dir); - create_img(buffer, size); - char *s_loop, *t_loop; - s_loop = mount_image(img, SOURCE_TMP); - if (s_loop == NULL) return 1; - t_loop = mount_image(buffer, TARGET_TMP); - if (t_loop == NULL) return 1; + if (enforce) { + // Check the image size + struct stat st; + stat(img, &st); + if (st.st_size / 1048576 != size) { + // Sammy crap occurs or resize2fs failed, lets create a new image! + snprintf(buffer, sizeof(buffer), "%s/tmp.img", dirname(img)); + create_img(buffer, size); + char *s_loop, *t_loop; + s_loop = mount_image(img, SOURCE_TMP); + if (s_loop == NULL) + return 1; + t_loop = mount_image(buffer, TARGET_TMP); + if (t_loop == NULL) + return 1; - cp_afc(SOURCE_TMP, TARGET_TMP); - umount_image(SOURCE_TMP, s_loop); - umount_image(TARGET_TMP, t_loop); - rmdir(SOURCE_TMP); - rmdir(TARGET_TMP); - free(s_loop); - free(t_loop); - rename(buffer, img); + cp_afc(SOURCE_TMP, TARGET_TMP); + umount_image(SOURCE_TMP, s_loop); + umount_image(TARGET_TMP, t_loop); + rmdir(SOURCE_TMP); + rmdir(TARGET_TMP); + free(s_loop); + free(t_loop); + rename(buffer, img); + } } - return 0; } @@ -152,11 +189,13 @@ char *mount_image(const char *img, const char *target) { return device; } -void umount_image(const char *target, const char *device) { - xumount(target); +int umount_image(const char *target, const char *device) { + int ret = 0; + ret |= xumount(target); int fd = xopen(device, O_RDWR); - ioctl(fd, LOOP_CLR_FD); + ret |= ioctl(fd, LOOP_CLR_FD); close(fd); + return ret; } int merge_img(const char *source, const char *target) { @@ -178,22 +217,30 @@ int merge_img(const char *source, const char *target) { char buffer[PATH_MAX]; - // resize target to worst case - int s_used, s_total, t_used, t_total, n_total; - get_img_size(source, &s_used, &s_total); - get_img_size(target, &t_used, &t_total); - n_total = round_size(s_used + t_used); - if (n_total > t_total) - resize_img(target, n_total); - xmkdir(SOURCE_TMP, 0755); xmkdir(TARGET_TMP, 0755); char *s_loop, *t_loop; s_loop = mount_image(source, SOURCE_TMP); - if (s_loop == NULL) return 1; + if (s_loop == NULL) + return 1; t_loop = mount_image(target, TARGET_TMP); - if (t_loop == NULL) return 1; + if (t_loop == NULL) + return 1; + struct fs_info src, tgt; + check_filesystem(&src, source, SOURCE_TMP); + check_filesystem(&tgt, target, TARGET_TMP); + + // resize target to worst case + if (src.used >= tgt.free) { + umount_image(TARGET_TMP, t_loop); + free(t_loop); + resize_img(target, round_size(tgt.size + src.used - tgt.free), 1); + t_loop = mount_image(target, TARGET_TMP); + } + + snprintf(buffer, sizeof(buffer), "%s/%s", TARGET_TMP, "lost+found"); + rm_rf(buffer); DIR *dir; struct dirent *entry; if (!(dir = xopendir(SOURCE_TMP))) @@ -207,12 +254,9 @@ int merge_img(const char *source, const char *target) { continue; // Cleanup old module if exists snprintf(buffer, sizeof(buffer), "%s/%s", TARGET_TMP, entry->d_name); - if (access(buffer, F_OK) == 0) { - LOGI("Upgrade module: %s\n", entry->d_name); + if (access(buffer, F_OK) == 0) rm_rf(buffer); - } else { - LOGI("New module: %s\n", entry->d_name); - } + LOGI("Upgrade/New module: %s\n", entry->d_name); } } closedir(dir); @@ -229,10 +273,18 @@ int merge_img(const char *source, const char *target) { return 0; } -void trim_img(const char *img) { - int used, total, new_size; - get_img_size(img, &used, &total); - new_size = round_size(used); - if (new_size != total) - resize_img(img, new_size); +int trim_img(const char *img, const char *mount, char *loop) { + struct fs_info info; + check_filesystem(&info, img, mount); + int new_size = round_size(info.used); + if (info.size > new_size) { + umount_image(mount, loop); + free(loop); + resize_img(img, new_size, 0); + loop = mount_image(img, mount); + if (loop == NULL) + return 1; + } + free(loop); + return 0; } diff --git a/scripts/util_functions.sh b/scripts/util_functions.sh index 276f88e76..d0d739572 100644 --- a/scripts/util_functions.sh +++ b/scripts/util_functions.sh @@ -375,52 +375,55 @@ mktouch() { } request_size_check() { - reqSizeM=`du -s $1 | cut -f1` - reqSizeM=$((reqSizeM / 1024 + 1)) + reqSizeM=`du -ms $1 | cut -f1` } request_zip_size_check() { - reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int($1 / 1048567 + 1) }'` + reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'` } -image_size_check() { - SIZE="`$MAGISKBIN/magisk --imgsize $IMG`" - curUsedM=`echo "$SIZE" | cut -d" " -f1` - curSizeM=`echo "$SIZE" | cut -d" " -f2` - curFreeM=$((curSizeM - curUsedM)) +check_filesystem() { + curSizeM=`wc -c < $1` + curSizeM=$((curSizeM / 1048576)) + local DF=`df -P $2 | grep $2` + curUsedM=`echo $DF | awk '{ print int($3 / 1024) }'` + curFreeM=`echo $DF | awk '{ print int($4 / 1024) }'` +} + +mount_snippet() { + MAGISKLOOP=`$MAGISKBIN/magisk imgtool mount $IMG $MOUNTPATH` + is_mounted $MOUNTPATH || abort "! $IMG mount failed..." } mount_magisk_img() { [ -z reqSizeM ] && reqSizeM=0 + mkdir -p $MOUNTPATH 2>/dev/null if [ -f "$IMG" ]; then ui_print "- Found $IMG" - image_size_check $IMG - if [ "$reqSizeM" -gt "$curFreeM" ]; then - newSizeM=$(((reqSizeM + curUsedM) / 32 * 32 + 64)) + mount_snippet + check_filesystem $IMG $MOUNTPATH + if [ $reqSizeM -gt $curFreeM ]; then + newSizeM=$(((curSizeM + reqSizeM - curFreeM) / 32 * 32 + 64)) ui_print "- Resizing $IMG to ${newSizeM}M" - $MAGISKBIN/magisk --resizeimg $IMG $newSizeM >&2 + $MAGISKBIN/magisk imgtool umount $MOUNTPATH $MAGISKLOOP + $MAGISKBIN/magisk imgtool resize $IMG $newSizeM >&2 + mount_snippet fi + ui_print "- Mount $IMG to $MOUNTPATH" else - newSizeM=$((reqSizeM / 32 * 32 + 64)); + newSizeM=$((reqSizeM / 32 * 32 + 64)) ui_print "- Creating $IMG with size ${newSizeM}M" - $MAGISKBIN/magisk --createimg $IMG $newSizeM >&2 + $MAGISKBIN/magisk imgtool create $IMG $newSizeM >&2 + mount_snippet fi - - ui_print "- Mounting $IMG to $MOUNTPATH" - mkdir -p $MOUNTPATH 2>/dev/null - MAGISKLOOP=`$MAGISKBIN/magisk --mountimg $IMG $MOUNTPATH` - is_mounted $MOUNTPATH || abort "! $IMG mount failed..." } unmount_magisk_img() { - $MAGISKBIN/magisk --umountimg $MOUNTPATH $MAGISKLOOP - - # Shrink the image if possible - image_size_check $IMG + check_filesystem $IMG $MOUNTPATH newSizeM=$((curUsedM / 32 * 32 + 64)) + $MAGISKBIN/magisk imgtool umount $MOUNTPATH $MAGISKLOOP if [ $curSizeM -gt $newSizeM ]; then ui_print "- Shrinking $IMG to ${newSizeM}M" - $MAGISKBIN/magisk --resizeimg $IMG $newSizeM + $MAGISKBIN/magisk imgtool resize $IMG $newSizeM >&2 fi } -