blob: 6261ced0d720300c2a054492a72cf9993bb81327 [file] [log] [blame]
/* SPDX-License-Identifier: MediaTekProprietary */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h> //for read directories
#include <errno.h>
#include <cutils/properties.h>
#include "prop_file.h"
#include "prop_db.h"
#include "prop_debug.h"
#include "prop_core.h"
#include "prop_svc.h"
typedef enum
{
svc_cmd_type_command=1,
svc_cmd_type_service,
svc_cmd_type_onproperty,
svc_cmd_type_others
}prop_file_svc_cmd_t;
/*for APSIM, must put in /mnt/sncfg/apsim/*/
#if defined(PARTITION_FOR_APSIM)
#define PROP_CORE_PERSISTENT_PROPERTY_DIR "/mnt/sncfg/apsim/property"
#define PROP_CORE_PROPERTY_DIR "/mnt/sncfg/apsim/property"
#else
#define PROP_CORE_PERSISTENT_PROPERTY_DIR "/data/property"
#define PROP_CORE_PROPERTY_DIR "/data/property"
#endif
#define PROP_CORE_SERVICE_DIR "/"
#define PROP_CORE_PROP_DEFAULT "/default.prop"
#define PROP_CORE_PROP_SYSTEM_BUILD "/system/build.prop"
#define PROP_CORE_PROP_VENDOR_BUILD "/vendor/build.prop"
#define PROP_CORE_PROP_LOCAL "/data/local.prop"
#define PROP_CORE_PROP_FACTORY "/factory/factory.prop"
static int prop_file_persist_load_done = 0;
static int prop_file_persist_bootup_sync = 0;
static void _prop_file_trim_line(char *line)
{
int len;
int index;
if (!line)
return;
len = strlen(line);
if (len <= 0)
return;
for (index=len-1; index >= 0; index-- ) {
if ((line[index] == ' ') ||
(line[index] == '\n')) {
line[index] = '\0';
} else {
break;
}
}
return;
}
/*
* Filter is used to decide which properties to load: NULL loads all keys,
* "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
*/
static void _prop_file_load_properties(char *data, const char *filter)
{
char *key, *value, *eol, *sol, *tmp;
size_t flen = 0;
if (filter) {
flen = strlen(filter);
}
sol = data;
while ((eol = strchr(sol, '\n')))
{
key = sol;
*eol++ = 0;
sol = eol;
while (isspace(*key)) key++;
if (*key == '#')
continue;
tmp = eol - 2;
while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
{
value = strchr(key, '=');
if (!value) continue;
*value++ = 0;
tmp = value - 2;
while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
while (isspace(*value)) value++;
if (flen > 0) {
if (filter[flen - 1] == '*') {
if (strncmp(key, filter, flen - 1)) continue;
} else {
if (strcmp(key, filter)) continue;
}
}
prop_core_set(key, value);
}
}
}
static int _prop_file_parse_svc_service(const char *line_buf, char *prop_key, char *daemon_name)
{
char *key_ptr, *value_ptr, *temp_ptr;
int length_key, length_value;
key_ptr = strstr(line_buf, PROP_SVC_SERVICE);
if (!key_ptr) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Not the service line...Line:%s ", line_buf);
return -1;
}
if (strlen(key_ptr) < 8) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "service length wrong. len:%d Line:%s ", strlen(key_ptr), line_buf);
return -1;
}
/*skip the : and space*/
key_ptr = key_ptr + strlen(PROP_SVC_SERVICE);
while (*key_ptr == ' ') {
key_ptr++;
}
temp_ptr = strstr(key_ptr, " ");
if (!temp_ptr) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Wrong line...key:%s line:%s ", key_ptr, line_buf);
return -1;
}
length_key = (int)temp_ptr - (int)key_ptr;
if (length_key >= PROPERTY_KEY_MAX) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Wrong key len:%d line:%s ", length_key, line_buf);
return -1;
}
strncpy(prop_key, key_ptr, length_key);
prop_key[length_key] = '\0';
value_ptr = temp_ptr;
while (*value_ptr == ' ') {
value_ptr++;
}
length_value = strlen(value_ptr);
if (length_value>= PROP_SVC_ACTION_MAX_SIZE) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Wrong value len:%d line:%s ", length_value, line_buf);
return -1;
}
strcpy(daemon_name, value_ptr);
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " line:%s key:%s value:%s ", line_buf, prop_key, daemon_name);
return 0;
}
static int _prop_file_parse_svc_onproperty(char *line_buf, char *prop_key, char *prop_value)
{
char *key_ptr, *value_ptr, *temp_ptr;
int length_key, length_value;
key_ptr = strstr(line_buf, ":");
if (!key_ptr) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Wrong line...Line:%s ", line_buf);
return -1;
}
if (strlen(key_ptr) < 4) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Wrong line len:%d Line:%s ", strlen(key_ptr), line_buf);
return -1;
}
/*skip the : and space*/
key_ptr++;
while (*key_ptr == ' ') {
key_ptr++;
}
temp_ptr = strstr(key_ptr, "=");
if (!temp_ptr) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Wrong line without '=' line:%s Line:%s ", key_ptr, line_buf);
return -1;
}
while ((temp_ptr >= key_ptr) && *temp_ptr == ' ') {
temp_ptr--;
}
if (temp_ptr <= key_ptr) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Wrong line...2...Line:%s ", line_buf);
return -1;
}
length_key = (int)temp_ptr - (int)key_ptr;
strncpy(prop_key, key_ptr, length_key);
prop_key[length_key] = '\0';
value_ptr = strstr(temp_ptr, "=");
if (strlen(value_ptr) < 2) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Wrong line...3...value:%s ", value_ptr);
return -1;
}
/*skip the = and space*/
value_ptr++;
while (*value_ptr == ' ') {
value_ptr++;
}
length_value = strlen(value_ptr);
if (length_value>= PROPERTY_VALUE_MAX)
length_value = PROPERTY_VALUE_MAX - 1;
if ((length_value+length_key) >= PROPERTY_VALUE_MAX) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Wrong value or length. key_len:%d value_len:%d value:%s ",
length_key, length_value, value_ptr);
return -1;
}
strncpy(prop_value, value_ptr, length_value);
prop_value[length_value] = '\0';
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " End. key:%s value:%s line_buf:%s ", prop_key, prop_value, value_ptr);
return 0;
}
prop_file_svc_cmd_t _prop_file_parse_svc_type(char *line_buf)
{
char on_property[] = "on property:";
char service[] = "service ";
prop_file_svc_cmd_t cur_command_type;
if (strncmp(line_buf, on_property, strlen(on_property)) == 0) {
cur_command_type = svc_cmd_type_onproperty;
} else if (strncmp(line_buf, service, strlen(service)) == 0) {
cur_command_type = svc_cmd_type_service;
} else if ( (line_buf[0] == ' ') &&
(line_buf[1] == ' ') &&
(line_buf[2] == ' ') &&
(line_buf[3] == ' ') &&
(line_buf[4] != ' ')) {
/*how many space?*/
cur_command_type = svc_cmd_type_command;
} else {
cur_command_type = svc_cmd_type_others;
}
return cur_command_type;
}
/* reads a file, making sure it is terminated with \n \0 */
void *_prop_file_read_file(const char *fn, unsigned *_sz)
{
char *data = NULL;
int sz;
int fd;
data = 0;
fd = open(fn, O_RDONLY);
if (fd < 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "... :%s ", fn);
return 0;
}
sz = lseek(fd, 0, SEEK_END);
if (sz < 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "... :%s ", fn);
goto oops;
}
if (lseek(fd, 0, SEEK_SET) != 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "... :%s ", fn);
goto oops;
}
data = (char*) malloc(sz + 2);
if (data == 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "... :%s ", fn);
goto oops;
}
if (read(fd, data, sz) != sz) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "... :%s ", fn);
goto oops;
}
close(fd);
data[sz] = '\n';
data[sz+1] = 0;
if(_sz) *_sz = sz;
return data;
oops:
close(fd);
if (data != 0)
free(data);
return 0;
}
static void _prop_file_load_dir_svc(void)
{
#define LINE_BUFFER_MAX_SIZE 256
DIR *dir;
struct dirent* entry;
char folder_path[264];
FILE *read_file;
char line_buf[LINE_BUFFER_MAX_SIZE];
prop_file_svc_cmd_t cur_command_type;
prop_svc_t *cur_svc;
prop_svc_t svc_buf;
char *act_ptr;
char act_name[PROP_SVC_ACTION_MAX_SIZE];
int index;
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " Begin. ");
dir = opendir(PROP_CORE_SERVICE_DIR);
if (!dir) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to open default property directory %s errno: %d", PROP_CORE_SERVICE_DIR, errno);
return;
}
while ((entry = readdir(dir)) != NULL) {
if (!strstr(entry->d_name, ".rc"))
continue;
sprintf(folder_path, "%s/%s", PROP_CORE_SERVICE_DIR, entry->d_name);
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " Begin parse the line. file-name:%s ", folder_path);
read_file = fopen(folder_path , "r" );
if (!read_file) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to open default file %s errno: %d\n", folder_path, errno);
continue;
}
cur_svc = NULL;
while (fgets(line_buf, LINE_BUFFER_MAX_SIZE-1, read_file ) != NULL) {
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " line:%s len:%d", line_buf, strlen(line_buf));
/*trim out '\n'...*/
_prop_file_trim_line(line_buf);
/*filter out #*/
index = 0;
while (line_buf[index] == ' ') index++;
if (line_buf[index] == '#')
continue;
cur_command_type = _prop_file_parse_svc_type(line_buf);
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " line_buf:%s len:%d command_type:%d ", line_buf, strlen(line_buf), cur_command_type);
switch (cur_command_type) {
case svc_cmd_type_command:
if (cur_svc) {
act_ptr = line_buf;
while (*act_ptr == ' ')
act_ptr++;
if (strlen(act_ptr) >= PROP_SVC_ACTION_MAX_SIZE) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Action length exceed MAX %s ", act_ptr);
} else {
if (prop_svc_add_act(cur_svc->svc_name, cur_svc->svc_key, cur_svc->svc_value, act_ptr) < 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Can not add the action.name:%s %s ", cur_svc->svc_key, act_ptr);
}
}
} else {
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, "Wrong command, because of no prefix. Line:%s ", line_buf);
}
break;
case svc_cmd_type_service:
cur_svc = &svc_buf;
memset(cur_svc, 0x0, sizeof(prop_svc_t));
INIT_LIST(&(cur_svc->act_list));
INIT_LIST(&(cur_svc->slist));
strcpy(cur_svc->svc_name, entry->d_name);
cur_svc->svc_type = PROP_SVC_TYPE_SERVICE;
if (_prop_file_parse_svc_service(line_buf, cur_svc->svc_key, act_name) < 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to parse the name %s\n", line_buf);
cur_svc = NULL;
} else {
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " service! name:%s daemon:%s ", cur_svc->svc_key, act_name);
if (prop_svc_add(cur_svc) < 0)
{
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to add the on property");
cur_svc = NULL;
} else {
if (prop_svc_add_act(cur_svc->svc_name, cur_svc->svc_key, NULL, act_name) < 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to add the property");
cur_svc = NULL;
}
}
}
/*Init the cur_svc, since only need the first line for service*/
cur_svc = NULL;
break;
case svc_cmd_type_onproperty:
cur_svc = &svc_buf;
/*parse key and value*/
memset(cur_svc, 0x0, sizeof(prop_svc_t));
INIT_LIST(&(cur_svc->act_list));
INIT_LIST(&(cur_svc->slist));
strcpy(cur_svc->svc_name, entry->d_name);
cur_svc->svc_type = PROP_SVC_TYPE_ON_PROPERTY;
if (_prop_file_parse_svc_onproperty(line_buf, cur_svc->svc_key, cur_svc->svc_value) < 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to parse the name %s ", line_buf);
cur_svc = NULL;
} else {
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " onproperty!line_buf:%s key:%s value:%s ",
line_buf, cur_svc->svc_key, cur_svc->svc_value);
if (prop_svc_add(cur_svc) < 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to add the onproperty");
cur_svc = NULL;
}
}
break;
case svc_cmd_type_others:
default:
cur_svc = NULL;
break;
}
}
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " File end. ");
fclose ( read_file );
}
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " Directory end. ");
closedir(dir);
}
static void _prop_file_load_props_file(const char *file_path)
{
char *data;
unsigned sz;
data = _prop_file_read_file(file_path, &sz);
if(0 == data) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to read file data. File:%s ", file_path);
return;
}
_prop_file_load_properties(data, NULL);
free(data);
return;
}
static void _prop_file_load_dir_props(void)
{
DIR *dir;
struct dirent* entry;
char folder_path[256];
char *data;
unsigned sz;
dir = opendir(PROP_CORE_PROPERTY_DIR);
if (!dir) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to open default property directory %s errno: %d ", PROP_CORE_PROPERTY_DIR, errno);
return;
}
while ((entry = readdir(dir)) != NULL) {
if (!strstr(entry->d_name, ".prop"))
continue;
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " *.prop file. file:%s ", entry->d_name);
sprintf(folder_path, "%s/%s", PROP_CORE_PROPERTY_DIR, entry->d_name);
data = _prop_file_read_file(folder_path, &sz);
if(data != 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to read file data. File:%s ", folder_path);
_prop_file_load_properties(data, NULL);
free(data);
}
}
closedir(dir);
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " End. ");
}
static void _prop_file_load_dir_persistent(void)
{
DIR *dir;
int dir_fd;
struct dirent* entry;
char value[PROPERTY_VALUE_MAX];
int fd, length;
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " Begin. ");
dir = opendir(PROP_CORE_PERSISTENT_PROPERTY_DIR);
if (!dir) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to open persistent property directory %s errno: %d\n", PROP_CORE_PERSISTENT_PROPERTY_DIR, errno);
return;
}
dir_fd = dirfd(dir);
while ((entry = readdir(dir)) != NULL) {
if (strncmp("persist.", entry->d_name, strlen("persist.")))
continue;
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " persist.* file. file:%s ", entry->d_name);
/* open the file and read the property value */
fd = openat(dir_fd, entry->d_name, O_RDONLY);
if (fd < 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to open persistent property file. %s errno: %d ",
entry->d_name, errno);
continue;
}
length = read(fd, value, sizeof(value) - 1);
close(fd);
if (length >= 0) {
value[length] = 0;
prop_core_set(entry->d_name, value);
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " name:%s value:%s ", entry->d_name, value);
} else {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to read persistent property file %s errno: %d\n",
entry->d_name, errno);
}
}
closedir(dir);
PROP_DEBUG_PRINT(PROP_DEBUG_TRACE, " End. ");
}
void prop_file_write_persistent(const char *name, const char *value)
{
#define PROP_FILE_PATH_MAX 256
char temp_path[PROP_FILE_PATH_MAX];
char path[PROP_FILE_PATH_MAX];
FILE *file_ptr;
/*avoid to overwrite by default value*/
if (!prop_file_persist_load_done) {
snprintf(path, sizeof(path), "%s/%s", PROP_CORE_PERSISTENT_PROPERTY_DIR, name);
if (0 == access(path, F_OK)){
return;
}
prop_file_persist_bootup_sync = 1;
}
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "key:%s value:%s ", name, value);
snprintf(temp_path, sizeof(temp_path), "%s/.temp.xxx", PROP_CORE_PERSISTENT_PROPERTY_DIR);
file_ptr = fopen(temp_path , "w");
if (!file_ptr) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to write persistent property to temp file %s errno: %d", temp_path, errno);
return;
}
fwrite(value, 1, strlen(value), file_ptr);
fflush(file_ptr);
fclose(file_ptr);
snprintf(path, sizeof(path), "%s/%s", PROP_CORE_PERSISTENT_PROPERTY_DIR, name);
if (rename(temp_path, path) < 0) {
PROP_DEBUG_PRINT(PROP_DEBUG_ERROR, "Unable to rename persistent property file %s to %s ", temp_path, path);
}
/*bootup performance*/
if (prop_file_persist_load_done) {
sync();
}
}
void prop_file_load_props(void)
{
char temp_path[128];
prop_file_persist_load_done = 0;
/*make sure folder exist*/
snprintf(temp_path, sizeof(temp_path), "mkdir -p %s", PROP_CORE_PERSISTENT_PROPERTY_DIR);
system(temp_path);
_prop_file_load_props_file(PROP_CORE_PROP_DEFAULT);
_prop_file_load_props_file(PROP_CORE_PROP_SYSTEM_BUILD);
_prop_file_load_props_file(PROP_CORE_PROP_VENDOR_BUILD);
_prop_file_load_props_file(PROP_CORE_PROP_FACTORY);
_prop_file_load_props_file(PROP_CORE_PROP_LOCAL);
_prop_file_load_dir_persistent();
if (prop_file_persist_bootup_sync){
sync();
}
prop_file_persist_load_done = 1;
}
void prop_file_load_svc(void)
{
_prop_file_load_dir_svc();
}