mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-19 06:27:39 +00:00
253 lines
8.2 KiB
C
253 lines
8.2 KiB
C
|
#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;
|
||
|
}
|