12下一页
返回列表 发新帖

TrickyStore的target.txt自动更新程序C源码

[复制链接]

282

主题

4131

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
5838
好评
23
信誉
128

考神MT论坛新人MT论坛最佳新人MT论坛帅哥MT论坛活跃会员MT论坛灌水老大

发表于 2026-6-29 15:10:09 来自手机  | 显示全部楼层 | 阅读模式  来自 天津
核心代码:

  1.     int wd = inotify_add_watch(fd, "/data/system", IN_MODIFY | IN_MOVED_TO);
  2.     if (wd < 0) {
  3.         log_e("inotify_add_watch 失败: %s", strerror(errno));
  4.         close(fd);
  5.         free_entries(old, old_cnt);
  6.         return 1;
  7.     }
复制代码

可以把日志输出到/tmp/HJ-TSUpdate.log(可自定义,我的手机这个路径有个tmpfs,重启后直接清,非常适合放日志
你要是放别的地方的话,记得在启动时unlink文件)#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <time.h>

#define EVENT_SIZE  (sizeof(struct inotify_event))
#define BUF_LEN     (1024 * (EVENT_SIZE + 16))
#define LOG_FILE    "/tmp/HJ-TSUpdate.log"
#define TARGET_FILE "/data/adb/tricky_store/target.txt"
#define PKG_LIST    "/data/system/packages.list"

static int need_sort = 0;

typedef struct {
    char *pkg;
} Entry;

void log_i(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    time_t now = time(NULL);
    struct tm *tm_info = localtime(&now);
    char time_buf[20];
    strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tm_info);
    char msg[1024];
    vsnprintf(msg, sizeof(msg), fmt, args);
    va_end(args);
    fprintf(stderr, "[%s] [INFO] %s\n", time_buf, msg);
    FILE *fp = fopen(LOG_FILE, "a");
    if (fp) {
        fprintf(fp, "[%s] [INFO] %s\n", time_buf, msg);
        fclose(fp);
    }
}

void log_e(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    time_t now = time(NULL);
    struct tm *tm_info = localtime(&now);
    char time_buf[20];
    strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tm_info);
    char msg[1024];
    vsnprintf(msg, sizeof(msg), fmt, args);
    va_end(args);
    fprintf(stderr, "[%s] [ERROR] %s\n", time_buf, msg);
    FILE *fp = fopen(LOG_FILE, "a");
    if (fp) {
        fprintf(fp, "[%s] [ERROR] %s\n", time_buf, msg);
        fclose(fp);
    }
}

int cmp_entry(const void *a, const void *b) {
    const Entry *ea = (const Entry *)a;
    const Entry *eb = (const Entry *)b;
    return strcmp(ea->pkg, eb->pkg);
}

int is_sorted(Entry *entries, int count) {
    for (int i = 1; i < count; i++) {
        if (strcmp(entries[i-1].pkg, entries.pkg) > 0)
            return 0;
    }
    return 1;
}

Entry *read_entries(const char *path, int *count) {
    FILE *fp = fopen(path, "r");
    if (!fp) {
        *count = -1;
        return NULL;
    }
    Entry *entries = NULL;
    *count = 0;
    char buf[1024];
    while (fgets(buf, sizeof(buf), fp)) {
        size_t len = strlen(buf);
        if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
        if (len == 0) continue;
        char *p = buf;
        while (*p && *p != ' ' && *p != '\t') p++;
        *p = '\0';
        entries = realloc(entries, (*count + 1) * sizeof(Entry));
        entries[*count].pkg = strdup(buf);
        (*count)++;
    }
    fclose(fp);
    if (need_sort) {
        qsort(entries, *count, sizeof(Entry), cmp_entry);
    } else {
        if (!is_sorted(entries, *count)) {
            need_sort = 1;
            qsort(entries, *count, sizeof(Entry), cmp_entry);
        }
    }
    return entries;
}

void free_entries(Entry *entries, int count) {
    for (int i = 0; i < count; i++) free(entries.pkg);
    free(entries);
}

void find_diff(Entry *old, int old_cnt, Entry *new, int new_cnt,
               char ***added, int *added_cnt,
               char ***removed, int *removed_cnt) {
    *added = NULL;
    *removed = NULL;
    *added_cnt = 0;
    *removed_cnt = 0;
    int i = 0, j = 0;
    while (i < old_cnt && j < new_cnt) {
        int cmp = strcmp(old.pkg, new[j].pkg);
        if (cmp == 0) {
            i++; j++;
        } else if (cmp < 0) {
            *removed = realloc(*removed, (*removed_cnt + 1) * sizeof(char *));
            (*removed)[*removed_cnt] = strdup(old.pkg);
            (*removed_cnt)++;
            i++;
        } else {
            *added = realloc(*added, (*added_cnt + 1) * sizeof(char *));
            (*added)[*added_cnt] = strdup(new[j].pkg);
            (*added_cnt)++;
            j++;
        }
    }
    while (i < old_cnt) {
        *removed = realloc(*removed, (*removed_cnt + 1) * sizeof(char *));
        (*removed)[*removed_cnt] = strdup(old.pkg);
        (*removed_cnt)++;
        i++;
    }
    while (j < new_cnt) {
        *added = realloc(*added, (*added_cnt + 1) * sizeof(char *));
        (*added)[*added_cnt] = strdup(new[j].pkg);
        (*added_cnt)++;
        j++;
    }
}

