#include #include #include #include #include #include #include #include #include #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; }