Add Protobuf support to resetprop
This commit is contained in:
parent
fc706dcb40
commit
fb491cfdcf
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -25,3 +25,6 @@
|
|||||||
[submodule "xz"]
|
[submodule "xz"]
|
||||||
path = native/jni/external/xz
|
path = native/jni/external/xz
|
||||||
url = https://github.com/xz-mirror/xz.git
|
url = https://github.com/xz-mirror/xz.git
|
||||||
|
[submodule "nanopb"]
|
||||||
|
path = native/jni/external/nanopb
|
||||||
|
url = https://github.com/nanopb/nanopb.git
|
||||||
|
@ -9,6 +9,7 @@ LIBLZMA := $(EXT_PATH)/xz/src/liblzma/api
|
|||||||
LIBLZ4 := $(EXT_PATH)/lz4/lib
|
LIBLZ4 := $(EXT_PATH)/lz4/lib
|
||||||
LIBBZ2 := $(EXT_PATH)/bzip2
|
LIBBZ2 := $(EXT_PATH)/bzip2
|
||||||
LIBFDT := $(EXT_PATH)/dtc/libfdt
|
LIBFDT := $(EXT_PATH)/dtc/libfdt
|
||||||
|
LIBNANOPB := $(EXT_PATH)/nanopb
|
||||||
UTIL_SRC := utils/cpio.c \
|
UTIL_SRC := utils/cpio.c \
|
||||||
utils/file.c \
|
utils/file.c \
|
||||||
utils/img.c \
|
utils/img.c \
|
||||||
@ -28,12 +29,13 @@ ifneq "$(or $(PRECOMPILE), $(GRADLE))" ""
|
|||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := magisk
|
LOCAL_MODULE := magisk
|
||||||
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
|
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
|
||||||
|
LOCAL_STATIC_LIBRARIES := libnanopb
|
||||||
LOCAL_C_INCLUDES := \
|
LOCAL_C_INCLUDES := \
|
||||||
jni/include \
|
jni/include \
|
||||||
jni/magiskpolicy \
|
jni/magiskpolicy \
|
||||||
$(EXT_PATH)/include \
|
$(EXT_PATH)/include \
|
||||||
$(LIBSELINUX)
|
$(LIBSELINUX) \
|
||||||
|
$(LIBNANOPB)
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
core/magisk.c \
|
core/magisk.c \
|
||||||
@ -44,7 +46,8 @@ LOCAL_SRC_FILES := \
|
|||||||
magiskhide/magiskhide.c \
|
magiskhide/magiskhide.c \
|
||||||
magiskhide/proc_monitor.c \
|
magiskhide/proc_monitor.c \
|
||||||
magiskhide/hide_utils.c \
|
magiskhide/hide_utils.c \
|
||||||
resetprop/resetprop.cpp \
|
resetprop/persist_props.c \
|
||||||
|
resetprop/resetprop.c \
|
||||||
resetprop/system_properties.cpp \
|
resetprop/system_properties.cpp \
|
||||||
su/su.c \
|
su/su.c \
|
||||||
su/activity.c \
|
su/activity.c \
|
||||||
|
10
native/jni/external/Android.mk
vendored
10
native/jni/external/Android.mk
vendored
@ -28,6 +28,16 @@ LOCAL_SRC_FILES := \
|
|||||||
mincrypt/sha256.c
|
mincrypt/sha256.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
# libnanopb.a
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE:= libnanopb
|
||||||
|
LOCAL_C_INCLUDES := $(LIBNANOPB)
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
nanopb/pb_common.c \
|
||||||
|
nanopb/pb_decode.c \
|
||||||
|
nanopb/pb_encode.c
|
||||||
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
# libfdt.a
|
# libfdt.a
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE:= libfdt
|
LOCAL_MODULE:= libfdt
|
||||||
|
1
native/jni/external/nanopb
vendored
Submodule
1
native/jni/external/nanopb
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 04cd1f94cc513b4cb3eac924c74039ccc05a944b
|
@ -63,13 +63,6 @@ int create_links(const char *bin, const char *path);
|
|||||||
int magiskhide_main(int argc, char *argv[]);
|
int magiskhide_main(int argc, char *argv[]);
|
||||||
int magiskpolicy_main(int argc, char *argv[]);
|
int magiskpolicy_main(int argc, char *argv[]);
|
||||||
int su_client_main(int argc, char *argv[]);
|
int su_client_main(int argc, char *argv[]);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
int resetprop_main(int argc, char *argv[]);
|
int resetprop_main(int argc, char *argv[]);
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,10 +4,6 @@
|
|||||||
#ifndef _RESETPROP_H_
|
#ifndef _RESETPROP_H_
|
||||||
#define _RESETPROP_H_
|
#define _RESETPROP_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int prop_exist(const char *name);
|
int prop_exist(const char *name);
|
||||||
int setprop(const char *name, const char *value);
|
int setprop(const char *name, const char *value);
|
||||||
int setprop2(const char *name, const char *value, const int trigger);
|
int setprop2(const char *name, const char *value, const int trigger);
|
||||||
@ -16,10 +12,6 @@ char *getprop2(const char *name, int persist);
|
|||||||
int deleteprop(const char *name);
|
int deleteprop(const char *name);
|
||||||
int deleteprop2(const char *name, const int persist);
|
int deleteprop2(const char *name, const int persist);
|
||||||
int read_prop_file(const char* filename, const int trigger);
|
int read_prop_file(const char* filename, const int trigger);
|
||||||
void getprop_all(void (*callback)(const char*, const char*));
|
void getprop_all(void (*callback)(const char *, const char *, void *), void *cookie);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -56,7 +56,7 @@ void hide_sensitive_props() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rm_magisk_prop(const char *name, const char *value) {
|
static void rm_magisk_prop(const char *name, const char *value, void *v) {
|
||||||
if (strstr(name, "magisk")) {
|
if (strstr(name, "magisk")) {
|
||||||
deleteprop2(name, 0);
|
deleteprop2(name, 0);
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ static void rm_magisk_prop(const char *name, const char *value) {
|
|||||||
|
|
||||||
void clean_magisk_props() {
|
void clean_magisk_props() {
|
||||||
LOGD("hide_utils: Cleaning magisk props\n");
|
LOGD("hide_utils: Cleaning magisk props\n");
|
||||||
getprop_all(rm_magisk_prop);
|
getprop_all(rm_magisk_prop, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_list(char *proc) {
|
int add_list(char *proc) {
|
||||||
|
31
native/jni/resetprop/_resetprop.h
Normal file
31
native/jni/resetprop/_resetprop.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/* resetprop.h - Internal struct definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MAGISK_PROPS_H
|
||||||
|
#define MAGISK_PROPS_H
|
||||||
|
|
||||||
|
#include "system_properties.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
extern int prop_verbose;
|
||||||
|
|
||||||
|
#define PRINT_D(...) { LOGD(__VA_ARGS__); if (prop_verbose) fprintf(stderr, __VA_ARGS__); }
|
||||||
|
#define PRINT_E(...) { LOGE(__VA_ARGS__); fprintf(stderr, __VA_ARGS__); }
|
||||||
|
|
||||||
|
struct prop_t {
|
||||||
|
char *name;
|
||||||
|
char value[PROP_VALUE_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct read_cb_t {
|
||||||
|
void (*func)(const char *name, const char *value, void *cookie);
|
||||||
|
void *cookie;
|
||||||
|
};
|
||||||
|
|
||||||
|
char *persist_getprop(const char *name);
|
||||||
|
void persist_getprop_all(struct read_cb_t *read_cb);
|
||||||
|
bool persist_deleteprop(const char *name);
|
||||||
|
void collect_props(const char *name, const char *value, void *prop_list);
|
||||||
|
|
||||||
|
#endif //MAGISK_PROPS_H
|
252
native/jni/resetprop/persist_props.c
Normal file
252
native/jni/resetprop/persist_props.c
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include <pb.h>
|
||||||
|
#include <pb_decode.h>
|
||||||
|
#include <pb_encode.h>
|
||||||
|
|
||||||
|
#include "_resetprop.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
#define PERSISTENT_PROPERTY_DIR "/data/property"
|
||||||
|
|
||||||
|
/* ***********************************************************************
|
||||||
|
* Auto generated header and constant definitions compiled from
|
||||||
|
* android/platform/system/core/master/init/persistent_properties.proto
|
||||||
|
* using Nanopb's protoc
|
||||||
|
* Nanopb: https://github.com/nanopb/nanopb
|
||||||
|
* ***********************************************************************/
|
||||||
|
|
||||||
|
/* Automatically generated nanopb header */
|
||||||
|
/* Generated by nanopb-0.3.9.1 at Sun Apr 22 14:36:22 2018. */
|
||||||
|
|
||||||
|
/* @@protoc_insertion_point(includes) */
|
||||||
|
#if PB_PROTO_HEADER_VERSION != 30
|
||||||
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Struct definitions */
|
||||||
|
typedef struct _PersistentProperties {
|
||||||
|
pb_callback_t properties;
|
||||||
|
/* @@protoc_insertion_point(struct:PersistentProperties) */
|
||||||
|
} PersistentProperties;
|
||||||
|
|
||||||
|
typedef struct _PersistentProperties_PersistentPropertyRecord {
|
||||||
|
pb_callback_t name;
|
||||||
|
bool has_value;
|
||||||
|
char value[92];
|
||||||
|
/* @@protoc_insertion_point(struct:PersistentProperties_PersistentPropertyRecord) */
|
||||||
|
} PersistentProperties_PersistentPropertyRecord;
|
||||||
|
|
||||||
|
/* Default values for struct fields */
|
||||||
|
|
||||||
|
/* Initializer values for message structs */
|
||||||
|
#define PersistentProperties_init_default {{{NULL}, NULL}}
|
||||||
|
#define PersistentProperties_PersistentPropertyRecord_init_default {{{NULL}, NULL}, false, ""}
|
||||||
|
#define PersistentProperties_init_zero {{{NULL}, NULL}}
|
||||||
|
#define PersistentProperties_PersistentPropertyRecord_init_zero {{{NULL}, NULL}, false, ""}
|
||||||
|
|
||||||
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
|
#define PersistentProperties_properties_tag 1
|
||||||
|
#define PersistentProperties_PersistentPropertyRecord_name_tag 1
|
||||||
|
#define PersistentProperties_PersistentPropertyRecord_value_tag 2
|
||||||
|
|
||||||
|
/* Automatically generated nanopb constant definitions */
|
||||||
|
/* Generated by nanopb-0.3.9.1 at Sun Apr 22 14:36:22 2018. */
|
||||||
|
|
||||||
|
/* Struct field encoding specification for nanopb */
|
||||||
|
const pb_field_t PersistentProperties_PersistentPropertyRecord_fields[3] = {
|
||||||
|
PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, PersistentProperties_PersistentPropertyRecord, name, name, 0),
|
||||||
|
PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, PersistentProperties_PersistentPropertyRecord, value, name, 0),
|
||||||
|
PB_LAST_FIELD
|
||||||
|
};
|
||||||
|
|
||||||
|
const pb_field_t PersistentProperties_fields[2] = {
|
||||||
|
PB_FIELD( 1, MESSAGE , REPEATED, CALLBACK, FIRST, PersistentProperties, properties, properties, &PersistentProperties_PersistentPropertyRecord_fields),
|
||||||
|
PB_LAST_FIELD
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Maximum encoded size of messages (where known) */
|
||||||
|
/* PersistentProperties_size depends on runtime parameters */
|
||||||
|
/* PersistentProperties_PersistentPropertyRecord_size depends on runtime parameters */
|
||||||
|
|
||||||
|
/* Message IDs (where set with "msgid" option) */
|
||||||
|
#ifdef PB_MSGID
|
||||||
|
|
||||||
|
#define PROPS_MESSAGES \
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/* @@protoc_insertion_point(eof) */
|
||||||
|
|
||||||
|
|
||||||
|
/* ***************************
|
||||||
|
* End of auto generated code
|
||||||
|
* ***************************/
|
||||||
|
|
||||||
|
static bool name_decode(pb_istream_t *stream, const pb_field_t *field, void **arg) {
|
||||||
|
uint8_t *name = xmalloc(stream->bytes_left + 1);
|
||||||
|
name[stream->bytes_left] = '\0';
|
||||||
|
if (!pb_read(stream, name, stream->bytes_left))
|
||||||
|
return false;
|
||||||
|
*arg = name;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool name_encode(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
|
||||||
|
return pb_encode_tag_for_field(stream, field) && pb_encode_string(stream, *arg, strlen(*arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool prop_decode(pb_istream_t *stream, const pb_field_t *field, void **arg) {
|
||||||
|
PersistentProperties_PersistentPropertyRecord prop = {};
|
||||||
|
prop.name.funcs.decode = name_decode;
|
||||||
|
if (!pb_decode(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop))
|
||||||
|
return false;
|
||||||
|
struct read_cb_t *read_cb = *arg;
|
||||||
|
read_cb->func(prop.name.arg, prop.value, read_cb->cookie);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool prop_encode(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
|
||||||
|
PersistentProperties_PersistentPropertyRecord prop = {};
|
||||||
|
prop.name.funcs.encode = name_encode;
|
||||||
|
prop.has_value = true;
|
||||||
|
struct vector *v = *arg;
|
||||||
|
struct prop_t *e;
|
||||||
|
vec_for_each(v, e) {
|
||||||
|
if (e == NULL)
|
||||||
|
continue;
|
||||||
|
if (!pb_encode_tag_for_field(stream, field))
|
||||||
|
return false;
|
||||||
|
prop.name.arg = e->name;
|
||||||
|
strcpy(prop.value, e->value);
|
||||||
|
if (!pb_encode_submessage(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop))
|
||||||
|
return false;
|
||||||
|
free(e->name);
|
||||||
|
free(e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count) {
|
||||||
|
int fd = (intptr_t)stream->state;
|
||||||
|
return xwrite(fd, buf, count) == count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pb_ostream_t create_ostream(const char *filename) {
|
||||||
|
int fd = creat(filename, 0644);
|
||||||
|
pb_ostream_t o = {&write_callback, (void*)(intptr_t)fd, SIZE_MAX, 0};
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pb_getprop_cb(const char *name, const char *value, void *v) {
|
||||||
|
struct prop_t *prop = v;
|
||||||
|
if (prop->name && strcmp(name, prop->name) == 0) {
|
||||||
|
strcpy(prop->value, value);
|
||||||
|
prop->name = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void persist_getprop_all(struct read_cb_t *read_cb) {
|
||||||
|
if (access(PERSISTENT_PROPERTY_DIR "/persistent_properties", R_OK) == 0) {
|
||||||
|
PRINT_D("resetprop: decode with protobuf from [" PERSISTENT_PROPERTY_DIR "/persistent_properties]\n");
|
||||||
|
PersistentProperties props = PersistentProperties_init_zero;
|
||||||
|
props.properties.funcs.decode = prop_decode;
|
||||||
|
props.properties.arg = read_cb;
|
||||||
|
uint8_t *buf;
|
||||||
|
size_t size;
|
||||||
|
mmap_ro(PERSISTENT_PROPERTY_DIR "/persistent_properties", (void **) &buf, &size);
|
||||||
|
pb_istream_t stream = pb_istream_from_buffer(buf, size);
|
||||||
|
pb_decode(&stream, PersistentProperties_fields, &props);
|
||||||
|
munmap(buf, size);
|
||||||
|
} else {
|
||||||
|
DIR *dir = opendir(PERSISTENT_PROPERTY_DIR);
|
||||||
|
struct dirent *entry;
|
||||||
|
while ((entry = readdir(dir))) {
|
||||||
|
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 )
|
||||||
|
continue;
|
||||||
|
char *value = persist_getprop(entry->d_name);
|
||||||
|
if (value) {
|
||||||
|
read_cb->func(strdup(entry->d_name), value, read_cb->cookie);
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *persist_getprop(const char *name) {
|
||||||
|
struct prop_t prop;
|
||||||
|
prop.name = (char *) name;
|
||||||
|
if (access(PERSISTENT_PROPERTY_DIR "/persistent_properties", R_OK) == 0) {
|
||||||
|
struct read_cb_t read_cb = {
|
||||||
|
.func = pb_getprop_cb,
|
||||||
|
.cookie = &prop
|
||||||
|
};
|
||||||
|
persist_getprop_all(&read_cb);
|
||||||
|
if (prop.name)
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
// Try to read from file
|
||||||
|
char path[PATH_MAX];
|
||||||
|
snprintf(path, sizeof(path), PERSISTENT_PROPERTY_DIR "/%s", name);
|
||||||
|
int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||||
|
if (fd < 0)
|
||||||
|
return NULL;
|
||||||
|
PRINT_D("resetprop: read prop from [%s]\n", path);
|
||||||
|
prop.value[read(fd, prop.value, sizeof(PROP_VALUE_MAX))] = '\0'; // Null terminate the read value
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
return strdup(prop.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool persist_deleteprop(const char *name) {
|
||||||
|
if (access(PERSISTENT_PROPERTY_DIR "/persistent_properties", R_OK) == 0) {
|
||||||
|
struct vector v;
|
||||||
|
vec_init(&v);
|
||||||
|
struct read_cb_t read_cb = {
|
||||||
|
.func = collect_props,
|
||||||
|
.cookie = &v
|
||||||
|
};
|
||||||
|
persist_getprop_all(&read_cb);
|
||||||
|
struct prop_t *p;
|
||||||
|
bool reencode = false;
|
||||||
|
vec_for_each(&v, p) {
|
||||||
|
if (strcmp(p->name, name) == 0) {
|
||||||
|
// Remove the prop from the list
|
||||||
|
free(p->name);
|
||||||
|
free(p);
|
||||||
|
vec_cur(&v) = NULL;
|
||||||
|
reencode = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reencode) {
|
||||||
|
// Dump the props back
|
||||||
|
PersistentProperties props = PersistentProperties_init_zero;
|
||||||
|
pb_ostream_t ostream = create_ostream(PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp");
|
||||||
|
props.properties.funcs.encode = prop_encode;
|
||||||
|
props.properties.arg = &v;
|
||||||
|
PRINT_D("resetprop: encode with protobuf to [" PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp]\n");
|
||||||
|
if (!pb_encode(&ostream, PersistentProperties_fields, &props))
|
||||||
|
return false;
|
||||||
|
clone_attr(PERSISTENT_PROPERTY_DIR "/persistent_properties", PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp");
|
||||||
|
rename(PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp", PERSISTENT_PROPERTY_DIR "/persistent_properties");
|
||||||
|
}
|
||||||
|
|
||||||
|
vec_destroy(&v);
|
||||||
|
return reencode;
|
||||||
|
} else {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
snprintf(path, sizeof(path), PERSISTENT_PROPERTY_DIR "/%s", name);
|
||||||
|
if (unlink(path) == 0) {
|
||||||
|
PRINT_D("resetprop: unlink [%s]\n", path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
@ -19,15 +19,11 @@
|
|||||||
|
|
||||||
#include "magisk.h"
|
#include "magisk.h"
|
||||||
#include "resetprop.h"
|
#include "resetprop.h"
|
||||||
extern "C" {
|
#include "_resetprop.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
}
|
#include "utils.h"
|
||||||
|
|
||||||
#define PRINT_D(...) { LOGD(__VA_ARGS__); if (verbose) fprintf(stderr, __VA_ARGS__); }
|
int prop_verbose = 0;
|
||||||
#define PRINT_E(...) { LOGE(__VA_ARGS__); fprintf(stderr, __VA_ARGS__); }
|
|
||||||
#define PERSISTENT_PROPERTY_DIR "/data/property"
|
|
||||||
|
|
||||||
static int verbose = 0;
|
|
||||||
|
|
||||||
static int check_legal_property_name(const char *name) {
|
static int check_legal_property_name(const char *name) {
|
||||||
int namelen = strlen(name);
|
int namelen = strlen(name);
|
||||||
@ -83,6 +79,49 @@ static int usage(char* arg0) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The callback passes to __system_property_read_callback2, actually runs the callback in read_cb
|
||||||
|
static void callback_wrapper(void *read_cb, const char *name, const char *value, uint32_t serial) {
|
||||||
|
((struct read_cb_t *) read_cb)->func(name, value, ((struct read_cb_t *) read_cb)->cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **********************************
|
||||||
|
* Callback functions for read_cb_t
|
||||||
|
* **********************************/
|
||||||
|
|
||||||
|
void collect_props(const char *name, const char *value, void *prop_list) {
|
||||||
|
struct prop_t *p = (struct prop_t *) xmalloc(sizeof(*p));
|
||||||
|
p->name = strdup(name);
|
||||||
|
strcpy(p->value, value);
|
||||||
|
vec_push_back(prop_list, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collect_unique_props(const char *name, const char *value, void *prop_list) {
|
||||||
|
struct vector *v = prop_list;
|
||||||
|
struct prop_t *p;
|
||||||
|
bool uniq = true;
|
||||||
|
vec_for_each(v, p) {
|
||||||
|
if (strcmp(name, p->name) == 0) {
|
||||||
|
uniq = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uniq)
|
||||||
|
collect_props(name, value, prop_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void store_prop_value(const char *name, const char *value, void *dst) {
|
||||||
|
strcpy(dst, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prop_foreach_cb(const prop_info* pi, void* read_cb) {
|
||||||
|
__system_property_read_callback2(pi, callback_wrapper, read_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparision function used to sort prop vectors
|
||||||
|
static int prop_cmp(const void *p1, const void *p2) {
|
||||||
|
return strcmp(((struct prop_t *) p1)->name, ((struct prop_t *) p2)->name);
|
||||||
|
}
|
||||||
|
|
||||||
static int init_resetprop() {
|
static int init_resetprop() {
|
||||||
if (__system_properties_init2()) {
|
if (__system_properties_init2()) {
|
||||||
PRINT_E("resetprop: Initialize error\n");
|
PRINT_E("resetprop: Initialize error\n");
|
||||||
@ -91,16 +130,36 @@ static int init_resetprop() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_props(int persist) {
|
||||||
|
struct prop_t *p;
|
||||||
|
struct vector prop_list;
|
||||||
|
vec_init(&prop_list);
|
||||||
|
getprop_all(collect_props, &prop_list);
|
||||||
|
if (persist) {
|
||||||
|
struct read_cb_t read_cb = {
|
||||||
|
.func = collect_unique_props,
|
||||||
|
.cookie = &prop_list
|
||||||
|
};
|
||||||
|
persist_getprop_all(&read_cb);
|
||||||
|
}
|
||||||
|
vec_sort(&prop_list, prop_cmp);
|
||||||
|
vec_for_each(&prop_list, p) {
|
||||||
|
printf("[%s]: [%s]\n", p->name, p->value);
|
||||||
|
free(p->name);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
vec_destroy(&prop_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************************************
|
||||||
|
* Implementations of functions in resetprop.h (APIs)
|
||||||
|
* **************************************************/
|
||||||
|
|
||||||
int prop_exist(const char *name) {
|
int prop_exist(const char *name) {
|
||||||
if (init_resetprop()) return 0;
|
if (init_resetprop()) return 0;
|
||||||
return __system_property_find2(name) != NULL;
|
return __system_property_find2(name) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_prop_info(void* cookie, const char *name, const char *value, uint32_t serial) {
|
|
||||||
strcpy((char *) cookie, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char *getprop(const char *name) {
|
char *getprop(const char *name) {
|
||||||
return getprop2(name, 0);
|
return getprop2(name, 0);
|
||||||
}
|
}
|
||||||
@ -109,103 +168,35 @@ char *getprop(const char *name) {
|
|||||||
char *getprop2(const char *name, int persist) {
|
char *getprop2(const char *name, int persist) {
|
||||||
if (check_legal_property_name(name))
|
if (check_legal_property_name(name))
|
||||||
return NULL;
|
return NULL;
|
||||||
char value[PROP_VALUE_MAX];
|
|
||||||
if (init_resetprop()) return NULL;
|
if (init_resetprop()) return NULL;
|
||||||
const prop_info *pi = __system_property_find2(name);
|
const prop_info *pi = __system_property_find2(name);
|
||||||
if (pi == NULL) {
|
if (pi == NULL) {
|
||||||
if (persist && strncmp(name, "persist.", 8) == 0) {
|
if (persist && strncmp(name, "persist.", 8) == 0) {
|
||||||
// Try to read from file
|
char *value = persist_getprop(name);
|
||||||
char path[PATH_MAX];
|
if (value)
|
||||||
snprintf(path, sizeof(path), PERSISTENT_PROPERTY_DIR "/%s", name);
|
return value;
|
||||||
int fd = open(path, O_RDONLY | O_CLOEXEC);
|
}
|
||||||
if (fd < 0) goto no_prop;
|
|
||||||
PRINT_D("resetprop: read prop from [%s]\n", path);
|
|
||||||
size_t len = read(fd, value, sizeof(value));
|
|
||||||
value[len] = '\0'; // Null terminate the read value
|
|
||||||
} else {
|
|
||||||
no_prop:
|
|
||||||
PRINT_D("resetprop: prop [%s] does not exist\n", name);
|
PRINT_D("resetprop: prop [%s] does not exist\n", name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
__system_property_read_callback2(pi, read_prop_info, value);
|
char value[PROP_VALUE_MAX];
|
||||||
}
|
struct read_cb_t read_cb = {
|
||||||
|
.func = store_prop_value,
|
||||||
|
.cookie = value
|
||||||
|
};
|
||||||
|
__system_property_read_callback2(pi, callback_wrapper, &read_cb);
|
||||||
PRINT_D("resetprop: getprop [%s]: [%s]\n", name, value);
|
PRINT_D("resetprop: getprop [%s]: [%s]\n", name, value);
|
||||||
return strdup(value);
|
return strdup(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wrapper {
|
void getprop_all(void (*callback)(const char *, const char *, void *), void *cookie) {
|
||||||
void (*func)(const char *, const char *);
|
|
||||||
};
|
|
||||||
|
|
||||||
static void cb_wrapper(void* cookie, const char *name, const char *value, uint32_t serial) {
|
|
||||||
((wrapper *) cookie)->func(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prop_foreach_cb(const prop_info* pi, void* cookie) {
|
|
||||||
__system_property_read_callback2(pi, cb_wrapper, cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
class property {
|
|
||||||
public:
|
|
||||||
property(const char *n, const char *v) {
|
|
||||||
name = strdup(n);
|
|
||||||
value = strdup(v);
|
|
||||||
}
|
|
||||||
~property() {
|
|
||||||
free((void *)name);
|
|
||||||
free((void *)value);
|
|
||||||
}
|
|
||||||
const char *name;
|
|
||||||
const char *value;
|
|
||||||
};
|
|
||||||
|
|
||||||
vector prop_list;
|
|
||||||
|
|
||||||
static int prop_cmp(const void *p1, const void *p2) {
|
|
||||||
return strcmp(((property *) p1)->name, ((property *) p2)->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_all_props_cb(const char *name, const char *value) {
|
|
||||||
vec_push_back(&prop_list, new property(name, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_all_props(int persist) {
|
|
||||||
void *p;
|
|
||||||
vec_init(&prop_list);
|
|
||||||
getprop_all(print_all_props_cb);
|
|
||||||
if (persist) {
|
|
||||||
// Check all persist props in data
|
|
||||||
DIR *dir = opendir(PERSISTENT_PROPERTY_DIR);
|
|
||||||
struct dirent *entry;
|
|
||||||
while ((entry = readdir(dir))) {
|
|
||||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 )
|
|
||||||
continue;
|
|
||||||
int found = 0;
|
|
||||||
vec_for_each(&prop_list, p) {
|
|
||||||
if (strcmp(((property *) p)->name, entry->d_name) == 0) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
vec_push_back(&prop_list, new property(entry->d_name, getprop2(entry->d_name, 1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vec_sort(&prop_list, prop_cmp);
|
|
||||||
vec_for_each(&prop_list, p) {
|
|
||||||
printf("[%s]: [%s]\n", ((property *) p)->name, ((property *) p)->value);
|
|
||||||
delete((property *) p);
|
|
||||||
}
|
|
||||||
vec_destroy(&prop_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getprop_all(void (*callback)(const char*, const char*)) {
|
|
||||||
if (init_resetprop()) return;
|
if (init_resetprop()) return;
|
||||||
struct wrapper wrap = {
|
struct read_cb_t read_cb = {
|
||||||
.func = callback
|
.func = callback,
|
||||||
|
.cookie = cookie
|
||||||
};
|
};
|
||||||
__system_property_foreach2(prop_foreach_cb, &wrap);
|
__system_property_foreach2(prop_foreach_cb, &read_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
int setprop(const char *name, const char *value) {
|
int setprop(const char *name, const char *value) {
|
||||||
@ -248,7 +239,7 @@ int deleteprop(const char *name) {
|
|||||||
return deleteprop2(name, 1);
|
return deleteprop2(name, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int deleteprop2(const char *name, const int persist) {
|
int deleteprop2(const char *name, int persist) {
|
||||||
if (check_legal_property_name(name))
|
if (check_legal_property_name(name))
|
||||||
return 1;
|
return 1;
|
||||||
if (init_resetprop()) return -1;
|
if (init_resetprop()) return -1;
|
||||||
@ -256,8 +247,8 @@ int deleteprop2(const char *name, const int persist) {
|
|||||||
path[0] = '\0';
|
path[0] = '\0';
|
||||||
PRINT_D("resetprop: deleteprop [%s]\n", name);
|
PRINT_D("resetprop: deleteprop [%s]\n", name);
|
||||||
if (persist && strncmp(name, "persist.", 8) == 0)
|
if (persist && strncmp(name, "persist.", 8) == 0)
|
||||||
snprintf(path, sizeof(path), PERSISTENT_PROPERTY_DIR "/%s", name);
|
persist = persist_deleteprop(name);
|
||||||
return __system_property_del(name) && unlink(path);
|
return __system_property_del(name) && !(persist && strncmp(name, "persist.", 8) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_prop_file(const char* filename, const int trigger) {
|
int read_prop_file(const char* filename, const int trigger) {
|
||||||
@ -290,7 +281,7 @@ int read_prop_file(const char* filename, const int trigger) {
|
|||||||
}
|
}
|
||||||
if (comment) continue;
|
if (comment) continue;
|
||||||
pch = strchr(line, '=');
|
pch = strchr(line, '=');
|
||||||
// Ignore ivalid formats
|
// Ignore invalid formats
|
||||||
if ( ((pch == NULL) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue;
|
if ( ((pch == NULL) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue;
|
||||||
// Separate the string
|
// Separate the string
|
||||||
*pch = '\0';
|
*pch = '\0';
|
||||||
@ -321,7 +312,7 @@ int resetprop_main(int argc, char *argv[]) {
|
|||||||
goto usage;
|
goto usage;
|
||||||
}
|
}
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = 1;
|
prop_verbose = 1;
|
||||||
continue;
|
continue;
|
||||||
case 'p':
|
case 'p':
|
||||||
persist = 1;
|
persist = 1;
|
||||||
@ -344,7 +335,7 @@ int resetprop_main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
switch (argc) {
|
switch (argc) {
|
||||||
case 0:
|
case 0:
|
||||||
print_all_props(persist);
|
print_props(persist);
|
||||||
return 0;
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
prop = getprop2(argv[0], persist);
|
prop = getprop2(argv[0], persist);
|
Loading…
Reference in New Issue
Block a user