ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/services/android_wrapper/ml_utilset/mll_utils.c b/marvell/services/android_wrapper/ml_utilset/mll_utils.c
new file mode 100644
index 0000000..d37c55d
--- /dev/null
+++ b/marvell/services/android_wrapper/ml_utilset/mll_utils.c
@@ -0,0 +1,1239 @@
+#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;
+}
+