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;
+}
+