frameworks_system_utils/kvdb/common.c

640 lines
17 KiB
C

/*
* Copyright (C) 2023 Xiaomi Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <kvdb.h>
#include "internal.h"
/****************************************************************************
* Private Types
****************************************************************************/
struct property_list_arg {
void* cookie;
void (*propfn)(const char* key, const char* value, void* cookie);
};
/****************************************************************************
* Private Functions
****************************************************************************/
static void property_list_fn(const char* key, const void* value, size_t val_len, void* cookie)
{
struct property_list_arg* list = (struct property_list_arg*)cookie;
*((char*)value + val_len) = '\0';
list->propfn(key, value, list->cookie);
}
static inline char nibble2ascii(unsigned char nibble)
{
if (nibble < 10)
return '0' + nibble;
else
return 'a' + nibble - 10;
}
static inline int ascii2nibble(char ascii)
{
if (isdigit(ascii))
return ascii - '0';
else if (isxdigit(ascii))
return tolower(ascii) - 'a' + 10;
else
return -ERANGE;
}
/****************************************************************************
* Name: property_set_
*
* Description:
* Store Key-Values to database.
*
* Input Parameters:
* const char* key: entry key string
* const char* value: entry value string
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_(const char* key, const char* value, bool oneway)
{
if (!value)
value = "";
/* in environment variable? */
if (getenv(key)) {
int ret = setenv(key, value, 1);
if (ret < 0)
ret = -errno;
return ret;
}
return property_set_binary(key, value, strlen(value) + 1, oneway);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: property_set
*
* Description:
* Store Key-Values to database.
*
* Input Parameters:
* const char* key: entry key string
* const char* value: entry value string
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
int property_set(const char* key, const char* value)
{
return property_set_(key, value, false);
}
/****************************************************************************
* Name: property_get_with_err
*
* Description:
* Retrieve Key-Values from database.
*
* Input Parameters:
* const char* key: entry key string
* char* value: not NULL : pointer to string buffer
* NULL : check whether this [key, value] exists
*
* Returned Value:
* On success returns the length of the value which will never be greater
* than PROP_NAME_MAX - 1 and will always be zero terminated.
* (the length does not include the terminating zero).
* On failure returns negative value.
*
****************************************************************************/
int property_get_with_err(const char* key, char* value)
{
/* in environment variable? */
const char* env = getenv(key);
if (env) {
size_t len = strlen(env);
if (len >= PROP_VALUE_MAX)
return -E2BIG;
if (value)
memcpy(value, env, len + 1);
return len;
}
ssize_t ret = property_get_binary(key, value, PROP_VALUE_MAX);
if (ret == 0) {
return -ENODATA;
} else if (ret > 0) {
*(value + ret) = '\0';
return strlen(value);
}
return ret;
}
/****************************************************************************
* Name: property_get
*
* Description:
* Retrieve Key-Values from database.
*
* Input Parameters:
* const char* key: entry key string
* char* value: not NULL : pointer to string buffer
* NULL : check whether this [key, value] exists
* const char* default_value: the value to return on failure
*
* Returned Value:
* On success returns the length of the value which will never be greater
* than PROP_NAME_MAX - 1 and will always be zero terminated.
* (the length does not include the terminating zero).
* On failure returns length of default_value.
*
****************************************************************************/
int property_get(const char* key, char* value, const char* default_value)
{
int ret = property_get_with_err(key, value);
if (ret <= 0) {
if (!default_value)
return -EINVAL;
size_t len = strlen(default_value);
if (value)
memcpy(value, default_value, len + 1);
return len;
}
return ret;
}
/****************************************************************************
* Name: property_list
*
* Description:
* List all KVs in every database and calls callback function.
*
* Input Parameters:
* property_callback propfn: callback function
* void* cookie: cookie data to pass to callback function
*
* Returned Value:
* Returns 0 on success, <0 if all databases failed to open.
*
****************************************************************************/
int property_list(void (*propfn)(const char* key, const char* value, void* cookie), void* cookie)
{
struct property_list_arg list;
list.cookie = cookie;
list.propfn = propfn;
return property_list_binary(property_list_fn, &list);
}
int property_set_oneway(const char* key, const char* value)
{
return property_set_(key, value, true);
}
/****************************************************************************
* Name: property_set_bool
*
* Description:
* Saves a boolean to database.
*
* Input Parameters:
* const char* key: entry key string
* int8_t value: entry value
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_bool_(const char* key, int8_t value, bool oneway)
{
return property_set_(key, value ? "true" : "false", oneway);
}
int property_set_bool(const char* key, int8_t value)
{
return property_set_bool_(key, value, false);
}
int property_set_bool_oneway(const char* key, int8_t value)
{
return property_set_bool_(key, value, true);
}
/****************************************************************************
* Name: property_get_bool_with_err
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as boolean.
* This is modified from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int8_t* value: the entry value
*
* Returned Value:
* On success returns zero.
* On failure returns non-zero.
*
****************************************************************************/
int property_get_bool_with_err(const char* key, int8_t* value)
{
char buf[PROP_VALUE_MAX];
if (value == NULL)
return -EINVAL;
int len = property_get_with_err(key, buf);
if (len < 0)
return len;
if (len == 1) {
char ch = buf[0];
if (ch == '0' || ch == 'n') {
*value = 0;
return 0;
} else if (ch == '1' || ch == 'y') {
*value = 1;
return 0;
}
} else if (len > 1) {
if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
*value = 0;
return 0;
} else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
*value = 1;
return 0;
}
}
return -ENODATA;
}
/****************************************************************************
* Name: property_get_bool
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as boolean.
* This is taken from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int8_t default_value: the value to return on failure
*
* Returned Value:
* On success returns a boolean.
* On failure returns default_value.
*
****************************************************************************/
int8_t property_get_bool(const char* key, int8_t default_value)
{
int8_t value;
int ret = property_get_bool_with_err(key, &value);
return ret ? default_value : value;
}
/****************************************************************************
* Name: property_set_int32
*
* Description:
* Saves an 32-bit integer to unqlite backend or nvs backend.
*
* Input Parameters:
* const char* key: entry key string
* int32_t value: entry value
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_int32_(const char* key, int32_t value, bool oneway)
{
char buf[32];
snprintf(buf, 32, "%" PRId32, value);
return property_set_(key, buf, oneway);
}
int property_set_int32(const char* key, int32_t value)
{
return property_set_int32_(key, value, false);
}
int property_set_int32_oneway(const char* key, int32_t value)
{
return property_set_int32_(key, value, true);
}
/****************************************************************************
* Name: property_get_int32_with_err
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as int32_t.
* This is modified from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int32_t* value: the entry value
*
* Returned Value:
* On success returns zero.
* On failure returns non-zero.
*
****************************************************************************/
int property_get_int32_with_err(const char* key, int32_t* value)
{
char buf[PROP_VALUE_MAX];
if (value == NULL)
return -EINVAL;
int32_t ret = property_get_with_err(key, buf);
if (ret < 0)
return ret;
errno = 0;
char* end;
ret = strtol(buf, &end, 0);
if (errno || *end || buf == end)
return -ENODATA;
*value = ret;
return 0;
}
/****************************************************************************
* Name: property_get_int32
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as int32_t.
* This is modified from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int32_t default_value: the value to return on failure
*
* Returned Value:
* On success returns a int32_t.
* On failure returns default_value.
*
****************************************************************************/
int32_t property_get_int32(const char* key, int32_t default_value)
{
int32_t value;
int ret = property_get_int32_with_err(key, &value);
return ret ? default_value : value;
}
/****************************************************************************
* Name: property_set_int64
*
* Description:
* Saves an 64-bit integer to unqlite backend or nvs backend.
*
* Input Parameters:
* const char* key: entry key string
* int64_t value: entry value
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_int64_(const char* key, int64_t value, bool oneway)
{
char buf[32];
snprintf(buf, 32, "%" PRId64, value);
return property_set_(key, buf, oneway);
}
int property_set_int64(const char* key, int64_t value)
{
return property_set_int64_(key, value, false);
}
int property_set_int64_oneway(const char* key, int64_t value)
{
return property_set_int64_(key, value, true);
}
/****************************************************************************
* Name: property_get_int64_with_err
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as int64_t.
* This is modified from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int64_t* value: the entry value
*
* Returned Value:
* On success returns zero.
* On failure returns non-zero.
*
****************************************************************************/
int property_get_int64_with_err(const char* key, int64_t* value)
{
char buf[PROP_VALUE_MAX];
if (value == NULL)
return -EINVAL;
int64_t ret = property_get_with_err(key, buf);
if (ret < 0)
return ret;
errno = 0;
char* end;
ret = strtoll(buf, &end, 0);
if (errno || *end || buf == end)
return -ENODATA;
*value = ret;
return 0;
}
/****************************************************************************
* Name: property_get_int64
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as int64_t.
* This is modified from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int64_t default_value: the value to return on failure
*
* Returned Value:
* On success returns a int64_t.
* On failure returns default_value.
*
****************************************************************************/
int64_t property_get_int64(const char* key, int64_t default_value)
{
int64_t value;
int ret = property_get_int64_with_err(key, &value);
return ret ? default_value : value;
}
/****************************************************************************
* Name: property_set_buffer
*
* Description:
* Saves a binary buffer to unqlite backend or nvs backend.
*
* Input Parameters:
* const char* key: entry key string
* const void* value: buffer value
* size_t size: buffer size
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_buffer_(const char* key, const void* value,
size_t size, bool oneway)
{
size_t buf_size = 2 * size;
if (buf_size >= PROP_VALUE_MAX)
return -E2BIG;
const unsigned char* tmp = value;
char buf[PROP_VALUE_MAX];
size_t i = 0;
while (i < buf_size) {
buf[i++] = nibble2ascii(*tmp >> 4);
buf[i++] = nibble2ascii(*tmp++ & 0x0f);
}
buf[i] = '\0';
return property_set_(key, buf, oneway);
}
int property_set_buffer(const char* key, const void* value, size_t size)
{
return property_set_buffer_(key, value, size, false);
}
int property_set_buffer_oneway(const char* key, const void* value, size_t size)
{
return property_set_buffer_(key, value, size, false);
}
/****************************************************************************
* Name: property_get_buffer
*
* Description:
* Retrieve a Key-Value from backend and interpret as binary buffer.
*
* Input Parameters:
* const char* key: entry key string
* void* value: buffer value
* size_t size: buffer size
*
* Returned Value:
* On success returns buffer length.
* On failure returns -errno.
*
****************************************************************************/
ssize_t property_get_buffer(const char* key, void* value, size_t size)
{
char buf[PROP_VALUE_MAX];
size_t buf_size = 2 * size;
int ret = property_get(key, buf, NULL);
if (ret < 0)
return ret;
char* tmp = value;
size_t i = 0;
while (buf[i]) {
if (i >= buf_size)
return -E2BIG;
ret = ascii2nibble(buf[i++]);
if (ret < 0)
return ret;
*tmp = ret << 4;
ret = ascii2nibble(buf[i++]);
if (ret < 0)
return ret;
*tmp++ |= ret;
}
return i / 2;
}