mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-27 13:57:38 +00:00
Modernize resetprop with fancy C++
This commit is contained in:
parent
c113f854a2
commit
aa8b23105f
@ -3,9 +3,10 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
int prop_exist(const char *name);
|
bool prop_exist(const char *name);
|
||||||
int setprop(const char *name, const char *value, bool trigger = true);
|
int setprop(const char *name, const char *value, bool trigger = true);
|
||||||
std::string getprop(const char *name, bool persist = false);
|
std::string getprop(const char *name, bool persist = false);
|
||||||
void getprop(void (*callback)(const char *, const char *, void *), void *cookie, bool persist = false);
|
void getprops(void (*callback)(const char *, const char *, void *),
|
||||||
|
void *cookie = nullptr, bool persist = false);
|
||||||
int delprop(const char *name, bool persist = false);
|
int delprop(const char *name, bool persist = false);
|
||||||
void load_prop_file(const char *filename, bool trigger = true);
|
void load_prop_file(const char *filename, bool trigger = true);
|
||||||
|
@ -1,57 +1,49 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <map>
|
||||||
#include <logging.hpp>
|
#include <logging.hpp>
|
||||||
|
|
||||||
#include <system_properties.h>
|
#include <system_properties.h>
|
||||||
|
|
||||||
struct prop_t {
|
|
||||||
char *name;
|
|
||||||
char value[PROP_VALUE_MAX];
|
|
||||||
prop_t() : name(nullptr) {}
|
|
||||||
explicit prop_t(const char *name) {
|
|
||||||
this->name = strdup(name);
|
|
||||||
value[0] = '\0';
|
|
||||||
}
|
|
||||||
prop_t(const char *name, const char *value) {
|
|
||||||
this->name = strdup(name);
|
|
||||||
strcpy(this->value, value);
|
|
||||||
}
|
|
||||||
prop_t(prop_t &&prop): name(nullptr) {
|
|
||||||
operator=(std::move(prop));
|
|
||||||
}
|
|
||||||
bool operator<(const prop_t &prop) const {
|
|
||||||
return strcmp(name, prop.name) < 0;
|
|
||||||
}
|
|
||||||
prop_t& operator=(prop_t &&prop) {
|
|
||||||
if (this != &prop) {
|
|
||||||
free(name);
|
|
||||||
name = prop.name;
|
|
||||||
strcpy(value, prop.value);
|
|
||||||
prop.name = nullptr;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
};
|
|
||||||
~prop_t() {
|
|
||||||
free(name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct read_cb_t {
|
|
||||||
void (*cb)(const char *, const char *, void *);
|
|
||||||
void *arg;
|
|
||||||
explicit read_cb_t(void (*cb)(const char *, const char *, void *) = nullptr, void *arg = nullptr)
|
|
||||||
: cb(cb), arg(arg) {}
|
|
||||||
void exec(const char *name, const char *value) {
|
|
||||||
cb(name, value, arg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PERSISTENT_PROPERTY_DIR "/data/property"
|
#define PERSISTENT_PROPERTY_DIR "/data/property"
|
||||||
|
|
||||||
|
struct prop_cb {
|
||||||
|
virtual void exec(const char *name, const char *value) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct prop_cb_impl : public prop_cb {
|
||||||
|
typedef void (*callback_type)(const char *, const char *, T&);
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wdangling-field" // Dangling field is expected
|
||||||
|
prop_cb_impl(T &arg, callback_type fn) : arg(arg), fn(fn) {}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
void exec(const char *name, const char *value) override {
|
||||||
|
fn(name, value, arg);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
T &arg;
|
||||||
|
callback_type fn;
|
||||||
|
};
|
||||||
|
|
||||||
extern bool use_pb;
|
extern bool use_pb;
|
||||||
|
|
||||||
|
using prop_list = std::map<std::string_view, std::string>;
|
||||||
|
|
||||||
|
struct prop_collector : prop_cb_impl<prop_list> {
|
||||||
|
prop_collector(prop_list &list) :
|
||||||
|
prop_cb_impl<prop_list>(list, [](auto name, auto val, auto list){ list.emplace(name, val); }) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, class Func>
|
||||||
|
prop_cb_impl<T> make_prop_cb(T &arg, Func f) {
|
||||||
|
return prop_cb_impl<T>(arg, f);
|
||||||
|
}
|
||||||
|
|
||||||
std::string persist_getprop(const char *name);
|
std::string persist_getprop(const char *name);
|
||||||
void persist_getprop(read_cb_t *read_cb);
|
void persist_getprops(prop_cb *prop_cb);
|
||||||
bool persist_deleteprop(const char *name);
|
bool persist_deleteprop(const char *name);
|
||||||
void collect_props(const char *name, const char *value, void *v_plist);
|
void persist_cleanup();
|
||||||
|
@ -88,8 +88,22 @@ const pb_field_t PersistentProperties_fields[2] = {
|
|||||||
* End of auto generated code
|
* End of auto generated code
|
||||||
* ***************************/
|
* ***************************/
|
||||||
|
|
||||||
|
#ifdef APPLET_STUB_MAIN
|
||||||
|
struct {
|
||||||
|
void push_back(...){};
|
||||||
|
} allocs;
|
||||||
|
void persist_cleanup(){}
|
||||||
|
#else
|
||||||
|
static thread_local vector<void *> allocs;
|
||||||
|
void persist_cleanup() {
|
||||||
|
std::for_each(allocs.begin(), allocs.end(), [](auto p){ free(p); });
|
||||||
|
allocs.clear();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool name_decode(pb_istream_t *stream, const pb_field_t *field, void **arg) {
|
static bool name_decode(pb_istream_t *stream, const pb_field_t *field, void **arg) {
|
||||||
auto name = new pb_byte_t[stream->bytes_left + 1];
|
auto name = (pb_byte_t *) malloc(stream->bytes_left + 1);
|
||||||
|
allocs.push_back(name); /* Record all mallocs to cleanup */
|
||||||
name[stream->bytes_left] = '\0';
|
name[stream->bytes_left] = '\0';
|
||||||
if (!pb_read(stream, name, stream->bytes_left))
|
if (!pb_read(stream, name, stream->bytes_left))
|
||||||
return false;
|
return false;
|
||||||
@ -107,8 +121,7 @@ static bool prop_decode(pb_istream_t *stream, const pb_field_t *field, void **ar
|
|||||||
prop.name.funcs.decode = name_decode;
|
prop.name.funcs.decode = name_decode;
|
||||||
if (!pb_decode(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop))
|
if (!pb_decode(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop))
|
||||||
return false;
|
return false;
|
||||||
((read_cb_t *) *arg)->exec((const char *) prop.name.arg, prop.value);
|
reinterpret_cast<prop_cb*>(*arg)->exec((const char *) prop.name.arg, prop.value);
|
||||||
delete[] (pb_byte_t *) prop.name.arg;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,12 +129,12 @@ static bool prop_encode(pb_ostream_t *stream, const pb_field_t *field, void * co
|
|||||||
PersistentProperties_PersistentPropertyRecord prop = {};
|
PersistentProperties_PersistentPropertyRecord prop = {};
|
||||||
prop.name.funcs.encode = name_encode;
|
prop.name.funcs.encode = name_encode;
|
||||||
prop.has_value = true;
|
prop.has_value = true;
|
||||||
auto &prop_list = *(vector<prop_t> *) *arg;
|
auto &list = *(prop_list *) *arg;
|
||||||
for (auto &p : prop_list) {
|
for (auto &p : list) {
|
||||||
if (!pb_encode_tag_for_field(stream, field))
|
if (!pb_encode_tag_for_field(stream, field))
|
||||||
return false;
|
return false;
|
||||||
prop.name.arg = p.name;
|
prop.name.arg = (void *) p.first.data();
|
||||||
strcpy(prop.value, p.value);
|
strcpy(prop.value, p.second.data());
|
||||||
if (!pb_encode_submessage(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop))
|
if (!pb_encode_submessage(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -144,17 +157,11 @@ static pb_ostream_t create_ostream(const char *filename) {
|
|||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pb_getprop_cb(const char *name, const char *value, void *v) {
|
static void pb_getprop(prop_cb *prop_cb) {
|
||||||
struct prop_t *prop = static_cast<prop_t *>(v);
|
|
||||||
if (prop->name && strcmp(name, prop->name) == 0)
|
|
||||||
strcpy(prop->value, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pb_getprop(read_cb_t *read_cb) {
|
|
||||||
LOGD("resetprop: decode with protobuf [" PERSISTENT_PROPERTY_DIR "/persistent_properties]\n");
|
LOGD("resetprop: decode with protobuf [" PERSISTENT_PROPERTY_DIR "/persistent_properties]\n");
|
||||||
PersistentProperties props = {};
|
PersistentProperties props = {};
|
||||||
props.properties.funcs.decode = prop_decode;
|
props.properties.funcs.decode = prop_decode;
|
||||||
props.properties.arg = read_cb;
|
props.properties.arg = prop_cb;
|
||||||
pb_byte_t *buf;
|
pb_byte_t *buf;
|
||||||
size_t size;
|
size_t size;
|
||||||
mmap_ro(PERSISTENT_PROPERTY_DIR "/persistent_properties", buf, size);
|
mmap_ro(PERSISTENT_PROPERTY_DIR "/persistent_properties", buf, size);
|
||||||
@ -175,9 +182,9 @@ static bool file_getprop(const char *name, char *value) {
|
|||||||
return value[0] != '\0';
|
return value[0] != '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void persist_getprop(read_cb_t *read_cb) {
|
void persist_getprops(prop_cb *prop_cb) {
|
||||||
if (use_pb) {
|
if (use_pb) {
|
||||||
pb_getprop(read_cb);
|
pb_getprop(prop_cb);
|
||||||
} else {
|
} else {
|
||||||
DIR *dir = opendir(PERSISTENT_PROPERTY_DIR);
|
DIR *dir = opendir(PERSISTENT_PROPERTY_DIR);
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
@ -186,16 +193,25 @@ void persist_getprop(read_cb_t *read_cb) {
|
|||||||
continue;
|
continue;
|
||||||
char value[PROP_VALUE_MAX];
|
char value[PROP_VALUE_MAX];
|
||||||
if (file_getprop(entry->d_name, value))
|
if (file_getprop(entry->d_name, value))
|
||||||
read_cb->exec(entry->d_name, value);
|
prop_cb->exec(entry->d_name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string persist_getprop(const char *name) {
|
string persist_getprop(const char *name) {
|
||||||
prop_t prop(name);
|
|
||||||
if (use_pb) {
|
if (use_pb) {
|
||||||
read_cb_t read_cb(pb_getprop_cb, &prop);
|
run_finally f([]{ persist_cleanup(); });
|
||||||
pb_getprop(&read_cb);
|
struct {
|
||||||
|
const char *name;
|
||||||
|
char value[PROP_VALUE_MAX];
|
||||||
|
} prop;
|
||||||
|
prop.name = name;
|
||||||
|
prop.value[0] = '\0';
|
||||||
|
auto reader = make_prop_cb(prop, [](auto name, auto value, auto prop) {
|
||||||
|
if (strcmp(name, prop.name) == 0)
|
||||||
|
strcpy(prop.value, value);
|
||||||
|
});
|
||||||
|
pb_getprop(&reader);
|
||||||
if (prop.value[0])
|
if (prop.value[0])
|
||||||
return prop.value;
|
return prop.value;
|
||||||
} else {
|
} else {
|
||||||
@ -209,19 +225,20 @@ string persist_getprop(const char *name) {
|
|||||||
|
|
||||||
bool persist_deleteprop(const char *name) {
|
bool persist_deleteprop(const char *name) {
|
||||||
if (use_pb) {
|
if (use_pb) {
|
||||||
vector<prop_t> prop_list;
|
run_finally f([]{ persist_cleanup(); });
|
||||||
read_cb_t read_cb(collect_props, &prop_list);
|
prop_list list;
|
||||||
persist_getprop(&read_cb);
|
prop_collector collector(list);
|
||||||
|
persist_getprops(&collector);
|
||||||
|
|
||||||
for (auto it = prop_list.begin(); it != prop_list.end(); ++it) {
|
for (auto it = list.begin(); it != list.end(); ++it) {
|
||||||
if (strcmp(it->name, name) == 0) {
|
if (it->first == name) {
|
||||||
prop_list.erase(it);
|
list.erase(it);
|
||||||
// Dump the props back
|
// Dump the props back
|
||||||
PersistentProperties props = PersistentProperties_init_zero;
|
PersistentProperties props = PersistentProperties_init_zero;
|
||||||
pb_ostream_t ostream = create_ostream(PERSISTENT_PROPERTY_DIR
|
pb_ostream_t ostream = create_ostream(PERSISTENT_PROPERTY_DIR
|
||||||
"/persistent_properties.tmp");
|
"/persistent_properties.tmp");
|
||||||
props.properties.funcs.encode = prop_encode;
|
props.properties.funcs.encode = prop_encode;
|
||||||
props.properties.arg = &prop_list;
|
props.properties.arg = &list;
|
||||||
LOGD("resetprop: encode with protobuf [" PERSISTENT_PROPERTY_DIR
|
LOGD("resetprop: encode with protobuf [" PERSISTENT_PROPERTY_DIR
|
||||||
"/persistent_properties.tmp]\n");
|
"/persistent_properties.tmp]\n");
|
||||||
if (!pb_encode(&ostream, PersistentProperties_fields, &props))
|
if (!pb_encode(&ostream, PersistentProperties_fields, &props))
|
||||||
@ -233,7 +250,6 @@ bool persist_deleteprop(const char *name) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <map>
|
||||||
|
|
||||||
#include <logging.hpp>
|
#include <logging.hpp>
|
||||||
#include <resetprop.hpp>
|
#include <resetprop.hpp>
|
||||||
@ -55,48 +55,34 @@ illegal:
|
|||||||
|
|
||||||
[[noreturn]] static void usage(char* arg0) {
|
[[noreturn]] static void usage(char* arg0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
NAME_WITH_VER(resetprop) " - System Props Modification Tool\n\n"
|
NAME_WITH_VER(resetprop) R"EOF(" - System Props Modification Tool
|
||||||
"Usage: %s [flags] [options...]\n"
|
|
||||||
"\n"
|
|
||||||
"Options:\n"
|
|
||||||
" -h, --help show this message\n"
|
|
||||||
" (no arguments) print all properties\n"
|
|
||||||
" NAME get property\n"
|
|
||||||
" NAME VALUE set property entry NAME with VALUE\n"
|
|
||||||
" --file FILE load props from FILE\n"
|
|
||||||
" --delete NAME delete property\n"
|
|
||||||
"\n"
|
|
||||||
"Flags:\n"
|
|
||||||
" -v print verbose output to stderr\n"
|
|
||||||
" -n set properties without init triggers\n"
|
|
||||||
" only affects setprop\n"
|
|
||||||
" -p access actual persist storage\n"
|
|
||||||
" only affects getprop and delprop\n"
|
|
||||||
"\n"
|
|
||||||
|
|
||||||
, arg0);
|
Usage: %s [flags] [options...]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help show this message
|
||||||
|
(no arguments) print all properties
|
||||||
|
NAME get property
|
||||||
|
NAME VALUE set property entry NAME with VALUE
|
||||||
|
--file FILE load props from FILE
|
||||||
|
--delete NAME delete property
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
-v print verbose output to stderr
|
||||||
|
-n set properties without going through init
|
||||||
|
affects setprop and prop file loading
|
||||||
|
-p also access props directly from persist storage
|
||||||
|
affects getprop and delprop
|
||||||
|
|
||||||
|
)EOF", arg0);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_props(const prop_info *pi, void *read_cb) {
|
static void read_props(const prop_info *pi, void *cb) {
|
||||||
__system_property_read_callback(
|
__system_property_read_callback(
|
||||||
pi, [](auto cb, auto name, auto value, auto) {
|
pi, [](auto cb, auto name, auto value, auto) {
|
||||||
((read_cb_t *) cb)->exec(name, value);
|
reinterpret_cast<prop_cb*>(cb)->exec(name, value);
|
||||||
}, read_cb);
|
}, cb);
|
||||||
}
|
|
||||||
|
|
||||||
void collect_props(const char *name, const char *value, void *v_plist) {
|
|
||||||
auto prop_list = static_cast<vector<prop_t> *>(v_plist);
|
|
||||||
prop_list->emplace_back(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void collect_unique_props(const char *name, const char *value, void *v_plist) {
|
|
||||||
auto &prop_list = *static_cast<vector<prop_t> *>(v_plist);
|
|
||||||
for (auto &prop : prop_list) {
|
|
||||||
if (strcmp(name, prop.name) == 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
collect_props(name, value, v_plist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_resetprop() {
|
static int init_resetprop() {
|
||||||
@ -109,11 +95,9 @@ static int init_resetprop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void print_props(bool persist) {
|
static void print_props(bool persist) {
|
||||||
vector<prop_t> prop_list;
|
getprops([](auto name, auto value, auto) {
|
||||||
getprop(collect_props, &prop_list, persist);
|
printf("[%s]: [%s]\n", name, value);
|
||||||
sort(prop_list.begin(), prop_list.end());
|
}, nullptr, persist);
|
||||||
for (auto &prop : prop_list)
|
|
||||||
printf("[%s]: [%s]\n", prop.name, prop.value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* **************************************************
|
/* **************************************************
|
||||||
@ -122,8 +106,8 @@ static void print_props(bool persist) {
|
|||||||
|
|
||||||
#define ENSURE_INIT(ret) if (init_resetprop()) return ret
|
#define ENSURE_INIT(ret) if (init_resetprop()) return ret
|
||||||
|
|
||||||
int prop_exist(const char *name) {
|
bool prop_exist(const char *name) {
|
||||||
ENSURE_INIT(0);
|
ENSURE_INIT(false);
|
||||||
return __system_property_find(name) != nullptr;
|
return __system_property_find(name) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,29 +121,31 @@ string getprop(const char *name, bool persist) {
|
|||||||
if (persist && strncmp(name, "persist.", 8) == 0) {
|
if (persist && strncmp(name, "persist.", 8) == 0) {
|
||||||
auto value = persist_getprop(name);
|
auto value = persist_getprop(name);
|
||||||
if (value.empty())
|
if (value.empty())
|
||||||
LOGD("resetprop: prop [%s] does not exist\n", name);
|
goto not_found;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
not_found:
|
||||||
|
LOGD("resetprop: prop [%s] does not exist\n", name);
|
||||||
return string();
|
return string();
|
||||||
} else {
|
} else {
|
||||||
char value[PROP_VALUE_MAX];
|
char buf[PROP_VALUE_MAX];
|
||||||
read_cb_t read_cb;
|
auto reader = make_prop_cb(buf, [](auto, auto value, auto buf) { strcpy(buf, value); });
|
||||||
read_cb.cb = [](auto, auto value, auto dst) -> void { strcpy((char *) dst, value); };
|
read_props(pi, &reader);
|
||||||
read_cb.arg = value;
|
LOGD("resetprop: getprop [%s]: [%s]\n", name, buf);
|
||||||
read_props(pi, &read_cb);
|
return buf;
|
||||||
LOGD("resetprop: getprop [%s]: [%s]\n", name, value);
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void getprop(void (*callback)(const char *, const char *, void *), void *cookie, bool persist) {
|
void getprops(void (*callback)(const char *, const char *, void *), void *cookie, bool persist) {
|
||||||
ENSURE_INIT();
|
ENSURE_INIT();
|
||||||
read_cb_t read_cb(callback, cookie);
|
prop_list list;
|
||||||
__system_property_foreach(read_props, &read_cb);
|
prop_collector collector(list);
|
||||||
if (persist) {
|
__system_property_foreach(read_props, &collector);
|
||||||
read_cb.cb = collect_unique_props;
|
if (persist)
|
||||||
persist_getprop(&read_cb);
|
persist_getprops(&collector);
|
||||||
}
|
for (auto &[key, val] : list)
|
||||||
|
callback(key.data(), val.data(), cookie);
|
||||||
|
persist_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
int setprop(const char *name, const char *value, bool trigger) {
|
int setprop(const char *name, const char *value, bool trigger) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user