// 安装时:直接追加,不检查重复
void append_pkg_direct(const char *pkg) {
    FILE *fp = fopen(TARGET_FILE, "a");
    if (!fp) {
        log_e("无法打开 target.txt 进行追加: %s", strerror(errno));
        return;
    }
    fprintf(fp, "%s\n", pkg);
    fclose(fp);
    log_i("已追加包名: %s", pkg);
}

// 卸载时:读取文件,删除所有匹配行,然后去重,写回
void remove_pkg_and_deduplicate(const char *pkg) {
    FILE *fp = fopen(TARGET_FILE, "r");
    if (!fp) {
        log_e("无法打开 target.txt 进行读取: %s", strerror(errno));
        return;
    }
    char **lines = NULL;
    int line_count = 0;
    char buf[256];
    while (fgets(buf, sizeof(buf), fp)) {
        size_t len = strlen(buf);
        if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
        if (len == 0) continue;
        if (strcmp(buf, pkg) != 0) {
            lines = realloc(lines, (line_count + 1) * sizeof(char *));
            lines[line_count] = strdup(buf);
            line_count++;
        }
    }
    fclose(fp);

    if (line_count == 0) {
        fp = fopen(TARGET_FILE, "w");
        if (fp) fclose(fp);
        log_i("已移除包名 %s,文件已空", pkg);
        return;
    }

    // 去重
    char **unique_lines = NULL;
    int unique_count = 0;
    for (int i = 0; i < line_count; i++) {
        int duplicate = 0;
        for (int j = 0; j < unique_count; j++) {
            if (strcmp(unique_lines[j], lines) == 0) {
                duplicate = 1;
                break;
            }
        }
        if (!duplicate) {
            unique_lines = realloc(unique_lines, (unique_count + 1) * sizeof(char *));
            unique_lines[unique_count] = strdup(lines);
            unique_count++;
        }
        free(lines);
    }
    free(lines);

    fp = fopen(TARGET_FILE, "w");
    if (!fp) {
        log_e("无法打开 target.txt 进行写入: %s", strerror(errno));
        for (int i = 0; i < unique_count; i++) free(unique_lines);
        free(unique_lines);
        return;
    }
    for (int i = 0; i < unique_count; i++) {
        fprintf(fp, "%s\n", unique_lines);
        free(unique_lines);
    }
    fclose(fp);
    free(unique_lines);
    log_i("已移除包名 %s 并完成去重", pkg);
}

int main() {
    // 判断 target.txt 是否存在,以此确定 Tricky Store 是否安装
    if (access(TARGET_FILE, F_OK) != 0) {
        log_e("未检测到 target.txt,tricky_store 可能未安装,程序退出");
        return 1;
    }

    mkdir("/tmp", 0755);
    log_i("启动 HJ-TSUpdate 监控程序");

    int old_cnt = 0;
    Entry *old = read_entries(PKG_LIST, &old_cnt);
    if (old_cnt < 0) {
        log_e("无法读取初始 packages.list: %s", strerror(errno));
        return 1;
    }
    log_i("已读取初始应用列表,共 %d 个包名", old_cnt);

    int fd = inotify_init1(IN_CLOEXEC);
    if (fd < 0) {
        log_e("inotify_init1 失败: %s", strerror(errno));
        free_entries(old, old_cnt);
        return 1;
    }

    int wd = inotify_add_watch(fd, "/data/system", IN_MODIFY | IN_MOVED_TO);
    if (wd < 0) {
        log_e("inotify_add_watch 失败: %s", strerror(errno));
        close(fd);
        free_entries(old, old_cnt);
        return 1;
    }

    log_i("开始监控 /data/system 目录中的 packages.list ...");

    char buf[BUF_LEN];
    while (1) {
        ssize_t len = read(fd, buf, sizeof(buf));
        if (len < 0) {
            log_e("read 失败: %s", strerror(errno));
            break;
        }

        int need_refresh = 0;
        for (char *ptr = buf; ptr < buf + len; ) {
            struct inotify_event *ev = (struct inotify_event *)ptr;
            if (ev->len > 0 && (ev->mask & (IN_MODIFY | IN_MOVED_TO))) {
                if (strcmp(ev->name, "packages.list") == 0) {
                    need_refresh = 1;
                    break;
                }
            }
            ptr += EVENT_SIZE + ev->len;
        }

        if (!need_refresh) continue;

        int new_cnt = 0;
        Entry *new = read_entries(PKG_LIST, &new_cnt);
        if (new_cnt < 0) {
            log_e("读取更新后的 packages.list 失败");
            continue;
        }

        char **added = NULL, **removed = NULL;
        int added_cnt = 0, removed_cnt = 0;
        find_diff(old, old_cnt, new, new_cnt, &added, &added_cnt, &removed, &removed_cnt);

        if (added_cnt > 0) {
            log_i("检测到 %d 个新安装应用", added_cnt);
            for (int i = 0; i < added_cnt; i++) {
                append_pkg_direct(added);
                free(added);
            }
            free(added);
        }
        if (removed_cnt > 0) {
            log_i("检测到 %d 个应用卸载", removed_cnt);
            for (int i = 0; i < removed_cnt; i++) {
                remove_pkg_and_deduplicate(removed);
                free(removed);
            }
            free(removed);
        }

        free_entries(old, old_cnt);
        old = new;
        old_cnt = new_cnt;
    }

    free_entries(old, old_cnt);
    inotify_rm_watch(fd, wd);
    close(fd);
    log_i("监控程序退出");
    return 0;
}
回复

