blob: d37c55d3936fc559ae0592eaf796cb1de903d9e8 [file] [log] [blame]
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/reboot.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <linux/capability.h>
#include <linux/prctl.h>
#include <linux/reboot.h>
#include <fcntl.h>
#include <pthread.h>
#include <libprop2uci/properties.h>
#include <paths_defs.h>
#include <mtd/mtd-user.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <sys/sysinfo.h>
#include <cutils/log.h>
#include <ml_utils.h>
/**
* ************************************************************
* mll_utils.c
* ************************************************************
*/
#define FOTA_FLAG_WRITE_COMMAND "busybox dd if=%s of=/dev/mtdblock%d bs=%d count=%d seek=%d conv=fsync"
#define FOTA_FLAG_ERASE_COMMAND "busybox flash_eraseall /dev/mtd%d"
#define FOTA_FLAG_TMP_FILENAME TEMP_DIR "FOTA_FLAG.bin"
#define FOTA_PARTITION_NAME "misc"
#define BLOCK_SIZE_MTD (1024)
#define FOTA_FLAG_BLOCK_COUNT (1)
#define FOTA_FLAG_OFFSET (0x0)
#define FOTA_FLAG_COMMAND_MAX_LEN (256)
#define MTD_PROC_FILENAME "/proc/mtd"
struct fota_info {
unsigned int fota_id;
unsigned int fota_status;
unsigned int num_retries;
unsigned int fota_mode;
};
int ml_reboot_service(int nosync, int poweroff, void *opt)
{
int pid;
int ret;
if (!nosync) {
sync();
/* Attempt to unmount the SD card first.
* No need to bother checking for errors.
*/
pid = fork();
if (pid == 0) {
/* ask vdc to unmount it */
execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
getenv("EXTERNAL_STORAGE"), "force", NULL);
} else if (pid > 0) {
/* wait until vdc succeeds or fails */
waitpid(pid, &ret, 0);
}
}
if (poweroff)
//ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
ret = reboot(RB_AUTOBOOT);
else if (opt)
//ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, opt);
ret = reboot(RB_AUTOBOOT);
else
ret = reboot(RB_AUTOBOOT);
if (ret < 0) {
fprintf(stderr, "%s: reboot failed: %s\n", __FUNCTION__, strerror(errno));
}
return ret;
}
static int ml_flashEraseBlockMTD(int mtd_block_num)
{
int retVal = 0;
int len;
char shell_cmd[FOTA_FLAG_COMMAND_MAX_LEN];
len = snprintf(shell_cmd, FOTA_FLAG_COMMAND_MAX_LEN,
FOTA_FLAG_ERASE_COMMAND,
mtd_block_num);
if (len > FOTA_FLAG_COMMAND_MAX_LEN)
return -1;
retVal = ml_system(10, shell_cmd);
sync();
return retVal;
}
struct fota_info info;
int ml_flash_flag_write(int flash_flag)
{
int len;
char shell_cmd[FOTA_FLAG_COMMAND_MAX_LEN];
FILE *file;
int retVal = 0;
int mtd_block_num;
/*fill fota info and write to temp file*/
// FOTA ID is 0x464F5441- here written the LE
info.fota_id = 0x41544f46;
info.fota_status = 0x00000000 | ((int)flash_flag);
info.num_retries = 0;
file = fopen(FOTA_FLAG_TMP_FILENAME, "w");
if (!file)
return -2;
retVal = fwrite(&info, sizeof(struct fota_info), 1, file);
if (retVal == 0)
return -2;
retVal = fclose(file);
if (retVal != 0)
return -2;
sync();
mtd_block_num = ml_get_mtd_block_num(FOTA_PARTITION_NAME);
if(mtd_block_num < 0)
return -1;
if(ml_flashEraseBlockMTD(mtd_block_num) < 0)
return -1;
/* write fota flag to flash using DD command*/ len = snprintf(
shell_cmd, FOTA_FLAG_COMMAND_MAX_LEN, FOTA_FLAG_WRITE_COMMAND,
FOTA_FLAG_TMP_FILENAME, mtd_block_num, BLOCK_SIZE_MTD,
FOTA_FLAG_BLOCK_COUNT, FOTA_FLAG_OFFSET);
if (len > FOTA_FLAG_COMMAND_MAX_LEN)
return -3;
/* initiate command */
retVal = ml_system(10, shell_cmd);
sync();
return retVal;
}
int ml_get_mtd_block_num (char *mtd_name)
{
char buf[2048];
const char *bufp;
int fd;
int ret = -1;
ssize_t nbytes;
if (mtd_name == NULL || *mtd_name == 0 ){
return -1;
}
/* Open and read the file contents.
*/
fd = open(MTD_PROC_FILENAME, O_RDONLY);
if (fd < 0) {
goto exit;
}
nbytes = read(fd, buf, sizeof(buf) - 1);
close(fd);
if (nbytes < 0) {
goto exit;
}
buf[nbytes] = '\0';
/* Parse the contents of the file, which looks like:
*
* # cat /proc/mtd
* dev: size erasesize name
* mtd0: 00080000 00020000 "bootloader"
* mtd1: 00400000 00020000 "mfg_and_gsm"
* mtd2: 00400000 00020000 "0000000c"
* mtd3: 00200000 00020000 "0000000d"
* mtd4: 04000000 00020000 "system"
* mtd5: 03280000 00020000 "userdata"
*/
bufp = buf;
while (nbytes > 0) {
int mtdnum, mtdsize, mtderasesize;
int matches;
char mtdname[64];
mtdname[0] = '\0';
mtdnum = -1;
matches = sscanf(bufp, "mtd%d: %x %x \"%63[^\"]",
&mtdnum, &mtdsize, &mtderasesize, mtdname);
/* This will fail on the first line, which just contains
* column headers.
*/
if (matches == 4) {
if(strcmp(mtdname,mtd_name) == 0 )
{
/* Found partition name, return partition number*/
ret = mtdnum;
goto exit;
}
}
/* Eat the line.
*/
while (nbytes > 0 && *bufp != '\n') {
bufp++;
nbytes--;
}
if (nbytes > 0) {
bufp++;
nbytes--;
}
}
exit:
if(fd >=0 )
close(fd);
return ret;
}
int ml_nand(int argc, char *argv[])
{
int ret = 0;
if (argc < 2) {
printf("please enter 2 params\n");
return -1;
}
info.fota_mode = atoi(argv[1]);
ret = ml_flash_flag_write(atoi(argv[0]));
return ret;
}
/**
* ************************************************************
* mll_phone.c
* ************************************************************
*/
#include <paths_defs.h>
#include <ml_utils.h>
static struct ml_imei g_imei;
static int g_imei_good;
static struct ml_vers g_vers;
static int g_vers_good;
static struct ml_bld_vers g_bld_vers;
static int g_bld_vers_good;
static struct ml_cp_ver g_cp_ver;
static int g_cp_ver_good;
char *ml_get_bld_vers(struct ml_bld_vers *m);
/*Mutex to synchronize getting unique id*/
static pthread_mutex_t hawk_unique_id_mutex = PTHREAD_MUTEX_INITIALIZER;
/**
* ml_set_long_property
* Sets value of the int number into android properties
*
* @param name - property name, value - int value to be saved
* into property
*/
void ml_set_property(const char *name, int value){
char tmp[255];
sprintf(tmp, "%d", value);
property_set(name, tmp);
}
/**
* ml_get_long_property
* This fucntion return android property as int number
*
* @param name - property name
* @return int numer stored in property, or 0 incase property
* doesn't exist
*/
int ml_get_property(const char *name){
int value = 0;
char tmp[255];
property_get(name, tmp, "0");
value = atoi(tmp);
return value;
}
/**
* ml_set_long_property
* Sets value of the long number into android properties
*
* @param name - property name, value - long value to be saved into property
*/
void ml_set_long_property(const char *name, long int value){
char tmp[255];
sprintf(tmp, "%ld", value);
property_set(name, tmp);
}
/**
* ml_long_property
* This fucntion return android property as long number
*
* @param name - property name
* @return Long numer stored in property, or 0 incase property doesn't exist
*/
long int ml_get_long_property(const char *name){
long int value = 0;
char tmp[255];
property_get(name, tmp, "0");
value = strtol(tmp, NULL, 10);
return value;
}
/**
* ml_set_long_property
* Sets value of the long number into android properties
*
* @param name - property name, value - unsigned long value to be saved into property
*/
void ml_set_ulong_long_property(const char *name, unsigned long long value){
char tmp[255];
sprintf(tmp, "%llu", value);
property_set(name, tmp);
}
/**
* ml_get_long_property
* This fucntion return android property as long number
*
* @param name - property name
* @return unsigned Long long numer stored in property, or 0 incase property doesn't exist
*/
unsigned long long ml_get_ulong_long_property(const char *name) {
unsigned long long value = 0;
char tmp[255];
property_get(name, tmp, "0");
value = strtoull(tmp, NULL, 10);
return value;
}
/**
* ml_get_files_size
* This fucntion return files size on partition. Number of block
* used multuply by block size (512)
*
* @param filenames - string with file names to be calculated
* @return Number of bytes actually used by the system to have those file/dir on partition.
*/
unsigned long long ml_get_files_size(char *filenames){
char * pch;
char *saveptr;
unsigned long long sum = 0;
pch = strtok_r(filenames," ,\n\r", &saveptr);
while (pch != NULL)
{
sum += ml_get_dir_size(pch);
pch = strtok_r(NULL," ,\n\r", &saveptr);
}
return sum;
}
/**
* ml_get_dir_size
* This fucntion return directory size on partition. Number of
* block used multuply by block size (512)
*
* @param filename - name of the directory/file
* @return Number of bytes actually used by the system to have this file/dir on partition.
*/
unsigned long long ml_get_dir_size(char *filename){
struct stat statbuf;
unsigned long long sum = 0;
if (stat(filename, &statbuf) != 0) {
return 0;
}
// value received in blocks, every block is 512 bytes.
sum = statbuf.st_blocks*512;
if (S_ISLNK(statbuf.st_mode) || S_ISREG(statbuf.st_mode)) {
return sum;
}
if (S_ISDIR(statbuf.st_mode)) {
DIR *dir;
struct dirent *entry;
char *newfile;
dir = opendir(filename);
if (!dir) {
return sum;
}
while ((entry = readdir(dir))) {
//ignore current dir and parent dir
if((strcmp(entry->d_name,"..")==0) || (strcmp(entry->d_name,".")==0))
continue;
newfile = (char *)malloc(sizeof(char)*(strlen(filename)+strlen(entry->d_name)+2));
if (newfile == NULL)
continue;
sprintf(newfile,"%s/%s", filename, entry->d_name);
sum += ml_get_dir_size(newfile);
free(newfile);
}
closedir(dir);
}
return sum;
}
/**
* Reads string from file
*
* @param fname file name to read from
* @param str pointer to buffer
* @param len length to read
* @param dopad true/false - if true then str will be pad to
* to fit requested length
*
* @return In case of success str pointer returned
*/
char *ml_file2str(char *fname, char *str, size_t len, int dopad)
{
int fd = -1, retries = 5;
char *ret = str;
char *sstr = str;
size_t slen = len, total = 0;
ssize_t rlen = 0;
while ((fd = open(fname, O_RDONLY | O_NONBLOCK)) == -1) {
if (errno == EINTR && --retries > 0)
continue;
ml_log_error("failed open %s %s\n", fname, strerror(errno));
ret = NULL;
goto mexit;
}
retries = 5;
do {
rlen = read(fd, sstr, slen);
if (rlen >= 0) {
sstr += rlen;
slen -= rlen;
total += rlen;
} else {
if (errno == EINTR && --retries > 0)
continue;
ml_log_error("failed read %s %s rlen %lx\n", fname, strerror(errno), rlen);
ret = NULL;
goto mexit;
}
} while (slen > 0 && rlen > 0);
mexit:
if (ret == NULL) {
str[0] = 0;
if (dopad)
ml_pad_string('0', str, len);
}
if (fd != -1) {
close(fd);
}
if (ret && total) {
// Ensure NULL termination
if (total < len) {
//If last char is new line remove it
if (str[total-1] < 32) {
str[total-1] = 0;
} else {
str[total] = 0;
}
} else {
str[len - 1] = 0;
}
if(dopad)
ml_pad_string('0', str, len);
}
return ret;
}
/**
* Atomicaly writes string to file
* NOTE: if (strlen() + 1) of the strings doesn't match passed length
* then output will be padded with ascii 'o'
* i.e. if passed "abla" but len == 10 the output 'abla00000\0'
* NOTE: Side effect - original string might be left padded
* after function execution
* @param fname Output file name
* @param str ascii string to write down
* @param len length to write - pay attention on strlen()
*
* @return In case of success str pointer returned
*/
char *ml_str2file(char *fname, char *str, size_t len)
{
int fd = -1, retries = 5;
char fname_tmp[128];
char *sstr = str;
size_t slen = len;
ssize_t rlen = 0;
snprintf(fname_tmp, 127, "%s.tmp", fname);
while ((fd = open(fname_tmp, O_CREAT | O_WRONLY | O_TRUNC, 0660)) == -1) {
if (errno == EINTR && --retries > 0)
continue;
ml_log_error("failed open %s %s\n", fname_tmp, strerror(errno));
return NULL;
}
ml_pad_string('0', str, len);
retries = 5;
do {
rlen = write(fd, sstr, slen);
if (rlen >= 0) {
sstr += rlen;
slen -= rlen;
} else {
if (errno == EINTR && --retries > 0)
continue;
ml_log_error("failed write to %s %s\n", fname_tmp, strerror(errno));
close(fd);
return NULL;
}
} while (rlen > 0 && slen > 0);
close(fd);
if (rename(fname_tmp, fname)) {
ml_log_error("failed rename '%s %s' - %s\n", fname_tmp, fname, strerror(errno));
return NULL;
}
sync();
return str;
}
char *ml_get_uniqid(struct ml_uniqid *unqd)
{
//Mutex protection against recreating same unique id
pthread_mutex_lock(&hawk_unique_id_mutex);
struct timeval detail_time;
static int srandom_seed = 0;
unsigned int rand;
struct ml_uniqid tmp;
if (!srandom_seed) {
gettimeofday(&detail_time, NULL);
srandom_seed = 1;
srandom(detail_time.tv_usec);
}
ml_get_imei(&tmp.imei);
ml_get_bld_vers(&tmp.vers);
rand = ((unsigned int)random()) % 10000;
snprintf(tmp.rand.s, sizeof(tmp.rand), "%04d", rand);
ml_get_mseq(&tmp.mseq);
snprintf((char *)unqd, sizeof(*unqd), "%s_%s_%s_%s", tmp.imei.s, tmp.vers.s, tmp.mseq.s, tmp.rand.s);
pthread_mutex_unlock(&hawk_unique_id_mutex);
return (char *)unqd;
}
char *ml_get_imei(struct ml_imei *m)
{
if (g_imei_good) {
memcpy(m->s, g_imei.s, sizeof(g_imei.s));
return m->s;
}
property_get(ML_IMEI_PROP, m->s, "000000000000000");
if (strcmp(m->s, "000000000000000")) {
memcpy(g_imei.s, m->s, sizeof(m->s));
g_imei_good = 1;
return m->s;
}
ml_log_info("IMEI not found\n");
return NULL;
}
/**
* Receive boot sequence number
* Based on static variable and file.
*/
int ml_get_boot_sequence(void)
{
char boot_seq[10] = {0};
static int boot_seq_no = 0;
//If static value exist then return it
if (boot_seq_no)
return boot_seq_no;
//read sequnece number from property
property_get(ML_BOOTSEQ_PROP, boot_seq, "0");
boot_seq_no = (atoi(boot_seq) + 1) % 10000;
snprintf(boot_seq, sizeof(boot_seq), "%04d", boot_seq_no);
property_set(ML_BOOTSEQ_PROP, boot_seq);
return boot_seq_no;
}
char *ml_get_mseq(struct ml_mseq *m)
{
int seq = 0;
struct ml_mseq tmp;
property_get(ML_MSEQ_PROP, m->s, "0000");
if (m->s)
seq = atoi(m->s);
snprintf(tmp.s, sizeof(tmp.s), "%04d", (seq + 1) % 10000);
property_set(ML_MSEQ_PROP, tmp.s);
return m->s;
}
char *ml_get_vers(struct ml_vers *m)
{
char *ret;
if (g_vers_good) {
memcpy(m->s, g_vers.s, sizeof(g_vers.s));
return m->s;
}
ret = ml_file2str(ML_VERS_FNAME, m->s, sizeof(m->s), 0);
if (ret) {
memcpy(g_vers.s, m->s, sizeof(m->s));
g_vers_good = 1;
}
return ret;
}
char *ml_get_bld_vers(struct ml_bld_vers *m)
{
struct ml_vers full_ver;
char *bld_num = NULL;
char *ver_num = NULL;
if (g_bld_vers_good) {
memcpy(m->s, g_bld_vers.s, sizeof(g_bld_vers.s));
return m->s;
}
ver_num = ml_get_vers(&full_ver);
/* check if full version exist */
if(!ver_num)
return NULL;
/* build number is xxxx in _branch_bldxxxx */
bld_num = strstr(ver_num, "_bld");
if (bld_num){
bld_num = bld_num + sizeof("_bld") - 1;
strncpy(m->s, bld_num, sizeof(m->s) - 1);
strncpy(g_bld_vers.s, bld_num, sizeof(g_bld_vers.s) - 1);
} else {
strcpy(m->s, "0000");
strcpy(g_bld_vers.s, "0000");
}
g_bld_vers_good = 1;
return m->s;
}
char *ml_get_cp_ver(struct ml_cp_ver *m)
{
if (g_cp_ver_good) {
memcpy(m->s, g_cp_ver.s, sizeof(g_cp_ver.s));
return m->s;
}
property_get(ML_CP_VER_PROP, m->s, "000000");
if (strcmp(m->s, "000000")) {
memcpy(g_cp_ver.s, m->s, sizeof(m->s));
g_cp_ver_good = 1;
return m->s;
}
ml_log_info("CP_VER not found\n");
return NULL;
}
char *ml_update_imei(struct ml_imei *m)
{
struct ml_imei imei;
char *ret;
if ((ret = ml_get_imei(&imei))) {
ml_log_info("IMEI: exists %s\n", imei.s);
return ret;
}
m->s[sizeof(m->s) - 1] = 0;
property_set(ML_IMEI_PROP, m->s);
memcpy(g_imei.s, m->s, sizeof(m->s));
g_imei_good = 1;
ml_log_info("IMEI: updated %s\n", m->s);
return m->s;
}
char *ml_update_cp_ver(struct ml_cp_ver *m)
{
struct ml_cp_ver cp_ver;
char *ret;
if ((ret = ml_get_cp_ver(&cp_ver))) {
ml_log_info("CP_VER: exists %s\n", cp_ver.s);
return ret;
}
m->s[sizeof(m->s) - 1] = 0;
property_set(ML_CP_VER_PROP, m->s);
memcpy(g_cp_ver.s, m->s, sizeof(m->s));
g_cp_ver_good = 1;
ml_log_info("CP_VER: updated %s\n", m->s);
return m->s;
}
char *ml_extract_cp_from_full_vers(void)
{
struct ml_vers full_ver;
struct ml_cp_ver cp_ver;
int i = 0;
int cp_type = ml_get_property(ML_CP_TYPE_PROP);
char *str_tmp = ml_get_vers(&full_ver);
char *token = NULL;
if(!str_tmp)
return NULL;
while ((token=strsep(&str_tmp, "_"))&& (i < (cp_type+2)))
i++;
if(token)
strncpy(cp_ver.s, token, sizeof(cp_ver.s) - 1);
return ml_update_cp_ver(&cp_ver);
}
/**
* ************************************************************
* mll_string.c
* ************************************************************
*/
/**
* Trim leading and trailing whitespaces
*
* @param str string to modify
*
* @return pointer to in-place modified string
*/
char *ml_chomp(char *str)
{
char *p = str;
int length;
if (!p || (length = strlen(p)) == 0)
return p;
// chomp space chars from end
while (length && isspace(p[length - 1])) {
p[--length] = 0;
}
// chomp space chars from start
while (*p && isspace(*p)) {
++p;
--length;
}
memmove(str, p, length + 1);
return str;
}
void ml_pad_string(char pad, char *str, size_t len)
{
size_t i;
if (!str)
return;
str[len - 1] = 0;
for (i = strlen(str); i < (len - 1); i++)
str[i] = pad;
}
/**
* ************************************************************
* mll_system.c
* ************************************************************
*/
static void ml_child(char *cmd)
{
char *argv[4];
if (!cmd) {
ml_log_info("Got empty cmd line\n");
exit(-1);
}
argv[0] = "sh";
argv[1] = "-c";
argv[2] = cmd;
argv[3] = NULL;
if (execvp(argv[0], argv)) {
ml_log_info("executing %s failed: %s\n", argv[0], strerror(errno));
exit(-1);
}
}
int ml_system_retry(int max_tries, int timeout, char *cmd)
{
int ret = -1, i = 0, tries = max_tries > 0 ? max_tries : 1;
while (ret != 0 && i++ < tries) {
ret = ml_system(timeout, cmd);
}
return ret;
}
int ml_system(int timeout, char *cmd)
{
int timo, status = 0xAAAA, i, ret = -1, forced_kill = 0;
struct sysinfo info1, info2;
pid_t end_pid, child_pid;
char pdetails[64], edt[192], strerr[128];
timo = (timeout < 1 || timeout > ML_SYSTEM_MAX_TIMEOUT) ? ML_SYSTEM_MAX_TIMEOUT : timeout;
//sprintf(pdetails, "[%d:%d]", getpid(), gettid());
sprintf(pdetails, "[%d]", getpid());
if (!cmd) {
ml_log_info("%s Got empty cmd line\n", pdetails);
return -1;
}
info1.uptime = info2.uptime = 0;
ml_log_info("%s cmdstart (timo %d sec): ==%s==\n", pdetails, timo, cmd);
sysinfo(&info1);
child_pid = fork();
if (child_pid < 0) {
ml_log_info("%s Failed to fork\n", pdetails);
} else if (child_pid == 0) {
ml_child(cmd);
}
for (i = 0; i <= timo; i++) {
while ((end_pid = waitpid(child_pid, &status, WNOHANG | WUNTRACED)) == -1 && errno == EINTR) {
/*signal interrupt */ };
if (end_pid == 0) { /* child still running */
if (i < timo) {
sleep(1);
continue;
}
/*Force sub-process shutdown */
kill(child_pid, SIGKILL);
forced_kill = 1;
while ((end_pid = wait(&status)) == -1 && errno == EINTR) {
/*signal interrupt */ };
}
if (end_pid == -1) { /* error calling waitpid */
strerror_r(errno, strerr, sizeof(strerr));
snprintf(edt, sizeof(edt), "waitpid() fail: %s (%d)", strerr, errno);
break;
}
/* child ended */
if (WIFEXITED(status)) {
snprintf(edt, sizeof(edt), "terminated by exit(%d)", WEXITSTATUS(status));
ret = WEXITSTATUS(status) ? -1 : 0;
break;
}
if (WIFSIGNALED(status)) {
snprintf(edt, sizeof(edt), "terminated by signal %d", WTERMSIG(status));
break;
}
if (WIFSTOPPED(status)) {
snprintf(edt, sizeof(edt), "stopped by signal %d", WSTOPSIG(status));
break;
}
}
sysinfo(&info2);
i = (int)(info2.uptime - info1.uptime);
ml_log_info("%s cmdend: %s (%s) : %d seconds\n", pdetails, edt, forced_kill ? "forced_kill":"self exited", i ? i : 1);
return ret;
}
/* Check if path exist, return 1 if path exist */
int ml_check_path(const char* path, int r, int w)
{
int mode = 0;
if (r)
mode |= R_OK;
if (w)
mode |= W_OK;
if (access(path, mode)){
ml_log_error("Can't access %s. %s\n", path, strerror(errno));
return 0;
}
return 1;
}
/* Check if directory exist, and create it if not, return 1 for success */
int ml_dir_update(char *dir2add)
{
struct stat buf;
if (stat(dir2add, &buf) != 0) {
if (mkdir(dir2add, 0777) != 0) {
ml_log_error("Failed to mkdir %s. %s\n", dir2add, strerror(errno));
return 0;
}
}
return 1;
}
/**
* ************************************************************
* mll_log.c
* ************************************************************
*/
pthread_mutex_t mll_log_plock = PTHREAD_MUTEX_INITIALIZER;
int ml_max_log = ML_LOG_INFO;
extern int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
void ml_set_log_level(int logLevel)
{
ml_max_log = logLevel;
}
int ml_get_log_level()
{
return ml_max_log;
}
static void ml_sout(FILE * fout, char *buf)
{
if (!fout)
return;
fwrite(buf, strlen(buf) + 1, 1, fout);
}
static struct {
char *tag;
char buf[32];
} ltag = {
.tag = 0,.buf = {
0}
};
char *ml_get_local_tag()
{
FILE *f;
if (ltag.tag)
return ltag.tag;
pthread_mutex_lock(&mll_log_plock);
if ((f = fopen("/proc/self/status", "r")) == NULL)
goto done;
if (1 != fscanf(f, "Name: %s", ltag.buf))
goto done;
ltag.tag = ltag.buf;
done:
pthread_mutex_unlock(&mll_log_plock);
if (!ltag.tag)
return "ML_LOG";
return ltag.tag;
}
void ml_log(int dest, int level, const char *tag, const char *fmt, ...)
{
va_list vl;
char buf[1024];
size_t buf_size;
if (!tag)
tag = ml_get_local_tag();
va_start(vl, fmt);
buf_size = vsnprintf(buf, 1024, fmt, vl);
va_end(vl);
if (dest & MLL_LOGCAT)
__android_log_printf(LOG_ID_RADIO, level, buf);
if (dest & MLL_KMSG) {
static int dev_kmsg = -1;
pthread_mutex_lock(&mll_log_plock);
if (dev_kmsg < 0)
dev_kmsg = open("/dev/kmsg", O_RDWR | O_SYNC);
if (dev_kmsg >= 0) {
buf[buf_size] = '\0';
write(dev_kmsg, buf, buf_size);
}
pthread_mutex_unlock(&mll_log_plock);
}
if (dest & MLL_CONSOLE) {
static FILE *dev_console = NULL;
pthread_mutex_lock(&mll_log_plock);
if (!dev_console)
dev_console = fopen("/dev/console", "w");
ml_sout(dev_console, buf);
pthread_mutex_unlock(&mll_log_plock);
}
if (dest & MLL_STDERR) {
pthread_mutex_lock(&mll_log_plock);
ml_sout(stderr, buf);
pthread_mutex_unlock(&mll_log_plock);
}
}
/**
* ************************************************************
* mll_fifo.c
* ************************************************************
*/
int ml_mounted_update(char *mountdir, char *dir2add)
{
char line[128 * 3], dev[128], dir[128];
struct stat buf;
FILE *filed;
int ret = 0;
if (!mountdir) {
ml_log_error("no param supplied\n");
return 0;
}
filed = fopen("/proc/mounts", "r");
if (!filed) {
ml_log_error("Failed open %s %s \n", "/proc/mounts", strerror(errno));
exit(1);
}
while (fgets(line, sizeof(line), filed)) {
if (sscanf(line, "%128s %128s", dev, dir) < 2)
continue;
if (strcmp(mountdir, dir) != 0)
continue;
if (!dir2add) {
ret = 1;
break;
}
if (stat(dir2add, &buf) != 0) {
if (mkdir(dir2add, 0777) != 0) {
ml_log_error("Failed to mkdir %s. %s\n", dir2add, strerror(errno));
break;
}
} else if (!S_ISDIR(buf.st_mode)) {
ml_log_error("Gen failure %s is not directory.\n", dir2add);
break;
}
ret = 1;
break;
}
fclose(filed);
return ret;
}
int ml_create_fifo(struct ml_fifo *fifo)
{
int ret, retries;
struct stat buf;
ret = mkfifo(fifo->fname, 0666);
if (ret != 0) {
if (errno == EEXIST) {
if (stat(fifo->fname, &buf) != 0 || !S_ISFIFO(buf.st_mode)) {
ml_log_error("%s is not fifo\n", fifo->fname);
return -1;
}
} else {
ml_log_error("fifo not created %s\n", strerror(errno));
return -1;
}
}
retries = 5;
/* Hold two open file descriptors on FIFO for select() to work correctly */
while ((fifo->fdr = open(fifo->fname, O_RDONLY | O_NONBLOCK)) == -1) {
if (errno == EINTR && --retries > 0)
continue;
ml_log_error("failed open %s %s\n", fifo->fname, strerror(errno));
return -1;
}
retries = 5;
while ((fifo->fdw = open(fifo->fname, O_WRONLY | O_NONBLOCK)) == -1) {
if (errno == EINTR && --retries > 0)
continue;
close(fifo->fdr);
ml_log_error("failed open %s %s\n", fifo->fname, strerror(errno));
return -1;
}
return 0;
}
int ml_flock(int fd, char *fname, int mode)
{
int retries = 5, ret;
while (1) {
ret = flock(fd, mode);
if (ret == 0)
return 0;
if (errno == EINTR && --retries > 0)
continue;
ml_log_error("failed flock [%d %s mode %d] on %s\n", fd, fname, mode, strerror(errno));
break;
}
return -1;
}
int ml_write_fifo(struct ml_fifo *fifo, char *str, int len)
{
int retries = 5;
char *sstr = str;
size_t slen = len;
ssize_t rlen = 0;
retries = 5;
ml_flock(fifo->fdw, fifo->fname, LOCK_EX);
do {
rlen = write(fifo->fdw, str, len);
if (rlen >= 0) {
sstr += rlen;
slen -= rlen;
} else {
if (errno == EINTR && --retries > 0)
continue;
ml_log_error("failed write to %s %s\n", fifo->fname, strerror(errno));
break;
}
} while (rlen > 0 && slen > 0);
fflush(NULL);
ml_flock(fifo->fdw, fifo->fname, LOCK_UN);
/* should be 0 if all written OK */
rlen = len - slen;
if (!rlen) {
ml_log_error("data not written ok to %s - %d/%d bytes written\n", fifo->fname, (int)rlen, (int)len);
}
return rlen;
}
char *ml_read_fifo(struct ml_fifo *fifo, char *str, int len, struct timeval *timeout)
{
fd_set set;
struct timeval tm = *timeout;
char tmp[1], *sstr = str;
size_t slen = len;
ssize_t rlen = 0;
int ret;
while (1) {
FD_ZERO(&set);
FD_SET(fifo->fdr, &set);
ret = select(fifo->fdr + 1, &set, NULL, NULL, &tm);
if (ret < 0) {
if (errno != EINTR) {
ml_log_error("select failed with '%s'\n", strerror(errno));
exit(1);
}
continue;
}
if (ret == 0) {
/*timeout */
return NULL;
}
rlen = read(fifo->fdr, tmp, 1);
if (rlen > 0) {
*sstr = *tmp;
if (*tmp == '\0' || *tmp == '\n' || *tmp == '\r') {
*sstr = '\0';
return str;
} else {
sstr += rlen;
slen -= rlen;
}
} else {
ml_log_error("read interrupted ? '%s'\n", strerror(errno));
continue;
}
if (slen < 2) {
ml_log_error("Message to big '%s'\n", str);
*str = 0;
return NULL;
}
}
return str;
}