blob: d37c55d3936fc559ae0592eaf796cb1de903d9e8 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#include <errno.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <stdarg.h>
6#include <string.h>
7#include <ctype.h>
8#include <time.h>
9#include <sys/file.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <sys/reboot.h>
13#include <sys/wait.h>
14#include <sys/time.h>
15#include <linux/capability.h>
16#include <linux/prctl.h>
17#include <linux/reboot.h>
18#include <fcntl.h>
19#include <pthread.h>
20#include <libprop2uci/properties.h>
21#include <paths_defs.h>
22#include <mtd/mtd-user.h>
23#include <sys/ioctl.h>
24#include <dirent.h>
25#include <sys/sysinfo.h>
26#include <cutils/log.h>
27#include <ml_utils.h>
28
29/**
30 * ************************************************************
31 * mll_utils.c
32 * ************************************************************
33 */
34
35#define FOTA_FLAG_WRITE_COMMAND "busybox dd if=%s of=/dev/mtdblock%d bs=%d count=%d seek=%d conv=fsync"
36#define FOTA_FLAG_ERASE_COMMAND "busybox flash_eraseall /dev/mtd%d"
37#define FOTA_FLAG_TMP_FILENAME TEMP_DIR "FOTA_FLAG.bin"
38#define FOTA_PARTITION_NAME "misc"
39#define BLOCK_SIZE_MTD (1024)
40#define FOTA_FLAG_BLOCK_COUNT (1)
41#define FOTA_FLAG_OFFSET (0x0)
42#define FOTA_FLAG_COMMAND_MAX_LEN (256)
43
44#define MTD_PROC_FILENAME "/proc/mtd"
45
46struct fota_info {
47 unsigned int fota_id;
48 unsigned int fota_status;
49 unsigned int num_retries;
50 unsigned int fota_mode;
51};
52
53
54int ml_reboot_service(int nosync, int poweroff, void *opt)
55{
56 int pid;
57 int ret;
58
59 if (!nosync) {
60 sync();
61 /* Attempt to unmount the SD card first.
62 * No need to bother checking for errors.
63 */
64 pid = fork();
65 if (pid == 0) {
66 /* ask vdc to unmount it */
67 execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
68 getenv("EXTERNAL_STORAGE"), "force", NULL);
69 } else if (pid > 0) {
70 /* wait until vdc succeeds or fails */
71 waitpid(pid, &ret, 0);
72 }
73 }
74
75 if (poweroff)
76 //ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
77 ret = reboot(RB_AUTOBOOT);
78 else if (opt)
79 //ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, opt);
80 ret = reboot(RB_AUTOBOOT);
81 else
82 ret = reboot(RB_AUTOBOOT);
83
84 if (ret < 0) {
85 fprintf(stderr, "%s: reboot failed: %s\n", __FUNCTION__, strerror(errno));
86 }
87 return ret;
88}
89
90static int ml_flashEraseBlockMTD(int mtd_block_num)
91{
92 int retVal = 0;
93 int len;
94 char shell_cmd[FOTA_FLAG_COMMAND_MAX_LEN];
95
96 len = snprintf(shell_cmd, FOTA_FLAG_COMMAND_MAX_LEN,
97 FOTA_FLAG_ERASE_COMMAND,
98 mtd_block_num);
99 if (len > FOTA_FLAG_COMMAND_MAX_LEN)
100 return -1;
101 retVal = ml_system(10, shell_cmd);
102 sync();
103 return retVal;
104}
105
106struct fota_info info;
107
108int ml_flash_flag_write(int flash_flag)
109{
110 int len;
111 char shell_cmd[FOTA_FLAG_COMMAND_MAX_LEN];
112 FILE *file;
113 int retVal = 0;
114 int mtd_block_num;
115
116 /*fill fota info and write to temp file*/
117 // FOTA ID is 0x464F5441- here written the LE
118 info.fota_id = 0x41544f46;
119 info.fota_status = 0x00000000 | ((int)flash_flag);
120 info.num_retries = 0;
121
122 file = fopen(FOTA_FLAG_TMP_FILENAME, "w");
123 if (!file)
124 return -2;
125 retVal = fwrite(&info, sizeof(struct fota_info), 1, file);
126 if (retVal == 0)
127 return -2;
128 retVal = fclose(file);
129 if (retVal != 0)
130 return -2;
131 sync();
132
133 mtd_block_num = ml_get_mtd_block_num(FOTA_PARTITION_NAME);
134 if(mtd_block_num < 0)
135 return -1;
136
137 if(ml_flashEraseBlockMTD(mtd_block_num) < 0)
138 return -1;
139
140 /* write fota flag to flash using DD command*/ len = snprintf(
141 shell_cmd, FOTA_FLAG_COMMAND_MAX_LEN, FOTA_FLAG_WRITE_COMMAND,
142 FOTA_FLAG_TMP_FILENAME, mtd_block_num, BLOCK_SIZE_MTD,
143 FOTA_FLAG_BLOCK_COUNT, FOTA_FLAG_OFFSET);
144
145 if (len > FOTA_FLAG_COMMAND_MAX_LEN)
146 return -3;
147
148 /* initiate command */
149 retVal = ml_system(10, shell_cmd);
150 sync();
151 return retVal;
152}
153
154int ml_get_mtd_block_num (char *mtd_name)
155{
156 char buf[2048];
157 const char *bufp;
158 int fd;
159 int ret = -1;
160 ssize_t nbytes;
161
162 if (mtd_name == NULL || *mtd_name == 0 ){
163 return -1;
164 }
165
166 /* Open and read the file contents.
167 */
168 fd = open(MTD_PROC_FILENAME, O_RDONLY);
169 if (fd < 0) {
170 goto exit;
171 }
172 nbytes = read(fd, buf, sizeof(buf) - 1);
173 close(fd);
174 if (nbytes < 0) {
175 goto exit;
176 }
177 buf[nbytes] = '\0';
178
179 /* Parse the contents of the file, which looks like:
180 *
181 * # cat /proc/mtd
182 * dev: size erasesize name
183 * mtd0: 00080000 00020000 "bootloader"
184 * mtd1: 00400000 00020000 "mfg_and_gsm"
185 * mtd2: 00400000 00020000 "0000000c"
186 * mtd3: 00200000 00020000 "0000000d"
187 * mtd4: 04000000 00020000 "system"
188 * mtd5: 03280000 00020000 "userdata"
189 */
190 bufp = buf;
191 while (nbytes > 0) {
192 int mtdnum, mtdsize, mtderasesize;
193 int matches;
194 char mtdname[64];
195 mtdname[0] = '\0';
196 mtdnum = -1;
197
198 matches = sscanf(bufp, "mtd%d: %x %x \"%63[^\"]",
199 &mtdnum, &mtdsize, &mtderasesize, mtdname);
200 /* This will fail on the first line, which just contains
201 * column headers.
202 */
203 if (matches == 4) {
204 if(strcmp(mtdname,mtd_name) == 0 )
205 {
206 /* Found partition name, return partition number*/
207 ret = mtdnum;
208 goto exit;
209 }
210 }
211 /* Eat the line.
212 */
213 while (nbytes > 0 && *bufp != '\n') {
214 bufp++;
215 nbytes--;
216 }
217 if (nbytes > 0) {
218 bufp++;
219 nbytes--;
220 }
221 }
222exit:
223 if(fd >=0 )
224 close(fd);
225 return ret;
226}
227
228
229int ml_nand(int argc, char *argv[])
230{
231
232 int ret = 0;
233 if (argc < 2) {
234 printf("please enter 2 params\n");
235 return -1;
236 }
237 info.fota_mode = atoi(argv[1]);
238 ret = ml_flash_flag_write(atoi(argv[0]));
239
240 return ret;
241}
242
243/**
244 * ************************************************************
245 * mll_phone.c
246 * ************************************************************
247 */
248#include <paths_defs.h>
249#include <ml_utils.h>
250
251static struct ml_imei g_imei;
252static int g_imei_good;
253static struct ml_vers g_vers;
254static int g_vers_good;
255static struct ml_bld_vers g_bld_vers;
256static int g_bld_vers_good;
257static struct ml_cp_ver g_cp_ver;
258static int g_cp_ver_good;
259
260char *ml_get_bld_vers(struct ml_bld_vers *m);
261
262/*Mutex to synchronize getting unique id*/
263static pthread_mutex_t hawk_unique_id_mutex = PTHREAD_MUTEX_INITIALIZER;
264
265/**
266 * ml_set_long_property
267 * Sets value of the int number into android properties
268 *
269 * @param name - property name, value - int value to be saved
270 * into property
271 */
272void ml_set_property(const char *name, int value){
273 char tmp[255];
274 sprintf(tmp, "%d", value);
275 property_set(name, tmp);
276}
277
278/**
279 * ml_get_long_property
280 * This fucntion return android property as int number
281 *
282 * @param name - property name
283 * @return int numer stored in property, or 0 incase property
284 * doesn't exist
285 */
286int ml_get_property(const char *name){
287 int value = 0;
288 char tmp[255];
289 property_get(name, tmp, "0");
290 value = atoi(tmp);
291 return value;
292}
293
294/**
295 * ml_set_long_property
296 * Sets value of the long number into android properties
297 *
298 * @param name - property name, value - long value to be saved into property
299 */
300void ml_set_long_property(const char *name, long int value){
301 char tmp[255];
302 sprintf(tmp, "%ld", value);
303 property_set(name, tmp);
304}
305
306/**
307 * ml_long_property
308 * This fucntion return android property as long number
309 *
310 * @param name - property name
311 * @return Long numer stored in property, or 0 incase property doesn't exist
312 */
313long int ml_get_long_property(const char *name){
314 long int value = 0;
315 char tmp[255];
316 property_get(name, tmp, "0");
317 value = strtol(tmp, NULL, 10);
318 return value;
319}
320
321/**
322 * ml_set_long_property
323 * Sets value of the long number into android properties
324 *
325 * @param name - property name, value - unsigned long value to be saved into property
326 */
327void ml_set_ulong_long_property(const char *name, unsigned long long value){
328 char tmp[255];
329 sprintf(tmp, "%llu", value);
330 property_set(name, tmp);
331}
332
333/**
334 * ml_get_long_property
335 * This fucntion return android property as long number
336 *
337 * @param name - property name
338 * @return unsigned Long long numer stored in property, or 0 incase property doesn't exist
339 */
340unsigned long long ml_get_ulong_long_property(const char *name) {
341 unsigned long long value = 0;
342 char tmp[255];
343 property_get(name, tmp, "0");
344 value = strtoull(tmp, NULL, 10);
345 return value;
346}
347
348/**
349 * ml_get_files_size
350 * This fucntion return files size on partition. Number of block
351 * used multuply by block size (512)
352 *
353 * @param filenames - string with file names to be calculated
354 * @return Number of bytes actually used by the system to have those file/dir on partition.
355 */
356unsigned long long ml_get_files_size(char *filenames){
357 char * pch;
358 char *saveptr;
359 unsigned long long sum = 0;
360 pch = strtok_r(filenames," ,\n\r", &saveptr);
361 while (pch != NULL)
362 {
363 sum += ml_get_dir_size(pch);
364 pch = strtok_r(NULL," ,\n\r", &saveptr);
365 }
366 return sum;
367}
368/**
369 * ml_get_dir_size
370 * This fucntion return directory size on partition. Number of
371 * block used multuply by block size (512)
372 *
373 * @param filename - name of the directory/file
374 * @return Number of bytes actually used by the system to have this file/dir on partition.
375 */
376unsigned long long ml_get_dir_size(char *filename){
377 struct stat statbuf;
378 unsigned long long sum = 0;
379
380 if (stat(filename, &statbuf) != 0) {
381 return 0;
382 }
383 // value received in blocks, every block is 512 bytes.
384 sum = statbuf.st_blocks*512;
385
386 if (S_ISLNK(statbuf.st_mode) || S_ISREG(statbuf.st_mode)) {
387 return sum;
388 }
389
390 if (S_ISDIR(statbuf.st_mode)) {
391 DIR *dir;
392 struct dirent *entry;
393 char *newfile;
394
395 dir = opendir(filename);
396 if (!dir) {
397 return sum;
398 }
399
400 while ((entry = readdir(dir))) {
401 //ignore current dir and parent dir
402 if((strcmp(entry->d_name,"..")==0) || (strcmp(entry->d_name,".")==0))
403 continue;
404 newfile = (char *)malloc(sizeof(char)*(strlen(filename)+strlen(entry->d_name)+2));
405 if (newfile == NULL)
406 continue;
407 sprintf(newfile,"%s/%s", filename, entry->d_name);
408 sum += ml_get_dir_size(newfile);
409 free(newfile);
410 }
411 closedir(dir);
412 }
413
414 return sum;
415}
416
417/**
418 * Reads string from file
419 *
420 * @param fname file name to read from
421 * @param str pointer to buffer
422 * @param len length to read
423 * @param dopad true/false - if true then str will be pad to
424 * to fit requested length
425 *
426 * @return In case of success str pointer returned
427 */
428char *ml_file2str(char *fname, char *str, size_t len, int dopad)
429{
430 int fd = -1, retries = 5;
431 char *ret = str;
432 char *sstr = str;
433 size_t slen = len, total = 0;
434 ssize_t rlen = 0;
435
436 while ((fd = open(fname, O_RDONLY | O_NONBLOCK)) == -1) {
437 if (errno == EINTR && --retries > 0)
438 continue;
439 ml_log_error("failed open %s %s\n", fname, strerror(errno));
440 ret = NULL;
441 goto mexit;
442 }
443
444 retries = 5;
445 do {
446 rlen = read(fd, sstr, slen);
447 if (rlen >= 0) {
448 sstr += rlen;
449 slen -= rlen;
450 total += rlen;
451 } else {
452 if (errno == EINTR && --retries > 0)
453 continue;
454
455 ml_log_error("failed read %s %s rlen %lx\n", fname, strerror(errno), rlen);
456 ret = NULL;
457 goto mexit;
458 }
459 } while (slen > 0 && rlen > 0);
460
461mexit:
462
463 if (ret == NULL) {
464 str[0] = 0;
465 if (dopad)
466 ml_pad_string('0', str, len);
467 }
468
469 if (fd != -1) {
470 close(fd);
471 }
472
473 if (ret && total) {
474 // Ensure NULL termination
475 if (total < len) {
476 //If last char is new line remove it
477 if (str[total-1] < 32) {
478 str[total-1] = 0;
479 } else {
480 str[total] = 0;
481 }
482 } else {
483 str[len - 1] = 0;
484 }
485 if(dopad)
486 ml_pad_string('0', str, len);
487 }
488 return ret;
489}
490
491/**
492 * Atomicaly writes string to file
493 * NOTE: if (strlen() + 1) of the strings doesn't match passed length
494 * then output will be padded with ascii 'o'
495 * i.e. if passed "abla" but len == 10 the output 'abla00000\0'
496 * NOTE: Side effect - original string might be left padded
497 * after function execution
498 * @param fname Output file name
499 * @param str ascii string to write down
500 * @param len length to write - pay attention on strlen()
501 *
502 * @return In case of success str pointer returned
503 */
504char *ml_str2file(char *fname, char *str, size_t len)
505{
506 int fd = -1, retries = 5;
507 char fname_tmp[128];
508 char *sstr = str;
509 size_t slen = len;
510 ssize_t rlen = 0;
511
512 snprintf(fname_tmp, 127, "%s.tmp", fname);
513
514 while ((fd = open(fname_tmp, O_CREAT | O_WRONLY | O_TRUNC, 0660)) == -1) {
515 if (errno == EINTR && --retries > 0)
516 continue;
517 ml_log_error("failed open %s %s\n", fname_tmp, strerror(errno));
518 return NULL;
519 }
520
521 ml_pad_string('0', str, len);
522 retries = 5;
523
524 do {
525 rlen = write(fd, sstr, slen);
526
527 if (rlen >= 0) {
528 sstr += rlen;
529 slen -= rlen;
530 } else {
531 if (errno == EINTR && --retries > 0)
532 continue;
533 ml_log_error("failed write to %s %s\n", fname_tmp, strerror(errno));
534 close(fd);
535 return NULL;
536 }
537 } while (rlen > 0 && slen > 0);
538
539 close(fd);
540 if (rename(fname_tmp, fname)) {
541 ml_log_error("failed rename '%s %s' - %s\n", fname_tmp, fname, strerror(errno));
542 return NULL;
543 }
544 sync();
545 return str;
546}
547
548char *ml_get_uniqid(struct ml_uniqid *unqd)
549{
550 //Mutex protection against recreating same unique id
551 pthread_mutex_lock(&hawk_unique_id_mutex);
552 struct timeval detail_time;
553 static int srandom_seed = 0;
554 unsigned int rand;
555 struct ml_uniqid tmp;
556
557 if (!srandom_seed) {
558 gettimeofday(&detail_time, NULL);
559 srandom_seed = 1;
560 srandom(detail_time.tv_usec);
561 }
562
563 ml_get_imei(&tmp.imei);
564 ml_get_bld_vers(&tmp.vers);
565
566 rand = ((unsigned int)random()) % 10000;
567 snprintf(tmp.rand.s, sizeof(tmp.rand), "%04d", rand);
568
569 ml_get_mseq(&tmp.mseq);
570 snprintf((char *)unqd, sizeof(*unqd), "%s_%s_%s_%s", tmp.imei.s, tmp.vers.s, tmp.mseq.s, tmp.rand.s);
571
572 pthread_mutex_unlock(&hawk_unique_id_mutex);
573 return (char *)unqd;
574}
575
576char *ml_get_imei(struct ml_imei *m)
577{
578 if (g_imei_good) {
579 memcpy(m->s, g_imei.s, sizeof(g_imei.s));
580 return m->s;
581 }
582
583 property_get(ML_IMEI_PROP, m->s, "000000000000000");
584 if (strcmp(m->s, "000000000000000")) {
585 memcpy(g_imei.s, m->s, sizeof(m->s));
586 g_imei_good = 1;
587 return m->s;
588 }
589 ml_log_info("IMEI not found\n");
590 return NULL;
591}
592
593/**
594* Receive boot sequence number
595* Based on static variable and file.
596*/
597int ml_get_boot_sequence(void)
598{
599 char boot_seq[10] = {0};
600 static int boot_seq_no = 0;
601
602 //If static value exist then return it
603 if (boot_seq_no)
604 return boot_seq_no;
605
606 //read sequnece number from property
607 property_get(ML_BOOTSEQ_PROP, boot_seq, "0");
608 boot_seq_no = (atoi(boot_seq) + 1) % 10000;
609
610 snprintf(boot_seq, sizeof(boot_seq), "%04d", boot_seq_no);
611 property_set(ML_BOOTSEQ_PROP, boot_seq);
612
613 return boot_seq_no;
614}
615
616char *ml_get_mseq(struct ml_mseq *m)
617{
618 int seq = 0;
619 struct ml_mseq tmp;
620
621 property_get(ML_MSEQ_PROP, m->s, "0000");
622
623 if (m->s)
624 seq = atoi(m->s);
625
626 snprintf(tmp.s, sizeof(tmp.s), "%04d", (seq + 1) % 10000);
627 property_set(ML_MSEQ_PROP, tmp.s);
628
629 return m->s;
630}
631
632char *ml_get_vers(struct ml_vers *m)
633{
634 char *ret;
635
636 if (g_vers_good) {
637 memcpy(m->s, g_vers.s, sizeof(g_vers.s));
638 return m->s;
639 }
640
641 ret = ml_file2str(ML_VERS_FNAME, m->s, sizeof(m->s), 0);
642
643 if (ret) {
644 memcpy(g_vers.s, m->s, sizeof(m->s));
645 g_vers_good = 1;
646 }
647
648 return ret;
649}
650
651char *ml_get_bld_vers(struct ml_bld_vers *m)
652{
653 struct ml_vers full_ver;
654 char *bld_num = NULL;
655 char *ver_num = NULL;
656
657 if (g_bld_vers_good) {
658 memcpy(m->s, g_bld_vers.s, sizeof(g_bld_vers.s));
659 return m->s;
660 }
661
662 ver_num = ml_get_vers(&full_ver);
663
664 /* check if full version exist */
665 if(!ver_num)
666 return NULL;
667
668 /* build number is xxxx in _branch_bldxxxx */
669 bld_num = strstr(ver_num, "_bld");
670
671 if (bld_num){
672 bld_num = bld_num + sizeof("_bld") - 1;
673 strncpy(m->s, bld_num, sizeof(m->s) - 1);
674 strncpy(g_bld_vers.s, bld_num, sizeof(g_bld_vers.s) - 1);
675 } else {
676 strcpy(m->s, "0000");
677 strcpy(g_bld_vers.s, "0000");
678 }
679
680 g_bld_vers_good = 1;
681
682 return m->s;
683}
684
685char *ml_get_cp_ver(struct ml_cp_ver *m)
686{
687 if (g_cp_ver_good) {
688 memcpy(m->s, g_cp_ver.s, sizeof(g_cp_ver.s));
689 return m->s;
690 }
691
692 property_get(ML_CP_VER_PROP, m->s, "000000");
693 if (strcmp(m->s, "000000")) {
694 memcpy(g_cp_ver.s, m->s, sizeof(m->s));
695 g_cp_ver_good = 1;
696 return m->s;
697 }
698 ml_log_info("CP_VER not found\n");
699 return NULL;
700}
701
702char *ml_update_imei(struct ml_imei *m)
703{
704 struct ml_imei imei;
705 char *ret;
706
707 if ((ret = ml_get_imei(&imei))) {
708 ml_log_info("IMEI: exists %s\n", imei.s);
709 return ret;
710 }
711
712 m->s[sizeof(m->s) - 1] = 0;
713
714 property_set(ML_IMEI_PROP, m->s);
715
716 memcpy(g_imei.s, m->s, sizeof(m->s));
717 g_imei_good = 1;
718 ml_log_info("IMEI: updated %s\n", m->s);
719 return m->s;
720}
721
722char *ml_update_cp_ver(struct ml_cp_ver *m)
723{
724 struct ml_cp_ver cp_ver;
725 char *ret;
726
727 if ((ret = ml_get_cp_ver(&cp_ver))) {
728 ml_log_info("CP_VER: exists %s\n", cp_ver.s);
729 return ret;
730 }
731
732 m->s[sizeof(m->s) - 1] = 0;
733
734 property_set(ML_CP_VER_PROP, m->s);
735
736 memcpy(g_cp_ver.s, m->s, sizeof(m->s));
737 g_cp_ver_good = 1;
738 ml_log_info("CP_VER: updated %s\n", m->s);
739 return m->s;
740}
741
742char *ml_extract_cp_from_full_vers(void)
743{
744 struct ml_vers full_ver;
745 struct ml_cp_ver cp_ver;
746 int i = 0;
747 int cp_type = ml_get_property(ML_CP_TYPE_PROP);
748 char *str_tmp = ml_get_vers(&full_ver);
749 char *token = NULL;
750
751 if(!str_tmp)
752 return NULL;
753
754 while ((token=strsep(&str_tmp, "_"))&& (i < (cp_type+2)))
755 i++;
756
757 if(token)
758 strncpy(cp_ver.s, token, sizeof(cp_ver.s) - 1);
759
760 return ml_update_cp_ver(&cp_ver);
761}
762
763/**
764 * ************************************************************
765 * mll_string.c
766 * ************************************************************
767 */
768
769/**
770 * Trim leading and trailing whitespaces
771 *
772 * @param str string to modify
773 *
774 * @return pointer to in-place modified string
775 */
776char *ml_chomp(char *str)
777{
778 char *p = str;
779 int length;
780
781 if (!p || (length = strlen(p)) == 0)
782 return p;
783
784 // chomp space chars from end
785 while (length && isspace(p[length - 1])) {
786 p[--length] = 0;
787 }
788 // chomp space chars from start
789 while (*p && isspace(*p)) {
790 ++p;
791 --length;
792 }
793
794 memmove(str, p, length + 1);
795 return str;
796}
797
798void ml_pad_string(char pad, char *str, size_t len)
799{
800 size_t i;
801
802 if (!str)
803 return;
804
805 str[len - 1] = 0;
806 for (i = strlen(str); i < (len - 1); i++)
807 str[i] = pad;
808}
809
810/**
811 * ************************************************************
812 * mll_system.c
813 * ************************************************************
814 */
815
816static void ml_child(char *cmd)
817{
818 char *argv[4];
819
820 if (!cmd) {
821 ml_log_info("Got empty cmd line\n");
822 exit(-1);
823 }
824
825 argv[0] = "sh";
826 argv[1] = "-c";
827 argv[2] = cmd;
828 argv[3] = NULL;
829
830 if (execvp(argv[0], argv)) {
831 ml_log_info("executing %s failed: %s\n", argv[0], strerror(errno));
832 exit(-1);
833 }
834}
835
836int ml_system_retry(int max_tries, int timeout, char *cmd)
837{
838 int ret = -1, i = 0, tries = max_tries > 0 ? max_tries : 1;
839
840 while (ret != 0 && i++ < tries) {
841 ret = ml_system(timeout, cmd);
842 }
843 return ret;
844}
845
846int ml_system(int timeout, char *cmd)
847{
848 int timo, status = 0xAAAA, i, ret = -1, forced_kill = 0;
849 struct sysinfo info1, info2;
850 pid_t end_pid, child_pid;
851 char pdetails[64], edt[192], strerr[128];
852
853 timo = (timeout < 1 || timeout > ML_SYSTEM_MAX_TIMEOUT) ? ML_SYSTEM_MAX_TIMEOUT : timeout;
854
855 //sprintf(pdetails, "[%d:%d]", getpid(), gettid());
856 sprintf(pdetails, "[%d]", getpid());
857 if (!cmd) {
858 ml_log_info("%s Got empty cmd line\n", pdetails);
859 return -1;
860 }
861 info1.uptime = info2.uptime = 0;
862
863 ml_log_info("%s cmdstart (timo %d sec): ==%s==\n", pdetails, timo, cmd);
864 sysinfo(&info1);
865 child_pid = fork();
866 if (child_pid < 0) {
867 ml_log_info("%s Failed to fork\n", pdetails);
868 } else if (child_pid == 0) {
869 ml_child(cmd);
870 }
871
872 for (i = 0; i <= timo; i++) {
873 while ((end_pid = waitpid(child_pid, &status, WNOHANG | WUNTRACED)) == -1 && errno == EINTR) {
874 /*signal interrupt */ };
875
876 if (end_pid == 0) { /* child still running */
877 if (i < timo) {
878 sleep(1);
879 continue;
880 }
881 /*Force sub-process shutdown */
882 kill(child_pid, SIGKILL);
883 forced_kill = 1;
884 while ((end_pid = wait(&status)) == -1 && errno == EINTR) {
885 /*signal interrupt */ };
886 }
887 if (end_pid == -1) { /* error calling waitpid */
888 strerror_r(errno, strerr, sizeof(strerr));
889 snprintf(edt, sizeof(edt), "waitpid() fail: %s (%d)", strerr, errno);
890 break;
891 }
892
893 /* child ended */
894 if (WIFEXITED(status)) {
895 snprintf(edt, sizeof(edt), "terminated by exit(%d)", WEXITSTATUS(status));
896 ret = WEXITSTATUS(status) ? -1 : 0;
897 break;
898 }
899 if (WIFSIGNALED(status)) {
900 snprintf(edt, sizeof(edt), "terminated by signal %d", WTERMSIG(status));
901 break;
902 }
903 if (WIFSTOPPED(status)) {
904 snprintf(edt, sizeof(edt), "stopped by signal %d", WSTOPSIG(status));
905 break;
906 }
907 }
908
909 sysinfo(&info2);
910 i = (int)(info2.uptime - info1.uptime);
911 ml_log_info("%s cmdend: %s (%s) : %d seconds\n", pdetails, edt, forced_kill ? "forced_kill":"self exited", i ? i : 1);
912 return ret;
913}
914
915/* Check if path exist, return 1 if path exist */
916int ml_check_path(const char* path, int r, int w)
917{
918 int mode = 0;
919
920 if (r)
921 mode |= R_OK;
922 if (w)
923 mode |= W_OK;
924
925 if (access(path, mode)){
926 ml_log_error("Can't access %s. %s\n", path, strerror(errno));
927 return 0;
928 }
929
930 return 1;
931}
932
933/* Check if directory exist, and create it if not, return 1 for success */
934int ml_dir_update(char *dir2add)
935{
936 struct stat buf;
937
938 if (stat(dir2add, &buf) != 0) {
939 if (mkdir(dir2add, 0777) != 0) {
940 ml_log_error("Failed to mkdir %s. %s\n", dir2add, strerror(errno));
941 return 0;
942 }
943 }
944
945 return 1;
946}
947
948/**
949 * ************************************************************
950 * mll_log.c
951 * ************************************************************
952 */
953
954pthread_mutex_t mll_log_plock = PTHREAD_MUTEX_INITIALIZER;
955
956int ml_max_log = ML_LOG_INFO;
957
958extern int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
959
960void ml_set_log_level(int logLevel)
961{
962 ml_max_log = logLevel;
963}
964
965int ml_get_log_level()
966{
967 return ml_max_log;
968}
969
970static void ml_sout(FILE * fout, char *buf)
971{
972 if (!fout)
973 return;
974 fwrite(buf, strlen(buf) + 1, 1, fout);
975}
976
977static struct {
978 char *tag;
979 char buf[32];
980} ltag = {
981 .tag = 0,.buf = {
982 0}
983};
984
985char *ml_get_local_tag()
986{
987 FILE *f;
988
989 if (ltag.tag)
990 return ltag.tag;
991
992 pthread_mutex_lock(&mll_log_plock);
993 if ((f = fopen("/proc/self/status", "r")) == NULL)
994 goto done;
995
996 if (1 != fscanf(f, "Name: %s", ltag.buf))
997 goto done;
998
999 ltag.tag = ltag.buf;
1000
1001done:
1002 pthread_mutex_unlock(&mll_log_plock);
1003 if (!ltag.tag)
1004 return "ML_LOG";
1005 return ltag.tag;
1006}
1007
1008void ml_log(int dest, int level, const char *tag, const char *fmt, ...)
1009{
1010 va_list vl;
1011 char buf[1024];
1012 size_t buf_size;
1013
1014 if (!tag)
1015 tag = ml_get_local_tag();
1016
1017 va_start(vl, fmt);
1018 buf_size = vsnprintf(buf, 1024, fmt, vl);
1019 va_end(vl);
1020
1021 if (dest & MLL_LOGCAT)
1022 __android_log_printf(LOG_ID_RADIO, level, buf);
1023
1024 if (dest & MLL_KMSG) {
1025 static int dev_kmsg = -1;
1026 pthread_mutex_lock(&mll_log_plock);
1027 if (dev_kmsg < 0)
1028 dev_kmsg = open("/dev/kmsg", O_RDWR | O_SYNC);
1029 if (dev_kmsg >= 0) {
1030 buf[buf_size] = '\0';
1031 write(dev_kmsg, buf, buf_size);
1032 }
1033 pthread_mutex_unlock(&mll_log_plock);
1034 }
1035
1036 if (dest & MLL_CONSOLE) {
1037 static FILE *dev_console = NULL;
1038 pthread_mutex_lock(&mll_log_plock);
1039 if (!dev_console)
1040 dev_console = fopen("/dev/console", "w");
1041 ml_sout(dev_console, buf);
1042 pthread_mutex_unlock(&mll_log_plock);
1043 }
1044
1045 if (dest & MLL_STDERR) {
1046 pthread_mutex_lock(&mll_log_plock);
1047 ml_sout(stderr, buf);
1048 pthread_mutex_unlock(&mll_log_plock);
1049 }
1050}
1051
1052/**
1053 * ************************************************************
1054 * mll_fifo.c
1055 * ************************************************************
1056 */
1057
1058int ml_mounted_update(char *mountdir, char *dir2add)
1059{
1060 char line[128 * 3], dev[128], dir[128];
1061 struct stat buf;
1062 FILE *filed;
1063 int ret = 0;
1064
1065 if (!mountdir) {
1066 ml_log_error("no param supplied\n");
1067 return 0;
1068 }
1069
1070 filed = fopen("/proc/mounts", "r");
1071 if (!filed) {
1072 ml_log_error("Failed open %s %s \n", "/proc/mounts", strerror(errno));
1073 exit(1);
1074 }
1075 while (fgets(line, sizeof(line), filed)) {
1076 if (sscanf(line, "%128s %128s", dev, dir) < 2)
1077 continue;
1078
1079 if (strcmp(mountdir, dir) != 0)
1080 continue;
1081
1082 if (!dir2add) {
1083 ret = 1;
1084 break;
1085 }
1086
1087 if (stat(dir2add, &buf) != 0) {
1088 if (mkdir(dir2add, 0777) != 0) {
1089 ml_log_error("Failed to mkdir %s. %s\n", dir2add, strerror(errno));
1090 break;
1091 }
1092 } else if (!S_ISDIR(buf.st_mode)) {
1093 ml_log_error("Gen failure %s is not directory.\n", dir2add);
1094 break;
1095 }
1096 ret = 1;
1097 break;
1098 }
1099
1100 fclose(filed);
1101 return ret;
1102}
1103
1104int ml_create_fifo(struct ml_fifo *fifo)
1105{
1106 int ret, retries;
1107 struct stat buf;
1108
1109 ret = mkfifo(fifo->fname, 0666);
1110 if (ret != 0) {
1111 if (errno == EEXIST) {
1112 if (stat(fifo->fname, &buf) != 0 || !S_ISFIFO(buf.st_mode)) {
1113 ml_log_error("%s is not fifo\n", fifo->fname);
1114 return -1;
1115 }
1116 } else {
1117 ml_log_error("fifo not created %s\n", strerror(errno));
1118 return -1;
1119 }
1120 }
1121 retries = 5;
1122 /* Hold two open file descriptors on FIFO for select() to work correctly */
1123 while ((fifo->fdr = open(fifo->fname, O_RDONLY | O_NONBLOCK)) == -1) {
1124 if (errno == EINTR && --retries > 0)
1125 continue;
1126 ml_log_error("failed open %s %s\n", fifo->fname, strerror(errno));
1127 return -1;
1128 }
1129 retries = 5;
1130 while ((fifo->fdw = open(fifo->fname, O_WRONLY | O_NONBLOCK)) == -1) {
1131 if (errno == EINTR && --retries > 0)
1132 continue;
1133 close(fifo->fdr);
1134 ml_log_error("failed open %s %s\n", fifo->fname, strerror(errno));
1135 return -1;
1136 }
1137 return 0;
1138}
1139
1140int ml_flock(int fd, char *fname, int mode)
1141{
1142 int retries = 5, ret;
1143
1144 while (1) {
1145 ret = flock(fd, mode);
1146 if (ret == 0)
1147 return 0;
1148 if (errno == EINTR && --retries > 0)
1149 continue;
1150 ml_log_error("failed flock [%d %s mode %d] on %s\n", fd, fname, mode, strerror(errno));
1151 break;
1152 }
1153 return -1;
1154}
1155
1156int ml_write_fifo(struct ml_fifo *fifo, char *str, int len)
1157{
1158 int retries = 5;
1159 char *sstr = str;
1160 size_t slen = len;
1161 ssize_t rlen = 0;
1162
1163 retries = 5;
1164
1165 ml_flock(fifo->fdw, fifo->fname, LOCK_EX);
1166 do {
1167 rlen = write(fifo->fdw, str, len);
1168 if (rlen >= 0) {
1169 sstr += rlen;
1170 slen -= rlen;
1171 } else {
1172 if (errno == EINTR && --retries > 0)
1173 continue;
1174 ml_log_error("failed write to %s %s\n", fifo->fname, strerror(errno));
1175 break;
1176 }
1177 } while (rlen > 0 && slen > 0);
1178
1179 fflush(NULL);
1180 ml_flock(fifo->fdw, fifo->fname, LOCK_UN);
1181 /* should be 0 if all written OK */
1182 rlen = len - slen;
1183 if (!rlen) {
1184 ml_log_error("data not written ok to %s - %d/%d bytes written\n", fifo->fname, (int)rlen, (int)len);
1185 }
1186 return rlen;
1187}
1188
1189char *ml_read_fifo(struct ml_fifo *fifo, char *str, int len, struct timeval *timeout)
1190{
1191 fd_set set;
1192 struct timeval tm = *timeout;
1193 char tmp[1], *sstr = str;
1194 size_t slen = len;
1195 ssize_t rlen = 0;
1196 int ret;
1197
1198 while (1) {
1199 FD_ZERO(&set);
1200 FD_SET(fifo->fdr, &set);
1201
1202 ret = select(fifo->fdr + 1, &set, NULL, NULL, &tm);
1203 if (ret < 0) {
1204 if (errno != EINTR) {
1205 ml_log_error("select failed with '%s'\n", strerror(errno));
1206 exit(1);
1207 }
1208 continue;
1209 }
1210 if (ret == 0) {
1211 /*timeout */
1212 return NULL;
1213 }
1214
1215 rlen = read(fifo->fdr, tmp, 1);
1216 if (rlen > 0) {
1217 *sstr = *tmp;
1218
1219 if (*tmp == '\0' || *tmp == '\n' || *tmp == '\r') {
1220 *sstr = '\0';
1221 return str;
1222 } else {
1223 sstr += rlen;
1224 slen -= rlen;
1225 }
1226 } else {
1227 ml_log_error("read interrupted ? '%s'\n", strerror(errno));
1228 continue;
1229 }
1230 if (slen < 2) {
1231 ml_log_error("Message to big '%s'\n", str);
1232 *str = 0;
1233 return NULL;
1234 }
1235 }
1236
1237 return str;
1238}
1239