|
|
核心代码:
- 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;
- }
复制代码
可以把日志输出到/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;
} |
|