@ -10,12 +10,25 @@
# include <dirent.h>
# include <dirent.h>
# include <sys/file.h>
# include <sys/file.h>
# include <sys/stat.h>
# include <sys/stat.h>
# include <mutex>
# include <csignal>
# include <csignal>
# include <string.h>
# include <string.h>
# include "common/util.h"
# include "common/util.h"
# include "common/swaglog.h"
// keep trying if x gets interrupted by a signal
# define HANDLE_EINTR(x) \
( { \
decltype ( x ) ret ; \
int try_cnt = 0 ; \
do { \
ret = ( x ) ; \
} while ( ret = = - 1 & & errno = = EINTR & & try_cnt + + < 100 ) ; \
ret ; \
} )
namespace {
# if defined(QCOM) || defined(QCOM2)
# if defined(QCOM) || defined(QCOM2)
const std : : string default_params_path = " /data/params " ;
const std : : string default_params_path = " /data/params " ;
@ -35,8 +48,8 @@ void params_sig_handler(int signal) {
params_do_exit = 1 ;
params_do_exit = 1 ;
}
}
static int fsync_dir ( const char * path ) {
int fsync_dir ( const char * path ) {
int fd = open ( path , O_RDONLY , 0755 ) ;
int fd = HANDLE_EINTR ( open ( path , O_RDONLY , 0755 ) ) ;
if ( fd < 0 ) {
if ( fd < 0 ) {
return - 1 ;
return - 1 ;
}
}
@ -50,7 +63,7 @@ static int fsync_dir(const char* path){
}
}
// TODO: replace by std::filesystem::create_directories
// TODO: replace by std::filesystem::create_directories
static int mkdir_p ( std : : string path ) {
int mkdir_p ( std : : string path ) {
char * _path = ( char * ) path . c_str ( ) ;
char * _path = ( char * ) path . c_str ( ) ;
mode_t prev_mask = umask ( 0 ) ;
mode_t prev_mask = umask ( 0 ) ;
@ -71,7 +84,7 @@ static int mkdir_p(std::string path) {
return 0 ;
return 0 ;
}
}
static bool ensure_params_path ( const std : : string & param_path , const std : : string & key_path ) {
bool ensure_params_path ( const std : : string & param_path , const std : : string & key_path ) {
// Make sure params path exists
// Make sure params path exists
if ( ! util : : file_exists ( param_path ) & & mkdir_p ( param_path ) ! = 0 ) {
if ( ! util : : file_exists ( param_path ) & & mkdir_p ( param_path ) ! = 0 ) {
return false ;
return false ;
@ -110,6 +123,31 @@ static bool ensure_params_path(const std::string ¶m_path, const std::string
return chmod ( key_path . c_str ( ) , 0777 ) = = 0 ;
return chmod ( key_path . c_str ( ) , 0777 ) = = 0 ;
}
}
class FileLock {
public :
FileLock ( const std : : string & file_name , int op ) : fn_ ( file_name ) , op_ ( op ) { }
void lock ( ) {
fd_ = HANDLE_EINTR ( open ( fn_ . c_str ( ) , O_CREAT , 0775 ) ) ;
if ( fd_ < 0 ) {
LOGE ( " Failed to open lock file %s, errno=%d " , fn_ . c_str ( ) , errno ) ;
return ;
}
if ( HANDLE_EINTR ( flock ( fd_ , op_ ) ) < 0 ) {
close ( fd_ ) ;
LOGE ( " Failed to lock file %s, errno=%d " , fn_ . c_str ( ) , errno ) ;
}
}
void unlock ( ) { close ( fd_ ) ; }
private :
int fd_ = - 1 , op_ ;
std : : string fn_ ;
} ;
} // namespace
Params : : Params ( bool persistent_param ) : Params ( persistent_param ? persistent_params_path : default_params_path ) { }
Params : : Params ( bool persistent_param ) : Params ( persistent_param ? persistent_params_path : default_params_path ) { }
Params : : Params ( const std : : string & path ) : params_path ( path ) {
Params : : Params ( const std : : string & path ) : params_path ( path ) {
@ -126,110 +164,54 @@ int Params::put(const char* key, const char* value, size_t value_size) {
// 4) rename the temp file to the real name
// 4) rename the temp file to the real name
// 5) fsync() the containing directory
// 5) fsync() the containing directory
int lock_fd = - 1 ;
std : : string tmp_path = params_path + " /.tmp_value_XXXXXX " ;
int tmp_fd = - 1 ;
int tmp_fd = mkstemp ( ( char * ) tmp_path . c_str ( ) ) ;
int result ;
if ( tmp_fd < 0 ) return - 1 ;
std : : string path ;
std : : string tmp_path ;
int result = - 1 ;
ssize_t bytes_written ;
do {
// Write value to temp.
// Write value to temp.
ssize_t bytes_written = HANDLE_EINTR ( write ( tmp_fd , value , value_size ) ) ;
tmp_path = params_path + " /.tmp_value_XXXXXX " ;
if ( bytes_written < 0 | | ( size_t ) bytes_written ! = value_size ) {
tmp_fd = mkstemp ( ( char * ) tmp_path . c_str ( ) ) ;
result = - 20 ;
bytes_written = write ( tmp_fd , value , value_size ) ;
break ;
if ( bytes_written < 0 | | ( size_t ) bytes_written ! = value_size ) {
}
result = - 20 ;
goto cleanup ;
}
// Build lock path
path = params_path + " /.lock " ;
lock_fd = open ( path . c_str ( ) , O_CREAT , 0775 ) ;
// Build key path
path = params_path + " /d/ " + std : : string ( key ) ;
// Take lock.
result = flock ( lock_fd , LOCK_EX ) ;
if ( result < 0 ) {
goto cleanup ;
}
// change permissions to 0666 for apks
// change permissions to 0666 for apks
result = fchmod ( tmp_fd , 0666 ) ;
if ( ( result = fchmod ( tmp_fd , 0666 ) ) < 0 ) break ;
if ( result < 0 ) {
// fsync to force persist the changes.
goto cleanup ;
if ( ( result = fsync ( tmp_fd ) ) < 0 ) break ;
}
// fsync to force persist the changes.
FileLock file_lock ( params_path + " /.lock " , LOCK_EX ) ;
result = fsync ( tmp_fd ) ;
std : : lock_guard < FileLock > lk ( file_lock ) ;
if ( result < 0 ) {
goto cleanup ;
}
// Move temp into place.
// Move temp into place.
result = rename ( tmp_path . c_str ( ) , path . c_str ( ) ) ;
std : : string path = params_path + " /d/ " + std : : string ( key ) ;
if ( result < 0 ) {
if ( ( result = rename ( tmp_path . c_str ( ) , path . c_str ( ) ) ) < 0 ) break ;
goto cleanup ;
}
// fsync parent directory
// fsync parent directory
path = params_path + " /d " ;
path = params_path + " /d " ;
result = fsync_dir ( path . c_str ( ) ) ;
result = fsync_dir ( path . c_str ( ) ) ;
if ( result < 0 ) {
} while ( 0 ) ;
goto cleanup ;
}
cleanup :
close ( tmp_fd ) ;
// Release lock.
remove ( tmp_path . c_str ( ) ) ;
if ( lock_fd > = 0 ) {
close ( lock_fd ) ;
}
if ( tmp_fd > = 0 ) {
if ( result < 0 ) {
remove ( tmp_path . c_str ( ) ) ;
}
close ( tmp_fd ) ;
}
return result ;
return result ;
}
}
int Params : : remove ( const char * key ) {
int Params : : remove ( const char * key ) {
int lock_fd = - 1 ;
FileLock file_lock ( params_path + " /.lock " , LOCK_EX ) ;
int result ;
std : : lock_guard < FileLock > lk ( file_lock ) ;
std : : string path ;
// Build lock path, and open lockfile
path = params_path + " /.lock " ;
lock_fd = open ( path . c_str ( ) , O_CREAT , 0775 ) ;
// Take lock.
result = flock ( lock_fd , LOCK_EX ) ;
if ( result < 0 ) {
goto cleanup ;
}
// Delete value.
// Delete value.
path = params_path + " /d/ " + key ;
std : : string path = params_path + " /d/ " + key ;
result = : : remove ( path . c_str ( ) ) ;
int result = : : remove ( path . c_str ( ) ) ;
if ( result ! = 0 ) {
if ( result ! = 0 ) {
result = ERR_NO_VALUE ;
result = ERR_NO_VALUE ;
goto cleanup ;
return result ;
}
}
// fsync parent directory
// fsync parent directory
path = params_path + " /d " ;
path = params_path + " /d " ;
result = fsync_dir ( path . c_str ( ) ) ;
return fsync_dir ( path . c_str ( ) ) ;
if ( result < 0 ) {
goto cleanup ;
}
cleanup :
// Release lock.
if ( lock_fd > = 0 ) {
close ( lock_fd ) ;
}
return result ;
}
}
std : : string Params : : get ( const char * key , bool block ) {
std : : string Params : : get ( const char * key , bool block ) {
@ -257,37 +239,20 @@ std::string Params::get(const char *key, bool block) {
}
}
int Params : : read_db_all ( std : : map < std : : string , std : : string > * params ) {
int Params : : read_db_all ( std : : map < std : : string , std : : string > * params ) {
int err = 0 ;
FileLock file_lock ( params_path + " /.lock " , LOCK_SH ) ;
std : : lock_guard < FileLock > lk ( file_lock ) ;
std : : string lock_path = params_path + " /.lock " ;
int lock_fd = open ( lock_path . c_str ( ) , 0 ) ;
if ( lock_fd < 0 ) return - 1 ;
err = flock ( lock_fd , LOCK_SH ) ;
if ( err < 0 ) {
close ( lock_fd ) ;
return err ;
}
std : : string key_path = params_path + " /d " ;
std : : string key_path = params_path + " /d " ;
DIR * d = opendir ( key_path . c_str ( ) ) ;
DIR * d = opendir ( key_path . c_str ( ) ) ;
if ( ! d ) {
if ( ! d ) return - 1 ;
close ( lock_fd ) ;
return - 1 ;
}
struct dirent * de = NULL ;
struct dirent * de = NULL ;
while ( ( de = readdir ( d ) ) ) {
while ( ( de = readdir ( d ) ) ) {
if ( ! isalnum ( de - > d_name [ 0 ] ) ) continue ;
if ( isalnum ( de - > d_name [ 0 ] ) ) {
std : : string key = std : : string ( de - > d_name ) ;
( * params ) [ de - > d_name ] = util : : read_file ( key_path + " / " + de - > d_name ) ;
std : : string value = util : : read_file ( key_path + " / " + key ) ;
}
( * params ) [ key ] = value ;
}
}
closedir ( d ) ;
closedir ( d ) ;
close ( lock_fd ) ;
return 0 ;
return 0 ;
}
}