diff --git a/jni/magisk.h b/jni/magisk.h index c83d93c94..c2da6fe98 100644 --- a/jni/magisk.h +++ b/jni/magisk.h @@ -46,6 +46,9 @@ static inline void stub(const char *fmt, ...) {} extern char *argv0; /* For changing process name */ +extern char *applet[]; +extern int (*applet_main[]) (int, char *[]); + // Multi-call entrypoints int magiskhide_main(int argc, char *argv[]); int magiskpolicy_main(int argc, char *argv[]); diff --git a/jni/main.c b/jni/main.c index f79d8b2bb..628229853 100644 --- a/jni/main.c +++ b/jni/main.c @@ -2,6 +2,7 @@ */ #include +#include #include "utils.h" #include "magisk.h" @@ -9,10 +10,44 @@ char *argv0; +char *applet[] = + { "su", "resetprop", "magiskpolicy", "supolicy", "magiskhide", NULL }; + +int (*applet_main[]) (int, char *[]) = + { su_client_main, resetprop_main, magiskpolicy_main, magiskpolicy_main, magiskhide_main, NULL }; + // Global error hander function // Should be changed each thread/process __thread void (*err_handler)(void); +static void usage() { + fprintf(stderr, + "Magisk v" xstr(VERSION) " multi-call binary\n" + "\n" + "Usage: %s [applet [arguments]...]\n" + " or: %s --install [SOURCE] \n" + " or: %s --list\n" + " or: %s --[boot stage] start boot stage service\n" + " or: %s [options]\n" + " or: applet [arguments]...\n" + "\n" + "Supported boot stages:\n" + " post-fs, post-fs-data, service\n" + "\n" + "Options:\n" + " -v print client and daemon version\n" + " -V print daemon version code\n" + "\n" + "Supported applets:\n" + , argv0, argv0, argv0, argv0, argv0); + + for (int i = 0; applet[i]; ++i) { + fprintf(stderr, i ? ", %s" : " %s", applet[i]); + } + fprintf(stderr, "\n"); + exit(1); +} + int main(int argc, char *argv[]) { argv0 = argv[0]; // Exit the whole app if error occurs by default @@ -20,6 +55,7 @@ int main(int argc, char *argv[]) { char * arg = strrchr(argv[0], '/'); if (arg) ++arg; if (strcmp(arg, "magisk") == 0) { + if (argc < 2) usage(); if (strcmp(argv[1], "-v") == 0) { printf("Client: %s\n", VERSION_STR); int fd = connect_daemon(); @@ -33,6 +69,14 @@ int main(int argc, char *argv[]) { write_int(fd, CHECK_VERSION_CODE); printf("%d\n", read_int(fd)); return 0; + } else if (strcmp(argv[1], "--install") == 0) { + if (argc < 3) usage(); + if (argc == 3) return create_links(NULL, argv[2]); + else return create_links(argv[2], argv[3]); + } else if (strcmp(argv[1], "--list") == 0) { + for (int i = 0; applet[i]; ++i) + printf("%s\n", applet[i]); + return 0; } else if (strcmp(argv[1], "--post-fs") == 0) { // TODO: post-fs mode return 0; @@ -42,9 +86,6 @@ int main(int argc, char *argv[]) { } else if (strcmp(argv[1], "--service") == 0) { // TODO: late_start service mode return 0; - } else if (strcmp(argv[1], "--install") == 0) { - // TODO: Install symlinks - return 0; } else if (strcmp(argv[1], "--test") == 0) { // Temporary testing entry int fd = connect_daemon(); @@ -60,16 +101,11 @@ int main(int argc, char *argv[]) { } // Applets - if (strcmp(arg, "su") == 0) { - return su_client_main(argc, argv); - } else if (strcmp(arg, "magiskpolicy") == 0) { - return magiskpolicy_main(argc, argv); - } else if (strcmp(arg, "resetprop") == 0) { - return resetprop_main(argc, argv); - } else if (strcmp(arg, "magiskhide") == 0) { - return magiskhide_main(argc, argv); - } else { - fprintf(stderr, "Applet \'%s\' not found\n", arg); + for (int i = 0; applet[i]; ++i) { + if (strcmp(arg, applet[i]) == 0) + return (*applet_main[i])(argc, argv); } + + fprintf(stderr, "%s: applet not found\n", arg); return 1; } diff --git a/jni/utils/misc.c b/jni/utils/misc.c index 6df17877a..292c9b385 100644 --- a/jni/utils/misc.c +++ b/jni/utils/misc.c @@ -135,3 +135,18 @@ void ps_filter_proc_name(const char *pattern, void (*func)(int)) { ps_filter_pattern = ((pattern == NULL) ? "" : pattern); ps(proc_name_filter); } + +int create_links(const char *bin, const char *path) { + char self[PATH_MAX], linkpath[PATH_MAX]; + if (bin == NULL) { + xreadlink("/proc/self/exe", self, PATH_MAX); + bin = self; + } + int ret = 0; + for (int i = 0; applet[i]; ++i) { + snprintf(linkpath, PATH_MAX, "%s/%s", path, applet[i]); + unlink(linkpath); + ret |= symlink(bin, linkpath); + } + return ret; +} diff --git a/jni/utils/utils.h b/jni/utils/utils.h index 1ae3b2978..fdf721e41 100644 --- a/jni/utils/utils.h +++ b/jni/utils/utils.h @@ -46,6 +46,8 @@ int xpthread_create(pthread_t *thread, const pthread_attr_t *attr, int xsocketpair(int domain, int type, int protocol, int sv[2]); int xstat(const char *pathname, struct stat *buf); int xdup2(int oldfd, int newfd); +ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz); +int xsymlink(const char *target, const char *linkpath); // misc.c @@ -58,5 +60,6 @@ int isNum(const char *s); ssize_t fdreadline(int fd, char *buf, size_t size); void ps(void (*func)(int)); void ps_filter_proc_name(const char *filter, void (*func)(int)); +int create_links(const char *bin, const char *path); #endif diff --git a/jni/utils/xwrap.c b/jni/utils/xwrap.c index 28b26f4f9..eb92cd660 100644 --- a/jni/utils/xwrap.c +++ b/jni/utils/xwrap.c @@ -226,4 +226,22 @@ int xdup2(int oldfd, int newfd) { return ret; } +ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz) { + ssize_t ret = readlink(pathname, buf, bufsiz); + if (ret == -1) { + PLOGE("readlink %s", pathname); + } else { + buf[ret] = '\0'; + } + return ret; +} + +int xsymlink(const char *target, const char *linkpath) { + int ret = symlink(target, linkpath); + if (ret == -1) { + PLOGE("symlink %s->%s", target, linkpath); + } + return ret; +} +