使用道具 举报

282

主题

4131

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
5838
好评
23
信誉
128

考神MT论坛新人MT论坛最佳新人MT论坛帅哥MT论坛活跃会员MT论坛灌水老大

发表于 2026-6-29 15:11:13 来自手机  | 显示全部楼层  来自 天津
道无相 发表于 2026-6-29 15:10
沙发
?!强强!?
这么快?
沙发现在是我的了
回复

使用道具 举报

22

主题

2389

回帖

7305

积分

硕士生

Rank: 6Rank: 6

金币
1430
好评
21
信誉
101

MT论坛新人考神

发表于 2026-6-29 15:10:30 来自手机  | 显示全部楼层  来自 湖南
沙发
回复

使用道具 举报

0

主题

1314

回帖

4563

积分

大学生

Rank: 5Rank: 5

金币
3005
好评
1
信誉
100
发表于 2026-6-29 15:23:35 来自手机  | 显示全部楼层  来自 广东
瞧一瞧看一看
回复

使用道具 举报

2

主题

2323

回帖

7331

积分

硕士生

Rank: 6Rank: 6

金币
3650
好评
2
信誉
106

考神MT论坛帅哥

发表于 2026-6-29 15:32:28 来自手机  | 显示全部楼层  来自 山东
感谢分享
回复

使用道具 举报

8

主题

1万

回帖

2万

积分

博士后

Rank: 8Rank: 8

金币
5136
好评
1
信誉
100
发表于 2026-6-29 15:47:09 来自手机  | 显示全部楼层  来自 山东
看看隐藏
回复

使用道具 举报

0

主题

1万

回帖

2万

积分

博士后

Rank: 8Rank: 8

金币
6870
好评
1
信誉
100
发表于 2026-6-29 15:48:34 来自手机  | 显示全部楼层  来自 河北
谢谢分享
回复

使用道具 举报

14

主题

607

回帖

2512

积分

大学生

Rank: 5Rank: 5

金币
850
好评
1
信誉
102
发表于 2026-6-29 15:56:02 来自手机  | 显示全部楼层  来自 广东
受教了真的受教了
回复

使用道具 举报

10

主题

620

回帖

1663

积分

高中生

Rank: 4

金币
1245
好评
0
信誉
100
发表于 2026-6-29 15:58:14 来自手机  | 显示全部楼层  来自 广东
感谢分享
回复

使用道具 举报

41

主题

1万

回帖

2万

积分

博士后

Rank: 8Rank: 8

金币
6142
好评
3
信誉
98
发表于 2026-6-29 15:59:32 来自手机  | 显示全部楼层  来自 山东
看看隐藏
回复

使用道具 举报

47

主题

1410

回帖

5825

积分

硕士生

Rank: 6Rank: 6

金币
2776
好评
2
信誉
111
发表于 2026-6-29 16:57:32 来自手机  | 显示全部楼层  来自 四川
回复

使用道具 举报

0

主题

2964

回帖

6897

积分

硕士生

Rank: 6Rank: 6

金币
3316
好评
0
信誉
100

MT论坛新人考神MT论坛帅哥

发表于 2026-6-29 17:10:37 来自手机  | 显示全部楼层  来自 浙江
感谢分享
回复

使用道具 举报

63

主题

2767

回帖

7651

积分

硕士生

Rank: 6Rank: 6

金币
1102
好评
10
信誉
100
发表于 2026-6-29 17:26:05 来自手机  | 显示全部楼层  来自 浙江
看看
回复

使用道具 举报

39

主题

5418

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
4480
好评
18
信誉
108
发表于 2026-6-29 19:10:37 来自手机  | 显示全部楼层  来自 北京
看看隐藏
回复

使用道具 举报

2

主题

4507

回帖

1万

积分

禁止访问

iKUN

金币
1214
好评
16
信誉
111
发表于 2026-6-29 19:18:14 来自手机  | 显示全部楼层  来自 广西
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表